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