diff --git a/Documentation/build.py b/Documentation/build.py
index 55ab5ff0301..df252b054f8 100644
--- a/Documentation/build.py
+++ b/Documentation/build.py
@@ -131,6 +131,9 @@ class CommonExampleInfo(ExampleInfo):
print(f.name)
if (f.name != "README.md"): shutil.copy(f, here) # Workaround for https://github.com/mkdocs/mkdocs/issues/3313
+(here / "Libraries" / "CLI").mkdir(exist_ok=True)
+shutil.copy(Path("Libraries") / "CLI" / "README.md", here / "Libraries" / "CLI" / "README.md") # TODO: Less hard-coded way of pulling these in
+
# String replace "##__EXAMPLES_LIST__##" with autogenerated tables
# Note: We use the copy for the site build in the Documentation folder so that the
# tracked "source" doc in the root of the repo is unmodified.
diff --git a/Examples/MAX78000/SDHC_FTHR/.cproject b/Examples/MAX78000/SDHC_FTHR/.cproject
index b001f11bddc..c54b0386416 100644
--- a/Examples/MAX78000/SDHC_FTHR/.cproject
+++ b/Examples/MAX78000/SDHC_FTHR/.cproject
@@ -32,8 +32,9 @@
-
-
+
+
+
diff --git a/Examples/MAX78000/SDHC_FTHR/.vscode/settings.json b/Examples/MAX78000/SDHC_FTHR/.vscode/settings.json
index 481e754a7c2..bbd64a08f3d 100755
--- a/Examples/MAX78000/SDHC_FTHR/.vscode/settings.json
+++ b/Examples/MAX78000/SDHC_FTHR/.vscode/settings.json
@@ -54,7 +54,8 @@
"${config:MAXIM_PATH}/Libraries/MiscDrivers/PushButton",
"${config:MAXIM_PATH}/Libraries/MiscDrivers/Touchscreen",
"${config:MAXIM_PATH}/Libraries/SDHC/Include",
- "${config:MAXIM_PATH}/Libraries/SDHC/ff14/Source"
+ "${config:MAXIM_PATH}/Libraries/SDHC/ff13/Source",
+ "${config:MAXIM_PATH}/Libraries/CLI/inc"
],
"C_Cpp.default.browse.path": [
"${workspaceFolder}",
@@ -68,7 +69,8 @@
"${config:MAXIM_PATH}/Libraries/MiscDrivers/PushButton",
"${config:MAXIM_PATH}/Libraries/MiscDrivers/Touchscreen",
"${config:MAXIM_PATH}/Libraries/MiscDrivers",
- "${config:MAXIM_PATH}/Libraries/SDHC/ff14/Source"
+ "${config:MAXIM_PATH}/Libraries/SDHC/ff13/Source",
+ "${config:MAXIM_PATH}/Libraries/CLI/src"
],
"C_Cpp.default.defines": [
diff --git a/Examples/MAX78000/SDHC_FTHR/README.md b/Examples/MAX78000/SDHC_FTHR/README.md
index 9931a3c7bd5..4bbf3354c77 100644
--- a/Examples/MAX78000/SDHC_FTHR/README.md
+++ b/Examples/MAX78000/SDHC_FTHR/README.md
@@ -1,5 +1,7 @@
## Description
+This example demonstrates the SDHC FAT Filesystem. The terminal prompts with a list of user-selectable tasks to run on the inserted Micro SD Card.
+
## Software
### Project Usage
@@ -8,4 +10,149 @@ Universal instructions on building, flashing, and debugging this project can be
### Project-Specific Build Notes
-* This project comes pre-configured for the MAX78000EVKIT. See [Board Support Packages](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#board-support-packages) in the UG for instructions on changing the target board.
\ No newline at end of file
+* This project comes pre-configured for the MAX78000FTHR. See [Board Support Packages](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#board-support-packages) in the UG for instructions on changing the target board.
+
+## Required Connections
+
+- Connect a USB cable between the PC and the CN1 (USB/PWR) connector.
+- Open a terminal application on the PC and connect to the EV kit's console UART at 115200, 8-N-1.
+- Insert the SD card into the Micro SD Card Connector.
+
+## Expected Output
+
+```
+***** MAX78000 SDHC FAT Filesystem Example *****
+Card inserted.
+CLI Initialized! Enter 'help' to see a list of available commands.
+
+$ help
+help
+
+size:
+ Usage: size
+ Description: Find the Size of the SD Card and Free Space
+
+format:
+ Usage: format
+ Description: Format the Card
+
+mount:
+ Usage: mount
+ Description: Manually Mount Card
+
+ls:
+ Usage: ls
+ Description: list the contents of the current directory
+
+mkdir:
+ Usage: mkdir
+ Description: Create a directory
+
+file_create:
+ Usage: file_create
+ Description: Create a file of random data
+
+cd:
+ Usage: cd
+ Description: Move into a directory
+
+add_data:
+ Usage: add_data
+ Description: Add random Data to an Existing File
+
+del:
+ Usage: del
+ Description: Delete a file
+
+fatfs:
+ Usage: fatfs
+ Description: Format Card and Run Example of FatFS Operations
+
+unmount:
+ Usage: unmount
+ Description: Unmount card
+
+
+$ format
+format
+
+
+*****THE DRIVE WILL BE FORMATTED IN 5 SECONDS*****
+**************PRESS ANY KEY TO ABORT**************
+
+FORMATTING DRIVE
+Drive formatted.
+SD card mounted.
+SD card unmounted.
+
+$ size
+size
+SD card mounted.
+Disk Size: 7760896 bytes
+Available: 7760864 bytes
+
+$ mount
+mount
+SD card mounted.
+
+$ mkdir Analog_Devices
+mkdir Analog_Devices
+Creating directory...
+Directory Analog_Devices created.
+
+$ cd Analog_Devices
+cd Analog_Devices
+Changed to Analog_Devices
+
+$ file_create ADI 30
+file_create ADI 30
+Creating file ADI with length 30
+File opened!
+30 bytes written to file!
+File Closed!
+
+$ add_data ADI 25
+add_data ADI 25
+File opened!
+25 bytes written to file
+File closed.
+
+$ ls
+ls
+Listing Contents of 0:/Analog_Devices -
+0:/Analog_Devices/ADI
+
+Finished listing contents
+
+$ del ADI
+del ADI
+Deleted file ADI
+
+$ fatfs
+fatfs
+
+
+*****THE DRIVE WILL BE FORMATTED IN 5 SECONDS*****
+**************PRESS ANY KEY TO ABORT**************
+
+FORMATTING DRIVE
+Drive formatted.
+SD card mounted.
+SD card unmounted.
+SD card mounted.
+SD Card Opened!
+File opened!
+256 bytes written to file!
+File Closed!
+Creating Directory...
+Renaming File...
+Attempting to read back file...
+Read Back 256 bytes
+Message: sjVNXdwfl-owoXGcTZ,5z,Sy8lfsNqDGrzio'O6vntRMoWODcIKP!C'y7tF.'W88ZjR81BpiibPhokQfa3w'cvmnr0EgE1MNDIhXKfBJGP6b?0tvHEPK-WNc7yuPdFNL6FPq10',Q,GSf3jSyY?MU0wv'FToTI!ct.E6Q4nbVuavg6h'48D5sR5mcepxf1l!MesddI7aZ9s?KIVnybRwZ.UBJpX1b?5oXP9wLKZcgW-k,gZ5HMIMwAcy!n9S?E57Analog_Devices
+File Closed!
+
+$ unmount
+unmount
+SD card unmounted.
+```
+
diff --git a/Examples/MAX78000/SDHC_FTHR/include/sdhc.h b/Examples/MAX78000/SDHC_FTHR/include/sdhc.h
new file mode 100644
index 00000000000..0ed2f804344
--- /dev/null
+++ b/Examples/MAX78000/SDHC_FTHR/include/sdhc.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+#ifndef EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_SDHC_H_
+#define EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_SDHC_H_
+
+/***** Includes *****/
+#include
+#include
+#include
+#include
+
+#include "board.h"
+#include "mxc_delay.h"
+#include "mxc_device.h"
+#include "gpio.h"
+#include "uart.h"
+#include "ff.h"
+
+/***** Definitions *****/
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define MAXLEN 256
+
+/***** FUNCTION PROTOTYPES *****/
+
+void generateMessage(unsigned length);
+
+int mount();
+
+int umount();
+
+int formatSDHC();
+
+int getSize();
+
+int ls();
+
+int createFile(char *file_name, unsigned int length);
+
+int appendFile(char *file_name, unsigned int length);
+
+int mkdir(char *dir_name);
+
+int cd(char *dir_name);
+
+int deleteFile(char *file_name);
+
+int example();
+
+void waitCardInserted();
+
+#endif // EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_SDHC_H_
diff --git a/Examples/MAX78000/SDHC_FTHR/include/user-cli.h b/Examples/MAX78000/SDHC_FTHR/include/user-cli.h
new file mode 100644
index 00000000000..ecb8850eab8
--- /dev/null
+++ b/Examples/MAX78000/SDHC_FTHR/include/user-cli.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+#ifndef EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_USER_CLI_H_
+#define EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_USER_CLI_H_
+
+/* -------------------------------------------------- */
+// GLOBAL VARIABLE
+/* -------------------------------------------------- */
+extern const command_t user_commands[];
+extern const unsigned int num_user_commands;
+
+/* -------------------------------------------------- */
+// FUNCTION PROTOTYPES
+/* -------------------------------------------------- */
+int handle_size(int argc, char *argv[]);
+
+int handle_format(int argc, char *argv[]);
+
+int handle_mount(int argc, char *argv[]);
+
+int handle_ls(int argc, char *argv[]);
+
+int handle_mkdir(int argc, char *argv[]);
+
+int handle_createfile(int argc, char *argv[]);
+
+int handle_cd(int argc, char *argv[]);
+
+int handle_add_data(int argc, char *argv[]);
+
+int handle_del(int argc, char *argv[]);
+
+int handle_fatfs(int argc, char *argv[]);
+
+int handle_unmount(int argc, char *argv[]);
+
+#endif // EXAMPLES_MAX78000_SDHC_FTHR_INCLUDE_USER_CLI_H_
diff --git a/Examples/MAX78000/SDHC_FTHR/main.c b/Examples/MAX78000/SDHC_FTHR/main.c
index 5216dc9ed1a..fb72a39f3e7 100644
--- a/Examples/MAX78000/SDHC_FTHR/main.c
+++ b/Examples/MAX78000/SDHC_FTHR/main.c
@@ -36,628 +36,42 @@
* @brief read and write sdhc
* @details This example uses the sdhc and ffat to read/write the file system on
* an SD card. The Fat library used supports long filenames (see ffconf.h)
- * the max length is 256 characters.
+ * the max length is 256 characters. It uses the CLI library for taking user
+ * user commands.
*
* You must connect an sd card to the sd card slot.
*/
/***** Includes *****/
-#include
-#include
-#include
-#include
-
#include "board.h"
-#include "mxc_delay.h"
-#include "mxc_device.h"
-#include "gpio.h"
+#include "cli.h"
+#include "nvic_table.h"
+#include "sdhc.h"
#include "uart.h"
-
-#include "ff.h"
+#include "user-cli.h"
#ifdef BOARD_EVKIT_V1
#warning This example is not supported by the MAX78000EVKIT.
#endif
-/***** Definitions *****/
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-
-#define MAXLEN 256
-
-/***** Globals *****/
-FATFS *fs; //FFat Filesystem Object
-FATFS fs_obj;
-FIL file; //FFat File Object
-FRESULT err; //FFat Result (Struct)
-FILINFO fno; //FFat File Information Object
-DIR dir; //FFat Directory Object
-TCHAR message[MAXLEN], directory[MAXLEN], cwd[MAXLEN], filename[MAXLEN], volume_label[24],
- volume = '0';
-TCHAR *FF_ERRORS[20];
-DWORD clusters_free = 0, sectors_free = 0, sectors_total = 0, volume_sn = 0;
-UINT bytes_written = 0, bytes_read = 0, mounted = 0;
-BYTE work[4096];
-static char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-#'?!";
-mxc_gpio_cfg_t SDPowerEnablePin = { MXC_GPIO1, MXC_GPIO_PIN_12, MXC_GPIO_FUNC_OUT,
- MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO };
-
-/***** FUNCTIONS *****/
-
-void generateMessage(unsigned length)
-{
- for (int i = 0; i < length; i++) {
- /*Generate some random data to put in file*/
- message[i] = charset[rand() % (sizeof(charset) - 1)];
- }
-}
-
-int mount()
-{
- fs = &fs_obj;
-
- if ((err = f_mount(fs, "", 1)) != FR_OK) { //Mount the default drive to fs now
- printf("Error opening SD card: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- } else {
- printf("SD card mounted.\n");
- mounted = 1;
- }
-
- f_getcwd(cwd, sizeof(cwd)); //Set the Current working directory
-
- return err;
-}
-
-int umount()
-{
- if ((err = f_mount(NULL, "", 0)) != FR_OK) { //Unmount the default drive from its mount point
- printf("Error unmounting volume: %s\n", FF_ERRORS[err]);
- } else {
- printf("SD card unmounted.\n");
- mounted = 0;
- }
-
- return err;
-}
-
-int formatSDHC()
-{
- printf("\n\n*****THE DRIVE WILL BE FORMATTED IN 5 SECONDS*****\n");
- printf("**************PRESS ANY KEY TO ABORT**************\n\n");
- MXC_UART_ClearRXFIFO(MXC_UART0);
- MXC_Delay(MSEC(5000));
-
- if (MXC_UART_GetRXFIFOAvailable(MXC_UART0) > 0) {
- return E_ABORT;
- }
-
- printf("FORMATTING DRIVE\n");
-
- if ((err = f_mkfs("", FM_ANY, 0, work, sizeof(work))) !=
- FR_OK) { //Format the default drive to FAT32
- printf("Error formatting SD card: %s\n", FF_ERRORS[err]);
- } else {
- printf("Drive formatted.\n");
- }
-
- mount();
-
- if ((err = f_setlabel("MAXIM")) != FR_OK) {
- printf("Error setting drive label: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- }
-
- umount();
-
- return err;
-}
-
-int getSize()
-{
- if (!mounted) {
- mount();
- }
-
- if ((err = f_getfree(&volume, &clusters_free, &fs)) != FR_OK) {
- printf("Error finding free size of card: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- }
-
- sectors_total = (fs->n_fatent - 2) * fs->csize;
- sectors_free = clusters_free * fs->csize;
-
- printf("Disk Size: %u bytes\n", sectors_total / 2);
- printf("Available: %u bytes\n", sectors_free / 2);
-
- return err;
-}
-
-int ls()
-{
- if (!mounted) {
- mount();
- }
-
- printf("Listing Contents of %s - \n", cwd);
-
- if ((err = f_opendir(&dir, cwd)) == FR_OK) {
- while (1) {
- err = f_readdir(&dir, &fno);
-
- if (err != FR_OK || fno.fname[0] == 0) {
- break;
- }
-
- printf("%s/%s", cwd, fno.fname);
-
- if (fno.fattrib & AM_DIR) {
- printf("/");
- }
-
- printf("\n");
- }
-
- f_closedir(&dir);
- } else {
- printf("Error opening directory!\n");
- return err;
- }
-
- printf("\nFinished listing contents\n");
-
- return err;
-}
-
-int createFile()
-{
- unsigned int length = 128;
-
- if (!mounted) {
- mount();
- }
-
- printf("Enter the name of the text file: \n");
- scanf("%255s", filename);
- printf("Enter the length of the file: (%d max)\n", MAXLEN);
- scanf("%d", &length);
-
- if (length > MAXLEN) {
- printf("Error. File size limit for this example is %d bytes.\n", MAXLEN);
- return FR_INVALID_PARAMETER;
- }
-
- printf("Creating file %s with length %d\n", filename, length);
-
- if ((err = f_open(&file, (const TCHAR *)filename, FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
- printf("Error opening file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("File opened!\n");
-
- generateMessage(length);
-
- if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
- printf("Error writing file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("%d bytes written to file!\n", bytes_written);
-
- if ((err = f_close(&file)) != FR_OK) {
- printf("Error closing file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("File Closed!\n");
- return err;
-}
-
-int appendFile()
-{
- unsigned int length = 0;
-
- if (!mounted) {
- mount();
- }
-
- printf("Enter name of file to append: \n");
- scanf("%255s", filename);
- printf("Enter length of random data to append: (%d max)\n", MAXLEN);
- scanf("%d", &length);
-
- if ((err = f_stat((const TCHAR *)filename, &fno)) == FR_NO_FILE) {
- printf("File %s doesn't exist!\n", (const TCHAR *)filename);
- return err;
- }
-
- if (length > MAXLEN) {
- printf("Error. Size limit for this example is %d bytes.\n", MAXLEN);
- return FR_INVALID_PARAMETER;
- }
-
- if ((err = f_open(&file, (const TCHAR *)filename, FA_OPEN_APPEND | FA_WRITE)) != FR_OK) {
- printf("Error opening file %s\n", FF_ERRORS[err]);
- return err;
- }
-
- printf("File opened!\n");
-
- generateMessage(length);
-
- if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
- printf("Error writing file: %s\n", FF_ERRORS[err]);
- return err;
- }
-
- printf("%d bytes written to file\n", bytes_written);
-
- if ((err = f_close(&file)) != FR_OK) {
- printf("Error closing file: %s\n", FF_ERRORS[err]);
- return err;
- }
-
- printf("File closed.\n");
- return err;
-}
-
-int mkdir()
-{
- if (!mounted) {
- mount();
- }
-
- printf("Enter directory name: \n");
- scanf("%255s", directory);
-
- err = f_stat((const TCHAR *)directory, &fno);
-
- if (err == FR_NO_FILE) {
- printf("Creating directory...\n");
-
- if ((err = f_mkdir((const TCHAR *)directory)) != FR_OK) {
- printf("Error creating directory: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- } else {
- printf("Directory %s created.\n", directory);
- }
-
- } else {
- printf("Directory already exists.\n");
- }
-
- return err;
-}
-
-int cd()
-{
- if (!mounted) {
- mount();
- }
-
- printf("Directory to change into: \n");
- scanf("%255s", directory);
-
- if ((err = f_stat((const TCHAR *)directory, &fno)) == FR_NO_FILE) {
- printf("Directory doesn't exist (Did you mean mkdir?)\n");
- return err;
- }
-
- if ((err = f_chdir((const TCHAR *)directory)) != FR_OK) {
- printf("Error in chdir: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("Changed to %s\n", directory);
- f_getcwd(cwd, sizeof(cwd));
-
- return err;
-}
-
-int delete ()
-{
- if (!mounted) {
- mount();
- }
-
- printf("File or directory to delete (always recursive!)\n");
- scanf("%255s", filename);
-
- if ((err = f_stat((const TCHAR *)filename, &fno)) == FR_NO_FILE) {
- printf("File or directory doesn't exist\n");
- return err;
- }
-
- if ((err = f_unlink(filename)) != FR_OK) {
- printf("Error deleting file\n");
- return err;
- }
-
- printf("Deleted file %s\n", filename);
- return err;
-}
-
-int example()
-{
- unsigned int length = 256;
-
- if ((err = formatSDHC()) != FR_OK) {
- printf("Error Formatting SD Card: %s\n", FF_ERRORS[err]);
- return err;
- }
-
- //open SD Card
- if ((err = mount()) != FR_OK) {
- printf("Error opening SD Card: %s\n", FF_ERRORS[err]);
- return err;
- }
-
- printf("SD Card Opened!\n");
-
- if ((err = f_setlabel("MAXIM")) != FR_OK) {
- printf("Error setting drive label: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- if ((err = f_getfree(&volume, &clusters_free, &fs)) != FR_OK) {
- printf("Error finding free size of card: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- if ((err = f_getlabel(&volume, volume_label, &volume_sn)) != FR_OK) {
- printf("Error reading drive label: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- if ((err = f_open(&file, "0:HelloWorld.txt", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
- printf("Error opening file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("File opened!\n");
-
- generateMessage(length);
-
- if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
- printf("Error writing file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("%d bytes written to file!\n", bytes_written);
-
- if ((err = f_close(&file)) != FR_OK) {
- printf("Error closing file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("File Closed!\n");
-
- if ((err = f_chmod("HelloWorld.txt", 0, AM_RDO | AM_ARC | AM_SYS | AM_HID)) != FR_OK) {
- printf("Error in chmod: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- err = f_stat("MaximSDHC", &fno);
-
- if (err == FR_NO_FILE) {
- printf("Creating Directory...\n");
-
- if ((err = f_mkdir("MaximSDHC")) != FR_OK) {
- printf("Error creating directory: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
- }
-
- printf("Renaming File...\n");
-
- if ((err = f_rename("0:HelloWorld.txt", "0:MaximSDHC/HelloMaxim.txt")) !=
- FR_OK) { //cr: clearify 0:file notation
- printf("Error moving file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- if ((err = f_chdir("/MaximSDHC")) != FR_OK) {
- printf("Error in chdir: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("Attempting to read back file...\n");
-
- if ((err = f_open(&file, "HelloMaxim.txt", FA_READ)) != FR_OK) {
- printf("Error opening file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- if ((err = f_read(&file, &message, bytes_written, &bytes_read)) != FR_OK) {
- printf("Error reading file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("Read Back %d bytes\n", bytes_read);
- printf("Message: ");
- printf("%s", message);
- printf("\n");
-
- if ((err = f_close(&file)) != FR_OK) {
- printf("Error closing file: %s\n", FF_ERRORS[err]);
- f_mount(NULL, "", 0);
- return err;
- }
-
- printf("File Closed!\n");
-
- //unmount SD Card
- //f_mount(fs, "", 0);
- if ((err = f_mount(NULL, "", 0)) != FR_OK) {
- printf("Error unmounting volume: %s\n", FF_ERRORS[err]);
- return err;
- }
-
- return 0;
-}
-
-void waitCardInserted()
-{
- // On the MAX78000FTHR board, P0.12 will be pulled low when a card is inserted.
- mxc_gpio_cfg_t cardDetect;
- cardDetect.port = MXC_GPIO0;
- cardDetect.mask = MXC_GPIO_PIN_12;
- cardDetect.func = MXC_GPIO_FUNC_IN;
- cardDetect.pad = MXC_GPIO_PAD_NONE;
- cardDetect.vssel = MXC_GPIO_VSSEL_VDDIOH;
- cardDetect.drvstr = MXC_GPIO_DRVSTR_0;
-
- MXC_GPIO_Config(&cardDetect);
-
- // Exit function if card is already inserted
- if (MXC_GPIO_InGet(MXC_GPIO0, MXC_GPIO_PIN_12) == 0) {
- return;
- }
-
- printf("Insert SD card to continue.\n");
-
- while (MXC_GPIO_InGet(MXC_GPIO0, MXC_GPIO_PIN_12) != 0) {
- // Spin waiting for card to be inserted.
- }
-
- // Card has been detected, exit the function.
-}
-
/******************************************************************************/
int main(void)
{
- FF_ERRORS[0] = "FR_OK";
- FF_ERRORS[1] = "FR_DISK_ERR";
- FF_ERRORS[2] = "FR_INT_ERR";
- FF_ERRORS[3] = "FR_NOT_READY";
- FF_ERRORS[4] = "FR_NO_FILE";
- FF_ERRORS[5] = "FR_NO_PATH";
- FF_ERRORS[6] = "FR_INVLAID_NAME";
- FF_ERRORS[7] = "FR_DENIED";
- FF_ERRORS[8] = "FR_EXIST";
- FF_ERRORS[9] = "FR_INVALID_OBJECT";
- FF_ERRORS[10] = "FR_WRITE_PROTECTED";
- FF_ERRORS[11] = "FR_INVALID_DRIVE";
- FF_ERRORS[12] = "FR_NOT_ENABLED";
- FF_ERRORS[13] = "FR_NO_FILESYSTEM";
- FF_ERRORS[14] = "FR_MKFS_ABORTED";
- FF_ERRORS[15] = "FR_TIMEOUT";
- FF_ERRORS[16] = "FR_LOCKED";
- FF_ERRORS[17] = "FR_NOT_ENOUGH_CORE";
- FF_ERRORS[18] = "FR_TOO_MANY_OPEN_FILES";
- FF_ERRORS[19] = "FR_INVALID_PARAMETER";
- srand(12347439);
- int run = 1, input = -1;
-
- printf("\n\n***** " TOSTRING(TARGET) " SDHC FAT Filesystem Example *****\n");
+ int err;
+ printf("\n\n***** MAX78000 SDHC FAT Filesystem Example *****\n");
+ // Wait for SD Card to be inserted
waitCardInserted();
printf("Card inserted.\n");
+ while (MXC_UART_GetActive(MXC_UART_GET_UART(CONSOLE_UART))) {}
- while (run) {
- f_getcwd(cwd, sizeof(cwd));
-
- printf("\nChoose one of the following options: \n");
- printf("0. Find the Size of the SD Card and Free Space\n");
- printf("1. Format the Card\n");
- printf("2. Manually Mount Card\n");
- printf("3. List Contents of Current Directory\n");
- printf("4. Create a Directory\n");
- printf("5. Move into a Directory (cd)\n");
- printf("6. Create a File of Random Data\n");
- printf("7. Add Random Data to an Existing File\n");
- printf("8. Delete a File\n");
- printf("9. Format Card and Run Exmaple of FatFS Operations\n");
- printf("10. Unmount Card and Quit\n");
- printf("%s>>", cwd);
-
- input = -1;
- scanf("%d", &input);
- printf("%d\n", input);
-
- err = 0;
-
- switch (input) {
- case 0:
- getSize();
- break;
-
- case 1:
- formatSDHC();
- break;
-
- case 3:
- ls();
- break;
-
- case 6:
- createFile();
- break;
-
- case 7:
- appendFile();
- break;
-
- case 4:
- mkdir();
- break;
-
- case 5:
- cd();
- break;
-
- case 9:
- example();
- break;
-
- case 10:
- umount();
- run = 0;
- break;
-
- case 2:
- mount();
- break;
-
- case 8:
- delete ();
- break;
-
- default:
- printf("Invalid Selection %d!\n", input);
- err = -1;
- break;
- }
-
- if (err >= 0 && err <= 20) {
- printf("Function Returned with code: %s\n", FF_ERRORS[err]);
- } else {
- printf("Function Returned with code: %d\n", err);
- }
-
- MXC_Delay(MSEC(500));
+ // Initialize CLI
+ if ((err = MXC_CLI_Init(MXC_UART_GET_UART(CONSOLE_UART), user_commands, num_user_commands)) !=
+ E_NO_ERROR) {
+ return err;
}
- printf("End of example, please try to read the card.\n");
- return 0;
+ // Run CLI
+ while (1) {}
}
diff --git a/Examples/MAX78000/SDHC_FTHR/project.mk b/Examples/MAX78000/SDHC_FTHR/project.mk
index 08f6be48995..8b063ff751d 100644
--- a/Examples/MAX78000/SDHC_FTHR/project.mk
+++ b/Examples/MAX78000/SDHC_FTHR/project.mk
@@ -19,5 +19,8 @@ ifneq ($(BOARD),FTHR_RevA)
$(error ERR_NOTSUPPORTED: This project requires an SD card slot and is only supported for the MAX78000FTHR)
endif
+# Enable SDHC library
LIB_SDHC = 1
+# Enable CLI library
+LIB_CLI = 1
diff --git a/Examples/MAX78000/SDHC_FTHR/src/sdhc.c b/Examples/MAX78000/SDHC_FTHR/src/sdhc.c
new file mode 100644
index 00000000000..f842e42f69d
--- /dev/null
+++ b/Examples/MAX78000/SDHC_FTHR/src/sdhc.c
@@ -0,0 +1,500 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+
+#include "sdhc.h"
+
+/***** Globals *****/
+FATFS *fs; //FFat Filesystem Object
+FATFS fs_obj;
+FIL file; //FFat File Object
+FRESULT err; //FFat Result (Struct)
+FILINFO fno; //FFat File Information Object
+DIR dir; //FFat Directory Object
+TCHAR *FF_ERRORS[20];
+BYTE work[4096];
+
+DWORD clusters_free = 0, sectors_free = 0, sectors_total = 0, volume_sn = 0;
+UINT bytes_written = 0, bytes_read = 0, mounted = 0;
+
+static char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-#'?!";
+TCHAR message[MAXLEN], directory[MAXLEN], cwd[MAXLEN], filename[MAXLEN], volume_label[24],
+ volume = '0';
+mxc_gpio_cfg_t SDPowerEnablePin = { MXC_GPIO1, MXC_GPIO_PIN_12, MXC_GPIO_FUNC_OUT,
+ MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO };
+
+// /***** FUNCTIONS *****/
+
+void generateMessage(unsigned length)
+{
+ for (int i = 0; i < length; i++) {
+ /*Generate some random data to put in file*/
+ message[i] = charset[rand() % (sizeof(charset) - 1)];
+ }
+}
+
+int mount()
+{
+ fs = &fs_obj;
+
+ if ((err = f_mount(fs, "", 1)) != FR_OK) { //Mount the default drive to fs now
+ printf("Error opening SD card: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ } else {
+ printf("SD card mounted.\n");
+ mounted = 1;
+ }
+
+ f_getcwd(cwd, sizeof(cwd)); //Set the Current working directory
+
+ return err;
+}
+
+int umount()
+{
+ if ((err = f_mount(NULL, "", 0)) != FR_OK) { //Unmount the default drive from its mount point
+ printf("Error unmounting volume: %s\n", FF_ERRORS[err]);
+ } else {
+ printf("SD card unmounted.\n");
+ mounted = 0;
+ }
+
+ return err;
+}
+
+int formatSDHC()
+{
+ printf("\n\n*****THE DRIVE WILL BE FORMATTED IN 5 SECONDS*****\n");
+ printf("**************PRESS ANY KEY TO ABORT**************\n\n");
+ MXC_UART_ClearRXFIFO(MXC_UART0);
+ MXC_Delay(MSEC(5000));
+
+ if (MXC_UART_GetRXFIFOAvailable(MXC_UART0) > 0) {
+ return E_ABORT;
+ }
+
+ printf("FORMATTING DRIVE\n");
+
+ if ((err = f_mkfs("", FM_ANY, 0, work, sizeof(work))) !=
+ FR_OK) { //Format the default drive to FAT32
+ printf("Error formatting SD card: %s\n", FF_ERRORS[err]);
+ } else {
+ printf("Drive formatted.\n");
+ }
+
+ mount();
+
+ if ((err = f_setlabel("MAXIM")) != FR_OK) {
+ printf("Error setting drive label: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ }
+
+ umount();
+
+ return err;
+}
+
+int getSize()
+{
+ if (!mounted) {
+ mount();
+ }
+
+ if ((err = f_getfree(&volume, &clusters_free, &fs)) != FR_OK) {
+ printf("Error finding free size of card: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ }
+
+ sectors_total = (fs->n_fatent - 2) * fs->csize;
+ sectors_free = clusters_free * fs->csize;
+
+ printf("Disk Size: %u bytes\n", sectors_total / 2);
+ printf("Available: %u bytes\n", sectors_free / 2);
+
+ return err;
+}
+
+int ls()
+{
+ if (!mounted) {
+ mount();
+ }
+
+ printf("Listing Contents of %s - \n", cwd);
+
+ if ((err = f_opendir(&dir, cwd)) == FR_OK) {
+ while (1) {
+ err = f_readdir(&dir, &fno);
+
+ if (err != FR_OK || fno.fname[0] == 0) {
+ break;
+ }
+
+ printf("%s/%s", cwd, fno.fname);
+
+ if (fno.fattrib & AM_DIR) {
+ printf("/");
+ }
+
+ printf("\n");
+ }
+
+ f_closedir(&dir);
+ } else {
+ printf("Error opening directory!\n");
+ return err;
+ }
+
+ printf("\nFinished listing contents\n");
+
+ return err;
+}
+
+int createFile(char *file_name, unsigned int length)
+{
+ // unsigned int length = 128;
+
+ if (!mounted) {
+ mount();
+ }
+
+ snprintf(filename, MAXLEN, "%s", file_name);
+
+ if (length > MAXLEN) {
+ printf("Error. File size limit for this example is %d bytes.\n", MAXLEN);
+ return FR_INVALID_PARAMETER;
+ }
+
+ printf("Creating file %s with length %d\n", filename, length);
+
+ if ((err = f_open(&file, (const TCHAR *)filename, FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
+ printf("Error opening file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("File opened!\n");
+
+ generateMessage(length);
+
+ if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
+ printf("Error writing file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("%d bytes written to file!\n", bytes_written);
+
+ if ((err = f_close(&file)) != FR_OK) {
+ printf("Error closing file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("File Closed!\n");
+ return err;
+}
+
+int appendFile(char *file_name, unsigned int length)
+{
+ if (!mounted) {
+ mount();
+ }
+
+ snprintf(filename, MAXLEN, "%s", file_name);
+
+ if ((err = f_stat((const TCHAR *)filename, &fno)) == FR_NO_FILE) {
+ printf("File %s doesn't exist!\n", (const TCHAR *)filename);
+ return err;
+ }
+
+ if (length > MAXLEN) {
+ printf("Error. Size limit for this example is %d bytes.\n", MAXLEN);
+ return FR_INVALID_PARAMETER;
+ }
+
+ if ((err = f_open(&file, (const TCHAR *)filename, FA_OPEN_APPEND | FA_WRITE)) != FR_OK) {
+ printf("Error opening file %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ printf("File opened!\n");
+
+ generateMessage(length);
+
+ if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
+ printf("Error writing file: %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ printf("%d bytes written to file\n", bytes_written);
+
+ if ((err = f_close(&file)) != FR_OK) {
+ printf("Error closing file: %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ printf("File closed.\n");
+ return err;
+}
+
+int mkdir(char *dir_name)
+{
+ if (!mounted) {
+ mount();
+ }
+
+ snprintf(directory, MAXLEN, "%s", dir_name);
+
+ err = f_stat((const TCHAR *)directory, &fno);
+
+ if (err == FR_NO_FILE) {
+ printf("Creating directory...\n");
+
+ if ((err = f_mkdir((const TCHAR *)directory)) != FR_OK) {
+ printf("Error creating directory: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ } else {
+ printf("Directory %s created.\n", directory);
+ }
+
+ } else {
+ printf("Directory already exists.\n");
+ }
+
+ return err;
+}
+
+int cd(char *dir_name)
+{
+ if (!mounted) {
+ mount();
+ }
+
+ snprintf(directory, MAXLEN, "%s", dir_name);
+
+ if ((err = f_stat((const TCHAR *)directory, &fno)) == FR_NO_FILE) {
+ printf("Directory doesn't exist (Did you mean mkdir?)\n");
+ return err;
+ }
+
+ if ((err = f_chdir((const TCHAR *)directory)) != FR_OK) {
+ printf("Error in chdir: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("Changed to %s\n", directory);
+ f_getcwd(cwd, sizeof(cwd));
+
+ return err;
+}
+
+int deleteFile(char *file_name)
+{
+ if (!mounted) {
+ mount();
+ }
+
+ snprintf(filename, MAXLEN, "%s", file_name);
+
+ if ((err = f_stat((const TCHAR *)filename, &fno)) == FR_NO_FILE) {
+ printf("File or directory doesn't exist\n");
+ return err;
+ }
+
+ if ((err = f_unlink(filename)) != FR_OK) {
+ printf("Error deleting file\n");
+ return err;
+ }
+
+ printf("Deleted file %s\n", filename);
+ return err;
+}
+
+int example()
+{
+ unsigned int length = 256;
+
+ if ((err = formatSDHC()) != FR_OK) {
+ printf("Error Formatting SD Card: %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ //open SD Card
+ if ((err = mount()) != FR_OK) {
+ printf("Error opening SD Card: %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ printf("SD Card Opened!\n");
+
+ if ((err = f_setlabel("MAXIM")) != FR_OK) {
+ printf("Error setting drive label: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ if ((err = f_getfree(&volume, &clusters_free, &fs)) != FR_OK) {
+ printf("Error finding free size of card: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ if ((err = f_getlabel(&volume, volume_label, &volume_sn)) != FR_OK) {
+ printf("Error reading drive label: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ if ((err = f_open(&file, "0:HelloWorld.txt", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
+ printf("Error opening file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("File opened!\n");
+
+ generateMessage(length);
+
+ if ((err = f_write(&file, &message, length, &bytes_written)) != FR_OK) {
+ printf("Error writing file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("%d bytes written to file!\n", bytes_written);
+
+ if ((err = f_close(&file)) != FR_OK) {
+ printf("Error closing file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("File Closed!\n");
+
+ if ((err = f_chmod("HelloWorld.txt", 0, AM_RDO | AM_ARC | AM_SYS | AM_HID)) != FR_OK) {
+ printf("Error in chmod: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ err = f_stat("MaximSDHC", &fno);
+
+ if (err == FR_NO_FILE) {
+ printf("Creating Directory...\n");
+
+ if ((err = f_mkdir("MaximSDHC")) != FR_OK) {
+ printf("Error creating directory: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+ }
+
+ printf("Renaming File...\n");
+
+ if ((err = f_rename("0:HelloWorld.txt", "0:MaximSDHC/HelloMaxim.txt")) !=
+ FR_OK) { //cr: clearify 0:file notation
+ printf("Error moving file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ if ((err = f_chdir("/MaximSDHC")) != FR_OK) {
+ printf("Error in chdir: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("Attempting to read back file...\n");
+
+ if ((err = f_open(&file, "HelloMaxim.txt", FA_READ)) != FR_OK) {
+ printf("Error opening file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ if ((err = f_read(&file, &message, bytes_written, &bytes_read)) != FR_OK) {
+ printf("Error reading file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("Read Back %d bytes\n", bytes_read);
+ printf("Message: ");
+ printf("%s", message);
+ printf("\n");
+
+ if ((err = f_close(&file)) != FR_OK) {
+ printf("Error closing file: %s\n", FF_ERRORS[err]);
+ f_mount(NULL, "", 0);
+ return err;
+ }
+
+ printf("File Closed!\n");
+
+ //unmount SD Card
+ //f_mount(fs, "", 0);
+ if ((err = f_mount(NULL, "", 0)) != FR_OK) {
+ printf("Error unmounting volume: %s\n", FF_ERRORS[err]);
+ return err;
+ }
+
+ return 0;
+}
+
+void waitCardInserted()
+{
+ // On the MAX78000FTHR board, P0.12 will be pulled low when a card is inserted.
+ mxc_gpio_cfg_t cardDetect;
+ cardDetect.port = MXC_GPIO0;
+ cardDetect.mask = MXC_GPIO_PIN_12;
+ cardDetect.func = MXC_GPIO_FUNC_IN;
+ cardDetect.pad = MXC_GPIO_PAD_NONE;
+ cardDetect.vssel = MXC_GPIO_VSSEL_VDDIOH;
+
+ MXC_GPIO_Config(&cardDetect);
+
+ // Exit function if card is already inserted
+ if (MXC_GPIO_InGet(MXC_GPIO0, MXC_GPIO_PIN_12) == 0) {
+ return;
+ }
+
+ printf("Insert SD card to continue.\n");
+
+ while (MXC_GPIO_InGet(MXC_GPIO0, MXC_GPIO_PIN_12) != 0) {
+ // Spin waiting for card to be inserted.
+ }
+
+ // Card has been detected, exit the function.
+}
diff --git a/Examples/MAX78000/SDHC_FTHR/src/user-cli.c b/Examples/MAX78000/SDHC_FTHR/src/user-cli.c
new file mode 100644
index 00000000000..5800768c471
--- /dev/null
+++ b/Examples/MAX78000/SDHC_FTHR/src/user-cli.c
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+
+#include
+#include "cli.h"
+#include "sdhc.h"
+#include "user-cli.h"
+
+const command_t user_commands[] = {
+ { "size", "size", "Find the Size of the SD Card and Free Space", handle_size },
+ { "format", "format", "Format the Card", handle_format },
+ { "mount", "mount", "Manually Mount Card", handle_mount },
+ { "ls", "ls", "list the contents of the current directory", handle_ls },
+ { "mkdir", "mkdir ", "Create a directory", handle_mkdir },
+ { "file_create", "file_create ",
+ "Create a file of random data", handle_createfile },
+ { "cd", "cd ", "Move into a directory", handle_cd },
+ { "add_data", "add_data ",
+ "Add random Data to an Existing File", handle_add_data },
+ { "del", "del ", "Delete a file", handle_del },
+ { "fatfs", "fatfs", "Format Card and Run Example of FatFS Operations", handle_fatfs },
+ { "unmount", "unmount", "Unmount card", handle_unmount },
+};
+
+const unsigned int num_user_commands = sizeof(user_commands) / sizeof(command_t);
+
+int handle_size(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return getSize();
+}
+
+int handle_format(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return formatSDHC();
+}
+
+int handle_mount(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return mount();
+}
+
+int handle_ls(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return ls();
+}
+
+int handle_mkdir(int argc, char *argv[])
+{
+ if (argc != 2) {
+ printf("Incorrect usage. Please provide directory name.\n");
+ return E_INVALID;
+ }
+
+ return mkdir(argv[1]);
+}
+
+int handle_createfile(int argc, char *argv[])
+{
+ if (argc != 3) {
+ printf("Incorrect usage. Please provide filename and length.\n");
+ return E_INVALID;
+ }
+
+ unsigned int length = atoi(argv[2]);
+ return createFile(argv[1], length);
+}
+
+int handle_cd(int argc, char *argv[])
+{
+ if (argc != 2) {
+ printf("Incorrect usage. Please provide directory name.\n");
+ return E_INVALID;
+ }
+
+ return cd(argv[1]);
+}
+
+int handle_add_data(int argc, char *argv[])
+{
+ if (argc != 3) {
+ printf("Incorrect usage. Please provide filename and length.\n");
+ return E_INVALID;
+ }
+
+ unsigned int length = atoi(argv[2]);
+ return appendFile(argv[1], length);
+}
+
+int handle_del(int argc, char *argv[])
+{
+ if (argc != 2) {
+ printf("Incorrect usage. Please provide filename.\n");
+ return E_INVALID;
+ }
+
+ return deleteFile(argv[1]);
+}
+
+int handle_fatfs(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return example();
+}
+
+int handle_unmount(int argc, char *argv[])
+{
+ if (argc != 1) {
+ printf("Incorrect usage. Too many parameters.\n");
+ return E_INVALID;
+ }
+
+ return umount();
+}
diff --git a/Libraries/CLI/CLI.mk b/Libraries/CLI/CLI.mk
new file mode 100644
index 00000000000..fcc5d551ca5
--- /dev/null
+++ b/Libraries/CLI/CLI.mk
@@ -0,0 +1,61 @@
+################################################################################
+ # Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ #
+ # Permission is hereby granted, free of charge, to any person obtaining a
+ # copy of this software and associated documentation files (the "Software"),
+ # to deal in the Software without restriction, including without limitation
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ # and/or sell copies of the Software, and to permit persons to whom the
+ # Software is furnished to do so, subject to the following conditions:
+ #
+ # The above copyright notice and this permission notice shall be included
+ # in all copies or substantial portions of the Software.
+ #
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ # IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ # OTHER DEALINGS IN THE SOFTWARE.
+ #
+ # Except as contained in this notice, the name of Maxim Integrated
+ # Products, Inc. shall not be used except as stated in the Maxim Integrated
+ # Products, Inc. Branding Policy.
+ #
+ # The mere transfer of this software does not imply any licenses
+ # of trade secrets, proprietary technology, copyrights, patents,
+ # trademarks, maskwork rights, or any other form of intellectual
+ # property whatsoever. Maxim Integrated Products, Inc. retains all
+ # ownership rights.
+ #
+ ###############################################################################
+
+################################################################################
+# This file can be included in a project makefile to build the library for the
+# project.
+###############################################################################
+
+ifeq "$(LIB_CLI_DIR)" ""
+# If CLI_DIR is not specified, this Makefile will locate itself.
+LIB_CLI_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+endif
+
+IPATH += ${LIB_CLI_DIR}/inc
+VPATH += ${LIB_CLI_DIR}/src
+SRCS += cli.c
+
+# By default, with USE_CLI_LIB_IRQHANDLER defined, the CLI library will handle the
+# UART interrupts internally. Users have the option to define their own UART IRQ
+# Handler for the CLI UART in their application. If users choose to define their own
+# IRQ handler they should delete this definition of USE_CLI_LIB_IRQHANDLER and call
+# MXC_CLI_Handler in their handler function when the CLI is in use.
+LIB_CLI_USE_DEFAULT_HANDLER ?= 1
+ifeq "$(LIB_CLI_USE_DEFAULT_HANDLER)" "1"
+PROJ_CFLAGS += -DUSE_CLI_LIB_IRQHANDLER
+endif
+
+# Use absolute paths if building within eclipse environment.
+ifeq "$(ECLIPSE)" "1"
+SRCS := $(abspath $(SRCS))
+endif
diff --git a/Libraries/CLI/README.md b/Libraries/CLI/README.md
new file mode 100644
index 00000000000..9e8bf026cba
--- /dev/null
+++ b/Libraries/CLI/README.md
@@ -0,0 +1,81 @@
+# MSDK CLI Library
+
+## Description
+
+#### What is a Command Line Interface(CLI)?
+
+A command-line interface or command language interpreter (CLI), also known as command-line user interface, console user interface, and character user interface (CUI), is a means of interacting with an embedded system where the user (or client) issues commands to the program in the form of successive lines of text (command lines).
+
+This library provides an extensible command processor to:
+
+- Quickly and easily wrap user functions with a CLI
+- Allow developers to get diagnostics and change device parameters interactively
+- Easily automate testing of the device, through PC-side scripting
+
+The current CLI Library includes the following features:
+
+- UART interface support
+- Custom commands with support for multiple arguments
+- No modification of functions required. Users implement a command table and simple wrapper functions.
+- Case insensitive commands & arguments.
+- White-space insensitive.
+- Easy built-in 'help' command and custom help strings.
+
+## Usage Guide
+
+To use the CLI library, users are expected to implement the following steps in their application:
+
+1. Add the following line to your [project.mk](../../USERGUIDE.md#build-configuration-variables) file to enable the CLI library for your project:
+
+ :::Makefile
+ LIB_CLI = 1
+
+2. `#include "cli.h"` in your application code.
+
+3. Define an array of type `const command_t`. This is your command table. Include an array element for each command you want your CLI to support. Each element should define:
+
+ 1. The name of the command
+ 2. A string showing how to enter the command in the terminal
+ 3. A description of what the command does
+ 4. A function pointer to a wrapper function.
+
+ For example, the following is subset of the SDHC example command set:
+
+ :::C
+ const command_t user_commands[] = {{ "format", "format", "Format the Card", handle_format },
+ { "mkdir", "mkdir ", "Create a directory", handle_mkdir }}
+
+4. Implement a handler function for each command.
+
+ The handler functions provided to the `user_commands` table are "wrappers" around the code that should be run for each received command. The handlers must conform to the following definition:
+
+ Parameters
+
+ - `int argc` - This tells the handler function how many arguments were received.
+ - `char* argv[]` - This array holds the received arguments (in order) as strings. (Note: argv[0] holds the command string, argv[1:argc] are the arguments (if any are passed), and the last element in the argument vector is always a NULL pointer.)
+
+ Return Value
+
+ - The function needs to return an integer type. It should return 0 (E_NO_ERROR) if the command was executed successfuly, otherwise it should return a negative integer as an error code.
+
+ Below is a sample handler function for a "make directory" command, where `mkdir` is some function in the user's application code that does the work.
+
+ :::C
+ int handle_mkdir(int argc, char *argv[]) {
+ mkdir(argv[1]);
+ }
+
+ As an example, suppose a user entered the command:
+
+ :::C
+ mkdir new_folder
+
+ The CLI library will tokenize the command string "mkdir new_folder" into "mkdir" and "new_folder" and assigns them to argv[0] and argv[1] respectively. The library would then determine that this is the "make directory" command and would call "handle_mkdir" with argc=2 and a pointer to the argument vector.
+
+5. Add a call to `MXC_CLI_Init` to the application's startup code.
+
+ Pass in the UART instance for the CLI to use, a pointer to the command table, and the number of commands in the command table.
+
+6. (OPTIONAL) The CLI library will enable and handle UART interrupts automatically. Users who would like more control over the interrupt handling have the option to disable the default handler and define their own.
+
+ To do so, set the `LIB_CLI_USE_DEFAULT_HANDLER` [build configuration variable](../../USERGUIDE.md#build-configuration-variables) to `0`. Users may now enable and handle the interrupt with a custom function. However, users must call `MXC_CLI_Handler()` from the custom function for the CLI to work.
diff --git a/Libraries/CLI/inc/cli.h b/Libraries/CLI/inc/cli.h
new file mode 100644
index 00000000000..d131e9897f3
--- /dev/null
+++ b/Libraries/CLI/inc/cli.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+
+/*! \file cli.h
+ \brief A CLI Implementation using a command table to store command string, function pointer and a help string is dispatched.
+
+ Details.
+
+ 1. Line Accumlator
+
+ Reads the incoming bytes
+ Accumulates into a line buffer
+ Echos char back to the emulator
+ Handles backspace
+
+ 2. Prcoess Command
+
+ Processes input into a series of tokens
+ All tokes are seperated by whitespace characters
+ Lookup first token in a table of functions
+ Dispatch to handler functions
+*/
+
+#ifndef LIBRARIES_CLI_INC_CLI_H_
+#define LIBRARIES_CLI_INC_CLI_H_
+
+#include
+#include "uart.h"
+
+/**
+ * @brief Command handler function prototype. Once a command is entered in the CLI, it is parsed
+ * ("tokenized") into an argument vector. The argument counter and argument vector are
+ * passed to the command's handler function where the command is executed.
+ *
+ * @param argc Number of tokens in the argument vector
+ * @param argv[] Array of arguments storing different tokens of the command string in the
+ * same order as they were passed in the command line. (argv[0] is the command,
+ * argv[1:argc] are the arguments (if any are passed), and the last element in the
+ * argument vector is always a NULL pointer.)
+ *
+ * @returns E_NO_ERROR if successful, otherwise an error code (error code must be a negative integer)
+ */
+typedef int (*command_handler_t)(int argc, char *argv[]);
+
+/**
+ * @brief Structure used to define the commands supported by the CLI
+ */
+typedef struct {
+ const char *cmd; /**< name of the command (as it should be entered on the command line) */
+ const char *usage; /**< string to show how the command should be entered on the command line */
+ const char *description; /**< string describing what the command does */
+ command_handler_t handler; /**< function pointer of the command handler function */
+} command_t;
+
+/**
+ * @brief Initializes the CLI state variables and configures the uart for CLI operations.
+ *
+ * @param uart Pointer to UART instance to use for the CLI
+ * @param commands Pointer to the command table storing user-defined CLI commands
+ * @param num_commands Number of commands in the command table
+ *
+ * @return E_NO_ERROR if successful, otherwise an error code.
+ */
+int MXC_CLI_Init(mxc_uart_regs_t *uart, const command_t *commands, unsigned int num_commands);
+
+/**
+ * @brief Shuts down the CLI. (UART will remain enabled.)
+ *
+ * @return E_NO_ERROR if successful, otheriwse an error code.
+ */
+int MXC_CLI_Shutdown(void);
+
+/**
+ * @brief IRQ Handler for the CLI UART. This function should be called from the
+ * MXC_UARTx_Handler in the user application.
+ */
+void MXC_CLI_Handler(void);
+
+#endif // LIBRARIES_CLI_INC_CLI_H_
diff --git a/Libraries/CLI/res/CLI-Processing-steps.png b/Libraries/CLI/res/CLI-Processing-steps.png
new file mode 100644
index 00000000000..9de200d925a
Binary files /dev/null and b/Libraries/CLI/res/CLI-Processing-steps.png differ
diff --git a/Libraries/CLI/src/cli.c b/Libraries/CLI/src/cli.c
new file mode 100644
index 00000000000..008e2aa8bfa
--- /dev/null
+++ b/Libraries/CLI/src/cli.c
@@ -0,0 +1,365 @@
+/******************************************************************************
+ * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ ******************************************************************************/
+
+/* -------------------------------------------------- */
+// INCLUDES
+/* -------------------------------------------------- */
+#include
+#include
+#include
+
+#include "board.h"
+#include "cli.h"
+#include "nvic_table.h"
+
+/* -------------------------------------------------- */
+// MACROS
+/* -------------------------------------------------- */
+// Characters
+#define ENTER 0x0D
+#define NEW_LINE 0x0A
+#define SPACE 0x20
+#define BACKSPACE 0x08
+#define DOLLAR 0x24
+
+// Define a buffer length to store commands
+#define MAX_COMMAND_LENGTH 256
+#define MAX_COMMAND_TOKENS 10
+
+#define UART_BAUD 115200
+#define BUFF_SIZE 1
+
+/* -------------------------------------------------- */
+// FUNCTION PROTOTYPES
+/* -------------------------------------------------- */
+void line_accumulator(uint8_t user_char);
+void process_command(char *input);
+int handle_help(int argc, char *argv[]);
+
+/* -------------------------------------------------- */
+// GLOBAL VARIABLES
+/* -------------------------------------------------- */
+char cmd_buf[MAX_COMMAND_LENGTH]; // Command buffer
+uint16_t buf_idx = 0;
+
+uint8_t char_recv; // Variable to store characters received by CLI UART
+mxc_uart_req_t cli_req; // CLI UART transaction request structure
+
+// Help Command
+const command_t help_command = { "Help", "help",
+ "Prints details regarding the usage of the supported commands.",
+ handle_help };
+
+// Command table parameters;
+const command_t *command_table = NULL;
+unsigned int command_table_sz = 0;
+
+// UART instance used for CLI operations
+mxc_uart_regs_t *cli_uart = NULL;
+
+/* -------------------------------------------------- */
+// PRIVATE FUNCTION DEFINITIONS
+/* -------------------------------------------------- */
+/**
+ * @brief Prints the CLI prompt
+ */
+void User_Prompt_Sequence(void)
+{
+ if (cli_uart == NULL) {
+ return;
+ }
+
+ MXC_UART_WriteCharacter(cli_uart, NEW_LINE);
+ MXC_UART_WriteCharacter(cli_uart, DOLLAR);
+ MXC_UART_WriteCharacter(cli_uart, SPACE);
+}
+
+/**
+ * @brief Clears the buffer storing the command string
+ */
+void Clear_buffer(void)
+{
+ memset(cmd_buf, '\0', MAX_COMMAND_LENGTH);
+}
+
+/**
+ * @brief Writes the backspace sequence to the UART console
+ */
+void Console_Backspace_Sequence(void)
+{
+ if (cli_uart == NULL) {
+ return;
+ }
+
+ MXC_UART_WriteCharacter(cli_uart, BACKSPACE);
+ MXC_UART_WriteCharacter(cli_uart, SPACE);
+ MXC_UART_WriteCharacter(cli_uart, BACKSPACE);
+}
+
+/**
+ * @brief Clears the line on the UART console
+ */
+void Console_Cmd_Clear(void)
+{
+ for (int i = 0; i < buf_idx; i++) {
+ Console_Backspace_Sequence();
+ }
+}
+
+/**
+ * @brief Adds characters to the command string as they are received and echos them to the terminal
+ */
+void line_accumulator(uint8_t user_char)
+{
+ if (cli_uart == NULL) {
+ return;
+ }
+
+ switch (user_char) {
+ case BACKSPACE:
+ // Handle Backspace and Delete
+ if (buf_idx > 0) {
+ //Sequence to implement a backspace on the terminal
+ Console_Backspace_Sequence();
+ buf_idx--;
+ cmd_buf[buf_idx] = '\0';
+ }
+ break;
+
+ case ENTER:
+ // Handle Enter or carriage return
+ MXC_UART_WriteCharacter(cli_uart, NEW_LINE);
+ MXC_UART_WriteCharacter(cli_uart, ENTER);
+
+ // Parse and execute command
+ process_command(cmd_buf);
+
+ // Reset command buffer
+ buf_idx = 0;
+ Clear_buffer();
+ break;
+
+ default:
+ // Handle all other characters
+ if (buf_idx < MAX_COMMAND_LENGTH) {
+ cmd_buf[buf_idx++] = user_char; //pushes characters into the buffer
+ MXC_UART_WriteCharacter(cli_uart, user_char);
+ }
+ break;
+ }
+}
+
+/**
+ * @brief Determines whether the command received was valid and calls the appropriate handler
+ *
+ * @param input Command string received by the CLI
+ */
+void process_command(char *input)
+{
+ // Initialize variables
+ char *argv[MAX_COMMAND_TOKENS + 1]; // Plus 1 so that argv can always be null terminated
+ int argc = 0;
+ int success_flag = 1;
+
+ // Initialize command string and token pointers
+ char *cmd = input;
+ char *token;
+
+ // Parse command string (delimiters: space and tab)
+ while (argc < MAX_COMMAND_TOKENS && (token = strtok_r(cmd, " \t", &cmd))) {
+ argv[argc++] = token;
+ }
+
+ // Set last argv value to NULL
+ argv[argc] = NULL;
+
+ // If no arguments, return
+ if (argc == 0) {
+ return;
+ }
+
+ // Check for a valid command
+ if (strcasecmp(argv[0], help_command.cmd) == 0) {
+ // Help command received
+ success_flag = help_command.handler(argc, argv);
+ } else {
+ // Help command not received, iterate over all user-defined commands
+ for (int i = 0; i < command_table_sz; i++) {
+ if (strcasecmp(argv[0], command_table[i].cmd) == 0) {
+ // Call corresponding command's handler
+ success_flag = command_table[i].handler(argc, argv);
+ break;
+ }
+ }
+ }
+
+ // Check for errors
+ if (success_flag == 1) {
+ // Command entered is not supported
+ printf("\nCommand isn't valid!\n");
+ } else if (success_flag < E_NO_ERROR) {
+ // Command entered is supported, but arguments entered incorrectly
+ printf("\nEnter 'help' for details on how to use the '%s' command.\n", argv[0]);
+ }
+
+ // Print prompt
+ User_Prompt_Sequence();
+}
+
+/**
+ * @brief Prints the help string of each command from the command table
+ *
+ * @param argc The command element number within the command string
+ * @param argv[] Array of arguments storing different tokens of the
+ * command string in the same order as they were passed
+ * in the command line.
+ *
+ * @returns E_NO_ERROR if successful, otherwise an error code.
+ */
+int handle_help(int argc, char *argv[])
+{
+ // Print out name, usage, and description of each supported command
+ for (int i = 0; i < command_table_sz; i++) {
+ printf("\n%s:\n", command_table[i].cmd);
+ printf(" Usage: %s\n", command_table[i].usage);
+ printf(" Description: %s\n\n", command_table[i].description);
+ }
+
+ return E_NO_ERROR;
+}
+
+/**
+ * @brief Callback function for when a character is received by the CLI
+ */
+void CLI_Callback(mxc_uart_req_t *req, int error)
+{
+ if (error == E_ABORT) {
+ // Shutdown called, nothing to do in callback
+ return;
+ }
+
+ // Process received character
+ line_accumulator(char_recv);
+
+ // Get ready to receive next character
+ MXC_UART_TransactionAsync(req);
+}
+
+/* -------------------------------------------------- */
+// PUBLIC FUNCTION DEFINITIONS
+/* -------------------------------------------------- */
+int MXC_CLI_Init(mxc_uart_regs_t *uart, const command_t *commands, unsigned int num_commands)
+{
+ int error;
+ int uart_idx = MXC_UART_GET_IDX(uart);
+
+ // Check for valid parameters
+ if (uart_idx < 0) {
+ return E_BAD_PARAM;
+ } else if (commands == NULL) {
+ return E_NULL_PTR;
+ } else if (num_commands <= 0) {
+ return E_BAD_PARAM;
+ }
+
+ // Return error if CLI is already initialized
+ if (cli_uart != NULL) {
+ return E_BAD_STATE;
+ }
+
+ // Save the command table
+ cli_uart = uart;
+ command_table = commands;
+ command_table_sz = num_commands;
+
+ // Initialize Console UART
+ if ((error = MXC_UART_Init(uart, UART_BAUD, MXC_UART_APB_CLK)) != E_NO_ERROR) {
+ printf("-->Error initializing CLI UART: %d\n", error);
+ return error;
+ }
+
+ // Initialize an asynchoronous request for the first character
+ cli_req.uart = cli_uart;
+ cli_req.rxData = &char_recv;
+ cli_req.rxLen = BUFF_SIZE;
+ cli_req.txLen = 0;
+ cli_req.callback = CLI_Callback;
+ if ((error = MXC_UART_TransactionAsync(&cli_req)) != E_NO_ERROR) {
+ return error;
+ }
+
+ // Print success message and prompt
+ printf("CLI Initialized! Enter 'help' to see a list of available commands.\n");
+ User_Prompt_Sequence();
+ while (MXC_UART_GetActive(uart)) {}
+
+#ifdef USE_CLI_LIB_IRQHANDLER
+ // Give users the option to define their own IRQ handler in their application. By default,
+ // we point the interrupt vector at MXC_CLI_Handler.
+ MXC_NVIC_SetVector(MXC_UART_GET_IRQ(uart_idx), MXC_CLI_Handler);
+#endif // USE_CLI_LIB_IRQHANDLER
+
+ // Enable interrupts
+ NVIC_EnableIRQ(MXC_UART_GET_IRQ(uart_idx));
+
+ return E_NO_ERROR;
+}
+
+int MXC_CLI_Shutdown(void)
+{
+ // Return if CLI is uninitialized
+ if (cli_uart == NULL) {
+ return E_BAD_STATE;
+ }
+
+ // Abort existing async transaction
+ MXC_UART_AbortAsync(cli_uart);
+
+ // Reset state variables
+ cli_uart = NULL;
+ command_table = NULL;
+ command_table_sz = 0;
+ buf_idx = 0;
+
+ return E_NO_ERROR;
+}
+
+void MXC_CLI_Handler(void)
+{
+ // Return if CLI is uninitialized
+ if (cli_uart == NULL) {
+ return;
+ }
+
+ MXC_UART_AsyncHandler(cli_uart);
+}
diff --git a/Libraries/libs.mk b/Libraries/libs.mk
index b71a9e56a00..75ca70bd53c 100644
--- a/Libraries/libs.mk
+++ b/Libraries/libs.mk
@@ -231,3 +231,12 @@ BARCODE_DECODER_DIR ?= $(LIBS_DIR)/MiscDrivers/BarcodeDecoder/zbar
include $(BARCODE_DECODER_DIR)/barcode_decoder.mk
endif
# ************************
+
+# CLI (Disabled by default)
+# ************************
+LIB_CLI ?= 0
+ifeq ($(LIB_CLI), 1)
+LIB_CLI_DIR ?= $(LIBS_DIR)/CLI
+include $(LIB_CLI_DIR)/CLI.mk
+endif
+# ************************
diff --git a/USERGUIDE.md b/USERGUIDE.md
index d8fd12fa4ac..0bc635ef6b7 100644
--- a/USERGUIDE.md
+++ b/USERGUIDE.md
@@ -1894,6 +1894,7 @@ The following variables can be used to modularly toggle the [available libraries
| `LIB_LWIP` | Include the lwIP library | |
| `LIB_MAXUSB` | Include the MaxUSB library | This option toggles the inclusion of the MAXUSB library, which facilitates the use of the native USB peripherals on some microcontrollers. Set to `0` to disable or `1` to enable. |
| `LIB_SDHC` | Include the SDHC library | This option toggles the Secure Digital High Capacity (SDHC) library, which can be used to interface with SD cards. Additionally, it enables the [FatFS](http://elm-chan.org/fsw/ff/00index_e.html) library, which implements a generic FAT filesystem. |
+| `LIB_CLI` | Include the MSDK's built-in CLI library | This option toggles the MSDK's built-in CLI library, which can be used to process received commands over UART. |
#### Build Variables for Secure Boot Tools (SBTs)
@@ -2299,6 +2300,13 @@ FreeRTOS is supported by all parts in the MSDK. See the `FreeRTOSDemo` example
- [FreeRTOS-Plus-CLI](https://www.freertos.org/FreeRTOS-Plus/index.html): **Supported**
- [FreeRTOS-Plus-TCP](https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html): **Not supported** (Contributions welcome!)
+
+### CLI
+
+Developing a UART Command-Line Interface (CLI) is a common task while developing embedded firmware. The MSDK contains a pre-made command processing library in the `Libraries/CLI` that can be used to simplify and speed up development.
+
+See the [`Libraries/CLI/README.md`](Libraries/CLI/README.md) document for more details.
+
### CoreMark
[EEMBC’s CoreMark®](https://www.eembc.org/coremark/) is a benchmark that measures the performance of microcontrollers (MCUs) and central processing units (CPUs) used in embedded systems. CoreMark is a simple, yet sophisticated benchmark that is designed specifically to test the functionality of a processor core. Running CoreMark produces a single-number score allowing users to make quick comparisons between processors.