+/*\r
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.\r
+ All rights reserved\r
+\r
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS provides completely free yet professionally developed, *\r
+ * robust, strictly quality controlled, supported, and cross *\r
+ * platform software that has become a de facto standard. *\r
+ * *\r
+ * Help yourself get started quickly and support the FreeRTOS *\r
+ * project by purchasing a FreeRTOS tutorial book, reference *\r
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *\r
+ * *\r
+ * Thank you! *\r
+ * *\r
+ ***************************************************************************\r
+\r
+ This file is part of the FreeRTOS distribution.\r
+\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
+\r
+ >>! NOTE: The modification to the GPL is included to allow you to distribute\r
+ >>! a combined work that includes FreeRTOS without being obliged to provide\r
+ >>! the source code for proprietary components outside of the FreeRTOS\r
+ >>! kernel.\r
+\r
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following\r
+ link: http://www.freertos.org/a00114.html\r
+\r
+ 1 tab == 4 spaces!\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * Having a problem? Start by reading the FAQ "My application does *\r
+ * not run, what could be wrong?" *\r
+ * *\r
+ * http://www.FreeRTOS.org/FAQHelp.html *\r
+ * *\r
+ ***************************************************************************\r
+\r
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
+ license and Real Time Engineers Ltd. contact details.\r
+\r
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
+\r
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS\r
+ licenses offer ticketed support, indemnification and middleware.\r
+\r
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
+ engineered and independently SIL3 certified version for use in safety and\r
+ mission critical applications that require provable dependability.\r
+\r
+ 1 tab == 4 spaces!\r
+*/\r
+\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+/* Standard includes. */\r
+#include <stdint.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+/* FreeRTOS+CLI includes. */\r
+#include "FreeRTOS_CLI.h"\r
+\r
+/* File system includes. */\r
+#include "fat_sl.h"\r
+#include "api_mdriver_ram.h"\r
+\r
+#ifdef _WINDOWS_\r
+ #define snprintf _snprintf\r
+#endif\r
+\r
+#define cliNEW_LINE "\r\n"\r
+\r
+/*******************************************************************************\r
+ * See the URL in the comments within main.c for the location of the online\r
+ * documentation.\r
+ ******************************************************************************/\r
+\r
+/*\r
+ * Print out information on a single file.\r
+ */\r
+static void prvCreateFileInfoString( int8_t *pcBuffer, F_FIND *pxFindStruct );\r
+\r
+/*\r
+ * Copies an existing file into a newly created file.\r
+ */\r
+static portBASE_TYPE prvPerformCopy( int8_t *pcSourceFile,\r
+ int32_t lSourceFileLength,\r
+ int8_t *pcDestinationFile,\r
+ int8_t *pxWriteBuffer,\r
+ size_t xWriteBufferLen );\r
+\r
+/*\r
+ * Implements the DIR command.\r
+ */\r
+static portBASE_TYPE prvDIRCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString );\r
+\r
+/*\r
+ * Implements the CD command.\r
+ */\r
+static portBASE_TYPE prvCDCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString );\r
+\r
+/*\r
+ * Implements the DEL command.\r
+ */\r
+static portBASE_TYPE prvDELCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString );\r
+\r
+/*\r
+ * Implements the TYPE command.\r
+ */\r
+static portBASE_TYPE prvTYPECommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString );\r
+\r
+/*\r
+ * Implements the COPY command.\r
+ */\r
+static portBASE_TYPE prvCOPYCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString );\r
+\r
+/* Structure that defines the DIR command line command, which lists all the\r
+files in the current directory. */\r
+static const CLI_Command_Definition_t xDIR =\r
+{\r
+ ( const int8_t * const ) "dir", /* The command string to type. */\r
+ ( const int8_t * const ) "\r\ndir:\r\n Lists the files in the current directory\r\n",\r
+ prvDIRCommand, /* The function to run. */\r
+ 0 /* No parameters are expected. */\r
+};\r
+\r
+/* Structure that defines the CD command line command, which changes the\r
+working directory. */\r
+static const CLI_Command_Definition_t xCD =\r
+{\r
+ ( const int8_t * const ) "cd", /* The command string to type. */\r
+ ( const int8_t * const ) "\r\ncd <dir name>:\r\n Changes the working directory\r\n",\r
+ prvCDCommand, /* The function to run. */\r
+ 1 /* One parameter is expected. */\r
+};\r
+\r
+/* Structure that defines the TYPE command line command, which prints the\r
+contents of a file to the console. */\r
+static const CLI_Command_Definition_t xTYPE =\r
+{\r
+ ( const int8_t * const ) "type", /* The command string to type. */\r
+ ( const int8_t * const ) "\r\ntype <filename>:\r\n Prints file contents to the terminal\r\n",\r
+ prvTYPECommand, /* The function to run. */\r
+ 1 /* One parameter is expected. */\r
+};\r
+\r
+/* Structure that defines the DEL command line command, which deletes a file. */\r
+static const CLI_Command_Definition_t xDEL =\r
+{\r
+ ( const int8_t * const ) "del", /* The command string to type. */\r
+ ( const int8_t * const ) "\r\ndel <filename>:\r\n deletes a file or directory\r\n",\r
+ prvDELCommand, /* The function to run. */\r
+ 1 /* One parameter is expected. */\r
+};\r
+\r
+/* Structure that defines the COPY command line command, which deletes a file. */\r
+static const CLI_Command_Definition_t xCOPY =\r
+{\r
+ ( const int8_t * const ) "copy", /* The command string to type. */\r
+ ( const int8_t * const ) "\r\ncopy <source file> <dest file>:\r\n Copies <source file> to <dest file>\r\n",\r
+ prvCOPYCommand, /* The function to run. */\r
+ 2 /* Two parameters are expected. */\r
+};\r
+\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vRegisterFileSystemCLICommands( void )\r
+{\r
+ /* Register all the command line commands defined immediately above. */\r
+ FreeRTOS_CLIRegisterCommand( &xDIR );\r
+ FreeRTOS_CLIRegisterCommand( &xCD );\r
+ FreeRTOS_CLIRegisterCommand( &xTYPE );\r
+ FreeRTOS_CLIRegisterCommand( &xDEL );\r
+ FreeRTOS_CLIRegisterCommand( &xCOPY );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvTYPECommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString )\r
+{\r
+int8_t *pcParameter;\r
+portBASE_TYPE xParameterStringLength, xReturn = pdTRUE;\r
+static F_FILE *pxFile = NULL;\r
+int iChar;\r
+size_t xByte;\r
+size_t xColumns = 50U;\r
+\r
+ /* Ensure there is always a null terminator after each character written. */\r
+ memset( pcWriteBuffer, 0x00, xWriteBufferLen );\r
+\r
+ /* Ensure the buffer leaves space for the \r\n. */\r
+ configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
+ xWriteBufferLen -= strlen( cliNEW_LINE );\r
+\r
+ if( xWriteBufferLen < xColumns )\r
+ {\r
+ /* Ensure the loop that uses xColumns as an end condition does not\r
+ write off the end of the buffer. */\r
+ xColumns = xWriteBufferLen;\r
+ }\r
+\r
+ if( pxFile == NULL )\r
+ {\r
+ /* The file has not been opened yet. Find the file name. */\r
+ pcParameter = ( int8_t * ) FreeRTOS_CLIGetParameter\r
+ (\r
+ pcCommandString, /* The command string itself. */\r
+ 1, /* Return the first parameter. */\r
+ &xParameterStringLength /* Store the parameter string length. */\r
+ );\r
+\r
+ /* Sanity check something was returned. */\r
+ configASSERT( pcParameter );\r
+\r
+ /* Attempt to open the requested file. */\r
+ pxFile = f_open( ( const char * ) pcParameter, "r" );\r
+ }\r
+\r
+ if( pxFile != NULL )\r
+ {\r
+ /* Read the next chunk of data from the file. */\r
+ for( xByte = 0; xByte < xColumns; xByte++ )\r
+ {\r
+ iChar = f_getc( pxFile );\r
+\r
+ if( iChar == -1 )\r
+ {\r
+ /* No more characters to return. */\r
+ f_close( pxFile );\r
+ pxFile = NULL;\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ pcWriteBuffer[ xByte ] = ( int8_t ) iChar;\r
+ }\r
+ }\r
+ }\r
+\r
+ if( pxFile == NULL )\r
+ {\r
+ /* Either the file was not opened, or all the data from the file has\r
+ been returned and the file is now closed. */\r
+ xReturn = pdFALSE;\r
+ }\r
+\r
+ strcat( ( char * ) pcWriteBuffer, cliNEW_LINE );\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvCDCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString )\r
+{\r
+int8_t *pcParameter;\r
+portBASE_TYPE xParameterStringLength;\r
+unsigned char ucReturned;\r
+size_t xStringLength;\r
+\r
+ /* Obtain the parameter string. */\r
+ pcParameter = ( int8_t * ) FreeRTOS_CLIGetParameter\r
+ (\r
+ pcCommandString, /* The command string itself. */\r
+ 1, /* Return the first parameter. */\r
+ &xParameterStringLength /* Store the parameter string length. */\r
+ );\r
+\r
+ /* Sanity check something was returned. */\r
+ configASSERT( pcParameter );\r
+\r
+ /* Attempt to move to the requested directory. */\r
+ ucReturned = f_chdir( ( char * ) pcParameter );\r
+\r
+ if( ucReturned == F_NO_ERROR )\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "In: " );\r
+ xStringLength = strlen( ( const char * ) pcWriteBuffer );\r
+ f_getcwd( ( char * ) &( pcWriteBuffer[ xStringLength ] ), ( unsigned char ) ( xWriteBufferLen - xStringLength ) );\r
+ }\r
+ else\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Error" );\r
+ }\r
+\r
+ strcat( ( char * ) pcWriteBuffer, cliNEW_LINE );\r
+\r
+ return pdFALSE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvDIRCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString )\r
+{\r
+static F_FIND *pxFindStruct = NULL;\r
+unsigned char ucReturned;\r
+portBASE_TYPE xReturn = pdFALSE;\r
+\r
+ /* This assumes pcWriteBuffer is long enough. */\r
+ ( void ) pcCommandString;\r
+\r
+ /* Ensure the buffer leaves space for the \r\n. */\r
+ configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) );\r
+ xWriteBufferLen -= strlen( cliNEW_LINE );\r
+\r
+ if( pxFindStruct == NULL )\r
+ {\r
+ /* This is the first time this function has been executed since the Dir\r
+ command was run. Create the find structure. */\r
+ pxFindStruct = ( F_FIND * ) pvPortMalloc( sizeof( F_FIND ) );\r
+\r
+ if( pxFindStruct != NULL )\r
+ {\r
+ ucReturned = f_findfirst( "*.*", pxFindStruct );\r
+\r
+ if( ucReturned == F_NO_ERROR )\r
+ {\r
+ prvCreateFileInfoString( pcWriteBuffer, pxFindStruct );\r
+ xReturn = pdPASS;\r
+ }\r
+ else\r
+ {\r
+ snprintf( ( char * ) pcWriteBuffer, xWriteBufferLen, "Error: f_findfirst() failed." );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ snprintf( ( char * ) pcWriteBuffer, xWriteBufferLen, "Failed to allocate RAM (using heap_4.c will prevent fragmentation)." );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* The find struct has already been created. Find the next file in\r
+ the directory. */\r
+ ucReturned = f_findnext( pxFindStruct );\r
+\r
+ if( ucReturned == F_NO_ERROR )\r
+ {\r
+ prvCreateFileInfoString( pcWriteBuffer, pxFindStruct );\r
+ xReturn = pdPASS;\r
+ }\r
+ else\r
+ {\r
+ /* There are no more files. Free the find structure. */\r
+ vPortFree( pxFindStruct );\r
+ pxFindStruct = NULL;\r
+\r
+ /* No string to return. */\r
+ pcWriteBuffer[ 0 ] = 0x00;\r
+ }\r
+ }\r
+\r
+ strcat( ( char * ) pcWriteBuffer, cliNEW_LINE );\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvDELCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString )\r
+{\r
+int8_t *pcParameter;\r
+portBASE_TYPE xParameterStringLength;\r
+unsigned char ucReturned;\r
+\r
+ /* This function assumes xWriteBufferLen is large enough! */\r
+ ( void ) xWriteBufferLen;\r
+\r
+ /* Obtain the parameter string. */\r
+ pcParameter = ( int8_t * ) FreeRTOS_CLIGetParameter\r
+ (\r
+ pcCommandString, /* The command string itself. */\r
+ 1, /* Return the first parameter. */\r
+ &xParameterStringLength /* Store the parameter string length. */\r
+ );\r
+\r
+ /* Sanity check something was returned. */\r
+ configASSERT( pcParameter );\r
+\r
+ /* Attempt to delete the file. */\r
+ ucReturned = f_delete( ( const char * ) pcParameter );\r
+\r
+ if( ucReturned == F_NO_ERROR )\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "%s was deleted", pcParameter );\r
+ }\r
+ else\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Error" );\r
+ }\r
+\r
+ strcat( ( char * ) pcWriteBuffer, cliNEW_LINE );\r
+\r
+ return pdFALSE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvCOPYCommand( int8_t *pcWriteBuffer, size_t xWriteBufferLen, const int8_t *pcCommandString )\r
+{\r
+int8_t *pcSourceFile, *pcDestinationFile;\r
+portBASE_TYPE xParameterStringLength;\r
+long lSourceLength, lDestinationLength = 0;\r
+\r
+ /* Obtain the name of the destination file. */\r
+ pcDestinationFile = ( int8_t * ) FreeRTOS_CLIGetParameter\r
+ (\r
+ pcCommandString, /* The command string itself. */\r
+ 2, /* Return the second parameter. */\r
+ &xParameterStringLength /* Store the parameter string length. */\r
+ );\r
+\r
+ /* Sanity check something was returned. */\r
+ configASSERT( pcDestinationFile );\r
+\r
+ /* Obtain the name of the source file. */\r
+ pcSourceFile = ( int8_t * ) FreeRTOS_CLIGetParameter\r
+ (\r
+ pcCommandString, /* The command string itself. */\r
+ 1, /* Return the first parameter. */\r
+ &xParameterStringLength /* Store the parameter string length. */\r
+ );\r
+\r
+ /* Sanity check something was returned. */\r
+ configASSERT( pcSourceFile );\r
+\r
+ /* Terminate the string. */\r
+ pcSourceFile[ xParameterStringLength ] = 0x00;\r
+\r
+ /* See if the source file exists, obtain its length if it does. */\r
+ lSourceLength = f_filelength( ( const char * ) pcSourceFile );\r
+\r
+ if( lSourceLength == 0 )\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Source file does not exist" );\r
+ }\r
+ else\r
+ {\r
+ /* See if the destination file exists. */\r
+ lDestinationLength = f_filelength( ( const char * ) pcDestinationFile );\r
+\r
+ if( lDestinationLength != 0 )\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Error: Destination file already exists" );\r
+ }\r
+ }\r
+\r
+ /* Continue only if the source file exists and the destination file does\r
+ not exist. */\r
+ if( ( lSourceLength != 0 ) && ( lDestinationLength == 0 ) )\r
+ {\r
+ if( prvPerformCopy( pcSourceFile, lSourceLength, pcDestinationFile, pcWriteBuffer, xWriteBufferLen ) == pdPASS )\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Copy made" );\r
+ }\r
+ else\r
+ {\r
+ sprintf( ( char * ) pcWriteBuffer, "Error during copy" );\r
+ }\r
+ }\r
+\r
+ strcat( ( char * ) pcWriteBuffer, cliNEW_LINE );\r
+\r
+ return pdFALSE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvPerformCopy( int8_t *pcSourceFile,\r
+ int32_t lSourceFileLength,\r
+ int8_t *pcDestinationFile,\r
+ int8_t *pxWriteBuffer,\r
+ size_t xWriteBufferLen )\r
+{\r
+int32_t lBytesRead = 0, lBytesToRead, lBytesRemaining;\r
+F_FILE *pxFile;\r
+portBASE_TYPE xReturn = pdPASS;\r
+\r
+ /* NOTE: Error handling has been omitted for clarity. */\r
+\r
+ while( lBytesRead < lSourceFileLength )\r
+ {\r
+ /* How many bytes are left? */\r
+ lBytesRemaining = lSourceFileLength - lBytesRead;\r
+\r
+ /* How many bytes should be read this time around the loop. Can't\r
+ read more bytes than will fit into the buffer. */\r
+ if( lBytesRemaining > ( long ) xWriteBufferLen )\r
+ {\r
+ lBytesToRead = ( long ) xWriteBufferLen;\r
+ }\r
+ else\r
+ {\r
+ lBytesToRead = lBytesRemaining;\r
+ }\r
+\r
+ /* Open the source file, seek past the data that has already been\r
+ read from the file, read the next block of data, then close the\r
+ file again so the destination file can be opened. */\r
+ pxFile = f_open( ( const char * ) pcSourceFile, "r" );\r
+ if( pxFile != NULL )\r
+ {\r
+ f_seek( pxFile, lBytesRead, F_SEEK_SET );\r
+ f_read( pxWriteBuffer, lBytesToRead, 1, pxFile );\r
+ f_close( pxFile );\r
+ }\r
+ else\r
+ {\r
+ xReturn = pdFAIL;\r
+ break;\r
+ }\r
+\r
+ /* Open the destination file and write the block of data to the end of\r
+ the file. */\r
+ pxFile = f_open( ( const char * ) pcDestinationFile, "a" );\r
+ if( pxFile != NULL )\r
+ {\r
+ f_write( pxWriteBuffer, lBytesToRead, 1, pxFile );\r
+ f_close( pxFile );\r
+ }\r
+ else\r
+ {\r
+ xReturn = pdFAIL;\r
+ break;\r
+ }\r
+\r
+ lBytesRead += lBytesToRead;\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCreateFileInfoString( int8_t *pcBuffer, F_FIND *pxFindStruct )\r
+{\r
+const char *pcWritableFile = "writable file", *pcReadOnlyFile = "read only file", *pcDirectory = "directory";\r
+const char * pcAttrib;\r
+\r
+ /* Point pcAttrib to a string that describes the file. */\r
+ if( ( pxFindStruct->attr & F_ATTR_DIR ) != 0 )\r
+ {\r
+ pcAttrib = pcDirectory;\r
+ }\r
+ else if( pxFindStruct->attr & F_ATTR_READONLY )\r
+ {\r
+ pcAttrib = pcReadOnlyFile;\r
+ }\r
+ else\r
+ {\r
+ pcAttrib = pcWritableFile;\r
+ }\r
+\r
+ /* Create a string that includes the file name, the file size and the\r
+ attributes string. */\r
+ sprintf( ( char * ) pcBuffer, "%s [%s] [size=%d]", pxFindStruct->filename, pcAttrib, ( int ) pxFindStruct->filesize );\r
+}\r