1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\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
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
14 * -------------------------------- Arctic Core ------------------------------*/
\r
16 /** @reqSettings DEFAULT_SPECIFICATION_REVISION=3.1.5 */
\r
26 * Implements the Fee module
\r
29 * General Have Support
\r
30 * -------------------------------------------
\r
31 * FEE_DEV_ERROR_DETECT Y
\r
32 * FeeIndex N (always 0)
\r
33 * FEE_NVM_JOB_END_NOTIFICATION Y (Under ArcCore FEE_USE_JOB_NOTIFICATIONS is used)
\r
34 * FEE_NVM_JOB_ERROR_NOTIFICATION Y (Under ArcCore FEE_USE_JOB_NOTIFICATIONS is used)
\r
35 * FEE_POLLING_MODE Y
\r
36 * FEE_VERSION_INFO_API Y
\r
37 * FEE_VIRTUAL_PAGE_SIZE Y
\r
39 * Block Have Support
\r
40 * -------------------------------------------
\r
43 * FeeImmediateData N
\r
44 * FeeNumberOfWriteCycles N
\r
47 * Published Information Have Support
\r
48 * -------------------------------------------
\r
49 * FEE_BLOCK_OVERHEAD N
\r
50 * FEE_MAXIMUM_BLOCKING_TIME N
\r
51 * FEE_PAGE_OVERHEAD N
\r
55 //lint -emacro(904,DET_VALIDATE_RV,DET_VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).
\r
57 // Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero
\r
58 //lint -emacro(835, MIN_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'
\r
59 //lint -emacro(835, GET_BLOCK_INDEX_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'
\r
60 //lint -emacro(835, GET_DATASET_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'
\r
61 //lint -emacro(778, GET_DATASET_FROM_BLOCK_NUMBER) // 778 PC-lint: Constant expression evaluates to 0 in operation '-'
\r
62 //lint -emacro(845, GET_DATASET_FROM_BLOCK_NUMBER) // 845 PC-lint: The right argument to operator '&' is certain to be 0
\r
63 //lint -emacro(835, BLOCK_INDEX_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'
\r
67 #include "Fee_Cbk.h"
\r
68 #include "Fee_Memory_Cfg.h"
\r
71 #include "Rte.h" // ???
\r
72 #if defined(USE_DEM)
\r
75 //#include "SchM_NvM.h"
\r
79 //#define DEBUG_FEE 1
\r
80 #if defined(DEBUG_FEE)
\r
81 #define DEBUG_PRINTF(format,...) printf(format,## __VA_ARGS__ );
\r
83 #define DEBUG_PRINTF(format,...)
\r
95 #if ( FEE_DEV_ERROR_DETECT == STD_ON )
\r
97 #define DET_VALIDATE(_exp,_api,_err ) \
\r
99 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
102 #define DET_VALIDATE_RV(_exp,_api,_err,_rv ) \
\r
104 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
108 #define DET_VALIDATE_NO_RV(_exp,_api,_err ) \
\r
110 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
114 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)
\r
116 #define MIN_BLOCKNR ((uint16)((uint16)1 << NVM_DATASET_SELECTION_BITS))
\r
119 #define DET_VALIDATE(_exp,_api,_err )
\r
120 #define DET_VALIDATE_RV(_exp,_api,_err,_rv )
\r
121 #define DET_VALIDATE_NO_RV(_exp,_api,_err )
\r
122 #define DET_REPORTERROR(_module,_instance,_api,_err)
\r
127 * Block numbering recalculation macros
\r
129 #define GET_DATASET_FROM_BLOCK_NUMBER(_blocknr) ((_blocknr) & ((uint16)((uint16)1u << NVM_DATASET_SELECTION_BITS) - 1u))
\r
132 * Page alignment macros
\r
134 #define PAGE_ALIGN(_size) ((uint16)((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE))
\r
137 * Bank properties list
\r
139 #define NUM_OF_BANKS 2
\r
141 Fls_AddressType Start;
\r
142 Fls_LengthType End;
\r
145 static const BankPropType BankProp[NUM_OF_BANKS] = {
\r
147 .Start = FEE_BANK1_OFFSET,
\r
148 .End = FEE_BANK1_OFFSET + FEE_BANK1_LENGTH
\r
151 .Start = FEE_BANK2_OFFSET,
\r
152 .End = FEE_BANK2_OFFSET + FEE_BANK2_LENGTH
\r
159 * Macros and variables for flash bank administration
\r
161 #define BANK_STATUS_OLD 0x00
\r
162 #define BANK_STATUS_NEW 0xFF
\r
163 typedef uint8 FlsBankStatusType;
\r
165 #define BANK_CTRL_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBankStatusType))
\r
168 FlsBankStatusType BankStatus;
\r
169 uint8 Data[BANK_CTRL_PAGE_SIZE];
\r
170 } FlsBankCtrlPageType;
\r
174 * Macros and variables for flash block administration in flash
\r
176 #define BLOCK_STATUS_INUSE 0x00
\r
177 #define BLOCK_STATUS_INVALIDATED 0x02
\r
178 #define BLOCK_STATUS_EMPTY 0xFF
\r
179 typedef uint8 BlockStatusType;
\r
182 BlockStatusType Status;
\r
184 Fls_AddressType BlockDataAddress;
\r
185 uint16 BlockDataLength;
\r
186 } FlsBlockCtrlDataType;
\r
188 #define BLOCK_CTRL_DATA_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBlockCtrlDataType))
\r
191 FlsBlockCtrlDataType Data;
\r
192 uint8 Byte[BLOCK_CTRL_DATA_PAGE_SIZE];
\r
193 } FlsBlockCtrlDataPageType;
\r
196 #define BLOCK_MAGIC_LEN 4
\r
197 static const uint8 BlockMagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };
\r
198 #define BLOCK_CTRL_MAGIC_PAGE_SIZE PAGE_ALIGN(BLOCK_MAGIC_LEN)
\r
202 uint8 Magic[BLOCK_MAGIC_LEN];
\r
203 uint8 Byte[BLOCK_CTRL_MAGIC_PAGE_SIZE];
\r
204 } FlsBlockCtrlMagicPageType;
\r
207 FlsBlockCtrlDataPageType DataPage;
\r
208 FlsBlockCtrlMagicPageType MagicPage;
\r
209 } FlsBlockControlType;
\r
211 #define BLOCK_CTRL_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBlockControlType))
\r
213 #define BLOCK_CTRL_DATA_POS_OFFSET (/*lint --e(835)*/0) // Inform PC-Lint that I want the constant to be zero
\r
214 #define BLOCK_CTRL_MAGIC_POS_OFFSET BLOCK_CTRL_DATA_PAGE_SIZE
\r
217 FlsBlockControlType BlockCtrl;
\r
218 FlsBankCtrlPageType BankCtrl;
\r
219 uint8 Byte[BLOCK_CTRL_PAGE_SIZE];
\r
220 } ReadWriteBufferType;
\r
222 static ReadWriteBufferType RWBuffer;
\r
224 #define RWBUFFER_SIZE sizeof(ReadWriteBufferType)
\r
228 * Variables for flash administration
\r
231 BlockStatusType Status;
\r
232 Fls_AddressType BlockAdminAddress;
\r
233 Fls_AddressType BlockDataAddress;
\r
234 } AdminFlsBlockType;
\r
238 uint8 ForceGarbageCollect;
\r
239 uint8 NofFailedGarbageCollect;
\r
240 Fls_AddressType NewBlockAdminAddress;
\r
241 Fls_AddressType NewBlockDataAddress;
\r
242 FlsBankStatusType BankStatus[NUM_OF_BANKS];
\r
243 AdminFlsBlockType BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];
\r
246 static AdminFlsType AdminFls;
\r
250 * Variables for quick reporting of status and job result
\r
252 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;
\r
253 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;
\r
256 * Variables for the current job
\r
259 FEE_UNINITIALIZED = 0,
\r
260 FEE_STARTUP_REQUESTED,
\r
261 FEE_STARTUP_READ_BANK1_STATUS,
\r
262 FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,
\r
263 FEE_STARTUP_READ_BANK2_STATUS,
\r
264 FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,
\r
265 FEE_STARTUP_READ_BLOCK_ADMIN,
\r
269 FEE_WRITE_REQUESTED,
\r
270 FEE_WRITE_MARK_BANK_OLD,
\r
271 FEE_WRITE_HEADER_REQUESTED,
\r
273 FEE_WRITE_DATA_REQUESTED,
\r
275 FEE_WRITE_MAGIC_REQUESTED,
\r
278 FEE_READ_REQUESTED,
\r
281 FEE_INVALIDATE_REQUESTED,
\r
282 FEE_INVALIDATE_MARK_BANK_OLD,
\r
283 FEE_WRITE_INVALIDATE_HEADER_REQUESTED,
\r
284 FEE_WRITE_INVALIDATE_HEADER,
\r
286 FEE_GARBAGE_COLLECT_REQUESTED,
\r
287 FEE_GARBAGE_COLLECT_HEADER_WRITE,
\r
288 FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,
\r
289 FEE_GARBAGE_COLLECT_DATA_READ,
\r
290 FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,
\r
291 FEE_GARBAGE_COLLECT_DATA_WRITE,
\r
292 FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,
\r
293 FEE_GARBAGE_COLLECT_MAGIC_WRITE,
\r
294 FEE_GARBAGE_COLLECT_ERASE,
\r
298 } CurrentJobStateType;
\r
301 CurrentJobStateType State;
\r
302 uint16 BlockNumber;
\r
304 const Fee_BlockConfigType *BlockConfigPtr;
\r
305 AdminFlsBlockType *AdminFlsBlockPtr;
\r
310 Fls_AddressType BlockAdminAddress;
\r
318 Fls_AddressType WriteAdminAddress;
\r
319 Fls_AddressType WriteDataAddress;
\r
322 Fls_AddressType WriteAdminAddress;
\r
323 Fls_AddressType WriteDataAddress;
\r
327 Fls_AddressType WriteAdminAddress;
\r
328 Fls_AddressType WriteDataAddress;
\r
335 static CurrentJobType CurrentJob = {
\r
337 //lint -e{785} PC-Lint (785) - rest of structure members is initialized when used.
\r
343 #define MAX_NOF_FAILED_GC_ATTEMPTS 5
\r
344 /***************************************
\r
345 * Local functions *
\r
346 ***************************************/
\r
347 uint16 GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(uint16 blockNumber) {
\r
348 const Fee_BlockConfigType *FeeBlockCon;
\r
349 uint16 BlockIndex = FEE_NUM_OF_BLOCKS + 1; // An invalid block
\r
351 FeeBlockCon = Fee_Config.BlockConfig;
\r
352 for (uint16 i = 0; i < FEE_NUM_OF_BLOCKS; i++)
\r
354 if (FeeBlockCon[i].BlockNumber == blockNumber)
\r
365 #if (FEE_POLLING_MODE == STD_ON)
\r
366 #define SetFlsJobBusy() /* Nothing needs to be done here */
\r
368 static boolean CheckFlsJobFinnished(void)
\r
370 MemIf_JobResultType flsJobResult;
\r
372 flsJobResult = Fls_GetJobResult();
\r
373 return (flsJobResult != MEMIF_JOB_PENDING);
\r
376 static boolean FlsJobReady = TRUE;
\r
378 static void SetFlsJobBusy()
\r
380 FlsJobReady = FALSE;
\r
383 static boolean CheckFlsJobFinnished(void)
\r
385 return (FlsJobReady);
\r
391 static void FinnishStartup(void)
\r
393 CurrentJob.State = FEE_IDLE;
\r
394 ModuleStatus = MEMIF_IDLE;
\r
395 JobResult = MEMIF_JOB_OK;
\r
399 static void AbortStartup(MemIf_JobResultType result)
\r
401 CurrentJob.State = FEE_IDLE;
\r
402 ModuleStatus = MEMIF_IDLE;
\r
403 JobResult = result;
\r
407 static void FinnishJob(void)
\r
409 CurrentJob.State = FEE_IDLE;
\r
410 ModuleStatus = MEMIF_IDLE;
\r
411 JobResult = MEMIF_JOB_OK;
\r
412 if(!AdminFls.ForceGarbageCollect){
\r
413 if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {
\r
414 Fee_Config.General.NvmJobEndCallbackNotificationCallback();
\r
420 static void AbortJob(MemIf_JobResultType result)
\r
422 if(AdminFls.NofFailedGarbageCollect >= MAX_NOF_FAILED_GC_ATTEMPTS){
\r
423 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_GLOBAL_ID, FEE_FLASH_CORRUPT);
\r
424 AdminFls.ForceGarbageCollect = 0;
\r
425 CurrentJob.State = FEE_CORRUPTED;
\r
427 CurrentJob.State = FEE_IDLE;
\r
429 ModuleStatus = MEMIF_IDLE;
\r
430 JobResult = result;
\r
432 if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {
\r
433 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();
\r
439 * Start of bank status 1 read
\r
441 static void StartupStartJob(void)
\r
443 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
444 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;
\r
445 /* Read bank status of bank 1 */
\r
446 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR
\r
447 if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {
\r
450 AbortStartup(Fls_GetJobResult());
\r
457 * Check job result of bank 1 status read, if ok request for bank 2 status read
\r
459 static void StartupReadBank1Status(void)
\r
461 if (CheckFlsJobFinnished()) {
\r
462 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
463 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;
\r
465 AbortStartup(Fls_GetJobResult());
\r
472 * Start of bank status 2 read
\r
474 static void StartupReadBank2StatusRequested(void)
\r
476 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
477 /* Read bank status of bank 2 */
\r
478 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;
\r
479 // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR
\r
480 if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {
\r
483 AbortStartup(Fls_GetJobResult());
\r
490 * Check job result of bank status 2 read - request for block status reading
\r
492 static void StartupReadBank2Status(void)
\r
494 MemIf_JobResultType jobResult;
\r
496 if (CheckFlsJobFinnished()) {
\r
497 jobResult = Fls_GetJobResult();
\r
498 if (jobResult == MEMIF_JOB_OK) {
\r
499 /* Select which bank to start with */
\r
500 if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){
\r
501 /* None is marked as old, just start with one of them */
\r
502 CurrentJob.Op.Startup.BankNumber = 0;
\r
503 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
504 } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {
\r
505 /* Both banks are marked as old, this shall not be possible */
\r
506 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
507 jobResult = MEMIF_JOB_FAILED;
\r
508 } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {
\r
509 CurrentJob.Op.Startup.BankNumber = 0;
\r
510 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
512 CurrentJob.Op.Startup.BankNumber = 1;
\r
513 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
517 if (jobResult != MEMIF_JOB_OK) {
\r
518 AbortStartup(jobResult);
\r
520 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
521 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;
\r
527 * Start of block admin read
\r
529 static void StartupReadBlockAdminRequested(void)
\r
531 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
532 /* Start reading the banks */
\r
533 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;
\r
534 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {
\r
537 AbortStartup(Fls_GetJobResult());
\r
544 * Check job result of block admin read, if all block processed finish
\r
545 * otherwise request for a new block admin read
\r
547 static void StartupReadBlockAdmin(void)
\r
549 if (CheckFlsJobFinnished()) {
\r
550 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
551 if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {
\r
552 DET_VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
553 CurrentJob.Op.Startup.NrOfBanks--;
\r
554 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;
\r
555 CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
556 } else { /* Block not empty */
\r
557 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN) == 0) &&
\r
558 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {
\r
559 /* This is a valid admin block */
\r
563 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);
\r
564 dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);
\r
566 if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {
\r
567 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;
\r
568 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;
\r
569 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;
\r
571 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;
\r
572 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;
\r
573 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {
\r
574 /* This shall never happen */
\r
575 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
579 // TODO Check wrap around here
\r
580 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
581 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;
\r
584 if (CurrentJob.Op.Startup.NrOfBanks == 0) {
\r
585 /* If current bank is marked as old we need to switch to a new bank */
\r
586 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {
\r
587 AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;
\r
588 AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
589 AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;
\r
594 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;
\r
598 } else { /* ErrorStatus not E_OK */
\r
599 AbortStartup(Fls_GetJobResult());
\r
606 * Start of read block data
\r
608 static void ReadStartJob(void)
\r
610 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
611 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {
\r
612 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {
\r
613 CurrentJob.State = FEE_READ;
\r
614 /* Read the actual data */
\r
615 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {
\r
618 AbortJob(Fls_GetJobResult());
\r
622 AbortJob(MEMIF_BLOCK_INVALID);
\r
626 AbortJob(MEMIF_BLOCK_INCONSISTENT);
\r
632 * Check job result of block data read
\r
634 static void Reading(void)
\r
636 if (CheckFlsJobFinnished()) {
\r
637 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
640 AbortJob(Fls_GetJobResult());
\r
647 * Write bank header
\r
649 static void BankHeaderOldWrite(uint8 bank)
\r
651 /* Need to collect garbage */
\r
652 AdminFls.ForceGarbageCollect = 1;
\r
653 /* Mark the bank as old */
\r
654 memset(RWBuffer.BankCtrl.Data, 0xff, BANK_CTRL_PAGE_SIZE);
\r
655 RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;
\r
656 if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {
\r
659 AbortJob(Fls_GetJobResult());
\r
665 * Write block header
\r
667 static void BlockHeaderDataWrite(void)
\r
669 /* Write the header excluding the magic */
\r
670 memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_CTRL_DATA_PAGE_SIZE);
\r
671 RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;
\r
672 RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;
\r
673 RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;
\r
674 RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;
\r
675 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_DATA_PAGE_SIZE) == E_OK) {
\r
677 AdminFls.NewBlockDataAddress += CurrentJob.Length;
\r
678 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
680 AbortJob(Fls_GetJobResult());
\r
686 * Check if bank switch needed:
\r
687 * - Yes, start mark current bank as old
\r
688 * - No, start of header write
\r
690 static void WriteStartJob(void)
\r
692 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
693 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {
\r
694 /* Bank switch needed, mark current bank as "old" */
\r
695 CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;
\r
696 BankHeaderOldWrite(AdminFls.BankNumber);
\r
698 CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
699 CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
701 CurrentJob.State = FEE_WRITE_HEADER;
\r
702 BlockHeaderDataWrite();
\r
709 * Check job result of mark bank as old, if ok request for header write
\r
711 static void WriteMarkBankOldState(void)
\r
713 if (CheckFlsJobFinnished()) {
\r
714 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
715 /* Mark for garbage collection */
\r
716 AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;
\r
718 /* Change of bank */
\r
719 AdminFls.BankNumber ^= 0x1u;
\r
720 AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;
\r
721 AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
723 CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
724 CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
726 CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;
\r
728 AbortJob(Fls_GetJobResult());
\r
735 * Start of header write
\r
737 static void WriteHeaderRequested()
\r
739 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
740 CurrentJob.State = FEE_WRITE_HEADER;
\r
741 BlockHeaderDataWrite();
\r
747 * Check job result of write header, if ok request for block data write
\r
749 static void WriteHeaderState(void)
\r
751 if (CheckFlsJobFinnished()) {
\r
752 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
753 CurrentJob.State = FEE_WRITE_DATA_REQUESTED;
\r
755 AbortJob(Fls_GetJobResult());
\r
762 * Start block data write
\r
764 static void WriteDataRequested(void)
\r
766 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
767 CurrentJob.State = FEE_WRITE_DATA;
\r
768 /* Write the actual data */
\r
769 DEBUG_PRINTF("WriteDataRequested: 0x%x 0x%x %d ",CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length );
\r
771 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {
\r
774 AbortJob(Fls_GetJobResult());
\r
781 * Check job result of data write - request for magic write
\r
783 static void WriteDataState(void)
\r
785 if (CheckFlsJobFinnished()) {
\r
786 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
787 CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;
\r
789 AbortJob(Fls_GetJobResult());
\r
796 * Start magic write
\r
798 static void WriteMagicRequested(void)
\r
800 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
801 CurrentJob.State = FEE_WRITE_MAGIC;
\r
802 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);
\r
803 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);
\r
804 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {
\r
807 AbortJob(Fls_GetJobResult());
\r
814 * Check job result of write magic, if ok update the block admin table and finish
\r
816 static void WriteMagicState(void)
\r
818 if (CheckFlsJobFinnished()) {
\r
819 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
820 /* Update the block admin table */
\r
821 CurrentJob.AdminFlsBlockPtr->Status = BLOCK_STATUS_INUSE;
\r
822 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;
\r
823 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;
\r
827 AbortJob(Fls_GetJobResult());
\r
834 * Check if any bank is marked as old
\r
836 static void CheckIfGarbageCollectionNeeded(void)
\r
838 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {
\r
839 ModuleStatus = MEMIF_BUSY_INTERNAL;
\r
840 JobResult = MEMIF_JOB_PENDING;
\r
842 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;
\r
848 * Checks if any blocks needs to be moved if so start with writing a new header
\r
849 * or if no blocks needs to be moved request for bank erase.
\r
851 static void GarbageCollectStartJob(void)
\r
855 boolean found = FALSE;
\r
858 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
859 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {
\r
860 if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {
\r
866 for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && (!found); blockIndex++) {
\r
867 for (set = 0; (set < FEE_MAX_NUM_SETS) && (!found); set++) {
\r
868 if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {
\r
869 if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {
\r
870 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];
\r
871 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
872 CurrentJob.BlockNumber = Fee_Config.BlockConfig[blockIndex].BlockNumber;
\r
873 if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {
\r
874 CurrentJob.Length = 0;
\r
876 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
886 CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
887 CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
889 CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;
\r
890 BlockHeaderDataWrite();
\r
892 if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {
\r
894 CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;
\r
895 CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;
\r
897 AdminFls.NofFailedGarbageCollect++;
\r
898 AbortJob(Fls_GetJobResult());
\r
902 CurrentJob.State = FEE_IDLE;
\r
909 * Check job result of write header, if ok request for read block data
\r
911 static void GarbageCollectWriteHeader(void)
\r
913 if (CheckFlsJobFinnished()) {
\r
914 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
915 if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {
\r
916 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
917 CurrentJob.Op.GarbageCollect.DataOffset = 0;
\r
918 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;
\r
920 /* Yes, we are finished */
\r
921 DET_VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INVALIDATED, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);
\r
922 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;
\r
925 AdminFls.NofFailedGarbageCollect++;
\r
926 AbortJob(Fls_GetJobResult());
\r
933 * Start of read block data, if data length is more than buffer size
\r
934 * the reading is segmented.
\r
936 static void GarbageCollectReadDataRequested(void)
\r
938 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
939 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;
\r
940 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {
\r
941 CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;
\r
943 CurrentJob.Length = RWBUFFER_SIZE;
\r
945 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {
\r
948 AdminFls.NofFailedGarbageCollect++;
\r
949 AbortJob(Fls_GetJobResult());
\r
956 * Check job result of read block data, if ok request for a data write
\r
958 static void GarbageCollectReadData(void)
\r
960 if (CheckFlsJobFinnished()) {
\r
961 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
962 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;
\r
964 AdminFls.NofFailedGarbageCollect++;
\r
965 AbortJob(Fls_GetJobResult());
\r
972 * Start of write block data
\r
974 static void GarbageCollectWriteDataRequested(void)
\r
976 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
977 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;
\r
978 /* Write the actual data */
\r
979 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {
\r
982 AdminFls.NofFailedGarbageCollect++;
\r
983 AbortJob(Fls_GetJobResult());
\r
986 AdminFls.NofFailedGarbageCollect++;
\r
987 AbortJob(Fls_GetJobResult());
\r
993 * Check job result of write data, if ok request for write magic or
\r
994 * next data read depending on if there are more block data to move.
\r
996 static void GarbageCollectWriteData(void)
\r
998 if (CheckFlsJobFinnished()) {
\r
999 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1000 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {
\r
1001 /* Yes, we are finished */
\r
1002 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;
\r
1004 /* More data to move */
\r
1005 CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;
\r
1006 CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;
\r
1007 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;
\r
1010 AdminFls.NofFailedGarbageCollect++;
\r
1011 AbortJob(Fls_GetJobResult());
\r
1018 * Start write magic
\r
1020 static void GarbageCollectWriteMagicRequested(void)
\r
1022 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
1023 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;
\r
1024 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);
\r
1025 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);
\r
1026 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {
\r
1029 AdminFls.NofFailedGarbageCollect++;
\r
1030 AbortJob(Fls_GetJobResult());
\r
1037 * Check the job result of write magic, if ok update the admin table with the new position of data.
\r
1039 static void GarbageCollectWriteMagic(void)
\r
1041 if (CheckFlsJobFinnished()) {
\r
1042 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1043 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;
\r
1044 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;
\r
1045 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;
\r
1047 AdminFls.NofFailedGarbageCollect++;
\r
1048 AbortJob(Fls_GetJobResult());
\r
1055 * Check the result of the erase job
\r
1057 static void GarbageCollectErase(void)
\r
1059 if (CheckFlsJobFinnished()) {
\r
1060 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1061 AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;
\r
1062 AdminFls.ForceGarbageCollect = 0;
\r
1063 AdminFls.NofFailedGarbageCollect = 0;
\r
1066 AdminFls.NofFailedGarbageCollect++;
\r
1067 AbortJob(Fls_GetJobResult());
\r
1074 * Write an "Invalidated" block header
\r
1076 static void BlockHeaderInvalidWrite(void)
\r
1078 // Write the header including the magic
\r
1079 memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);
\r
1080 RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;
\r
1081 RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;
\r
1082 RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;
\r
1083 RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;
\r
1084 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);
\r
1085 memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);
\r
1087 if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {
\r
1089 AdminFls.NewBlockDataAddress += CurrentJob.Length;
\r
1090 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
1092 AbortJob(Fls_GetJobResult());
\r
1098 * Check if bank switch is needed, if yes request for marking current bank as old,
\r
1099 * if no request for writing a header with "Invalid" status set.
\r
1101 static void InvalidateStartJob(void)
\r
1103 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
1104 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {
\r
1105 /* Bank switch needed, mark current bank as "old" */
\r
1106 CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;
\r
1107 BankHeaderOldWrite(AdminFls.BankNumber);
\r
1109 CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
1110 CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
1112 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;
\r
1113 BlockHeaderInvalidWrite();
\r
1120 * Check job result of mark bank old, if ok continue with request for writing
\r
1121 * a header with "Invalid" status set.
\r
1123 static void InvalidateMarkBankOld(void)
\r
1125 if (CheckFlsJobFinnished()) {
\r
1126 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1127 // Mark for garbage collection
\r
1128 AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;
\r
1131 AdminFls.BankNumber ^= 0x1u;
\r
1132 AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;
\r
1133 AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
1135 CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
1136 CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
1138 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;
\r
1140 AbortJob(Fls_GetJobResult());
\r
1146 * Start the writing of the "Invalid" header.
\r
1148 static void InvalidateWriteInvalidateHeaderRequested(void)
\r
1150 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
1151 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;
\r
1152 BlockHeaderInvalidWrite();
\r
1158 * Check the job result of "Invalid" header write, if ok update the block admin table
\r
1160 static void InvalidateWriteInvalidateHeader(void)
\r
1162 if (CheckFlsJobFinnished()) {
\r
1163 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1164 // Update the block admin table
\r
1165 CurrentJob.AdminFlsBlockPtr->Status = BLOCK_STATUS_INVALIDATED;
\r
1166 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;
\r
1167 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;
\r
1171 AbortJob(Fls_GetJobResult());
\r
1177 /***************************************
\r
1178 * External accessible functions *
\r
1179 ***************************************/
\r
1181 * Procedure: Fee_Init
\r
1184 void Fee_Init(void)
\r
1188 /* Reporting information */
\r
1189 ModuleStatus = MEMIF_BUSY_INTERNAL;
\r
1190 JobResult = MEMIF_JOB_OK;
\r
1192 /* State of device */
\r
1193 CurrentJob.State = FEE_STARTUP_REQUESTED;
\r
1194 #if (FEE_POLLING_MODE == STD_OFF)
\r
1195 FlsJobReady = TRUE;
\r
1198 AdminFls.BankNumber = 0;
\r
1199 AdminFls.ForceGarbageCollect = 0;
\r
1200 AdminFls.NofFailedGarbageCollect = 0;
\r
1201 AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;
\r
1202 AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);
\r
1204 for (i = 0; i < NUM_OF_BANKS; i++) {
\r
1205 AdminFls.BankStatus[i] = BANK_STATUS_NEW;
\r
1208 for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {
\r
1209 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {
\r
1210 AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;
\r
1211 AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;
\r
1212 AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;
\r
1219 * Procedure: Fee_SetMode
\r
1222 void Fee_SetMode(MemIf_ModeType mode)
\r
1224 #if ( FLS_SET_MODE_API == STD_ON )
\r
1225 Fls_SetMode(mode);
\r
1227 //lint --e{715} PC-Lint (715) - variable "mode" not used in this case
\r
1228 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);
\r
1233 * Procedure: Fee_Read
\r
1236 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)
\r
1238 uint16 blockIndex;
\r
1241 DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1242 if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){
\r
1245 if( !(ModuleStatus == MEMIF_IDLE) ) {
\r
1246 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);
\r
1250 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1251 DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1252 DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);
\r
1253 DET_VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);
\r
1254 DET_VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);
\r
1256 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1257 DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1260 /** @req FEE022 */
\r
1261 ModuleStatus = MEMIF_BUSY;
\r
1262 JobResult = MEMIF_JOB_PENDING;
\r
1264 CurrentJob.BlockNumber = blockNumber;
\r
1265 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1266 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1267 CurrentJob.Length = length;
\r
1268 CurrentJob.Op.Read.Offset = blockOffset;
\r
1269 CurrentJob.Op.Read.RamPtr = dataBufferPtr;
\r
1270 CurrentJob.State = FEE_READ_REQUESTED;
\r
1277 * Procedure: Fee_Write
\r
1280 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)
\r
1282 uint16 blockIndex;
\r
1285 DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1286 if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){
\r
1289 if( !(ModuleStatus == MEMIF_IDLE) ) {
\r
1290 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);
\r
1294 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1295 DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1296 DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);
\r
1298 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1299 DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1302 /** @req FEE025 */
\r
1303 ModuleStatus = MEMIF_BUSY;
\r
1304 JobResult = MEMIF_JOB_PENDING;
\r
1306 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1307 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1308 CurrentJob.BlockNumber = blockNumber;
\r
1309 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
1310 CurrentJob.Op.Write.RamPtr = dataBufferPtr;
\r
1311 CurrentJob.State = FEE_WRITE_REQUESTED;
\r
1318 * Procedure: Fee_Cancel
\r
1321 void Fee_Cancel(void)
\r
1323 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);
\r
1328 * Procedure: Fee_GetStatus
\r
1331 MemIf_StatusType Fee_GetStatus(void)
\r
1333 if(AdminFls.ForceGarbageCollect && (FEE_IDLE == CurrentJob.State)){
\r
1334 return MEMIF_BUSY_INTERNAL;
\r
1336 return ModuleStatus;
\r
1342 * Procedure: Fee_GetJobResult
\r
1345 MemIf_JobResultType Fee_GetJobResult(void)
\r
1352 * Procedure: Fee_InvalidateBlock
\r
1355 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)
\r
1357 uint16 blockIndex;
\r
1360 DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1361 if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){
\r
1364 if( !(ModuleStatus == MEMIF_IDLE) ) {
\r
1365 DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);
\r
1369 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1370 DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1372 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1373 DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1376 ModuleStatus = MEMIF_BUSY;
\r
1377 JobResult = MEMIF_JOB_PENDING;
\r
1379 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1380 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1381 CurrentJob.BlockNumber = blockNumber;
\r
1382 CurrentJob.State = FEE_INVALIDATE_REQUESTED;
\r
1389 * Procedure: Fee_EraseImmediateBlock
\r
1392 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)
\r
1394 //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet
\r
1396 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);
\r
1403 /***************************************
\r
1404 * Scheduled functions *
\r
1405 ***************************************/
\r
1407 * Procedure: Fee_MainFunction
\r
1410 void Fee_MainFunction(void)
\r
1413 switch (CurrentJob.State) {
\r
1414 case FEE_UNINITIALIZED:
\r
1418 if (AdminFls.ForceGarbageCollect) {
\r
1419 CheckIfGarbageCollectionNeeded();
\r
1426 case FEE_STARTUP_REQUESTED:
\r
1427 StartupStartJob();
\r
1430 case FEE_STARTUP_READ_BANK1_STATUS:
\r
1431 StartupReadBank1Status();
\r
1434 case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:
\r
1435 StartupReadBank2StatusRequested();
\r
1438 case FEE_STARTUP_READ_BANK2_STATUS:
\r
1439 StartupReadBank2Status();
\r
1442 case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:
\r
1443 StartupReadBlockAdminRequested();
\r
1446 case FEE_STARTUP_READ_BLOCK_ADMIN:
\r
1447 StartupReadBlockAdmin();
\r
1453 case FEE_READ_REQUESTED:
\r
1464 case FEE_WRITE_REQUESTED:
\r
1468 case FEE_WRITE_MARK_BANK_OLD:
\r
1469 WriteMarkBankOldState();
\r
1472 case FEE_WRITE_HEADER_REQUESTED:
\r
1473 WriteHeaderRequested();
\r
1476 case FEE_WRITE_HEADER:
\r
1477 WriteHeaderState();
\r
1480 case FEE_WRITE_DATA_REQUESTED:
\r
1481 WriteDataRequested();
\r
1484 case FEE_WRITE_DATA:
\r
1488 case FEE_WRITE_MAGIC_REQUESTED:
\r
1489 WriteMagicRequested();
\r
1492 case FEE_WRITE_MAGIC:
\r
1493 WriteMagicState();
\r
1497 * Garbage collection states
\r
1499 case FEE_GARBAGE_COLLECT_REQUESTED:
\r
1500 GarbageCollectStartJob();
\r
1503 case FEE_GARBAGE_COLLECT_HEADER_WRITE:
\r
1504 GarbageCollectWriteHeader();
\r
1507 case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:
\r
1508 GarbageCollectReadDataRequested();
\r
1511 case FEE_GARBAGE_COLLECT_DATA_READ:
\r
1512 GarbageCollectReadData();
\r
1515 case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:
\r
1516 GarbageCollectWriteDataRequested();
\r
1519 case FEE_GARBAGE_COLLECT_DATA_WRITE:
\r
1520 GarbageCollectWriteData();
\r
1523 case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:
\r
1524 GarbageCollectWriteMagicRequested();
\r
1527 case FEE_GARBAGE_COLLECT_MAGIC_WRITE:
\r
1528 GarbageCollectWriteMagic();
\r
1531 case FEE_GARBAGE_COLLECT_ERASE:
\r
1532 GarbageCollectErase();
\r
1536 * Invalidate states
\r
1538 case FEE_INVALIDATE_REQUESTED:
\r
1539 InvalidateStartJob();
\r
1542 case FEE_INVALIDATE_MARK_BANK_OLD:
\r
1543 InvalidateMarkBankOld();
\r
1546 case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:
\r
1547 InvalidateWriteInvalidateHeaderRequested();
\r
1550 case FEE_WRITE_INVALIDATE_HEADER:
\r
1551 InvalidateWriteInvalidateHeader();
\r
1557 case FEE_CORRUPTED:
\r
1569 /***************************************
\r
1570 * Call-back notifications functions *
\r
1571 ***************************************/
\r
1572 #if (FEE_POLLING_MODE == STD_OFF)
\r
1574 * Procedure: Fee_JobEndNotification
\r
1577 void Fee_JobEndNotification(void)
\r
1579 FlsJobReady = TRUE;
\r
1584 * Procedure: Fee_JobErrorNotification
\r
1587 void Fee_JobErrorNotification(void)
\r
1589 FlsJobReady = TRUE;
\r