]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / portable / common / ff_ramdisk.c
1 /*\r
2  * FreeRTOS+FAT build 191128 - Note:  FreeRTOS+FAT is still in the lab!\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
5  *\r
6  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
7  * this software and associated documentation files (the "Software"), to deal in\r
8  * the Software without restriction, including without limitation the rights to\r
9  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
10  * the Software, and to permit persons to whom the Software is furnished to do so,\r
11  * subject to the following conditions:\r
12  *\r
13  * The above copyright notice and this permission notice shall be included in all\r
14  * copies or substantial portions of the Software.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * https://www.FreeRTOS.org\r
24  *\r
25  */\r
26 \r
27 /* Standard includes. */\r
28 #include <stdlib.h>\r
29 #include <string.h>\r
30 #include <stdarg.h>\r
31 #include <stdio.h>\r
32 \r
33 /* Scheduler include files. */\r
34 #include "FreeRTOS.h"\r
35 #include "task.h"\r
36 #include "semphr.h"\r
37 #include "portmacro.h"\r
38 \r
39 /* FreeRTOS+FAT includes. */\r
40 #include "ff_headers.h"\r
41 #include "ff_ramdisk.h"\r
42 #include "ff_sys.h"\r
43 \r
44 #define ramHIDDEN_SECTOR_COUNT          8\r
45 #define ramPRIMARY_PARTITIONS           1\r
46 #define ramHUNDRED_64_BIT                       100ULL\r
47 #define ramSECTOR_SIZE                          512UL\r
48 #define ramPARTITION_NUMBER                     0 /* Only a single partition is used. */\r
49 #define ramBYTES_PER_KB                         ( 1024ull )\r
50 #define ramSECTORS_PER_KB                       ( ramBYTES_PER_KB / 512ull )\r
51 \r
52 /* Used as a magic number to indicate that an FF_Disk_t structure is a RAM\r
53 disk. */\r
54 #define ramSIGNATURE                            0x41404342\r
55 \r
56 /*-----------------------------------------------------------*/\r
57 \r
58 /*\r
59  * The function that writes to the media - as this is implementing a RAM disk\r
60  * the media is just a RAM buffer.\r
61  */\r
62 static int32_t prvWriteRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );\r
63 \r
64 /*\r
65  * The function that reads from the media - as this is implementing a RAM disk\r
66  * the media is just a RAM buffer.\r
67  */\r
68 static int32_t prvReadRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );\r
69 \r
70 /*\r
71  * This is the driver for a RAM disk.  Unlike most media types, RAM disks are\r
72  * volatile so are created anew each time the system is booted.  As the disk is\r
73  * new and just created, it must also be partitioned and formatted.\r
74  */\r
75 static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk );\r
76 \r
77 /*-----------------------------------------------------------*/\r
78 \r
79 /* This is the prototype of the function used to initialise the RAM disk driver.\r
80 Other media drivers do not have to have the same prototype.\r
81 \r
82 In this example:\r
83  + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.\r
84  + pucDataBuffer is the start of the RAM to use as the disk.\r
85  + ulSectorCount is effectively the size of the disk, each sector is 512 bytes.\r
86  + xIOManagerCacheSize is the size of the IO manager's cache, which must be a\r
87    multiple of the sector size, and at least twice as big as the sector size.\r
88 */\r
89 FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize )\r
90 {\r
91 FF_Error_t xError;\r
92 FF_Disk_t *pxDisk = NULL;\r
93 FF_CreationParameters_t xParameters;\r
94 \r
95         /* Check the validity of the xIOManagerCacheSize parameter. */\r
96         configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );\r
97         configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );\r
98 \r
99         /* Attempt to allocated the FF_Disk_t structure. */\r
100         pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );\r
101 \r
102         if( pxDisk != NULL )\r
103         {\r
104                 /* Start with every member of the structure set to zero. */\r
105                 memset( pxDisk, '\0', sizeof( FF_Disk_t ) );\r
106 \r
107                 /* Clear the entire space. */\r
108                 memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE );\r
109 \r
110                 /* The pvTag member of the FF_Disk_t structure allows the structure to be\r
111                 extended to also include media specific parameters.  The only media\r
112                 specific data that needs to be stored in the FF_Disk_t structure for a\r
113                 RAM disk is the location of the RAM buffer itself - so this is stored\r
114                 directly in the FF_Disk_t's pvTag member. */\r
115                 pxDisk->pvTag = ( void * ) pucDataBuffer;\r
116 \r
117                 /* The signature is used by the disk read and disk write functions to\r
118                 ensure the disk being accessed is a RAM disk. */\r
119                 pxDisk->ulSignature = ramSIGNATURE;\r
120 \r
121                 /* The number of sectors is recorded for bounds checking in the read and\r
122                 write functions. */\r
123                 pxDisk->ulNumberOfSectors = ulSectorCount;\r
124 \r
125                 /* Create the IO manager that will be used to control the RAM disk. */\r
126                 memset( &xParameters, '\0', sizeof( xParameters ) );\r
127                 xParameters.pucCacheMemory = NULL;\r
128                 xParameters.ulMemorySize = xIOManagerCacheSize;\r
129                 xParameters.ulSectorSize = ramSECTOR_SIZE;\r
130                 xParameters.fnWriteBlocks = prvWriteRAM;\r
131                 xParameters.fnReadBlocks = prvReadRAM;\r
132                 xParameters.pxDisk = pxDisk;\r
133 \r
134                 /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.\r
135                 In this case the semaphore is only used to protect FAT data\r
136                 structures. */\r
137                 xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();\r
138                 xParameters.xBlockDeviceIsReentrant = pdFALSE;\r
139 \r
140                 pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );\r
141 \r
142                 if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )\r
143                 {\r
144                         /* Record that the RAM disk has been initialised. */\r
145                         pxDisk->xStatus.bIsInitialised = pdTRUE;\r
146 \r
147                         /* Create a partition on the RAM disk.  NOTE!  The disk is only\r
148                         being partitioned here because it is a new RAM disk.  It is\r
149                         known that the disk has not been used before, and cannot already\r
150                         contain any partitions.  Most media drivers will not perform\r
151                         this step because the media will have already been partitioned. */\r
152                         xError = prvPartitionAndFormatDisk( pxDisk );\r
153 \r
154                         if( FF_isERR( xError ) == pdFALSE )\r
155                         {\r
156                                 /* Record the partition number the FF_Disk_t structure is, then\r
157                                 mount the partition. */\r
158                                 pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;\r
159 \r
160                                 /* Mount the partition. */\r
161                                 xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );\r
162                                 FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );\r
163                         }\r
164 \r
165                         if( FF_isERR( xError ) == pdFALSE )\r
166                         {\r
167                                 /* The partition mounted successfully, add it to the virtual\r
168                                 file system - where it will appear as a directory off the file\r
169                                 system's root directory. */\r
170                                 FF_FS_Add( pcName, pxDisk );\r
171                         }\r
172                 }\r
173                 else\r
174                 {\r
175                         FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );\r
176 \r
177                         /* The disk structure was allocated, but the disk's IO manager could\r
178                         not be allocated, so free the disk again. */\r
179                         FF_RAMDiskDelete( pxDisk );\r
180                         pxDisk = NULL;\r
181                 }\r
182         }\r
183         else\r
184         {\r
185                 FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );\r
186         }\r
187 \r
188         return pxDisk;\r
189 }\r
190 /*-----------------------------------------------------------*/\r
191 \r
192 BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk )\r
193 {\r
194         if( pxDisk != NULL )\r
195         {\r
196                 pxDisk->ulSignature = 0;\r
197                 pxDisk->xStatus.bIsInitialised = 0;\r
198                 if( pxDisk->pxIOManager != NULL )\r
199                 {\r
200                         FF_DeleteIOManager( pxDisk->pxIOManager );\r
201                 }\r
202 \r
203                 vPortFree( pxDisk );\r
204         }\r
205 \r
206         return pdPASS;\r
207 }\r
208 /*-----------------------------------------------------------*/\r
209 \r
210 static int32_t prvReadRAM( uint8_t *pucDestination, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )\r
211 {\r
212 int32_t lReturn;\r
213 uint8_t *pucSource;\r
214 \r
215         if( pxDisk != NULL )\r
216         {\r
217                 if( pxDisk->ulSignature != ramSIGNATURE )\r
218                 {\r
219                         /* The disk structure is not valid because it doesn't contain a\r
220                         magic number written to the disk when it was created. */\r
221                         lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;\r
222                 }\r
223                 else if( pxDisk->xStatus.bIsInitialised == pdFALSE )\r
224                 {\r
225                         /* The disk has not been initialised. */\r
226                         lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;\r
227                 }\r
228                 else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )\r
229                 {\r
230                         /* The start sector is not within the bounds of the disk. */\r
231                         lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );\r
232                 }\r
233                 else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )\r
234                 {\r
235                         /* The end sector is not within the bounds of the disk. */\r
236                         lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );\r
237                 }\r
238                 else\r
239                 {\r
240                         /* Obtain the pointer to the RAM buffer being used as the disk. */\r
241                         pucSource = ( uint8_t * ) pxDisk->pvTag;\r
242 \r
243                         /* Move to the start of the sector being read. */\r
244                         pucSource += ( ramSECTOR_SIZE * ulSectorNumber );\r
245 \r
246                         /* Copy the data from the disk.  As this is a RAM disk this can be\r
247                         done using memcpy(). */\r
248                         memcpy( ( void * ) pucDestination,\r
249                                         ( void * ) pucSource,\r
250                                         ( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) );\r
251 \r
252                         lReturn = FF_ERR_NONE;\r
253                 }\r
254         }\r
255         else\r
256         {\r
257                 lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;\r
258         }\r
259 \r
260         return lReturn;\r
261 }\r
262 /*-----------------------------------------------------------*/\r
263 \r
264 static int32_t prvWriteRAM( uint8_t *pucSource, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )\r
265 {\r
266 int32_t lReturn = FF_ERR_NONE;\r
267 uint8_t *pucDestination;\r
268 \r
269         if( pxDisk != NULL )\r
270         {\r
271                 if( pxDisk->ulSignature != ramSIGNATURE )\r
272                 {\r
273                         /* The disk structure is not valid because it doesn't contain a\r
274                         magic number written to the disk when it was created. */\r
275                         lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;\r
276                 }\r
277                 else if( pxDisk->xStatus.bIsInitialised == pdFALSE )\r
278                 {\r
279                         /* The disk has not been initialised. */\r
280                         lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;\r
281                 }\r
282                 else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )\r
283                 {\r
284                         /* The start sector is not within the bounds of the disk. */\r
285                         lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );\r
286                 }\r
287                 else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )\r
288                 {\r
289                         /* The end sector is not within the bounds of the disk. */\r
290                         lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );\r
291                 }\r
292                 else\r
293                 {\r
294                         /* Obtain the location of the RAM being used as the disk. */\r
295                         pucDestination = ( uint8_t * ) pxDisk->pvTag;\r
296 \r
297                         /* Move to the sector being written to. */\r
298                         pucDestination += ( ramSECTOR_SIZE * ulSectorNumber );\r
299 \r
300                         /* Write to the disk.  As this is a RAM disk the write can use a\r
301                         memcpy(). */\r
302                         memcpy( ( void * ) pucDestination,\r
303                                         ( void * ) pucSource,\r
304                                         ( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE );\r
305 \r
306                         lReturn = FF_ERR_NONE;\r
307                 }\r
308         }\r
309         else\r
310         {\r
311                 lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;\r
312         }\r
313 \r
314         return lReturn;\r
315 }\r
316 /*-----------------------------------------------------------*/\r
317 \r
318 static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk )\r
319 {\r
320 FF_PartitionParameters_t xPartition;\r
321 FF_Error_t xError;\r
322 \r
323         /* Create a single partition that fills all available space on the disk. */\r
324         memset( &xPartition, '\0', sizeof( xPartition ) );\r
325         xPartition.ulSectorCount = pxDisk->ulNumberOfSectors;\r
326         xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT;\r
327         xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS;\r
328         xPartition.eSizeType = eSizeIsQuota;\r
329 \r
330         /* Partition the disk */\r
331         xError = FF_Partition( pxDisk, &xPartition );\r
332         FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );\r
333 \r
334         if( FF_isERR( xError ) == pdFALSE )\r
335         {\r
336                 /* Format the partition. */\r
337                 xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );\r
338                 FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );\r
339         }\r
340 \r
341         return xError;\r
342 }\r
343 /*-----------------------------------------------------------*/\r
344 \r
345 BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk )\r
346 {\r
347 FF_Error_t xError;\r
348 uint64_t ullFreeSectors;\r
349 uint32_t ulTotalSizeKB, ulFreeSizeKB;\r
350 int iPercentageFree;\r
351 FF_IOManager_t *pxIOManager;\r
352 const char *pcTypeName = "unknown type";\r
353 BaseType_t xReturn = pdPASS;\r
354 \r
355         if( pxDisk == NULL )\r
356         {\r
357                 xReturn = pdFAIL;\r
358         }\r
359         else\r
360         {\r
361                 pxIOManager = pxDisk->pxIOManager;\r
362 \r
363                 FF_PRINTF( "Reading FAT and calculating Free Space\n" );\r
364 \r
365                 switch( pxIOManager->xPartition.ucType )\r
366                 {\r
367                         case FF_T_FAT12:\r
368                                 pcTypeName = "FAT12";\r
369                                 break;\r
370 \r
371                         case FF_T_FAT16:\r
372                                 pcTypeName = "FAT16";\r
373                                 break;\r
374 \r
375                         case FF_T_FAT32:\r
376                                 pcTypeName = "FAT32";\r
377                                 break;\r
378 \r
379                         default:\r
380                                 pcTypeName = "UNKOWN";\r
381                                 break;\r
382                 }\r
383 \r
384                 FF_GetFreeSize( pxIOManager, &xError );\r
385 \r
386                 ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;\r
387                 if( pxIOManager->xPartition.ulDataSectors == ( uint32_t )0 )\r
388                 {\r
389                         iPercentageFree = 0;\r
390                 }\r
391                 else\r
392                 {\r
393                         iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /\r
394                                 ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );\r
395                 }\r
396 \r
397                 ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB;\r
398                 ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB );\r
399 \r
400                 /* It is better not to use the 64-bit format such as %Lu because it\r
401                 might not be implemented. */\r
402                 FF_PRINTF( "Partition Nr   %8u\n", pxDisk->xStatus.bPartitionNumber );\r
403                 FF_PRINTF( "Type           %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );\r
404                 FF_PRINTF( "VolLabel       '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );\r
405                 FF_PRINTF( "TotalSectors   %8lu\n", pxIOManager->xPartition.ulTotalSectors );\r
406                 FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );\r
407                 FF_PRINTF( "Size           %8lu KB\n", ulTotalSizeKB );\r
408                 FF_PRINTF( "FreeSize       %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree );\r
409         }\r
410 \r
411         return xReturn;\r
412 }\r
413 /*-----------------------------------------------------------*/\r
414 \r
415 void FF_RAMDiskFlush( FF_Disk_t *pxDisk )\r
416 {\r
417         if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) )\r
418         {\r
419                 FF_FlushCache( pxDisk->pxIOManager );\r
420         }\r
421 }\r
422 /*-----------------------------------------------------------*/\r
423 \r