1 /* USER CODE BEGIN Header */
2 /**
3   ******************************************************************************
4   * @file    flash_manager.c
5   * @author  MCD Application Team
6   * @brief   The Flash Manager module provides an interface to write raw data
7   *          from SRAM to FLASH
8   ******************************************************************************
9   * @attention
10   *
11   * Copyright (c) 2024 STMicroelectronics.
12   * All rights reserved.
13   *
14   * This software is licensed under terms that can be found in the LICENSE file
15   * in the root directory of this software component.
16   * If no LICENSE file comes with this software, it is provided AS-IS.
17   *
18   ******************************************************************************
19   */
20 /* USER CODE END Header */
21 
22 /* Includes ------------------------------------------------------------------*/
23 #include <stdbool.h>
24 #include "flash_manager.h"
25 #include "rf_timing_synchro.h"
26 #include "flash_driver.h"
27 #include "utilities_conf.h"
28 
29 #include "stm32wbaxx_hal.h"
30 
31 /* Debug */
32 #include "log_module.h"
33 
34 /* Global variables ----------------------------------------------------------*/
35 /* Private typedef -----------------------------------------------------------*/
36 
37 /* State of the background process */
38 typedef enum FM_BackGround_States
39 {
40   FM_BKGND_NOWINDOW_FLASHOP,
41   FM_BKGND_WINDOWED_FLASHOP,
42 }FM_BackGround_States_t;
43 
44 /* Flash operation type */
45 typedef enum
46 {
47   FM_WRITE_OP,
48   FM_ERASE_OP
49 } FM_FlashOp_t;
50 
51 /**
52  * @brief Flash operation configuration struct
53  */
54 typedef struct FM_FlashOpConfig
55 {
56   uint32_t *writeSrc;
57   uint32_t *writeDest;
58   int32_t  writeSize;
59   uint32_t eraseFirstSect;
60   uint32_t eraseNbrSect;
61 }FM_FlashOpConfig_t;
62 
63 /* Private defines -----------------------------------------------------------*/
64 #define FLASH_PAGE_NBR    (FLASH_SIZE / FLASH_PAGE_SIZE)
65 #define FLASH_WRITE_BLOCK_SIZE  4U
66 #define ALIGNMENT_32   0x00000003
67 #define ALIGNMENT_128  0x0000000F
68 
69 /* Private macros ------------------------------------------------------------*/
70 /* Private variables ---------------------------------------------------------*/
71 
72 /**
73   * @brief Semaphore on Flash
74   */
75 static bool busy_flash_sem = FALSE;
76 
77 /**
78   * @brief Indicates if the flash manager module is available or not
79   */
80 static bool flash_manager_busy = FALSE;
81 
82 /**
83   * @brief Parameters for Flash Write command
84   */
85 static bool fm_window_granted = FALSE;
86 
87 /**
88   * @brief Callback node list for pending flash operation request
89   */
90 static tListNode fm_cb_pending_list;
91 
92 /**
93   * @brief Flag indicating if pending node list has been initialized
94   */
95 static bool fm_cb_pending_list_init = FALSE;
96 
97 /**
98   * @brief Pointer to current flash operation requester's callback
99   */
100 static void (*fm_running_cb)(FM_FlashOp_Status_t);
101 
102 /**
103   * @brief Type of current flash operation (Write/Erase)
104   */
105 static FM_FlashOp_t fm_flashop;
106 
107 /**
108   * @brief Parameters for Flash operation
109   */
110 static FM_FlashOpConfig_t fm_flashop_parameters;
111 
112 /**
113  * @brief State of the Background process
114  */
115 static FM_BackGround_States_t FM_CurrentBackGroundState;
116 
117 /* Private function prototypes -----------------------------------------------*/
118 
119 static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode);
120 static void FM_WindowAllowed_Callback(void);
121 
122 /* Functions Definition ------------------------------------------------------*/
123 
124 /**
125   * @brief  Request the Flash Manager module to initiate a Flash Write operation
126   * @param  Src: Address of the data to be stored in FLASH. It shall be 32bits aligned
127   * @param  Dest: Address where the data shall be written. It shall be 128bits aligned
128   * @param  Size: This is the size of data to be written in Flash.
129                   The size is a multiple of 32bits (size = 1 means 32bits)
130   * @param  CallbackNode: Pointer to the callback node for storage in list
131   * @retval FM_Cmd_Status_t: Status of the Flash Manager module
132   */
FM_Write(uint32_t * Src,uint32_t * Dest,int32_t Size,FM_CallbackNode_t * CallbackNode)133 FM_Cmd_Status_t FM_Write(uint32_t *Src, uint32_t *Dest, int32_t Size, FM_CallbackNode_t *CallbackNode)
134 {
135   FM_Cmd_Status_t status;
136 
137   if (((uint32_t)Dest < FLASH_BASE) || ((uint32_t)Dest > (FLASH_BASE + FLASH_SIZE))
138                                     || (((uint32_t)Dest + Size) > (FLASH_BASE + FLASH_SIZE)))
139   {
140     LOG_ERROR_SYSTEM("\r\nFM_Write - Destination address not part of the flash");
141 
142     /* Destination address not part of the flash */
143     return FM_ERROR;
144   }
145 
146   if (((uint32_t) Src & ALIGNMENT_32) || ((uint32_t) Dest & ALIGNMENT_128))
147   {
148     LOG_ERROR_SYSTEM("\r\nFM_Write - Source or destination address not properly aligned");
149 
150     /* Source or destination address not properly aligned */
151     return FM_ERROR;
152   }
153 
154   status = FM_CheckFlashManagerState(CallbackNode);
155 
156   if (status == FM_OK)
157   { /* Flash manager is available */
158 
159     /* Save Write parameters */
160     fm_flashop_parameters.writeSrc = Src;
161     fm_flashop_parameters.writeDest = Dest;
162     fm_flashop_parameters.writeSize = Size;
163 
164     fm_flashop = FM_WRITE_OP;
165 
166     FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
167 
168     /* Window request to be executed in background */
169     FM_ProcessRequest();
170   }
171 
172   LOG_INFO_SYSTEM("\r\nFM_Write - Returned value : %d", status);
173 
174   return status;
175 }
176 
177 /**
178   * @brief  Request the Flash Manager module to initiate a Flash Erase operation
179   * @param  FirstSect: Index of the first sector to erase
180   * @param  NbrSect: Number of sector to erase
181   * @param  CallbackNode: Pointer to the callback node for storage in list
182   * @retval FM_Cmd_Status_t: Status of the Flash Manager module
183   */
FM_Erase(uint32_t FirstSect,uint32_t NbrSect,FM_CallbackNode_t * CallbackNode)184 FM_Cmd_Status_t FM_Erase(uint32_t FirstSect, uint32_t NbrSect, FM_CallbackNode_t *CallbackNode)
185 {
186   FM_Cmd_Status_t status;
187 
188   if ((FirstSect > FLASH_PAGE_NBR) || ((FirstSect + NbrSect) > FLASH_PAGE_NBR))
189   {
190     LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
191 
192     /* Inconsistent request */
193     return FM_ERROR;
194   }
195 
196   if (NbrSect == 0)
197   {
198     LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
199 
200     /* Inconsistent request */
201     return FM_ERROR;
202   }
203 
204   status = FM_CheckFlashManagerState(CallbackNode);
205 
206   if (status == FM_OK)
207   { /* Flash manager is available */
208 
209     /* Save Erase parameters */
210     fm_flashop_parameters.eraseFirstSect = FirstSect;
211     fm_flashop_parameters.eraseNbrSect = NbrSect;
212 
213     fm_flashop = FM_ERASE_OP;
214 
215     FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
216 
217     /* Window request to be executed in background */
218     FM_ProcessRequest();
219   }
220 
221   LOG_INFO_SYSTEM("\r\nFM_Erase - Returned value : %d", status);
222 
223   return status;
224 }
225 
226 /**
227   * @brief  Execute Flash Manager background tasks
228   * @param  None
229   * @retval None
230   */
FM_BackgroundProcess(void)231 void FM_BackgroundProcess (void)
232 {
233   static uint32_t duration;
234   bool flashop_complete = false;
235   FD_FlashOp_Status_t fdReturnValue = FD_FLASHOP_SUCCESS;
236   FM_CallbackNode_t *pCbNode = NULL;
237 
238   switch (FM_CurrentBackGroundState)
239   {
240     case FM_BKGND_NOWINDOW_FLASHOP:
241     {
242       LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP");
243 
244       if (fm_flashop == FM_WRITE_OP)
245       {
246         LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Write operation");
247 
248         /* Update duration time value */
249         duration = TIME_WINDOW_WRITE_REQUEST;
250 
251         /* Set the next possible state - App could stop at anytime no window operation */
252         FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
253 
254         HAL_FLASH_Unlock();
255 
256         while((fm_flashop_parameters.writeSize > 0) &&
257               (fdReturnValue == FD_FLASHOP_SUCCESS))
258         {
259           fdReturnValue = FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
260                                        (uint32_t) fm_flashop_parameters.writeSrc);
261 
262           if (fdReturnValue == FD_FLASHOP_SUCCESS)
263           {
264             fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
265             fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
266             fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
267           }
268         }
269 
270         HAL_FLASH_Lock();
271 
272         /* Is write over ? */
273         if (fm_flashop_parameters.writeSize <= 0)
274         {
275           flashop_complete = true;
276         }
277       }
278       else
279       {
280         LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Erase operation");
281 
282         /* Update duration time value */
283         duration = TIME_WINDOW_ERASE_REQUEST;
284 
285         /* Set the next possible state */
286         FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
287 
288         HAL_FLASH_Unlock();
289 
290         while((fm_flashop_parameters.eraseNbrSect > 0) &&
291               (fdReturnValue == FD_FLASHOP_SUCCESS))
292         {
293           fdReturnValue = FD_EraseSectors(fm_flashop_parameters.eraseFirstSect);
294 
295           if (fdReturnValue == FD_FLASHOP_SUCCESS)
296           {
297             fm_flashop_parameters.eraseNbrSect--;
298             fm_flashop_parameters.eraseFirstSect++;
299           }
300         }
301 
302         HAL_FLASH_Lock();
303 
304         if (fm_flashop_parameters.eraseNbrSect == 0)
305         {
306           flashop_complete = true;
307         }
308       }
309       break;
310     }
311 
312     case FM_BKGND_WINDOWED_FLASHOP:
313     {
314       LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP");
315 
316       if (fm_window_granted == false)
317       {
318         LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - No time window granted yet, request one");
319 
320         /* No time window granted yet, request one */
321         RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
322       }
323       else
324       {
325         LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Time window granted");
326 
327         if (fm_flashop == FM_WRITE_OP)
328         {
329           /* Flash Write operation */
330           LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Write operation");
331 
332           HAL_FLASH_Unlock();
333 
334           while((fm_flashop_parameters.writeSize > 0) &&
335                 (FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
336                               (uint32_t) fm_flashop_parameters.writeSrc) == FD_FLASHOP_SUCCESS))
337           {
338               fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
339               fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
340               fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
341           }
342 
343           if (fm_flashop_parameters.writeSize <= 0)
344           {
345             flashop_complete = true;
346           }
347 
348       HAL_FLASH_Lock();
349 
350     }
351     else
352     {
353       /* Flash Erase operation */
354       LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Erase operation");
355 
356       HAL_FLASH_Unlock();
357 
358       /* Erase only one sector in a single time window */
359       if (FD_EraseSectors(fm_flashop_parameters.eraseFirstSect) == FD_FLASHOP_SUCCESS)
360       {
361         fm_flashop_parameters.eraseNbrSect--;
362         fm_flashop_parameters.eraseFirstSect++;
363       }
364 
365       if (fm_flashop_parameters.eraseNbrSect == 0)
366       {
367         flashop_complete = true;
368       }
369 
370       HAL_FLASH_Lock();
371     }
372 
373         /* Release the time window */
374         RFTS_RelWindow();
375 
376         /* Indicate that there is no more window */
377         fm_window_granted = false;
378       }
379 
380       break;
381     }
382 
383     default:
384     {
385       /* Nothing to do here */
386       break;
387     }
388   }
389 
390   if (flashop_complete == true)
391   {
392     UTILS_ENTER_CRITICAL_SECTION();
393 
394     /* Release semaphore on flash */
395     busy_flash_sem = false;
396 
397     /* Set Flash Manager busy */
398     flash_manager_busy = false;
399 
400     UTILS_EXIT_CRITICAL_SECTION();
401 
402     /* Invoke the running callback if present */
403     if (fm_running_cb != NULL)
404     {
405       fm_running_cb(FM_OPERATION_COMPLETE);
406     }
407 
408     /* notify pending requesters */
409     while((LST_is_empty (&fm_cb_pending_list) == false) &&
410           (busy_flash_sem == false) && (flash_manager_busy == false))
411     {
412       LST_remove_head (&fm_cb_pending_list, (tListNode**)&pCbNode);
413       pCbNode->Callback(FM_OPERATION_AVAILABLE);
414     }
415   }
416   else
417   {
418     /* Flash operation not complete yet */
419     LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Flash operation not complete yet, request a new time window");
420 
421     /* Request a new time window */
422     RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
423   }
424 }
425 
426 /**
427   * @brief  Check if the Flash Manager is busy or available
428   * @param  CallbackNode: Pointer to the callback node for storage in list
429   * @retval FM_Cmd_Status_t: Status of the Flash Manager module
430   */
FM_CheckFlashManagerState(FM_CallbackNode_t * CallbackNode)431 static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode)
432 {
433   bool fm_process_cmd = false;
434   FM_Cmd_Status_t status = FM_ERROR;
435 
436   /* Check if semaphore on flash is available */
437   UTILS_ENTER_CRITICAL_SECTION();
438 
439   /* Initialize pending list if not done */
440   if (fm_cb_pending_list_init == false)
441   {
442     LST_init_head(&fm_cb_pending_list);
443     fm_cb_pending_list_init = true;
444   }
445   /* Check if semaphore on flash is available */
446   if (busy_flash_sem == false)
447   { /* Check if Flash Manager is already busy */
448     if (flash_manager_busy == false)
449     {
450       busy_flash_sem = true; /* Get semaphore on flash */
451       flash_manager_busy = true; /* Set Flash Manager busy */
452       fm_process_cmd = true;
453     }
454     else
455     {
456       fm_process_cmd = false;
457     }
458   }
459   else
460   {
461     fm_process_cmd = false;
462   }
463   UTILS_EXIT_CRITICAL_SECTION();
464 
465   if (fm_process_cmd == false)
466   { /* Flash manager busy */
467 
468     /* Append callback to the pending list */
469     if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
470     {
471       LST_insert_tail(&fm_cb_pending_list, &(CallbackNode->NodeList));
472     }
473 
474     status = FM_BUSY;
475   }
476   else
477   { /* Flash manager is available */
478 
479     if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
480     {
481       UTILS_ENTER_CRITICAL_SECTION();
482 
483       fm_running_cb = CallbackNode->Callback;
484 
485       UTILS_EXIT_CRITICAL_SECTION();
486     }
487     else
488     {
489       UTILS_ENTER_CRITICAL_SECTION();
490 
491       fm_running_cb = NULL;
492 
493       UTILS_EXIT_CRITICAL_SECTION();
494     }
495 
496     status = FM_OK;
497   }
498   return status;
499 }
500 
501 /**
502   * @brief  Callback called by RF Timing Synchro module when a time window is available
503   * @param  None
504   * @retval None
505   */
FM_WindowAllowed_Callback(void)506 static void FM_WindowAllowed_Callback(void)
507 {
508   fm_window_granted = true;
509 
510   LOG_INFO_SYSTEM("\r\nFM_WindowAllowed_Callback");
511 
512   /* Flash operation to be executed in background */
513   FM_ProcessRequest();
514 }
515