--- /dev/null
+/*\r
+ * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!\r
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * https://www.FreeRTOS.org\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+/* Scheduler include files. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "semphr.h"\r
+#include "ff_headers.h"\r
+#include "event_groups.h"\r
+\r
+#ifndef configUSE_RECURSIVE_MUTEXES\r
+ #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h\r
+#else\r
+ #if( configUSE_RECURSIVE_MUTEXES != 1 )\r
+ #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h\r
+ #endif\r
+#endif /* configUSE_RECURSIVE_MUTEXES */\r
+\r
+#if ( INCLUDE_vTaskDelay != 1 )\r
+ #error Missing some FreeRTOS define\r
+#endif\r
+\r
+/* There are two areas which are protected with a semaphore:\r
+Directories and the FAT area.\r
+The masks below are used when calling Group Event functions. */\r
+#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK )\r
+#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK )\r
+\r
+/* This is not a real lock: it is a bit (or semaphore) will will be given\r
+each time when a sector buffer is released. */\r
+#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms )\r
+{\r
+BaseType_t xReturn;\r
+\r
+ /* HT: Actually FF_TrySemaphore is never used. */\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ return 0;\r
+ }\r
+ configASSERT( pxSemaphore );\r
+ xReturn = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, pdMS_TO_TICKS( ulTime_ms ) );\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_PendSemaphore( void *pxSemaphore )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* No need to take the semaphore. */\r
+ return;\r
+ }\r
+ configASSERT( pxSemaphore );\r
+ xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, portMAX_DELAY );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_ReleaseSemaphore( void *pxSemaphore )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ configASSERT( pxSemaphore );\r
+ xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) pxSemaphore );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_Sleep( uint32_t ulTime_ms )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* This sleep is used as a kind of yield.\r
+ Not necessary while the Scheduler does not run. */\r
+ return;\r
+ }\r
+ vTaskDelay( pdMS_TO_TICKS( ulTime_ms ) );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_DeleteEvents( FF_IOManager_t *pxIOManager )\r
+{\r
+ if( pxIOManager->xEventGroup != NULL )\r
+ {\r
+ vEventGroupDelete( pxIOManager->xEventGroup );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager )\r
+{\r
+BaseType_t xResult;\r
+\r
+ pxIOManager->xEventGroup = xEventGroupCreate();\r
+ if( pxIOManager->xEventGroup != NULL )\r
+ {\r
+ xEventGroupSetBits( pxIOManager->xEventGroup,\r
+ FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS );\r
+ xResult = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ xResult = pdFALSE;\r
+ }\r
+\r
+ return xResult;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_LockDirectory( FF_IOManager_t *pxIOManager )\r
+{\r
+ EventBits_t xBits;\r
+\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ for( ;; )\r
+ {\r
+ /* Called when a task want to make changes to a directory.\r
+ First it waits for the desired bit to come high. */\r
+ xEventGroupWaitBits( pxIOManager->xEventGroup,\r
+ FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
+ ( EventBits_t )0, /* xClearOnExit */\r
+ pdFALSE, /* xWaitForAllBits n.a. */\r
+ pdMS_TO_TICKS( 10000UL ) );\r
+\r
+ /* The next operation will only succeed for 1 task at a time,\r
+ because it is an atomary test & set operation: */\r
+ xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );\r
+\r
+ if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 )\r
+ {\r
+ /* This task has cleared the desired bit.\r
+ It now 'owns' the resource. */\r
+ break;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_UnlockDirectory( FF_IOManager_t *pxIOManager )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 );\r
+ xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )\r
+{\r
+int iReturn;\r
+\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return 0;\r
+ }\r
+ void *handle = xTaskGetCurrentTaskHandle();\r
+ if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
+ {\r
+ if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) )\r
+ {\r
+ iReturn = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ iReturn = pdFALSE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ iReturn = pdFALSE;\r
+ }\r
+ return iReturn;\r
+}\r
+\r
+void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )\r
+{\r
+ void *handle;\r
+\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ handle = xTaskGetCurrentTaskHandle();\r
+\r
+ if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
+ {\r
+ configASSERT( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) );\r
+\r
+ /* In case configASSERT() is not defined. */\r
+ ( void ) pxIOManager;\r
+ ( void ) handle;\r
+ }\r
+}\r
+\r
+void FF_LockFAT( FF_IOManager_t *pxIOManager )\r
+{\r
+EventBits_t xBits;\r
+\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE );\r
+\r
+ for( ;; )\r
+ {\r
+ /* Called when a task want to make changes to the FAT area.\r
+ First it waits for the desired bit to come high. */\r
+ xEventGroupWaitBits( pxIOManager->xEventGroup,\r
+ FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
+ ( EventBits_t )0, /* xClearOnExit */\r
+ pdFALSE, /* xWaitForAllBits n.a. */\r
+ pdMS_TO_TICKS( 10000UL ) );\r
+\r
+ /* The next operation will only succeed for 1 task at a time,\r
+ because it is an atomary test & set operation: */\r
+ xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );\r
+\r
+ if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
+ {\r
+ /* This task has cleared the desired bit.\r
+ It now 'owns' the resource. */\r
+ pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle();\r
+ break;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_UnlockFAT( FF_IOManager_t *pxIOManager )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 );\r
+ pxIOManager->pvFATLockHandle = NULL;\r
+ xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS )\r
+{\r
+EventBits_t xBits;\r
+BaseType_t xReturn;\r
+\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return pdTRUE;\r
+ }\r
+ /* This function is called when a task is waiting for a sector buffer\r
+ to become available. */\r
+ xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,\r
+ FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
+ FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */\r
+ pdFALSE, /* xWaitForAllBits n.a. */\r
+ pdMS_TO_TICKS( xWaitMS ) );\r
+ if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 )\r
+ {\r
+ xReturn = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ xReturn = pdFALSE;\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void FF_BufferProceed( FF_IOManager_t *pxIOManager )\r
+{\r
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
+ {\r
+ /* Scheduler not yet active. */\r
+ return;\r
+ }\r
+ /* Wake-up all tasks that are waiting for a sector buffer to become available. */\r
+ xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS );\r
+}\r
+/*-----------------------------------------------------------*/\r