]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / ff_locking.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 #include <stdio.h>\r
28 #include <stdlib.h>\r
29 #include <string.h>\r
30 \r
31 /* Scheduler include files. */\r
32 #include "FreeRTOS.h"\r
33 #include "task.h"\r
34 #include "semphr.h"\r
35 #include "ff_headers.h"\r
36 #include "event_groups.h"\r
37 \r
38 #ifndef configUSE_RECURSIVE_MUTEXES\r
39         #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h\r
40 #else\r
41         #if( configUSE_RECURSIVE_MUTEXES != 1 )\r
42                 #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h\r
43         #endif\r
44 #endif /* configUSE_RECURSIVE_MUTEXES */\r
45 \r
46 #if ( INCLUDE_vTaskDelay != 1 )\r
47         #error Missing some FreeRTOS define\r
48 #endif\r
49 \r
50 /* There are two areas which are protected with a semaphore:\r
51 Directories and the FAT area.\r
52 The masks below are used when calling Group Event functions. */\r
53 #define FF_FAT_LOCK_EVENT_BITS    ( ( const EventBits_t ) FF_FAT_LOCK )\r
54 #define FF_DIR_LOCK_EVENT_BITS    ( ( const EventBits_t ) FF_DIR_LOCK )\r
55 \r
56 /* This is not a real lock: it is a bit (or semaphore) will will be given\r
57 each time when a sector buffer is released. */\r
58 #define FF_BUF_LOCK_EVENT_BITS    ( ( const EventBits_t ) FF_BUF_LOCK )\r
59 \r
60 /*-----------------------------------------------------------*/\r
61 \r
62 BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms )\r
63 {\r
64 BaseType_t xReturn;\r
65 \r
66         /* HT: Actually FF_TrySemaphore is never used. */\r
67         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
68         {\r
69                 return 0;\r
70         }\r
71         configASSERT( pxSemaphore );\r
72         xReturn = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, pdMS_TO_TICKS( ulTime_ms ) );\r
73         return xReturn;\r
74 }\r
75 /*-----------------------------------------------------------*/\r
76 \r
77 void FF_PendSemaphore( void *pxSemaphore )\r
78 {\r
79         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
80         {\r
81                 /* No need to take the semaphore. */\r
82                 return;\r
83         }\r
84         configASSERT( pxSemaphore );\r
85         xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, portMAX_DELAY );\r
86 }\r
87 /*-----------------------------------------------------------*/\r
88 \r
89 void FF_ReleaseSemaphore( void *pxSemaphore )\r
90 {\r
91         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
92         {\r
93                 /* Scheduler not yet active. */\r
94                 return;\r
95         }\r
96         configASSERT( pxSemaphore );\r
97         xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) pxSemaphore );\r
98 }\r
99 /*-----------------------------------------------------------*/\r
100 \r
101 void FF_Sleep( uint32_t ulTime_ms )\r
102 {\r
103         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
104         {\r
105                 /* This sleep is used as a kind of yield.\r
106                 Not necessary while the Scheduler does not run. */\r
107                 return;\r
108         }\r
109         vTaskDelay( pdMS_TO_TICKS( ulTime_ms ) );\r
110 }\r
111 /*-----------------------------------------------------------*/\r
112 \r
113 void FF_DeleteEvents( FF_IOManager_t *pxIOManager )\r
114 {\r
115         if( pxIOManager->xEventGroup != NULL )\r
116         {\r
117                 vEventGroupDelete( pxIOManager->xEventGroup );\r
118         }\r
119 }\r
120 /*-----------------------------------------------------------*/\r
121 \r
122 BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager )\r
123 {\r
124 BaseType_t xResult;\r
125 \r
126         pxIOManager->xEventGroup = xEventGroupCreate();\r
127         if( pxIOManager->xEventGroup != NULL )\r
128         {\r
129                 xEventGroupSetBits( pxIOManager->xEventGroup,\r
130                         FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS );\r
131                 xResult = pdTRUE;\r
132         }\r
133         else\r
134         {\r
135                 xResult = pdFALSE;\r
136         }\r
137 \r
138         return xResult;\r
139 }\r
140 /*-----------------------------------------------------------*/\r
141 \r
142 void FF_LockDirectory( FF_IOManager_t *pxIOManager )\r
143 {\r
144         EventBits_t xBits;\r
145 \r
146         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
147         {\r
148                 /* Scheduler not yet active. */\r
149                 return;\r
150         }\r
151         for( ;; )\r
152         {\r
153                 /* Called when a task want to make changes to a directory.\r
154                 First it waits for the desired bit to come high. */\r
155                 xEventGroupWaitBits( pxIOManager->xEventGroup,\r
156                         FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
157                         ( EventBits_t )0,       /* xClearOnExit */\r
158                         pdFALSE,                /* xWaitForAllBits n.a. */\r
159                         pdMS_TO_TICKS( 10000UL ) );\r
160 \r
161                 /* The next operation will only succeed for 1 task at a time,\r
162                 because it is an atomary test & set operation: */\r
163                 xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );\r
164 \r
165                 if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 )\r
166                 {\r
167                         /* This task has cleared the desired bit.\r
168                         It now 'owns' the resource. */\r
169                         break;\r
170                 }\r
171         }\r
172 }\r
173 /*-----------------------------------------------------------*/\r
174 \r
175 void FF_UnlockDirectory( FF_IOManager_t *pxIOManager )\r
176 {\r
177         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
178         {\r
179                 /* Scheduler not yet active. */\r
180                 return;\r
181         }\r
182         configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 );\r
183         xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );\r
184 }\r
185 /*-----------------------------------------------------------*/\r
186 \r
187 int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )\r
188 {\r
189 int iReturn;\r
190 \r
191         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
192         {\r
193                 /* Scheduler not yet active. */\r
194                 return 0;\r
195         }\r
196         void *handle = xTaskGetCurrentTaskHandle();\r
197         if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
198         {\r
199                 if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) )\r
200                 {\r
201                         iReturn = pdTRUE;\r
202                 }\r
203                 else\r
204                 {\r
205                         iReturn = pdFALSE;\r
206                 }\r
207         }\r
208         else\r
209         {\r
210                 iReturn = pdFALSE;\r
211         }\r
212         return iReturn;\r
213 }\r
214 \r
215 void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )\r
216 {\r
217         void *handle;\r
218 \r
219         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
220         {\r
221                 /* Scheduler not yet active. */\r
222                 return;\r
223         }\r
224         handle = xTaskGetCurrentTaskHandle();\r
225 \r
226         if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
227         {\r
228                 configASSERT( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) );\r
229 \r
230                 /* In case configASSERT() is not defined. */\r
231                 ( void ) pxIOManager;\r
232                 ( void ) handle;\r
233         }\r
234 }\r
235 \r
236 void FF_LockFAT( FF_IOManager_t *pxIOManager )\r
237 {\r
238 EventBits_t xBits;\r
239 \r
240         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
241         {\r
242                 /* Scheduler not yet active. */\r
243                 return;\r
244         }\r
245         configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE );\r
246 \r
247         for( ;; )\r
248         {\r
249                 /* Called when a task want to make changes to the FAT area.\r
250                 First it waits for the desired bit to come high. */\r
251                 xEventGroupWaitBits( pxIOManager->xEventGroup,\r
252                         FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
253                         ( EventBits_t )0,       /* xClearOnExit */\r
254                         pdFALSE,                /* xWaitForAllBits n.a. */\r
255                         pdMS_TO_TICKS( 10000UL ) );\r
256 \r
257                 /* The next operation will only succeed for 1 task at a time,\r
258                 because it is an atomary test & set operation: */\r
259                 xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );\r
260 \r
261                 if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )\r
262                 {\r
263                         /* This task has cleared the desired bit.\r
264                         It now 'owns' the resource. */\r
265                         pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle();\r
266                         break;\r
267                 }\r
268         }\r
269 }\r
270 /*-----------------------------------------------------------*/\r
271 \r
272 void FF_UnlockFAT( FF_IOManager_t *pxIOManager )\r
273 {\r
274         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
275         {\r
276                 /* Scheduler not yet active. */\r
277                 return;\r
278         }\r
279         configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 );\r
280         pxIOManager->pvFATLockHandle = NULL;\r
281         xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );\r
282 }\r
283 /*-----------------------------------------------------------*/\r
284 \r
285 BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS )\r
286 {\r
287 EventBits_t xBits;\r
288 BaseType_t xReturn;\r
289 \r
290         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
291         {\r
292                 /* Scheduler not yet active. */\r
293                 return pdTRUE;\r
294         }\r
295         /* This function is called when a task is waiting for a sector buffer\r
296         to become available. */\r
297         xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,\r
298                 FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */\r
299                 FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */\r
300                 pdFALSE,                /* xWaitForAllBits n.a. */\r
301                 pdMS_TO_TICKS( xWaitMS ) );\r
302         if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 )\r
303         {\r
304                 xReturn = pdTRUE;\r
305         }\r
306         else\r
307         {\r
308                 xReturn = pdFALSE;\r
309         }\r
310 \r
311         return xReturn;\r
312 }\r
313 /*-----------------------------------------------------------*/\r
314 \r
315 void FF_BufferProceed( FF_IOManager_t *pxIOManager )\r
316 {\r
317         if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )\r
318         {\r
319                 /* Scheduler not yet active. */\r
320                 return;\r
321         }\r
322         /* Wake-up all tasks that are waiting for a sector buffer to become available. */\r
323         xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS );\r
324 }\r
325 /*-----------------------------------------------------------*/\r