summaryrefslogtreecommitdiff
path: root/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c')
-rw-r--r--FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c
new file mode 100644
index 000000000..19231393a
--- /dev/null
+++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c
@@ -0,0 +1,423 @@
+/*
+ * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * Authors include James Walmsley, Hein Tibosch and Richard Barry
+ *
+ * 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 THE AUTHORS OR
+ * COPYRIGHT HOLDERS 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.
+ *
+ * https://www.FreeRTOS.org
+ *
+ */
+
+/* Standard includes. */
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "portmacro.h"
+
+/* FreeRTOS+FAT includes. */
+#include "ff_headers.h"
+#include "ff_ramdisk.h"
+#include "ff_sys.h"
+
+#define ramHIDDEN_SECTOR_COUNT 8
+#define ramPRIMARY_PARTITIONS 1
+#define ramHUNDRED_64_BIT 100ULL
+#define ramSECTOR_SIZE 512UL
+#define ramPARTITION_NUMBER 0 /* Only a single partition is used. */
+#define ramBYTES_PER_KB ( 1024ull )
+#define ramSECTORS_PER_KB ( ramBYTES_PER_KB / 512ull )
+
+/* Used as a magic number to indicate that an FF_Disk_t structure is a RAM
+disk. */
+#define ramSIGNATURE 0x41404342
+
+/*-----------------------------------------------------------*/
+
+/*
+ * The function that writes to the media - as this is implementing a RAM disk
+ * the media is just a RAM buffer.
+ */
+static int32_t prvWriteRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
+
+/*
+ * The function that reads from the media - as this is implementing a RAM disk
+ * the media is just a RAM buffer.
+ */
+static int32_t prvReadRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
+
+/*
+ * This is the driver for a RAM disk. Unlike most media types, RAM disks are
+ * volatile so are created anew each time the system is booted. As the disk is
+ * new and just created, it must also be partitioned and formatted.
+ */
+static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk );
+
+/*-----------------------------------------------------------*/
+
+/* This is the prototype of the function used to initialise the RAM disk driver.
+Other media drivers do not have to have the same prototype.
+
+In this example:
+ + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.
+ + pucDataBuffer is the start of the RAM to use as the disk.
+ + ulSectorCount is effectively the size of the disk, each sector is 512 bytes.
+ + xIOManagerCacheSize is the size of the IO manager's cache, which must be a
+ multiple of the sector size, and at least twice as big as the sector size.
+*/
+FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize )
+{
+FF_Error_t xError;
+FF_Disk_t *pxDisk = NULL;
+FF_CreationParameters_t xParameters;
+
+ /* Check the validity of the xIOManagerCacheSize parameter. */
+ configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );
+ configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );
+
+ /* Attempt to allocated the FF_Disk_t structure. */
+ pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );
+
+ if( pxDisk != NULL )
+ {
+ /* Start with every member of the structure set to zero. */
+ memset( pxDisk, '\0', sizeof( FF_Disk_t ) );
+
+ /* Clear the entire space. */
+ memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE );
+
+ /* The pvTag member of the FF_Disk_t structure allows the structure to be
+ extended to also include media specific parameters. The only media
+ specific data that needs to be stored in the FF_Disk_t structure for a
+ RAM disk is the location of the RAM buffer itself - so this is stored
+ directly in the FF_Disk_t's pvTag member. */
+ pxDisk->pvTag = ( void * ) pucDataBuffer;
+
+ /* The signature is used by the disk read and disk write functions to
+ ensure the disk being accessed is a RAM disk. */
+ pxDisk->ulSignature = ramSIGNATURE;
+
+ /* The number of sectors is recorded for bounds checking in the read and
+ write functions. */
+ pxDisk->ulNumberOfSectors = ulSectorCount;
+
+ /* Create the IO manager that will be used to control the RAM disk. */
+ memset( &xParameters, '\0', sizeof( xParameters ) );
+ xParameters.pucCacheMemory = NULL;
+ xParameters.ulMemorySize = xIOManagerCacheSize;
+ xParameters.ulSectorSize = ramSECTOR_SIZE;
+ xParameters.fnWriteBlocks = prvWriteRAM;
+ xParameters.fnReadBlocks = prvReadRAM;
+ xParameters.pxDisk = pxDisk;
+
+ /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.
+ In this case the semaphore is only used to protect FAT data
+ structures. */
+ xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();
+ xParameters.xBlockDeviceIsReentrant = pdFALSE;
+
+ pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );
+
+ if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
+ {
+ /* Record that the RAM disk has been initialised. */
+ pxDisk->xStatus.bIsInitialised = pdTRUE;
+
+ /* Create a partition on the RAM disk. NOTE! The disk is only
+ being partitioned here because it is a new RAM disk. It is
+ known that the disk has not been used before, and cannot already
+ contain any partitions. Most media drivers will not perform
+ this step because the media will have already been partitioned. */
+ xError = prvPartitionAndFormatDisk( pxDisk );
+
+ if( FF_isERR( xError ) == pdFALSE )
+ {
+ /* Record the partition number the FF_Disk_t structure is, then
+ mount the partition. */
+ pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;
+
+ /* Mount the partition. */
+ xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
+ FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
+ }
+
+ if( FF_isERR( xError ) == pdFALSE )
+ {
+ /* The partition mounted successfully, add it to the virtual
+ file system - where it will appear as a directory off the file
+ system's root directory. */
+ FF_FS_Add( pcName, pxDisk );
+ }
+ }
+ else
+ {
+ FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
+
+ /* The disk structure was allocated, but the disk's IO manager could
+ not be allocated, so free the disk again. */
+ FF_RAMDiskDelete( pxDisk );
+ pxDisk = NULL;
+ }
+ }
+ else
+ {
+ FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );
+ }
+
+ return pxDisk;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk )
+{
+ if( pxDisk != NULL )
+ {
+ pxDisk->ulSignature = 0;
+ pxDisk->xStatus.bIsInitialised = 0;
+ if( pxDisk->pxIOManager != NULL )
+ {
+ FF_DeleteIOManager( pxDisk->pxIOManager );
+ }
+
+ vPortFree( pxDisk );
+ }
+
+ return pdPASS;
+}
+/*-----------------------------------------------------------*/
+
+static int32_t prvReadRAM( uint8_t *pucDestination, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
+{
+int32_t lReturn;
+uint8_t *pucSource;
+
+ if( pxDisk != NULL )
+ {
+ if( pxDisk->ulSignature != ramSIGNATURE )
+ {
+ /* The disk structure is not valid because it doesn't contain a
+ magic number written to the disk when it was created. */
+ lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
+ }
+ else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
+ {
+ /* The disk has not been initialised. */
+ lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
+ }
+ else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
+ {
+ /* The start sector is not within the bounds of the disk. */
+ lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
+ }
+ else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
+ {
+ /* The end sector is not within the bounds of the disk. */
+ lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
+ }
+ else
+ {
+ /* Obtain the pointer to the RAM buffer being used as the disk. */
+ pucSource = ( uint8_t * ) pxDisk->pvTag;
+
+ /* Move to the start of the sector being read. */
+ pucSource += ( ramSECTOR_SIZE * ulSectorNumber );
+
+ /* Copy the data from the disk. As this is a RAM disk this can be
+ done using memcpy(). */
+ memcpy( ( void * ) pucDestination,
+ ( void * ) pucSource,
+ ( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) );
+
+ lReturn = FF_ERR_NONE;
+ }
+ }
+ else
+ {
+ lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
+ }
+
+ return lReturn;
+}
+/*-----------------------------------------------------------*/
+
+static int32_t prvWriteRAM( uint8_t *pucSource, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
+{
+int32_t lReturn = FF_ERR_NONE;
+uint8_t *pucDestination;
+
+ if( pxDisk != NULL )
+ {
+ if( pxDisk->ulSignature != ramSIGNATURE )
+ {
+ /* The disk structure is not valid because it doesn't contain a
+ magic number written to the disk when it was created. */
+ lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
+ }
+ else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
+ {
+ /* The disk has not been initialised. */
+ lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
+ }
+ else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
+ {
+ /* The start sector is not within the bounds of the disk. */
+ lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
+ }
+ else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
+ {
+ /* The end sector is not within the bounds of the disk. */
+ lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
+ }
+ else
+ {
+ /* Obtain the location of the RAM being used as the disk. */
+ pucDestination = ( uint8_t * ) pxDisk->pvTag;
+
+ /* Move to the sector being written to. */
+ pucDestination += ( ramSECTOR_SIZE * ulSectorNumber );
+
+ /* Write to the disk. As this is a RAM disk the write can use a
+ memcpy(). */
+ memcpy( ( void * ) pucDestination,
+ ( void * ) pucSource,
+ ( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE );
+
+ lReturn = FF_ERR_NONE;
+ }
+ }
+ else
+ {
+ lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
+ }
+
+ return lReturn;
+}
+/*-----------------------------------------------------------*/
+
+static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk )
+{
+FF_PartitionParameters_t xPartition;
+FF_Error_t xError;
+
+ /* Create a single partition that fills all available space on the disk. */
+ memset( &xPartition, '\0', sizeof( xPartition ) );
+ xPartition.ulSectorCount = pxDisk->ulNumberOfSectors;
+ xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT;
+ xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS;
+ xPartition.eSizeType = eSizeIsQuota;
+
+ /* Partition the disk */
+ xError = FF_Partition( pxDisk, &xPartition );
+ FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
+
+ if( FF_isERR( xError ) == pdFALSE )
+ {
+ /* Format the partition. */
+ xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );
+ FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
+ }
+
+ return xError;
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk )
+{
+FF_Error_t xError;
+uint64_t ullFreeSectors;
+uint32_t ulTotalSizeKB, ulFreeSizeKB;
+int iPercentageFree;
+FF_IOManager_t *pxIOManager;
+const char *pcTypeName = "unknown type";
+BaseType_t xReturn = pdPASS;
+
+ if( pxDisk == NULL )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ pxIOManager = pxDisk->pxIOManager;
+
+ FF_PRINTF( "Reading FAT and calculating Free Space\n" );
+
+ switch( pxIOManager->xPartition.ucType )
+ {
+ case FF_T_FAT12:
+ pcTypeName = "FAT12";
+ break;
+
+ case FF_T_FAT16:
+ pcTypeName = "FAT16";
+ break;
+
+ case FF_T_FAT32:
+ pcTypeName = "FAT32";
+ break;
+
+ default:
+ pcTypeName = "UNKOWN";
+ break;
+ }
+
+ FF_GetFreeSize( pxIOManager, &xError );
+
+ ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
+ if( pxIOManager->xPartition.ulDataSectors == ( uint32_t )0 )
+ {
+ iPercentageFree = 0;
+ }
+ else
+ {
+ iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
+ ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
+ }
+
+ ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB;
+ ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB );
+
+ /* It is better not to use the 64-bit format such as %Lu because it
+ might not be implemented. */
+ FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
+ FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
+ FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
+ FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
+ FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
+ FF_PRINTF( "Size %8lu KB\n", ulTotalSizeKB );
+ FF_PRINTF( "FreeSize %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void FF_RAMDiskFlush( FF_Disk_t *pxDisk )
+{
+ if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) )
+ {
+ FF_FlushCache( pxDisk->pxIOManager );
+ }
+}
+/*-----------------------------------------------------------*/
+