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
26 #include "Fee_Cbk.h"
\r
29 #include "Rte.h" // ???
\r
30 #if defined(USE_DEM)
\r
33 //#include "SchM_NvM.h"
\r
43 #if ( FEE_DEV_ERROR_DETECT == STD_ON )
\r
45 #define VALIDATE(_exp,_api,_err ) \
\r
47 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
50 #define VALIDATE_RV(_exp,_api,_err,_rv ) \
\r
52 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
56 #define VALIDATE_NO_RV(_exp,_api,_err ) \
\r
58 Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \
\r
62 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)
\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
73 * Block numbering recalculation macros
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
80 * Page alignment macros
82 #define PAGE_ALIGN(_size) ((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE)
\r
87 #define NUM_OF_BANKS 2
\r
88 static const Fls_AddressType BankList[NUM_OF_BANKS] = {FEE_BANK1_OFFSET, FEE_BANK2_OFFSET};
\r
91 * Macros and variables for flash bank administration
94 BANK_STATUS_OLD = 0x00,
\r
95 BANK_STATUS_NEW = 0xFF
\r
96 } FlsBankStatusEnumType;
\r
97 typedef uint8 FlsBankStatusType;
\r
99 #define BANK_CTRL_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBankStatusType))
\r
102 FlsBankStatusType BankStatus;
\r
103 uint8 Data[BANK_CTRL_PAGE_SIZE];
\r
104 } FlsBankCtrlPageType;
\r
108 * Macros and variables for flash block administration in flash
111 BLOCK_STATUS_INUSE = 0x00,
\r
112 BLOCK_STATUS_INVALIDATED = 0x02,
\r
113 BLOCK_STATUS_EMPTY = 0xFF
\r
114 } BlockStatusEnumType;
\r
115 typedef uint8 BlockStatusType;
\r
118 BlockStatusType Status;
\r
120 Fls_AddressType BlockDataAddress;
\r
121 uint16 BlockDataLength;
\r
122 } FlsBlockDataType;
\r
124 #define BLOCK_DATA_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBlockDataType))
\r
127 FlsBlockDataType Data;
\r
128 uint8 Byte[BLOCK_DATA_PAGE_SIZE];
\r
129 } FlsBlockDataPageType;
\r
132 #define BLOCK_MAGIC_LEN 4
\r
133 static const uint8 MagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };
\r
134 #define BLOCK_MAGIC_PAGE_SIZE PAGE_ALIGN(BLOCK_MAGIC_LEN)
\r
138 uint8 Magic[BLOCK_MAGIC_LEN];
\r
139 uint8 Byte[BLOCK_MAGIC_PAGE_SIZE];
\r
140 } FlsBlockMagicPageType;
\r
143 FlsBlockDataPageType DataPage;
\r
144 FlsBlockMagicPageType MagicPage;
\r
145 } FlsBlockControlType;
\r
147 #define BLOCK_CTRL_PAGE_SIZE PAGE_ALIGN(sizeof(FlsBlockControlType))
\r
149 #define BLOCK_CTRL_DATA_POS_OFFSET 0
\r
150 #define BLOCK_CTRL_MAGIC_POS_OFFSET BLOCK_DATA_PAGE_SIZE
\r
153 FlsBlockControlType BlockCtrl;
\r
154 FlsBankCtrlPageType BankCtrl;
\r
155 uint8 Byte[BLOCK_CTRL_PAGE_SIZE];
\r
156 } ReadWriteBufferType;
\r
158 static ReadWriteBufferType RWBuffer;
\r
160 #define RWBUFFER_SIZE sizeof(ReadWriteBufferType)
\r
164 * Variables for flash administration
\r
167 BlockStatusType Status;
\r
168 Fls_AddressType BlockAdminAddress;
\r
169 Fls_AddressType BlockDataAddress;
\r
170 } AdminFlsBlockType;
\r
174 Fls_AddressType NewBlockAdminAddress;
\r
175 Fls_AddressType NewBlockDataAddress;
\r
176 FlsBankStatusType BankStatus[NUM_OF_BANKS];
\r
177 AdminFlsBlockType BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];
\r
180 static AdminFlsType AdminFls;
\r
184 * Variables for quick reporting of status and job result
186 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;
\r
187 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;
\r
190 * Variables for the current job
193 FEE_UNINITIALIZED = 0,
\r
194 FEE_STARTUP_REQUESTED,
\r
195 FEE_STARTUP_READ_BANK1_STATUS,
\r
196 FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,
\r
197 FEE_STARTUP_READ_BANK2_STATUS,
\r
198 FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,
\r
199 FEE_STARTUP_READ_BLOCK_ADMIN,
\r
203 FEE_WRITE_REQUESTED,
\r
204 FEE_WRITE_MARK_BANK_OLD,
\r
205 FEE_WRITE_HEADER_REQUESTED,
\r
207 FEE_WRITE_DATA_REQUESTED,
\r
209 FEE_WRITE_MAGIC_REQUESTED,
\r
212 FEE_READ_REQUESTED,
\r
215 FEE_CANCEL_REQUESTED,
\r
216 FEE_CANCEL_PENDING,
\r
218 FEE_INVALIDATE_REQUESTED,
\r
219 FEE_INVALIDATE_MARK_BANK_OLD,
\r
220 FEE_WRITE_INVALIDATE_HEADER_REQUESTED,
\r
221 FEE_WRITE_INVALIDATE_HEADER,
\r
223 FEE_GARBAGE_COLLECT_REQUESTED,
\r
224 FEE_GARBAGE_COLLECT_HEADER_WRITE,
\r
225 FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,
\r
226 FEE_GARBAGE_COLLECT_DATA_READ,
\r
227 FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,
\r
228 FEE_GARBAGE_COLLECT_DATA_WRITE,
\r
229 FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,
\r
230 FEE_GARBAGE_COLLECT_MAGIC_WRITE,
\r
231 FEE_GARBAGE_COLLECT_ERASE,
\r
232 } CurrentJobStateType;
\r
235 CurrentJobStateType State;
\r
236 uint16 InStateCounter;
\r
237 uint16 BlockNumber;
\r
239 const Fee_BlockConfigType *BlockConfigPtr;
\r
240 AdminFlsBlockType *AdminFlsBlockPtr;
\r
245 Fls_AddressType BlockAdminAddress;
\r
253 Fls_AddressType WriteAdminAddress;
\r
254 Fls_AddressType WriteDataAddress;
\r
257 Fls_AddressType WriteAdminAddress;
\r
258 Fls_AddressType WriteDataAddress;
\r
263 Fls_AddressType WriteAdminAddress;
\r
264 Fls_AddressType WriteDataAddress;
\r
271 static CurrentJobType CurrentJob = {
\r
273 .InStateCounter = 0
\r
279 #define STATE_COUNTER_MAX 0xffff
\r
280 #define GARBAGE_COLLECTION_DELAY 10
\r
282 /***************************************
\r
283 * Local functions *
\r
284 ***************************************/
\r
286 #if (FEE_POLLING_MODE == STD_ON)
\r
287 static void SetFlsJobBusy()
\r
289 /* Nothing needed here */
\r
292 static boolean CheckFlsJobFinnished(void)
\r
294 MemIf_JobResultType flsJobResult;
\r
296 flsJobResult = Fls_GetJobResult();
\r
297 return (flsJobResult != MEMIF_JOB_PENDING);
\r
300 static boolean FlsJobReady = TRUE;
\r
302 static void SetFlsJobBusy()
\r
304 FlsJobReady = FALSE;
\r
307 static boolean CheckFlsJobFinnished(void)
\r
309 return !(FlsJobReady);
\r
315 static void FinnishStartup(void)
\r
317 CurrentJob.State = FEE_IDLE;
\r
318 ModuleStatus = MEMIF_IDLE;
\r
319 JobResult = MEMIF_JOB_OK;
\r
323 static void AbortStartup(MemIf_JobResultType result)
\r
325 CurrentJob.State = FEE_IDLE;
\r
326 ModuleStatus = MEMIF_IDLE;
\r
327 JobResult = result;
\r
331 static void FinnishJob(void)
\r
333 CurrentJob.State = FEE_IDLE;
\r
334 ModuleStatus = MEMIF_IDLE;
\r
335 JobResult = MEMIF_JOB_OK;
\r
337 if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {
\r
338 Fee_Config.General.NvmJobEndCallbackNotificationCallback();
\r
343 static void AbortJob(MemIf_JobResultType result)
\r
345 CurrentJob.State = FEE_IDLE;
\r
346 ModuleStatus = MEMIF_IDLE;
\r
347 JobResult = result;
\r
349 if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {
\r
350 Fee_Config.General.NvmJobErrorCallbackNotificationCallback();
\r
356 * Start of bank status 1 read
\r
358 static void StartupStartJob(void)
\r
360 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
361 CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;
\r
362 /* Read bank status of bank 1 */
\r
363 if (Fls_Read(FEE_BANK1_OFFSET + FEE_BANK_LENGTH - BANK_CTRL_PAGE_SIZE, (uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {
\r
366 AbortStartup(Fls_GetJobResult());
\r
373 * Check job result of bank 1 status read, if ok request for bank 2 status read
\r
375 static void StartupReadBank1Status(void)
\r
377 if (CheckFlsJobFinnished()) {
\r
378 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
379 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;
\r
381 AbortStartup(Fls_GetJobResult());
\r
388 * Start of bank status 2 read
\r
390 static void StartupReadBank2StatusRequested(void)
\r
392 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
393 /* Read bank status of bank 2 */
\r
394 CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;
\r
395 if (Fls_Read(FEE_BANK2_OFFSET + FEE_BANK_LENGTH - BANK_CTRL_PAGE_SIZE, (uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {
\r
398 AbortStartup(Fls_GetJobResult());
\r
405 * Check job result of bank status 2 read - request for block status reading
407 static void StartupReadBank2Status(void)
\r
409 MemIf_JobResultType jobResult;
\r
411 if (CheckFlsJobFinnished()) {
\r
412 jobResult = Fls_GetJobResult();
\r
413 if (jobResult == MEMIF_JOB_OK) {
\r
414 /* Select which bank to start with */
\r
415 if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){
\r
416 /* None is marked as old, just start with one of them */
\r
417 CurrentJob.Op.Startup.BankNumber = 0;
\r
418 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
419 } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {
\r
420 /* Both banks are marked as old, this shall not be possible */
\r
421 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
422 jobResult = MEMIF_JOB_FAILED;
\r
423 } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {
\r
424 CurrentJob.Op.Startup.BankNumber = 0;
\r
425 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
427 CurrentJob.Op.Startup.BankNumber = 1;
\r
428 CurrentJob.Op.Startup.NrOfBanks = 2;
\r
432 if (jobResult != MEMIF_JOB_OK) {
\r
433 AbortStartup(jobResult);
\r
435 CurrentJob.Op.Startup.BlockAdminAddress = BankList[CurrentJob.Op.Startup.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
436 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;
\r
442 * Start of block admin read
444 static void StartupReadBlockAdminRequested(void)
\r
446 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
447 /* Start reading the banks */
\r
448 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;
\r
449 if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {
\r
452 AbortStartup(Fls_GetJobResult());
\r
459 * Check job result of block admin read, if all block processed finish
\r
460 * otherwise request for a new block admin read
462 static void StartupReadBlockAdmin(void)
\r
464 if (CheckFlsJobFinnished()) {
\r
465 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
466 if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {
\r
467 VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
468 CurrentJob.Op.Startup.NrOfBanks--;
\r
469 CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;
\r
470 CurrentJob.Op.Startup.BlockAdminAddress = BankList[CurrentJob.Op.Startup.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
471 } else { /* Block not empty */
\r
472 if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN) == 0) &&
\r
473 ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {
\r
474 /* This is a valid admin block */
\r
478 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);
\r
479 dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);
\r
481 if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {
\r
482 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;
\r
483 AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;
\r
484 AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;
\r
486 AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;
\r
487 AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;
\r
488 if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {
\r
489 /* This shall never happen */
\r
490 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);
\r
494 CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
495 AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;
\r
498 if (CurrentJob.Op.Startup.NrOfBanks == 0) {
\r
499 /* If current bank is marked as old we need to switch to a new bank */
\r
500 if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {
\r
501 AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;
\r
502 AdminFls.NewBlockAdminAddress = BankList[AdminFls.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
503 AdminFls.NewBlockDataAddress = BankList[AdminFls.BankNumber];
\r
508 CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;
\r
512 } else { /* ErrorStatus not E_OK */
\r
513 AbortStartup(Fls_GetJobResult());
\r
520 * Start of read block data
\r
522 static void ReadStartJob(void)
\r
524 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
525 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {
\r
526 if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {
\r
527 CurrentJob.State = FEE_READ;
\r
528 /* Read the actual data */
\r
529 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {
\r
532 AbortJob(Fls_GetJobResult());
\r
536 AbortJob(MEMIF_BLOCK_INVALID);
\r
540 AbortJob(MEMIF_BLOCK_INCONSISTENT);
\r
546 * Check job result of block data read
548 static void Reading(void)
\r
550 if (CheckFlsJobFinnished()) {
\r
551 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
554 AbortJob(Fls_GetJobResult());
\r
561 * Write bank header
\r
563 static void BankHeaderOldWrite(uint8 bank)
\r
565 /* Mark the bank as old */
\r
566 memset(RWBuffer.BankCtrl.Data, 0xff, BLOCK_DATA_PAGE_SIZE);
\r
567 RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;
\r
568 if (Fls_Write(BankList[bank] + FEE_BANK_LENGTH - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {
\r
571 AbortJob(Fls_GetJobResult());
\r
577 * Write block header
\r
579 static void BlockHeaderDataWrite(void)
\r
581 /* Write the header excluding the magic */
\r
582 memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_DATA_PAGE_SIZE);
\r
583 RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;
\r
584 RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;
\r
585 RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;
\r
586 RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;
\r
587 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_DATA_PAGE_SIZE) == E_OK) {
\r
589 AdminFls.NewBlockDataAddress += CurrentJob.Length;
\r
590 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
592 AbortJob(Fls_GetJobResult());
\r
598 * Check if bank switch needed:
\r
599 * - Yes, start mark current bank as old
\r
600 * - No, start of header write
\r
602 static void WriteStartJob(void)
\r
604 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
605 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {
\r
606 /* Bank switch needed, mark current bank as "old" */
\r
607 CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;
\r
608 BankHeaderOldWrite(AdminFls.BankNumber);
\r
610 CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
611 CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
613 CurrentJob.State = FEE_WRITE_HEADER;
\r
614 BlockHeaderDataWrite();
\r
621 * Check job result of mark bank as old, if ok request for header write
\r
623 static void WriteMarkBankOldState(void)
\r
625 if (CheckFlsJobFinnished()) {
\r
626 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
627 /* Mark for garbage collection */
\r
628 AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;
\r
630 /* Change of bank */
\r
631 AdminFls.BankNumber ^= 0x1;
\r
632 AdminFls.NewBlockDataAddress = BankList[AdminFls.BankNumber] + 0;
\r
633 AdminFls.NewBlockAdminAddress = BankList[AdminFls.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
635 CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
636 CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
638 CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;
\r
640 AbortJob(Fls_GetJobResult());
\r
647 * Start of header write
649 static void WriteHeaderRequested()
\r
651 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
652 CurrentJob.State = FEE_WRITE_HEADER;
\r
653 BlockHeaderDataWrite();
\r
659 * Check job result of write header, if ok request for block data write
\r
661 static void WriteHeaderState(void)
\r
663 if (CheckFlsJobFinnished()) {
\r
664 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
665 CurrentJob.State = FEE_WRITE_DATA_REQUESTED;
\r
667 AbortJob(Fls_GetJobResult());
\r
674 * Start block data write
676 static void WriteDataRequested(void)
\r
678 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
679 CurrentJob.State = FEE_WRITE_DATA;
\r
680 /* Write the actual data */
\r
681 if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {
\r
684 AbortJob(Fls_GetJobResult());
\r
691 * Check job result of data write - request for magic write
\r
693 static void WriteDataState(void)
\r
695 if (CheckFlsJobFinnished()) {
\r
696 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
697 CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;
\r
699 AbortJob(Fls_GetJobResult());
\r
708 static void WriteMagicRequested(void)
\r
710 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
711 CurrentJob.State = FEE_WRITE_MAGIC;
\r
712 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_MAGIC_PAGE_SIZE);
\r
713 memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);
\r
714 if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_MAGIC_PAGE_SIZE) == E_OK) {
\r
717 AbortJob(Fls_GetJobResult());
\r
724 * Check job result of write magic, if ok update the block admin table and finish
\r
726 static void WriteMagicState(void)
\r
728 if (CheckFlsJobFinnished()) {
\r
729 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
730 /* Update the block admin table */
\r
731 CurrentJob.AdminFlsBlockPtr->Status = BLOCK_STATUS_INUSE;
\r
732 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;
\r
733 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;
\r
737 AbortJob(Fls_GetJobResult());
\r
744 * Check if any bank is marked as old
\r
746 static void CheckIfGarbageCollectionNeeded(void)
\r
748 if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {
\r
749 ModuleStatus = MEMIF_BUSY_INTERNAL;
\r
750 JobResult = MEMIF_JOB_PENDING;
\r
752 CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;
\r
758 * Checks if any blocks needs to be moved if so start with writing a new header
\r
759 * or if no blocks needs to be moved request for bank erase.
\r
761 static void GarbageCollectStartJob(void)
\r
763 uint16 blockIndex,set;
\r
764 boolean found = FALSE;
\r
765 uint8 sourceBank, destBank;
\r
767 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
768 if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {
\r
771 } else if (AdminFls.BankStatus[1] == BANK_STATUS_OLD) {
\r
775 CurrentJob.State = FEE_IDLE;
\r
779 for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && !found; blockIndex++) {
\r
780 for (set = 0; (set < FEE_MAX_NUM_SETS) && !found; set++) {
\r
781 if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {
\r
782 if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankList[sourceBank]) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankList[sourceBank]+ FEE_BANK_LENGTH))) {
\r
783 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];
\r
784 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
785 CurrentJob.BlockNumber = BLOCK_INDEX_AND_SET_TO_BLOCKNR(blockIndex, set);
\r
786 if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {
\r
787 CurrentJob.Length = 0;
\r
789 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
799 CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
800 CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
802 CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;
\r
803 BlockHeaderDataWrite();
\r
805 if (Fls_Erase(BankList[sourceBank], FEE_BANK_LENGTH) == E_OK) {
\r
808 AbortJob(Fls_GetJobResult());
\r
810 CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;
\r
811 CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;
\r
818 * Check job result of write header, if ok request for read block data
\r
820 static void GarbageCollectWriteHeader(void)
\r
822 if (CheckFlsJobFinnished()) {
\r
823 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
824 if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {
\r
825 CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
826 CurrentJob.Op.GarbageCollect.DataOffset = 0;
\r
827 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;
\r
829 /* Yes, we are finished */
\r
830 VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_EMPTY, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);
\r
831 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;
\r
834 AbortJob(Fls_GetJobResult());
\r
841 * Start of read block data, if data length is more than buffer size
\r
842 * the reading is segmented.
\r
844 static void GarbageCollectReadDataRequested(void)
\r
846 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
847 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;
\r
848 if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {
\r
849 CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;
\r
851 CurrentJob.Length = RWBUFFER_SIZE;
\r
853 if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {
\r
856 AbortJob(Fls_GetJobResult());
\r
863 * Check job result of read block data, if ok request for a data write
\r
865 static void GarbageCollectReadData(void)
\r
867 if (CheckFlsJobFinnished()) {
\r
868 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
869 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;
\r
871 AbortJob(Fls_GetJobResult());
\r
878 * Start of write block data
\r
880 static void GarbageCollectWriteDataRequested(void)
\r
882 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
883 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;
\r
884 /* Write the actual data */
\r
885 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {
\r
888 AbortJob(Fls_GetJobResult());
\r
891 AbortJob(Fls_GetJobResult());
\r
897 * Check job result of write data, if ok request for write magic or
\r
898 * next data read depending on if there are more block data to move.
\r
900 static void GarbageCollectWriteData(void)
\r
902 if (CheckFlsJobFinnished()) {
\r
903 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
904 CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;
\r
905 CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;
\r
906 if (CurrentJob.Op.GarbageCollect.BytesLeft <= 0) {
\r
907 /* Yes, we are finished */
\r
908 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;
\r
910 /* More data to move */
\r
911 CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;
\r
914 AbortJob(Fls_GetJobResult());
\r
921 * Start write magic
\r
923 static void GarbageCollectWriteMagicRequested(void)
\r
925 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
926 CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;
\r
927 memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_MAGIC_PAGE_SIZE);
\r
928 memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);
\r
929 if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_MAGIC_PAGE_SIZE) == E_OK) {
\r
932 AbortJob(Fls_GetJobResult());
\r
939 * Check the job result of write magic, if ok update the admin table with the new position of data.
\r
941 static void GarbageCollectWriteMagic(void)
\r
943 if (CheckFlsJobFinnished()) {
\r
944 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
945 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;
\r
946 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;
\r
949 AbortJob(Fls_GetJobResult());
\r
956 * Check the result of the erase job
\r
958 static void GarbageCollectErase(void)
\r
960 if (CheckFlsJobFinnished()) {
\r
961 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
962 AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;
\r
965 AbortJob(Fls_GetJobResult());
\r
972 * Write an "Invalidated" block header
\r
974 static void BlockHeaderInvalidWrite(void)
\r
976 // Write the header including the magic
\r
977 memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);
\r
978 RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;
\r
979 RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;
\r
980 RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = 0;
\r
981 RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;
\r
982 memcpy(RWBuffer.BlockCtrl.MagicPage.Byte, MagicMaster, BLOCK_MAGIC_LEN);
\r
984 if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_DATA_PAGE_SIZE) == E_OK) {
\r
986 AdminFls.NewBlockDataAddress += CurrentJob.Length;
\r
987 AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;
\r
989 AbortJob(Fls_GetJobResult());
\r
995 * Check if bank switch is needed, if yes request for marking current bank as old,
\r
996 * if no request for writing a header with "Invalid" status set.
\r
998 static void InvalidateStartJob(void)
\r
1000 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
1001 if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {
\r
1002 /* Bank switch needed, mark current bank as "old" */
\r
1003 CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;
\r
1004 BankHeaderOldWrite(AdminFls.BankNumber);
\r
1006 CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
1007 CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
1009 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;
\r
1010 BlockHeaderInvalidWrite();
\r
1017 * Check job result of mark bank old, if ok continue with request for writing
\r
1018 * a header with "Invalid" status set.
\r
1020 static void InvalidateMarkBankOld(void)
\r
1022 if (CheckFlsJobFinnished()) {
\r
1023 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1024 // Mark for garbage collection
\r
1025 AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;
\r
1028 AdminFls.BankNumber ^= 0x1;
\r
1029 AdminFls.NewBlockDataAddress = BankList[AdminFls.BankNumber] + 0;
\r
1030 AdminFls.NewBlockAdminAddress = BankList[AdminFls.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
1032 CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;
\r
1033 CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;
\r
1035 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;
\r
1036 BlockHeaderInvalidWrite();
\r
1038 AbortJob(Fls_GetJobResult());
\r
1044 * Start the writing of the "Invalid" header.
1046 static void InvalidateWriteInvalidateHeaderRequested(void)
\r
1048 if (Fls_GetStatus() == MEMIF_IDLE) {
\r
1049 CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;
\r
1050 BlockHeaderInvalidWrite();
\r
1052 AbortJob(Fls_GetJobResult());
\r
1058 * Check the job result of "Invalid" header write, if ok update the block admin table
\r
1060 static void InvalidateWriteInvalidateHeader(void)
\r
1062 if (CheckFlsJobFinnished()) {
\r
1063 if (Fls_GetJobResult() == MEMIF_JOB_OK) {
\r
1064 // Update the block admin table
\r
1065 CurrentJob.AdminFlsBlockPtr->Status = BLOCK_STATUS_INUSE;
\r
1066 CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;
\r
1067 CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;
\r
1071 AbortJob(Fls_GetJobResult());
\r
1077 /***************************************
\r
1078 * External accessible functions *
\r
1079 ***************************************/
\r
1081 * Procedure: Fee_Init
\r
1084 void Fee_Init(void)
\r
1088 uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11;
\r
1089 t1 = sizeof(FlsBankStatusType);
\r
1090 t2 = BANK_CTRL_PAGE_SIZE;
\r
1091 t3 = sizeof(FlsBankCtrlPageType);
\r
1093 t4 = sizeof(BlockStatusType);
\r
1094 t5 = sizeof(FlsBlockDataType);
\r
1095 t6 = BLOCK_DATA_PAGE_SIZE;
\r
1096 t7 = sizeof(FlsBlockDataPageType);
\r
1099 t8 = sizeof(FlsBlockMagicPageType);
\r
1100 t9 = BLOCK_MAGIC_PAGE_SIZE;
\r
1101 t10 = sizeof(FlsBlockControlType);
\r
1102 t11 = BLOCK_CTRL_PAGE_SIZE;
\r
1107 /* Reporting information */
\r
1108 ModuleStatus = MEMIF_BUSY_INTERNAL;
\r
1109 JobResult = MEMIF_JOB_OK;
\r
1111 /* State of device */
\r
1112 CurrentJob.State = FEE_STARTUP_REQUESTED;
\r
1113 CurrentJob.InStateCounter = 0;
\r
1114 #if (FEE_POLLING_MODE == STD_OFF)
\r
1115 FlsJobReady = TRUE;
\r
1118 AdminFls.BankNumber = 0;
\r
1119 AdminFls.NewBlockDataAddress = BankList[AdminFls.BankNumber] + 0;
\r
1120 AdminFls.NewBlockAdminAddress = BankList[AdminFls.BankNumber] + FEE_BANK_LENGTH - BLOCK_CTRL_PAGE_SIZE - BANK_CTRL_PAGE_SIZE;
\r
1122 for (i = 0; i < NUM_OF_BANKS; i++) {
\r
1123 AdminFls.BankStatus[i] = BANK_STATUS_NEW;
\r
1126 for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {
\r
1127 for (j = 0; j < FEE_MAX_NUM_SETS; j++) {
\r
1128 AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;
\r
1129 AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;
\r
1130 AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;
\r
1137 * Procedure: Fee_SetMode
\r
1140 void Fee_SetMode(MemIf_ModeType mode)
\r
1142 #if ( FLS_SET_MODE_API == STD_ON )
\r
1143 Fls_SetMode(mode);
\r
1145 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);
\r
1150 * Procedure: Fee_Read
\r
1153 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)
\r
1155 uint16 blockIndex;
\r
1158 VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1159 VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);
\r
1161 VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1162 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1163 VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1164 VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);
\r
1165 VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);
\r
1166 VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);
\r
1168 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1169 VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1172 /** @req FEE022 */
\r
1173 ModuleStatus = MEMIF_BUSY;
\r
1174 JobResult = MEMIF_JOB_PENDING;
\r
1176 CurrentJob.BlockNumber = blockNumber;
\r
1177 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1178 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1179 CurrentJob.Length = length;
\r
1180 CurrentJob.Op.Read.Offset = blockOffset;
\r
1181 CurrentJob.Op.Read.RamPtr = dataBufferPtr;
\r
1182 CurrentJob.State = FEE_READ_REQUESTED;
\r
1189 * Procedure: Fee_Write
\r
1192 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)
\r
1194 uint16 blockIndex;
\r
1197 VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1198 VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_WRITE_ID, FEE_E_BUSY, E_NOT_OK);
\r
1200 VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1201 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1202 VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1203 VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);
\r
1205 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1206 VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1209 /** @req FEE025 */
\r
1210 ModuleStatus = MEMIF_BUSY;
\r
1211 JobResult = MEMIF_JOB_PENDING;
\r
1213 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1214 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1215 CurrentJob.BlockNumber = blockNumber;
\r
1216 CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);
\r
1217 CurrentJob.Op.Write.RamPtr = dataBufferPtr;
\r
1218 CurrentJob.State = FEE_WRITE_REQUESTED;
\r
1225 * Procedure: Fee_Cancel
\r
1228 void Fee_Cancel(void)
\r
1230 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_CANCEL_ID, FEE_E_NOT_IMPLEMENTED_YET);
\r
1235 * Procedure: Fee_GetStatus
\r
1238 MemIf_StatusType Fee_GetStatus(void)
\r
1240 return ModuleStatus;
\r
1245 * Procedure: Fee_GetJobResult
\r
1248 MemIf_JobResultType Fee_GetJobResult(void)
\r
1255 * Procedure: Fee_InvalidateBlock
\r
1258 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)
\r
1260 uint16 blockIndex;
\r
1263 VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);
\r
1264 VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_INVALIDATE_BLOCK_ID, FEE_E_BUSY, E_NOT_OK);
\r
1266 VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1267 blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);
\r
1268 VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1270 dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);
\r
1271 VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);
\r
1274 ModuleStatus = MEMIF_BUSY;
\r
1275 JobResult = MEMIF_JOB_PENDING;
\r
1277 CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];
\r
1278 CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];
\r
1279 CurrentJob.BlockNumber = blockNumber;
\r
1280 CurrentJob.State = FEE_INVALIDATE_REQUESTED;
\r
1287 * Procedure: Fee_EraseImmediateBlock
\r
1290 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)
\r
1292 DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);
\r
1298 /***************************************
\r
1299 * Scheduled functions *
\r
1300 ***************************************/
\r
1302 * Procedure: Fee_MainFunction
\r
1305 void Fee_MainFunction(void)
\r
1307 static CurrentJobStateType LastState = FEE_UNINITIALIZED;
\r
1309 if (CurrentJob.State == LastState) {
\r
1310 if (CurrentJob.InStateCounter < STATE_COUNTER_MAX) {
\r
1311 CurrentJob.InStateCounter++;
\r
1314 LastState = CurrentJob.State;
\r
1315 CurrentJob.InStateCounter = 0;
\r
1318 switch (CurrentJob.State) {
\r
1319 case FEE_UNINITIALIZED:
\r
1323 if (CurrentJob.InStateCounter > GARBAGE_COLLECTION_DELAY) {
\r
1324 CheckIfGarbageCollectionNeeded();
\r
1331 case FEE_STARTUP_REQUESTED:
\r
1332 StartupStartJob();
\r
1335 case FEE_STARTUP_READ_BANK1_STATUS:
\r
1336 StartupReadBank1Status();
\r
1339 case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:
\r
1340 StartupReadBank2StatusRequested();
\r
1343 case FEE_STARTUP_READ_BANK2_STATUS:
\r
1344 StartupReadBank2Status();
\r
1347 case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:
\r
1348 StartupReadBlockAdminRequested();
\r
1351 case FEE_STARTUP_READ_BLOCK_ADMIN:
\r
1352 StartupReadBlockAdmin();
\r
1358 case FEE_READ_REQUESTED:
\r
1369 case FEE_WRITE_REQUESTED:
\r
1373 case FEE_WRITE_MARK_BANK_OLD:
\r
1374 WriteMarkBankOldState();
\r
1377 case FEE_WRITE_HEADER_REQUESTED:
\r
1378 WriteHeaderRequested();
\r
1381 case FEE_WRITE_HEADER:
\r
1382 WriteHeaderState();
\r
1385 case FEE_WRITE_DATA_REQUESTED:
\r
1386 WriteDataRequested();
\r
1389 case FEE_WRITE_DATA:
\r
1393 case FEE_WRITE_MAGIC_REQUESTED:
\r
1394 WriteMagicRequested();
\r
1397 case FEE_WRITE_MAGIC:
\r
1398 WriteMagicState();
\r
1402 * Garbage collection states
1404 case FEE_GARBAGE_COLLECT_REQUESTED:
\r
1405 GarbageCollectStartJob();
\r
1408 case FEE_GARBAGE_COLLECT_HEADER_WRITE:
\r
1409 GarbageCollectWriteHeader();
\r
1412 case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:
\r
1413 GarbageCollectReadDataRequested();
\r
1416 case FEE_GARBAGE_COLLECT_DATA_READ:
\r
1417 GarbageCollectReadData();
\r
1420 case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:
\r
1421 GarbageCollectWriteDataRequested();
\r
1424 case FEE_GARBAGE_COLLECT_DATA_WRITE:
\r
1425 GarbageCollectWriteData();
\r
1428 case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:
\r
1429 GarbageCollectWriteMagicRequested();
\r
1432 case FEE_GARBAGE_COLLECT_MAGIC_WRITE:
\r
1433 GarbageCollectWriteMagic();
\r
1436 case FEE_GARBAGE_COLLECT_ERASE:
\r
1437 GarbageCollectErase();
\r
1443 case FEE_INVALIDATE_REQUESTED:
\r
1444 InvalidateStartJob();
\r
1447 case FEE_INVALIDATE_MARK_BANK_OLD:
\r
1448 InvalidateMarkBankOld();
\r
1451 case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:
\r
1452 InvalidateWriteInvalidateHeaderRequested();
\r
1455 case FEE_WRITE_INVALIDATE_HEADER:
\r
1456 InvalidateWriteInvalidateHeader();
\r
1469 /***************************************
\r
1470 * Call-back notifications functions *
\r
1471 ***************************************/
\r
1472 #if (FEE_POLLING_MODE == STD_OFF)
\r
1474 * Procedure: Fee_JobEndNotification
\r
1477 void Fee_JobEndNotification(void)
\r
1479 FlsJobReady = TRUE;
\r
1484 * Procedure: Fee_JobErrorNotification
\r
1487 void Fee_JobErrorNotification(void)
\r
1489 FlsJobReady = TRUE;
\r