]> rtime.felk.cvut.cz Git - arc.git/blob - memory/Fee/Fee.c
Merge of lint branches.
[arc.git] / memory / Fee / Fee.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 \r
17 \r
18 \r
19 \r
20 \r
21 \r
22 \r
23 //lint -emacro(904,VALIDATE_RV,VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).\r
24 \r
25 // Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero\r
26 //lint -emacro(835, MIN_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
27 //lint -emacro(835, GET_BLOCK_INDEX_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
28 //lint -emacro(835, GET_DATASET_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
29 //lint -emacro(778, GET_DATASET_FROM_BLOCK_NUMBER) // 778 PC-lint: Constant expression evaluates to 0 in operation '-'\r
30 //lint -emacro(845, GET_DATASET_FROM_BLOCK_NUMBER) // 845 PC-lint: The right argument to operator '&' is certain to be 0\r
31 //lint -emacro(835, BLOCK_INDEX_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
32 \r
33 #include <string.h>\r
34 #include "Fee.h"\r
35 #include "Fee_Cbk.h"\r
36 #include "Fee_Memory_Cfg.h"\r
37 #include "NvM.h"\r
38 #include "Fls.h"\r
39 #include "Rte.h" // ???\r
40 #if defined(USE_DEM)\r
41 #include "Dem.h"\r
42 #endif\r
43 //#include "SchM_NvM.h"\r
44 #include "MemMap.h"\r
45 \r
46 /*\r
47  * Local definitions\r
48  */\r
49 \r
50 /*\r
51  *  Validation macros\r
52  */\r
53 #if  ( FEE_DEV_ERROR_DETECT == STD_ON )\r
54 #include "Det.h"\r
55 #define VALIDATE(_exp,_api,_err ) \\r
56         if( !(_exp) ) { \\r
57           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
58         }\r
59 \r
60 #define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
61         if( !(_exp) ) { \\r
62           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
63           return _rv; \\r
64         }\r
65 \r
66 #define VALIDATE_NO_RV(_exp,_api,_err ) \\r
67   if( !(_exp) ) { \\r
68           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
69           return; \\r
70         }\r
71 \r
72 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
73 \r
74 #define MIN_BLOCKNR             ((uint16)((uint16)1 << NVM_DATASET_SELECTION_BITS))\r
75 \r
76 #else\r
77 #define VALIDATE(_exp,_api,_err )\r
78 #define VALIDATE_RV(_exp,_api,_err,_rv )\r
79 #define VALIDATE_NO_RV(_exp,_api,_err )\r
80 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
81 #endif\r
82 \r
83 \r
84 /*\r
85  * Block numbering recalculation macros
86  */\r
87 #define GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(_blocknr)     (((_blocknr) >> NVM_DATASET_SELECTION_BITS) - 1u)\r
88 #define GET_DATASET_FROM_BLOCK_NUMBER(_blocknr) ((_blocknr) & ((uint16)((uint16)1u << NVM_DATASET_SELECTION_BITS) - 1u))\r
89 #define BLOCK_INDEX_AND_SET_TO_BLOCKNR(_blocknr, _set)  ((uint16)((_blocknr + 1u) << NVM_DATASET_SELECTION_BITS) | _set)\r
90 \r
91 /*\r
92  * Page alignment macros
93  */\r
94 #define PAGE_ALIGN(_size)       ((uint16)((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE))\r
95 \r
96 /*\r
97  * Bank properties list
98  */\r
99 #define NUM_OF_BANKS    2\r
100 typedef struct {\r
101         Fls_AddressType         Start;\r
102         Fls_LengthType          End;\r
103 } BankPropType;\r
104 \r
105 static const BankPropType BankProp[NUM_OF_BANKS] = {\r
106         {\r
107                 .Start = FEE_BANK1_OFFSET,\r
108                 .End = FEE_BANK1_OFFSET + FEE_BANK1_LENGTH\r
109         },\r
110         {\r
111                 .Start = FEE_BANK2_OFFSET,\r
112                 .End = FEE_BANK2_OFFSET + FEE_BANK2_LENGTH\r
113         },\r
114 };\r
115 \r
116 \r
117 \r
118 /*\r
119  * Macros and variables for flash bank administration
120  */\r
121 #define BANK_STATUS_OLD         0x00\r
122 #define BANK_STATUS_NEW         0xFF\r
123 typedef uint8 FlsBankStatusType;\r
124 \r
125 #define BANK_CTRL_PAGE_SIZE             PAGE_ALIGN(sizeof(FlsBankStatusType))\r
126 \r
127 typedef union {\r
128         FlsBankStatusType       BankStatus;\r
129         uint8                           Data[BANK_CTRL_PAGE_SIZE];\r
130 } FlsBankCtrlPageType;\r
131 \r
132 \r
133 /*\r
134  * Macros and variables for flash block administration in flash
135  */\r
136 #define BLOCK_STATUS_INUSE                      0x00\r
137 #define BLOCK_STATUS_INVALIDATED        0x02\r
138 #define BLOCK_STATUS_EMPTY                      0xFF\r
139 typedef uint8 BlockStatusType;\r
140 \r
141 typedef struct {\r
142         BlockStatusType         Status;\r
143         uint16                          BlockNo;\r
144         Fls_AddressType         BlockDataAddress;\r
145         uint16                          BlockDataLength;\r
146 } FlsBlockCtrlDataType;\r
147 \r
148 #define BLOCK_CTRL_DATA_PAGE_SIZE               PAGE_ALIGN(sizeof(FlsBlockCtrlDataType))\r
149 \r
150 typedef union {\r
151         FlsBlockCtrlDataType    Data;\r
152         uint8                                   Byte[BLOCK_CTRL_DATA_PAGE_SIZE];\r
153 } FlsBlockCtrlDataPageType;\r
154 \r
155 \r
156 #define BLOCK_MAGIC_LEN         4\r
157 static const uint8 BlockMagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };\r
158 #define BLOCK_CTRL_MAGIC_PAGE_SIZE      PAGE_ALIGN(BLOCK_MAGIC_LEN)\r
159 \r
160 \r
161 typedef union {\r
162         uint8           Magic[BLOCK_MAGIC_LEN];\r
163         uint8           Byte[BLOCK_CTRL_MAGIC_PAGE_SIZE];\r
164 } FlsBlockCtrlMagicPageType;\r
165 \r
166 typedef struct {\r
167         FlsBlockCtrlDataPageType        DataPage;\r
168         FlsBlockCtrlMagicPageType       MagicPage;\r
169 } FlsBlockControlType;\r
170 \r
171 #define BLOCK_CTRL_PAGE_SIZE    PAGE_ALIGN(sizeof(FlsBlockControlType))\r
172 \r
173 #define BLOCK_CTRL_DATA_POS_OFFSET              (/*lint --e(835)*/0)            // Inform PC-Lint that I want the constant to be zero\r
174 #define BLOCK_CTRL_MAGIC_POS_OFFSET             BLOCK_CTRL_DATA_PAGE_SIZE\r
175 \r
176 typedef union {\r
177         FlsBlockControlType     BlockCtrl;\r
178         FlsBankCtrlPageType BankCtrl;\r
179         uint8                           Byte[BLOCK_CTRL_PAGE_SIZE];\r
180 } ReadWriteBufferType;\r
181 \r
182 static ReadWriteBufferType RWBuffer;\r
183 \r
184 #define RWBUFFER_SIZE   sizeof(ReadWriteBufferType)\r
185 \r
186 \r
187 /*\r
188  * Variables for flash administration\r
189  */\r
190 typedef struct {\r
191         BlockStatusType         Status;\r
192         Fls_AddressType         BlockAdminAddress;\r
193         Fls_AddressType         BlockDataAddress;\r
194 } AdminFlsBlockType;\r
195 \r
196 typedef struct {\r
197         uint8                           BankNumber;\r
198         Fls_AddressType         NewBlockAdminAddress;\r
199         Fls_AddressType         NewBlockDataAddress;\r
200         FlsBankStatusType       BankStatus[NUM_OF_BANKS];\r
201         AdminFlsBlockType       BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];\r
202 } AdminFlsType;\r
203 \r
204 static AdminFlsType AdminFls;\r
205 \r
206 \r
207 /*\r
208  * Variables for quick reporting of status and job result
209  */\r
210 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;\r
211 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;\r
212 \r
213 /*\r
214  * Variables for the current job
215  */\r
216 typedef enum {\r
217   FEE_UNINITIALIZED = 0,\r
218   FEE_STARTUP_REQUESTED,\r
219   FEE_STARTUP_READ_BANK1_STATUS,\r
220   FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,\r
221   FEE_STARTUP_READ_BANK2_STATUS,\r
222   FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,\r
223   FEE_STARTUP_READ_BLOCK_ADMIN,\r
224 \r
225   FEE_IDLE,\r
226 \r
227   FEE_WRITE_REQUESTED,\r
228   FEE_WRITE_MARK_BANK_OLD,\r
229   FEE_WRITE_HEADER_REQUESTED,\r
230   FEE_WRITE_HEADER,\r
231   FEE_WRITE_DATA_REQUESTED,\r
232   FEE_WRITE_DATA,\r
233   FEE_WRITE_MAGIC_REQUESTED,\r
234   FEE_WRITE_MAGIC,\r
235 \r
236   FEE_READ_REQUESTED,\r
237   FEE_READ,\r
238 \r
239   FEE_INVALIDATE_REQUESTED,\r
240   FEE_INVALIDATE_MARK_BANK_OLD,\r
241   FEE_WRITE_INVALIDATE_HEADER_REQUESTED,\r
242   FEE_WRITE_INVALIDATE_HEADER,\r
243 \r
244   FEE_GARBAGE_COLLECT_REQUESTED,\r
245   FEE_GARBAGE_COLLECT_HEADER_WRITE,\r
246   FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,\r
247   FEE_GARBAGE_COLLECT_DATA_READ,\r
248   FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,\r
249   FEE_GARBAGE_COLLECT_DATA_WRITE,\r
250   FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,\r
251   FEE_GARBAGE_COLLECT_MAGIC_WRITE,\r
252   FEE_GARBAGE_COLLECT_ERASE\r
253 } CurrentJobStateType;\r
254 \r
255 typedef struct {\r
256         CurrentJobStateType                     State;\r
257         uint16                                          InStateCounter;\r
258         uint16                                          BlockNumber;\r
259         uint16                                          Length;\r
260         const Fee_BlockConfigType       *BlockConfigPtr;\r
261         AdminFlsBlockType                       *AdminFlsBlockPtr;\r
262         union {\r
263                 struct {\r
264                         uint8                           NrOfBanks;\r
265                         uint8                           BankNumber;\r
266                         Fls_AddressType         BlockAdminAddress;\r
267                 }Startup;\r
268                 struct {\r
269                         uint16                          Offset;\r
270                         uint8                           *RamPtr;\r
271                 }Read;\r
272                 struct {\r
273                         uint8                           *RamPtr;\r
274                         Fls_AddressType         WriteAdminAddress;\r
275                         Fls_AddressType         WriteDataAddress;\r
276                 }Write;\r
277                 struct {\r
278                         Fls_AddressType         WriteAdminAddress;\r
279                         Fls_AddressType         WriteDataAddress;\r
280                 }Invalidate;\r
281                 struct {\r
282                         uint8                           BankNumber;\r
283                         Fls_AddressType         WriteAdminAddress;\r
284                         Fls_AddressType         WriteDataAddress;\r
285                         uint16                          BytesLeft;\r
286                         uint16                          DataOffset;\r
287                 }GarbageCollect;\r
288         } Op;\r
289 } CurrentJobType;\r
290 \r
291 static CurrentJobType CurrentJob = {\r
292                 .State = FEE_IDLE,\r
293                 .InStateCounter = 0\r
294                 //lint -e{785}          PC-Lint (785) - rest of structure members is initialized when used.\r
295 };\r
296 \r
297 /*\r
298  * Misc definitions
299  */\r
300 #define STATE_COUNTER_MAX                               0xffff\r
301 #define GARBAGE_COLLECTION_DELAY                10\r
302 \r
303 /***************************************\r
304  *           Local functions           *\r
305  ***************************************/\r
306 \r
307 #if (FEE_POLLING_MODE == STD_ON)\r
308 #define SetFlsJobBusy()                 /* Nothing needs to be done here */\r
309 \r
310 static boolean CheckFlsJobFinnished(void)\r
311 {\r
312         MemIf_JobResultType flsJobResult;\r
313 \r
314         flsJobResult = Fls_GetJobResult();\r
315         return (flsJobResult != MEMIF_JOB_PENDING);\r
316 }\r
317 #else\r
318 static boolean FlsJobReady = TRUE;\r
319 \r
320 static void SetFlsJobBusy()\r
321 {\r
322         FlsJobReady = FALSE;\r
323 }\r
324 \r
325 static boolean CheckFlsJobFinnished(void)\r
326 {\r
327         return (FlsJobReady);\r
328 }\r
329 \r
330 #endif\r
331 \r
332 \r
333 static void FinnishStartup(void)\r
334 {\r
335         CurrentJob.State = FEE_IDLE;\r
336         ModuleStatus = MEMIF_IDLE;\r
337         JobResult = MEMIF_JOB_OK;\r
338 }\r
339 \r
340 \r
341 static void AbortStartup(MemIf_JobResultType result)\r
342 {\r
343         CurrentJob.State = FEE_IDLE;\r
344         ModuleStatus = MEMIF_IDLE;\r
345         JobResult = result;\r
346 }\r
347 \r
348 \r
349 static void FinnishJob(void)\r
350 {\r
351         CurrentJob.State = FEE_IDLE;\r
352         ModuleStatus = MEMIF_IDLE;\r
353         JobResult = MEMIF_JOB_OK;\r
354 \r
355         if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {\r
356                 Fee_Config.General.NvmJobEndCallbackNotificationCallback();\r
357         }\r
358 }\r
359 \r
360 \r
361 static void AbortJob(MemIf_JobResultType result)\r
362 {\r
363         CurrentJob.State = FEE_IDLE;\r
364         ModuleStatus = MEMIF_IDLE;\r
365         JobResult = result;\r
366 \r
367         if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
368                 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
369         }\r
370 }\r
371 \r
372 \r
373 /*\r
374  * Start of bank status 1 read\r
375  */\r
376 static void StartupStartJob(void)\r
377 {\r
378         if (Fls_GetStatus() == MEMIF_IDLE) {\r
379                 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;\r
380                 /* Read bank status of bank 1 */\r
381                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
382                 if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {\r
383                         SetFlsJobBusy();\r
384                 } else {\r
385                         AbortStartup(Fls_GetJobResult());\r
386                 }\r
387         }\r
388 }\r
389 \r
390 \r
391 /*\r
392  *  Check job result of bank 1 status read, if ok request for bank 2 status read\r
393  */\r
394 static void StartupReadBank1Status(void)\r
395 {\r
396         if (CheckFlsJobFinnished()) {\r
397                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
398                         CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;\r
399                 } else {\r
400                         AbortStartup(Fls_GetJobResult());\r
401                 }\r
402         }\r
403 }\r
404 \r
405 \r
406 /*\r
407  * Start of bank status 2 read\r
408  */\r
409 static void StartupReadBank2StatusRequested(void)\r
410 {\r
411         if (Fls_GetStatus() == MEMIF_IDLE) {\r
412                 /* Read bank status of bank 2 */\r
413                 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;\r
414                 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
415                 if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {\r
416                         SetFlsJobBusy();\r
417                 } else {\r
418                         AbortStartup(Fls_GetJobResult());\r
419                 }\r
420         }\r
421 }\r
422 \r
423 \r
424 /*\r
425  * Check job result of bank status 2 read - request for block status reading
426  */\r
427 static void StartupReadBank2Status(void)\r
428 {\r
429         MemIf_JobResultType jobResult;\r
430 \r
431         if (CheckFlsJobFinnished()) {\r
432                 jobResult = Fls_GetJobResult();\r
433                 if (jobResult == MEMIF_JOB_OK) {\r
434                         /* Select which bank to start with */\r
435                         if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){\r
436                                 /* None is marked as old, just start with one of them */\r
437                                 CurrentJob.Op.Startup.BankNumber = 0;\r
438                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
439                         } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {\r
440                                 /* Both banks are marked as old, this shall not be possible */\r
441                                 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
442                                 jobResult = MEMIF_JOB_FAILED;\r
443                         } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
444                                 CurrentJob.Op.Startup.BankNumber = 0;\r
445                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
446                         } else {\r
447                                 CurrentJob.Op.Startup.BankNumber = 1;\r
448                                 CurrentJob.Op.Startup.NrOfBanks = 2;\r
449                         }\r
450                 }\r
451 \r
452                 if (jobResult != MEMIF_JOB_OK) {\r
453                         AbortStartup(jobResult);\r
454                 } else {\r
455                         CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
456                         CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
457                 }\r
458         }\r
459 }\r
460 \r
461 /*\r
462  * Start of block admin read
463  */\r
464 static void StartupReadBlockAdminRequested(void)\r
465 {\r
466         if (Fls_GetStatus() == MEMIF_IDLE) {\r
467                 /* Start reading the banks */\r
468                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;\r
469                 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
470                         SetFlsJobBusy();\r
471                 } else {\r
472                         AbortStartup(Fls_GetJobResult());\r
473                 }\r
474         }\r
475 }\r
476 \r
477 \r
478 /*\r
479  * Check job result of block admin read, if all block processed finish\r
480  * otherwise request for a new block admin read
481  */\r
482 static void StartupReadBlockAdmin(void)\r
483 {\r
484         if (CheckFlsJobFinnished()) {\r
485                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
486                         if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {\r
487                                 VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
488                                 CurrentJob.Op.Startup.NrOfBanks--;\r
489                                 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;\r
490                                 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
491                         } else { /* Block not empty */\r
492                                 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN) == 0) &&\r
493                                                 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {\r
494                                         /* This is a valid admin block */\r
495                                         uint16 blockIndex;\r
496                                         uint16 dataSet;\r
497 \r
498                                         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
499                                         dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
500 \r
501                                         if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {\r
502                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
503                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;\r
504                                                 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;\r
505 \r
506                                                 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;\r
507                                                 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;\r
508                                                 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {\r
509                                                         /* This shall never happen */\r
510                                                         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
511                                                 }\r
512                                         }\r
513                                 }\r
514                                 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
515                                 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
516                         }\r
517 \r
518                         if (CurrentJob.Op.Startup.NrOfBanks == 0) {\r
519                                 /* If current bank is marked as old we need to switch to a new bank */\r
520                                 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {\r
521                                         AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;\r
522                                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
523                                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
524                                 }\r
525                                 /* We are done! */\r
526                                 FinnishStartup();\r
527                         } else {\r
528                                 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
529                         }\r
530 \r
531 \r
532                 } else { /* ErrorStatus not E_OK */\r
533                         AbortStartup(Fls_GetJobResult());\r
534                 }\r
535         }\r
536 }\r
537 \r
538 \r
539 /*\r
540  * Start of read block data\r
541  */\r
542 static void ReadStartJob(void)\r
543 {\r
544         if (Fls_GetStatus() == MEMIF_IDLE) {\r
545                 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {\r
546                         if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {\r
547                                 CurrentJob.State = FEE_READ;\r
548                                 /* Read the actual data */\r
549                                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {\r
550                                         SetFlsJobBusy();\r
551                                 } else {\r
552                                         AbortJob(Fls_GetJobResult());\r
553                                 }\r
554                         } else {\r
555                                 /* Invalid */\r
556                                 AbortJob(MEMIF_BLOCK_INVALID);\r
557                         }\r
558                 } else {\r
559                         /* Inconsistent */\r
560                         AbortJob(MEMIF_BLOCK_INCONSISTENT);\r
561                 }\r
562         }\r
563 }\r
564 \r
565 /*\r
566  * Check job result of block data read
567  */\r
568 static void Reading(void)\r
569 {\r
570         if (CheckFlsJobFinnished()) {\r
571                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
572                         FinnishJob();\r
573                 } else {\r
574                         AbortJob(Fls_GetJobResult());\r
575                 }\r
576         }\r
577 }\r
578 \r
579 \r
580 /*\r
581  * Write bank header\r
582  */\r
583 static void BankHeaderOldWrite(uint8 bank)\r
584 {\r
585         /* Mark the bank as old */\r
586         memset(RWBuffer.BankCtrl.Data, 0xff, BANK_CTRL_PAGE_SIZE);\r
587         RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;\r
588         if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {\r
589                 SetFlsJobBusy();\r
590         } else {\r
591                 AbortJob(Fls_GetJobResult());\r
592         }\r
593 }\r
594 \r
595 \r
596 /*\r
597  * Write block header\r
598  */\r
599 static void BlockHeaderDataWrite(void)\r
600 {\r
601         /* Write the header excluding the magic */\r
602         memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_CTRL_DATA_PAGE_SIZE);\r
603         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;\r
604         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
605         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
606         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;\r
607         if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_DATA_PAGE_SIZE) == E_OK) {\r
608                 SetFlsJobBusy();\r
609                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
610                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
611         } else {\r
612                 AbortJob(Fls_GetJobResult());\r
613         }\r
614 }\r
615 \r
616 \r
617 /*\r
618  * Check if bank switch needed:\r
619  * - Yes, start mark current bank as old\r
620  * - No, start of header write\r
621  */\r
622 static void WriteStartJob(void)\r
623 {\r
624         if (Fls_GetStatus() == MEMIF_IDLE) {\r
625                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
626                         /* Bank switch needed, mark current bank as "old" */\r
627                         CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;\r
628                         BankHeaderOldWrite(AdminFls.BankNumber);\r
629                 } else {\r
630                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
631                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
632 \r
633                         CurrentJob.State = FEE_WRITE_HEADER;\r
634                         BlockHeaderDataWrite();\r
635                 }\r
636         }\r
637 }\r
638 \r
639 \r
640 /*\r
641  * Check job result of mark bank as old, if ok request for header write\r
642  */\r
643 static void WriteMarkBankOldState(void)\r
644 {\r
645         if (CheckFlsJobFinnished()) {\r
646                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
647                         /* Mark for garbage collection */\r
648                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
649 \r
650                         /* Change of bank */\r
651                         AdminFls.BankNumber ^= 0x1u;\r
652                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
653                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
654 \r
655                         CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
656                         CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
657 \r
658                         CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;\r
659                 } else {\r
660                         AbortJob(Fls_GetJobResult());\r
661                 }\r
662         }\r
663 }\r
664 \r
665 \r
666 /*\r
667  * Start of header write
668  */\r
669 static void WriteHeaderRequested()\r
670 {\r
671         if (Fls_GetStatus() == MEMIF_IDLE) {\r
672                 CurrentJob.State = FEE_WRITE_HEADER;\r
673                 BlockHeaderDataWrite();\r
674         }\r
675 }\r
676 \r
677 \r
678 /*\r
679  * Check job result of write header, if ok request for block data write\r
680  */\r
681 static void WriteHeaderState(void)\r
682 {\r
683         if (CheckFlsJobFinnished()) {\r
684                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
685                         CurrentJob.State = FEE_WRITE_DATA_REQUESTED;\r
686                 } else {\r
687                         AbortJob(Fls_GetJobResult());\r
688                 }\r
689         }\r
690 }\r
691 \r
692 \r
693 /*\r
694  * Start block data write
695  */\r
696 static void WriteDataRequested(void)\r
697 {\r
698         if (Fls_GetStatus() == MEMIF_IDLE) {\r
699                 CurrentJob.State = FEE_WRITE_DATA;\r
700                 /* Write the actual data */\r
701                 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {\r
702                         SetFlsJobBusy();\r
703                 } else {\r
704                         AbortJob(Fls_GetJobResult());\r
705                 }\r
706         }\r
707 }\r
708 \r
709 \r
710 /*\r
711  * Check job result of data write - request for magic write\r
712  */\r
713 static void WriteDataState(void)\r
714 {\r
715         if (CheckFlsJobFinnished()) {\r
716                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
717                         CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;\r
718                 } else {\r
719                         AbortJob(Fls_GetJobResult());\r
720                 }\r
721         }\r
722 }\r
723 \r
724 \r
725 /*\r
726  * Start magic write
727  */\r
728 static void WriteMagicRequested(void)\r
729 {\r
730         if (Fls_GetStatus() == MEMIF_IDLE) {\r
731                 CurrentJob.State = FEE_WRITE_MAGIC;\r
732                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
733                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
734                 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
735                         SetFlsJobBusy();\r
736                 } else {\r
737                         AbortJob(Fls_GetJobResult());\r
738                 }\r
739         }\r
740 }\r
741 \r
742 \r
743 /*\r
744  * Check job result of write magic, if ok update the block admin table and finish\r
745  */\r
746 static void WriteMagicState(void)\r
747 {\r
748         if (CheckFlsJobFinnished()) {\r
749                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
750                         /* Update the block admin table */\r
751                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
752                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;\r
753                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;\r
754 \r
755                         FinnishJob();\r
756                 } else {\r
757                         AbortJob(Fls_GetJobResult());\r
758                 }\r
759         }\r
760 }\r
761 \r
762 \r
763 /*\r
764  * Check if any bank is marked as old\r
765  */\r
766 static void CheckIfGarbageCollectionNeeded(void)\r
767 {\r
768         if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
769                 ModuleStatus = MEMIF_BUSY_INTERNAL;\r
770                 JobResult = MEMIF_JOB_PENDING;\r
771 \r
772                 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
773         }\r
774 }\r
775 \r
776 \r
777 /*\r
778  * Checks if any blocks needs to be moved if so start with writing a new header\r
779  * or if no blocks needs to be moved request for bank erase.\r
780  */\r
781 static void GarbageCollectStartJob(void)\r
782 {\r
783         uint16 blockIndex;\r
784         uint16 set;\r
785         boolean found = FALSE;\r
786         uint8 sourceBank;\r
787 \r
788         if (Fls_GetStatus() == MEMIF_IDLE) {\r
789                 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
790                         if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
791                                 sourceBank = 0;\r
792                         } else {\r
793                                 sourceBank = 1;\r
794                         }\r
795 \r
796                         for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && (!found); blockIndex++) {\r
797                                 for (set = 0; (set < FEE_MAX_NUM_SETS) && (!found); set++) {\r
798                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {\r
799                                                 if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {\r
800                                                         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];\r
801                                                         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
802                                                         CurrentJob.BlockNumber = BLOCK_INDEX_AND_SET_TO_BLOCKNR(blockIndex, set);\r
803                                                         if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {\r
804                                                                 CurrentJob.Length = 0;\r
805                                                         } else {\r
806                                                                 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
807                                                         }\r
808 \r
809                                                         found = TRUE;\r
810                                                 }\r
811                                         }\r
812                                 }\r
813                         }\r
814 \r
815                         if (found) {\r
816                                 CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
817                                 CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
818 \r
819                                 CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;\r
820                                 BlockHeaderDataWrite();\r
821                         } else {\r
822                                 if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {\r
823                                         SetFlsJobBusy();\r
824                                 } else {\r
825                                         AbortJob(Fls_GetJobResult());\r
826                                 }\r
827                                 CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;\r
828                                 CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;\r
829                         }\r
830                 } else {\r
831                         CurrentJob.State = FEE_IDLE;\r
832                 }\r
833         }\r
834 }\r
835 \r
836 \r
837 /*\r
838  * Check job result of write header, if ok request for read block data\r
839  */\r
840 static void GarbageCollectWriteHeader(void)\r
841 {\r
842         if (CheckFlsJobFinnished()) {\r
843                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
844                         if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {\r
845                                 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
846                                 CurrentJob.Op.GarbageCollect.DataOffset = 0;\r
847                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
848                         } else {\r
849                                 /* Yes, we are finished */\r
850                                 VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INVALIDATED, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);\r
851                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
852                         }\r
853                 } else {\r
854                         AbortJob(Fls_GetJobResult());\r
855                 }\r
856         }\r
857 }\r
858 \r
859 \r
860 /*\r
861  * Start of read block data, if data length is more than buffer size\r
862  * the reading is segmented.\r
863  */\r
864 static void GarbageCollectReadDataRequested(void)\r
865 {\r
866         if (Fls_GetStatus() == MEMIF_IDLE) {\r
867                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;\r
868                 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
869                         CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;\r
870                 } else {\r
871                         CurrentJob.Length = RWBUFFER_SIZE;\r
872                 }\r
873                 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
874                         SetFlsJobBusy();\r
875                 } else {\r
876                         AbortJob(Fls_GetJobResult());\r
877                 }\r
878         }\r
879 }\r
880 \r
881 \r
882 /*\r
883  * Check job result of read block data, if ok request for a data write\r
884  */\r
885 static void GarbageCollectReadData(void)\r
886 {\r
887         if (CheckFlsJobFinnished()) {\r
888                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
889                         CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;\r
890                 } else {\r
891                         AbortJob(Fls_GetJobResult());\r
892                 }\r
893         }\r
894 }\r
895 \r
896 \r
897 /*\r
898  * Start of write block data\r
899  */\r
900 static void GarbageCollectWriteDataRequested(void)\r
901 {\r
902         if (Fls_GetStatus() == MEMIF_IDLE) {\r
903                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;\r
904                 /* Write the actual data */\r
905                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
906                         SetFlsJobBusy();\r
907                 } else {\r
908                         AbortJob(Fls_GetJobResult());\r
909                 }\r
910         } else {\r
911                 AbortJob(Fls_GetJobResult());\r
912         }\r
913 }\r
914 \r
915 \r
916 /*\r
917  * Check job result of write data, if ok request for write magic or\r
918  * next data read depending on if there are more block data to move.\r
919  */\r
920 static void GarbageCollectWriteData(void)\r
921 {\r
922         if (CheckFlsJobFinnished()) {\r
923                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
924                         if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
925                                 /* Yes, we are finished */\r
926                                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
927                         } else {\r
928                                 /* More data to move */\r
929                                 CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;\r
930                                 CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;\r
931                                 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
932                         }\r
933                 } else {\r
934                         AbortJob(Fls_GetJobResult());\r
935                 }\r
936         }\r
937 }\r
938 \r
939 \r
940 /*\r
941  * Start write magic\r
942  */\r
943 static void GarbageCollectWriteMagicRequested(void)\r
944 {\r
945         if (Fls_GetStatus() == MEMIF_IDLE) {\r
946                 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;\r
947                 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
948                 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
949                 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
950                         SetFlsJobBusy();\r
951                 } else {\r
952                         AbortJob(Fls_GetJobResult());\r
953                 }\r
954         }\r
955 }\r
956 \r
957 \r
958 /*\r
959  * Check the job result of write magic, if ok update the admin table with the new position of data.\r
960  */\r
961 static void GarbageCollectWriteMagic(void)\r
962 {\r
963         if (CheckFlsJobFinnished()) {\r
964                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
965                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
966                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
967                         FinnishJob();\r
968                 } else {\r
969                         AbortJob(Fls_GetJobResult());\r
970                 }\r
971         }\r
972 }\r
973 \r
974 \r
975 /*\r
976  * Check the result of the erase job\r
977  */\r
978 static void GarbageCollectErase(void)\r
979 {\r
980         if (CheckFlsJobFinnished()) {\r
981                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
982                         AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
983                         FinnishJob();\r
984                 } else {\r
985                         AbortJob(Fls_GetJobResult());\r
986                 }\r
987         }\r
988 }\r
989 \r
990 \r
991 /*\r
992  * Write an "Invalidated" block header\r
993  */\r
994 static void BlockHeaderInvalidWrite(void)\r
995 {\r
996         // Write the header including the magic\r
997         memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
998         RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
999         RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
1000         RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
1001         RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
1002         memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
1003         memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
1004 \r
1005         if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
1006                 SetFlsJobBusy();\r
1007                 AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
1008                 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
1009         } else {\r
1010                 AbortJob(Fls_GetJobResult());\r
1011         }\r
1012 }\r
1013 \r
1014 \r
1015 /*\r
1016  * Check if bank switch is needed, if yes request for marking current bank as old,\r
1017  * if no request for writing a header with "Invalid" status set.\r
1018  */\r
1019 static void InvalidateStartJob(void)\r
1020 {\r
1021         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1022                 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
1023                         /* Bank switch needed, mark current bank as "old" */\r
1024                         CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
1025                         BankHeaderOldWrite(AdminFls.BankNumber);\r
1026                 } else {\r
1027                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1028                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1029 \r
1030                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1031                         BlockHeaderInvalidWrite();\r
1032                 }\r
1033         }\r
1034 }\r
1035 \r
1036 \r
1037 /*\r
1038  * Check job result of mark bank old, if ok continue with request for writing\r
1039  * a header with "Invalid" status set.\r
1040  */\r
1041 static void InvalidateMarkBankOld(void)\r
1042 {\r
1043         if (CheckFlsJobFinnished()) {\r
1044                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1045                         // Mark for garbage collection\r
1046                         AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
1047 \r
1048                         // Change of bank\r
1049                         AdminFls.BankNumber ^= 0x1u;\r
1050                         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1051                         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1052 \r
1053                         CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
1054                         CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
1055 \r
1056                         CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
1057                 } else {\r
1058                         AbortJob(Fls_GetJobResult());\r
1059                 }\r
1060         }\r
1061 }\r
1062 \r
1063 /*\r
1064  * Start the writing of the "Invalid" header.
1065  */\r
1066 static void InvalidateWriteInvalidateHeaderRequested(void)\r
1067 {\r
1068         if (Fls_GetStatus() == MEMIF_IDLE) {\r
1069                 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
1070                 BlockHeaderInvalidWrite();\r
1071         }\r
1072 }\r
1073 \r
1074 \r
1075 /*\r
1076  * Check the job result of "Invalid" header write, if ok update the block admin table\r
1077  */\r
1078 static void InvalidateWriteInvalidateHeader(void)\r
1079 {\r
1080         if (CheckFlsJobFinnished()) {\r
1081                 if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
1082                         // Update the block admin table\r
1083                         CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INVALIDATED;\r
1084                         CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
1085                         CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
1086 \r
1087                         FinnishJob();\r
1088                 } else {\r
1089                         AbortJob(Fls_GetJobResult());\r
1090                 }\r
1091         }\r
1092 }\r
1093 \r
1094 \r
1095 /***************************************\r
1096  *    External accessible functions    *\r
1097  ***************************************/\r
1098 /*\r
1099  * Procedure:   Fee_Init\r
1100  * Reentrant:   No\r
1101  */\r
1102 void Fee_Init(void)\r
1103 {\r
1104         uint16 i,j;\r
1105 \r
1106         /* Reporting information */\r
1107         ModuleStatus = MEMIF_BUSY_INTERNAL;\r
1108         JobResult = MEMIF_JOB_OK;\r
1109 \r
1110         /* State of device */\r
1111         CurrentJob.State = FEE_STARTUP_REQUESTED;\r
1112         CurrentJob.InStateCounter = 0;\r
1113 #if (FEE_POLLING_MODE == STD_OFF)\r
1114         FlsJobReady = TRUE;\r
1115 #endif\r
1116 \r
1117         AdminFls.BankNumber = 0;\r
1118         AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
1119         AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
1120 \r
1121         for (i = 0; i < NUM_OF_BANKS; i++) {\r
1122                 AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
1123         }\r
1124 \r
1125         for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
1126                 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
1127                         AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
1128                         AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
1129                         AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
1130                 }\r
1131         }\r
1132 }\r
1133 \r
1134 \r
1135 /*\r
1136  * Procedure:   Fee_SetMode\r
1137  * Reentrant:   No\r
1138  */\r
1139 void Fee_SetMode(MemIf_ModeType mode)\r
1140 {\r
1141 #if ( FLS_SET_MODE_API == STD_ON )\r
1142         Fls_SetMode(mode);\r
1143 #else\r
1144         //lint --e{715} PC-Lint (715) - variable "mode" not used in this case\r
1145         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
1146 #endif\r
1147 }\r
1148 \r
1149 /*\r
1150  * Procedure:   Fee_Read\r
1151  * Reentrant:   No\r
1152  */\r
1153 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
1154 {\r
1155         uint16 blockIndex;\r
1156         uint16 dataset;\r
1157 \r
1158         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
1159         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
1160 \r
1161         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1162         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1163         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1164         VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1165         VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
1166         VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
1167 \r
1168         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1169         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1170 \r
1171 \r
1172         /** @req FEE022 */\r
1173         ModuleStatus = MEMIF_BUSY;\r
1174         JobResult = MEMIF_JOB_PENDING;\r
1175 \r
1176         CurrentJob.BlockNumber = blockNumber;\r
1177         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1178         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1179         CurrentJob.Length = length;\r
1180         CurrentJob.Op.Read.Offset = blockOffset;\r
1181         CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
1182         CurrentJob.State = FEE_READ_REQUESTED;\r
1183 \r
1184         return E_OK;\r
1185 }\r
1186 \r
1187 \r
1188 /*\r
1189  * Procedure:   Fee_Write\r
1190  * Reentrant:   No\r
1191  */\r
1192 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
1193 {\r
1194         uint16 blockIndex;\r
1195         uint16 dataset;\r
1196 \r
1197         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
1198         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_WRITE_ID, FEE_E_BUSY, E_NOT_OK);\r
1199 \r
1200         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1201         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1202         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1203         VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
1204 \r
1205         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1206         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1207 \r
1208 \r
1209         /** @req FEE025 */\r
1210         ModuleStatus = MEMIF_BUSY;\r
1211         JobResult = MEMIF_JOB_PENDING;\r
1212 \r
1213         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1214         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1215         CurrentJob.BlockNumber = blockNumber;\r
1216         CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
1217         CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
1218         CurrentJob.State = FEE_WRITE_REQUESTED;\r
1219 \r
1220         return E_OK;\r
1221 }\r
1222 \r
1223 \r
1224 /*\r
1225  * Procedure:   Fee_Cancel\r
1226  * Reentrant:   No\r
1227  */\r
1228 void Fee_Cancel(void)\r
1229 {\r
1230         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1231 }\r
1232 \r
1233 \r
1234 /*\r
1235  * Procedure:   Fee_GetStatus\r
1236  * Reentrant:   No\r
1237  */\r
1238 MemIf_StatusType Fee_GetStatus(void)\r
1239 {\r
1240         return ModuleStatus;\r
1241 }\r
1242 \r
1243 \r
1244 /*\r
1245  * Procedure:   Fee_GetJobResult\r
1246  * Reentrant:   No\r
1247  */\r
1248 MemIf_JobResultType Fee_GetJobResult(void)\r
1249 {\r
1250         return JobResult;\r
1251 }\r
1252 \r
1253 \r
1254 /*\r
1255  * Procedure:   Fee_InvalidateBlock\r
1256  * Reentrant:   No\r
1257  */\r
1258 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
1259 {\r
1260         uint16 blockIndex;\r
1261         uint16 dataset;\r
1262 \r
1263         VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
1264         VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_INVALIDATE_BLOCK_ID, FEE_E_BUSY, E_NOT_OK);\r
1265 \r
1266         VALIDATE_RV(blockNumber >= MIN_BLOCKNR, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1267         blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
1268         VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1269 \r
1270         dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
1271         VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
1272 \r
1273 \r
1274         ModuleStatus = MEMIF_BUSY;\r
1275         JobResult = MEMIF_JOB_PENDING;\r
1276 \r
1277         CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
1278         CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
1279         CurrentJob.BlockNumber = blockNumber;\r
1280         CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
1281 \r
1282         return E_OK;\r
1283 }\r
1284 \r
1285 \r
1286 /*\r
1287  * Procedure:   Fee_EraseImmediateBlock\r
1288  * Reentrant:   No\r
1289  */\r
1290 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
1291 {\r
1292         //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet\r
1293 \r
1294         DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
1295 \r
1296 \r
1297         return E_NOT_OK;\r
1298 }\r
1299 \r
1300 \r
1301 /***************************************\r
1302  *         Scheduled functions         *\r
1303  ***************************************/\r
1304 /*\r
1305  * Procedure:   Fee_MainFunction\r
1306  * Reentrant:   No\r
1307  */\r
1308 void Fee_MainFunction(void)\r
1309 {\r
1310         static CurrentJobStateType LastState = FEE_UNINITIALIZED;\r
1311 \r
1312         if (CurrentJob.State == LastState) {\r
1313                 if (CurrentJob.InStateCounter < STATE_COUNTER_MAX) {\r
1314                         CurrentJob.InStateCounter++;\r
1315                 }\r
1316         } else {\r
1317                 LastState = CurrentJob.State;\r
1318                 CurrentJob.InStateCounter = 0;\r
1319         }\r
1320 \r
1321         switch (CurrentJob.State) {\r
1322         case FEE_UNINITIALIZED:\r
1323                 break;\r
1324 \r
1325         case FEE_IDLE:\r
1326                 if (CurrentJob.InStateCounter > GARBAGE_COLLECTION_DELAY) {\r
1327                         CheckIfGarbageCollectionNeeded();\r
1328                 }\r
1329                 break;\r
1330 \r
1331                 /*\r
1332                  * Startup states\r
1333                  */\r
1334         case FEE_STARTUP_REQUESTED:\r
1335                 StartupStartJob();\r
1336                 break;\r
1337 \r
1338         case FEE_STARTUP_READ_BANK1_STATUS:\r
1339                 StartupReadBank1Status();\r
1340                 break;\r
1341 \r
1342         case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
1343                 StartupReadBank2StatusRequested();\r
1344                 break;\r
1345 \r
1346         case FEE_STARTUP_READ_BANK2_STATUS:\r
1347                 StartupReadBank2Status();\r
1348                 break;\r
1349 \r
1350         case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
1351                 StartupReadBlockAdminRequested();\r
1352                 break;\r
1353 \r
1354         case FEE_STARTUP_READ_BLOCK_ADMIN:\r
1355                 StartupReadBlockAdmin();\r
1356                 break;\r
1357 \r
1358         /*\r
1359          *  Read states\r
1360          */\r
1361         case FEE_READ_REQUESTED:\r
1362                 ReadStartJob();\r
1363                 break;\r
1364 \r
1365         case FEE_READ:\r
1366                 Reading();\r
1367                 break;\r
1368 \r
1369         /*\r
1370          * Write states
1371          */\r
1372         case FEE_WRITE_REQUESTED:\r
1373                 WriteStartJob();\r
1374                 break;\r
1375 \r
1376         case FEE_WRITE_MARK_BANK_OLD:\r
1377                 WriteMarkBankOldState();\r
1378                 break;\r
1379 \r
1380         case FEE_WRITE_HEADER_REQUESTED:\r
1381                 WriteHeaderRequested();\r
1382                 break;\r
1383 \r
1384         case FEE_WRITE_HEADER:\r
1385                 WriteHeaderState();\r
1386                 break;\r
1387 \r
1388         case FEE_WRITE_DATA_REQUESTED:\r
1389                 WriteDataRequested();\r
1390                 break;\r
1391 \r
1392         case FEE_WRITE_DATA:\r
1393                 WriteDataState();\r
1394                 break;\r
1395 \r
1396         case FEE_WRITE_MAGIC_REQUESTED:\r
1397                 WriteMagicRequested();\r
1398                 break;\r
1399 \r
1400         case FEE_WRITE_MAGIC:\r
1401                 WriteMagicState();\r
1402                 break;\r
1403 \r
1404         /*\r
1405          * Garbage collection states
1406          */\r
1407         case FEE_GARBAGE_COLLECT_REQUESTED:\r
1408                 GarbageCollectStartJob();\r
1409                 break;\r
1410 \r
1411         case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
1412                 GarbageCollectWriteHeader();\r
1413                 break;\r
1414 \r
1415         case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
1416                 GarbageCollectReadDataRequested();\r
1417                 break;\r
1418 \r
1419         case FEE_GARBAGE_COLLECT_DATA_READ:\r
1420                 GarbageCollectReadData();\r
1421                 break;\r
1422 \r
1423         case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
1424                 GarbageCollectWriteDataRequested();\r
1425                 break;\r
1426 \r
1427         case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
1428                 GarbageCollectWriteData();\r
1429                 break;\r
1430 \r
1431         case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
1432                 GarbageCollectWriteMagicRequested();\r
1433                 break;\r
1434 \r
1435         case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
1436                 GarbageCollectWriteMagic();\r
1437                 break;\r
1438 \r
1439         case FEE_GARBAGE_COLLECT_ERASE:\r
1440                 GarbageCollectErase();\r
1441                 break;\r
1442 \r
1443         /*\r
1444          * Invalidate states
1445          */\r
1446         case FEE_INVALIDATE_REQUESTED:\r
1447                 InvalidateStartJob();\r
1448                 break;\r
1449 \r
1450         case FEE_INVALIDATE_MARK_BANK_OLD:\r
1451                 InvalidateMarkBankOld();\r
1452                 break;\r
1453 \r
1454         case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
1455                 InvalidateWriteInvalidateHeaderRequested();\r
1456                 break;\r
1457 \r
1458         case FEE_WRITE_INVALIDATE_HEADER:\r
1459                 InvalidateWriteInvalidateHeader();\r
1460                 break;\r
1461 \r
1462 \r
1463         /*\r
1464          * Other
1465          */\r
1466         default:\r
1467                 break;\r
1468         }\r
1469 }\r
1470 \r
1471 \r
1472 /***************************************\r
1473  *  Call-back notifications functions  *\r
1474  ***************************************/\r
1475 #if (FEE_POLLING_MODE == STD_OFF)\r
1476 /*\r
1477  * Procedure:   Fee_JobEndNotification\r
1478  * Reentrant:   No\r
1479  */\r
1480 void Fee_JobEndNotification(void)\r
1481 {\r
1482         FlsJobReady = TRUE;\r
1483 }\r
1484 \r
1485 \r
1486 /*\r
1487  * Procedure:   Fee_JobErrorNotification\r
1488  * Reentrant:   No\r
1489  */\r
1490 void Fee_JobErrorNotification(void)\r
1491 {\r
1492         FlsJobReady = TRUE;\r
1493 }\r
1494 #endif\r