]> rtime.felk.cvut.cz Git - arc.git/blobdiff - memory/Fee/Fee.c
Fee, removed counter which is no longer used.
[arc.git] / memory / Fee / Fee.c
index cf73f409d9151e6e1ba6022b1aee41c41d3629c4..671ad4c0bf5b9caadeddb2d42dc146ffcd119ea0 100644 (file)
  * for more details.\r
  * -------------------------------- Arctic Core ------------------------------*/\r
 \r
+/** @reqSettings DEFAULT_SPECIFICATION_REVISION=3.1.5 */\r
 \r
 \r
+/*\r
+ * Author: pete\r
+ *\r
+ * Part of Release:\r
+ *   3.1.5\r
+ *\r
+ * Description:\r
+ *   Implements the Fee module\r
+ *\r
+ * Support:\r
+ *   General                  Have Support\r
+ *   -------------------------------------------\r
+ *   FEE_DEV_ERROR_DETECT            Y\r
+ *   FeeIndex                                           N (always 0)\r
+ *   FEE_NVM_JOB_END_NOTIFICATION    Y (Under ArcCore FEE_USE_JOB_NOTIFICATIONS is used)\r
+ *   FEE_NVM_JOB_ERROR_NOTIFICATION  Y (Under ArcCore FEE_USE_JOB_NOTIFICATIONS is used)\r
+ *   FEE_POLLING_MODE                           Y\r
+ *   FEE_VERSION_INFO_API            Y\r
+ *   FEE_VIRTUAL_PAGE_SIZE           Y\r
+ *\r
+ *   Block                    Have Support\r
+ *   -------------------------------------------\r
+ *   FeeBlockNumber                    Y\r
+ *   FeeBlockSize                      Y\r
+ *   FeeImmediateData               N\r
+ *   FeeNumberOfWriteCycles         N\r
+ *   FeeDeviceIndex                    N\r
+ *\r
+ *   Published Information       Have Support\r
+ *   -------------------------------------------\r
+ *   FEE_BLOCK_OVERHEAD                N\r
+ *   FEE_MAXIMUM_BLOCKING_TIME         N\r
+ *   FEE_PAGE_OVERHEAD                         N\r
+ */\r
 \r
 \r
+//lint -emacro(904,DET_VALIDATE_RV,DET_VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).\r
 \r
-\r
-\r
+// Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero\r
+//lint -emacro(835, MIN_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
+//lint -emacro(835, GET_BLOCK_INDEX_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
+//lint -emacro(835, GET_DATASET_FROM_BLOCK_NUMBER) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
+//lint -emacro(778, GET_DATASET_FROM_BLOCK_NUMBER) // 778 PC-lint: Constant expression evaluates to 0 in operation '-'\r
+//lint -emacro(845, GET_DATASET_FROM_BLOCK_NUMBER) // 845 PC-lint: The right argument to operator '&' is certain to be 0\r
+//lint -emacro(835, BLOCK_INDEX_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'\r
 \r
 #include <string.h>\r
 #include "Fee.h"\r
 #include "Fee_Cbk.h"\r
+#include "Fee_Memory_Cfg.h"\r
 #include "NvM.h"\r
 #include "Fls.h"\r
 #include "Rte.h" // ???\r
 //#include "SchM_NvM.h"\r
 #include "MemMap.h"\r
 \r
+#include <stdio.h>\r
+//#define DEBUG_FEE    1\r
+#if defined(DEBUG_FEE)\r
+#define DEBUG_PRINTF(format,...)                                       printf(format,## __VA_ARGS__ );\r
+#else\r
+#define DEBUG_PRINTF(format,...)\r
+#endif\r
+\r
+\r
+\r
 /*\r
- * Local definitions
+ * Local definitions\r
  */\r
 \r
-// Validation macros\r
+/*\r
+ *  Validation macros\r
+ */\r
 #if  ( FEE_DEV_ERROR_DETECT == STD_ON )\r
 #include "Det.h"\r
-#define VALIDATE(_exp,_api,_err ) \\r
+#define DET_VALIDATE(_exp,_api,_err ) \\r
         if( !(_exp) ) { \\r
           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
         }\r
 \r
-#define VALIDATE_RV(_exp,_api,_err,_rv ) \\r
+#define DET_VALIDATE_RV(_exp,_api,_err,_rv ) \\r
         if( !(_exp) ) { \\r
           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
           return _rv; \\r
         }\r
 \r
-#define VALIDATE_NO_RV(_exp,_api,_err ) \\r
+#define DET_VALIDATE_NO_RV(_exp,_api,_err ) \\r
   if( !(_exp) ) { \\r
           Det_ReportError(MODULE_ID_FEE, 0, _api, _err); \\r
           return; \\r
         }\r
+\r
 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)\r
 \r
+#define MIN_BLOCKNR            ((uint16)((uint16)1 << NVM_DATASET_SELECTION_BITS))\r
+\r
 #else\r
-#define VALIDATE(_exp,_api,_err )\r
-#define VALIDATE_RV(_exp,_api,_err,_rv )\r
-#define VALIDATE_NO_RV(_exp,_api,_err )\r
+#define DET_VALIDATE(_exp,_api,_err )\r
+#define DET_VALIDATE_RV(_exp,_api,_err,_rv )\r
+#define DET_VALIDATE_NO_RV(_exp,_api,_err )\r
 #define DET_REPORTERROR(_module,_instance,_api,_err)\r
 #endif\r
 \r
-// Block numbering recalculation macros\r
-#define GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blocknr)     ((blocknr >> NVM_DATASET_SELECTION_BITS) - 1)\r
-#define GET_DATASET_FROM_BLOCK_NUMBER(blocknr) (blocknr & ((1 << NVM_DATASET_SELECTION_BITS) - 1))\r
 \r
-// Macro for checking if the flash is ready\r
-#define FLASH_READY    (FlsAdmin.State == FEE_FLS_STATE_READY)\r
+/*\r
+ * Block numbering recalculation macros\r
+ */\r
+#define GET_DATASET_FROM_BLOCK_NUMBER(_blocknr)        ((_blocknr) & ((uint16)((uint16)1u << NVM_DATASET_SELECTION_BITS) - 1u))\r
 \r
-// Macros and variables for flash block administration\r
-#define BLOCK_ADMIN_STATUS_VALID       0x01\r
-#define BLOCK_ADMIN_STATUS_EMPTY       0x02\r
+/*\r
+ * Page alignment macros\r
+ */\r
+#define PAGE_ALIGN(_size)      ((uint16)((((_size) + FEE_VIRTUAL_PAGE_SIZE - 1) / FEE_VIRTUAL_PAGE_SIZE) * FEE_VIRTUAL_PAGE_SIZE))\r
 \r
-#define BLOCK_ADMIN_MAGIC_LEN          4\r
+/*\r
+ * Bank properties list\r
+ */\r
+#define NUM_OF_BANKS   2\r
 typedef struct {\r
-       uint8   Status;\r
-       uint8   Spare;\r
-       uint8   Magic[BLOCK_ADMIN_MAGIC_LEN];\r
-} FlsBlockAdminType;\r
+       Fls_AddressType         Start;\r
+       Fls_LengthType          End;\r
+} BankPropType;\r
+\r
+static const BankPropType BankProp[NUM_OF_BANKS] = {\r
+       {\r
+               .Start = FEE_BANK1_OFFSET,\r
+               .End = FEE_BANK1_OFFSET + FEE_BANK1_LENGTH\r
+       },\r
+       {\r
+               .Start = FEE_BANK2_OFFSET,\r
+               .End = FEE_BANK2_OFFSET + FEE_BANK2_LENGTH\r
+       },\r
+};\r
 \r
-static FlsBlockAdminType FlsBlockAdmin;\r
 \r
-#define BLOCK_ADMIN_LEN                                (sizeof(FlsBlockAdminType))\r
-#define BLOCK_ADMIN_VALIDATE_POS       0\r
-#define BLOCK_ADMIN_MAGIC_POS          2\r
 \r
-static const uint8 MagicMaster[BLOCK_ADMIN_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };\r
-static const FlsBlockAdminType FlsBlockAdminMaster = {\r
-               .Status = BLOCK_ADMIN_STATUS_VALID | ~BLOCK_ADMIN_STATUS_EMPTY,\r
-               .Magic = { 0xeb, 0xba, 0xba, 0xbe }\r
-};\r
+/*\r
+ * Macros and variables for flash bank administration\r
+ */\r
+#define BANK_STATUS_OLD                0x00\r
+#define BANK_STATUS_NEW                0xFF\r
+typedef uint8 FlsBankStatusType;\r
 \r
-// Variables for keeping the state and status of the flash\r
-typedef enum {\r
-       FEE_FLS_STATE_IDLE,\r
-       FEE_FLS_STATE_PENDING,\r
-       FEE_FLS_STATE_READY\r
-} FlsStateType;\r
+#define BANK_CTRL_PAGE_SIZE            PAGE_ALIGN(sizeof(FlsBankStatusType))\r
+\r
+typedef union {\r
+       FlsBankStatusType       BankStatus;\r
+       uint8                           Data[BANK_CTRL_PAGE_SIZE];\r
+} FlsBankCtrlPageType;\r
+\r
+\r
+/*\r
+ * Macros and variables for flash block administration in flash\r
+ */\r
+#define BLOCK_STATUS_INUSE                     0x00\r
+#define BLOCK_STATUS_INVALIDATED       0x02\r
+#define BLOCK_STATUS_EMPTY                     0xFF\r
+typedef uint8 BlockStatusType;\r
 \r
 typedef struct {\r
-       FlsStateType State;\r
-       Std_ReturnType ErrorStatus;\r
-       MemIf_JobResultType JobResult;\r
-} FlsAdminType;\r
-\r
-static FlsAdminType FlsAdmin = {\r
-               .State = FEE_FLS_STATE_IDLE,\r
-               .ErrorStatus = E_OK,\r
-               .JobResult = MEMIF_JOB_OK\r
-};\r
+       BlockStatusType         Status;\r
+       uint16                          BlockNo;\r
+       Fls_AddressType         BlockDataAddress;\r
+       uint16                          BlockDataLength;\r
+} FlsBlockCtrlDataType;\r
+\r
+#define BLOCK_CTRL_DATA_PAGE_SIZE              PAGE_ALIGN(sizeof(FlsBlockCtrlDataType))\r
+\r
+typedef union {\r
+       FlsBlockCtrlDataType    Data;\r
+       uint8                                   Byte[BLOCK_CTRL_DATA_PAGE_SIZE];\r
+} FlsBlockCtrlDataPageType;\r
+\r
+\r
+#define BLOCK_MAGIC_LEN                4\r
+static const uint8 BlockMagicMaster[BLOCK_MAGIC_LEN] = { 0xeb, 0xba, 0xba, 0xbe };\r
+#define BLOCK_CTRL_MAGIC_PAGE_SIZE     PAGE_ALIGN(BLOCK_MAGIC_LEN)\r
+\r
+\r
+typedef union {\r
+       uint8           Magic[BLOCK_MAGIC_LEN];\r
+       uint8           Byte[BLOCK_CTRL_MAGIC_PAGE_SIZE];\r
+} FlsBlockCtrlMagicPageType;\r
+\r
+typedef struct {\r
+       FlsBlockCtrlDataPageType        DataPage;\r
+       FlsBlockCtrlMagicPageType       MagicPage;\r
+} FlsBlockControlType;\r
+\r
+#define BLOCK_CTRL_PAGE_SIZE   PAGE_ALIGN(sizeof(FlsBlockControlType))\r
+\r
+#define BLOCK_CTRL_DATA_POS_OFFSET             (/*lint --e(835)*/0)            // Inform PC-Lint that I want the constant to be zero\r
+#define BLOCK_CTRL_MAGIC_POS_OFFSET            BLOCK_CTRL_DATA_PAGE_SIZE\r
 \r
-// Variables for quick reporting of status and job result\r
+typedef union {\r
+       FlsBlockControlType     BlockCtrl;\r
+       FlsBankCtrlPageType BankCtrl;\r
+       uint8                           Byte[BLOCK_CTRL_PAGE_SIZE];\r
+} ReadWriteBufferType;\r
+\r
+static ReadWriteBufferType RWBuffer;\r
+\r
+#define RWBUFFER_SIZE  sizeof(ReadWriteBufferType)\r
+\r
+\r
+/*\r
+ * Variables for flash administration\r
+ */\r
+typedef struct {\r
+       BlockStatusType         Status;\r
+       Fls_AddressType         BlockAdminAddress;\r
+       Fls_AddressType         BlockDataAddress;\r
+} AdminFlsBlockType;\r
+\r
+typedef struct {\r
+       uint8                           BankNumber;\r
+       uint8                           ForceGarbageCollect;\r
+       uint8                           NofFailedGarbageCollect;\r
+       Fls_AddressType         NewBlockAdminAddress;\r
+       Fls_AddressType         NewBlockDataAddress;\r
+       FlsBankStatusType       BankStatus[NUM_OF_BANKS];\r
+       AdminFlsBlockType       BlockDescrTbl[FEE_NUM_OF_BLOCKS][FEE_MAX_NUM_SETS];\r
+} AdminFlsType;\r
+\r
+static AdminFlsType AdminFls;\r
+\r
+\r
+/*\r
+ * Variables for quick reporting of status and job result\r
+ */\r
 static MemIf_StatusType ModuleStatus = MEMIF_UNINIT;\r
 static MemIf_JobResultType JobResult = MEMIF_JOB_OK;\r
 \r
-// Variables for the current job\r
+/*\r
+ * Variables for the current job\r
+ */\r
 typedef enum {\r
   FEE_UNINITIALIZED = 0,\r
+  FEE_STARTUP_REQUESTED,\r
+  FEE_STARTUP_READ_BANK1_STATUS,\r
+  FEE_STARTUP_READ_BANK2_STATUS_REQUESTED,\r
+  FEE_STARTUP_READ_BANK2_STATUS,\r
+  FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED,\r
+  FEE_STARTUP_READ_BLOCK_ADMIN,\r
+\r
   FEE_IDLE,\r
+\r
   FEE_WRITE_REQUESTED,\r
-  FEE_WRITE_MAGIC_EREASE_PENDING,\r
-  FEE_WRITE_EREASE_PENDING,\r
-  FEE_WRITE_PENDING,\r
-  FEE_WRITE_BLOCK_ADMIN_PENDING,\r
+  FEE_WRITE_MARK_BANK_OLD,\r
+  FEE_WRITE_HEADER_REQUESTED,\r
+  FEE_WRITE_HEADER,\r
+  FEE_WRITE_DATA_REQUESTED,\r
+  FEE_WRITE_DATA,\r
+  FEE_WRITE_MAGIC_REQUESTED,\r
+  FEE_WRITE_MAGIC,\r
+\r
   FEE_READ_REQUESTED,\r
-  FEE_READ_BLOCK_ADMIN_PENDING,\r
-  FEE_READ_PENDING,\r
-  FEE_CANCEL_REQUESTED,\r
-  FEE_CANCEL_PENDING,\r
+  FEE_READ,\r
+\r
   FEE_INVALIDATE_REQUESTED,\r
-  FEE_INVALIDATE_PENDING,\r
-  FEE_ERASE_IMMEDIATE_REQUESTED,\r
-  FEE_ERASE_IMMEDIATE_PENDING\r
+  FEE_INVALIDATE_MARK_BANK_OLD,\r
+  FEE_WRITE_INVALIDATE_HEADER_REQUESTED,\r
+  FEE_WRITE_INVALIDATE_HEADER,\r
+\r
+  FEE_GARBAGE_COLLECT_REQUESTED,\r
+  FEE_GARBAGE_COLLECT_HEADER_WRITE,\r
+  FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED,\r
+  FEE_GARBAGE_COLLECT_DATA_READ,\r
+  FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED,\r
+  FEE_GARBAGE_COLLECT_DATA_WRITE,\r
+  FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED,\r
+  FEE_GARBAGE_COLLECT_MAGIC_WRITE,\r
+  FEE_GARBAGE_COLLECT_ERASE,\r
+\r
+  FEE_CORRUPTED\r
+\r
 } CurrentJobStateType;\r
 \r
 typedef struct {\r
        CurrentJobStateType                     State;\r
-       const Fee_BlockConfigType       *BlockConfigPtr;\r
+       uint16                                          BlockNumber;\r
        uint16                                          Length;\r
-       uint16                                          Offset;\r
-       uint32                                          FlsBlockAddr;           // Flash source/Dest depending of operation\r
-       uint32                                          FlsBlockAdminAddr;      // Startadress of admin block\r
-       uint8                                           *RamPtr;                // RAM source/Dest depending of operation\r
+       const Fee_BlockConfigType       *BlockConfigPtr;\r
+       AdminFlsBlockType                       *AdminFlsBlockPtr;\r
+       union {\r
+               struct {\r
+                       uint8                           NrOfBanks;\r
+                       uint8                           BankNumber;\r
+                       Fls_AddressType         BlockAdminAddress;\r
+               }Startup;\r
+               struct {\r
+                       uint16                          Offset;\r
+                       uint8                           *RamPtr;\r
+               }Read;\r
+               struct {\r
+                       uint8                           *RamPtr;\r
+                       Fls_AddressType         WriteAdminAddress;\r
+                       Fls_AddressType         WriteDataAddress;\r
+               }Write;\r
+               struct {\r
+                       Fls_AddressType         WriteAdminAddress;\r
+                       Fls_AddressType         WriteDataAddress;\r
+               }Invalidate;\r
+               struct {\r
+                       uint8                           BankNumber;\r
+                       Fls_AddressType         WriteAdminAddress;\r
+                       Fls_AddressType         WriteDataAddress;\r
+                       uint16                          BytesLeft;\r
+                       uint16                          DataOffset;\r
+               }GarbageCollect;\r
+       } Op;\r
 } CurrentJobType;\r
 \r
 static CurrentJobType CurrentJob = {\r
-               .State = FEE_IDLE\r
+               .State = FEE_IDLE,\r
+               //lint -e{785}          PC-Lint (785) - rest of structure members is initialized when used.\r
 };\r
 \r
-\r
 /*\r
- * Local functions
+ * Misc definitions\r
  */\r
+#define MAX_NOF_FAILED_GC_ATTEMPTS             5\r
+/***************************************\r
+ *           Local functions           *\r
+ ***************************************/\r
+uint16 GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(uint16 blockNumber) {\r
+       const Fee_BlockConfigType *FeeBlockCon;\r
+       uint16 BlockIndex = FEE_NUM_OF_BLOCKS + 1; // An invalid block\r
+\r
+       FeeBlockCon = Fee_Config.BlockConfig;\r
+       for (uint16 i = 0; i < FEE_NUM_OF_BLOCKS; i++)\r
+       {\r
+               if (FeeBlockCon[i].BlockNumber == blockNumber)\r
+               {\r
+                       BlockIndex = i;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       return BlockIndex;\r
+}\r
+\r
+\r
 #if (FEE_POLLING_MODE == STD_ON)\r
-void PollFlsJobResult(void)\r
-{\r
-       MemIf_JobResultType jobResult;\r
+#define SetFlsJobBusy()                        /* Nothing needs to be done here */\r
 \r
-       if (FlsAdmin.State == FEE_FLS_STATE_PENDING) {\r
-               jobResult = Fls_GetJobResult();\r
+static boolean CheckFlsJobFinnished(void)\r
+{\r
+       MemIf_JobResultType flsJobResult;\r
 \r
-               if (jobResult == MEMIF_JOB_OK) {\r
-                       FlsAdmin.ErrorStatus = E_OK;\r
-                       FlsAdmin.JobResult = jobResult;\r
-                       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-               } else if (jobResult != MEMIF_JOB_PENDING) {\r
-                       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                       FlsAdmin.JobResult = jobResult;\r
-                       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-               }\r
-       }\r
+       flsJobResult = Fls_GetJobResult();\r
+       return (flsJobResult != MEMIF_JOB_PENDING);\r
 }\r
 #else\r
-#define PollFlsJobResult(...)\r
+static boolean FlsJobReady = TRUE;\r
+\r
+static void SetFlsJobBusy()\r
+{\r
+       FlsJobReady = FALSE;\r
+}\r
+\r
+static boolean CheckFlsJobFinnished(void)\r
+{\r
+       return (FlsJobReady);\r
+}\r
+\r
 #endif\r
 \r
 \r
-void FinnishJob(void)\r
+static void FinnishStartup(void)\r
 {\r
-       FlsAdmin.State = FEE_FLS_STATE_IDLE;\r
        CurrentJob.State = FEE_IDLE;\r
+       ModuleStatus = MEMIF_IDLE;\r
+       JobResult = MEMIF_JOB_OK;\r
+}\r
 \r
+\r
+static void AbortStartup(MemIf_JobResultType result)\r
+{\r
+       CurrentJob.State = FEE_IDLE;\r
        ModuleStatus = MEMIF_IDLE;\r
-       JobResult = FlsAdmin.JobResult;\r
+       JobResult = result;\r
+}\r
 \r
-       if (FlsAdmin.ErrorStatus == E_OK) {\r
+\r
+static void FinnishJob(void)\r
+{\r
+       CurrentJob.State = FEE_IDLE;\r
+       ModuleStatus = MEMIF_IDLE;\r
+       JobResult = MEMIF_JOB_OK;\r
+       if(!AdminFls.ForceGarbageCollect){\r
                if (Fee_Config.General.NvmJobEndCallbackNotificationCallback != NULL) {\r
                        Fee_Config.General.NvmJobEndCallbackNotificationCallback();\r
                }\r
+       }\r
+}\r
+\r
+\r
+static void AbortJob(MemIf_JobResultType result)\r
+{\r
+       if(AdminFls.NofFailedGarbageCollect >= MAX_NOF_FAILED_GC_ATTEMPTS){\r
+               DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_GLOBAL_ID, FEE_FLASH_CORRUPT);\r
+               AdminFls.ForceGarbageCollect = 0;\r
+               CurrentJob.State = FEE_CORRUPTED;\r
        } else {\r
-               if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
-                       Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
+               CurrentJob.State = FEE_IDLE;\r
+       }\r
+       ModuleStatus = MEMIF_IDLE;\r
+       JobResult = result;\r
+\r
+       if (Fee_Config.General.NvmJobErrorCallbackNotificationCallback != NULL) {\r
+               Fee_Config.General.NvmJobErrorCallbackNotificationCallback();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of bank status 1 read\r
+ */\r
+static void StartupStartJob(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_STARTUP_READ_BANK1_STATUS;\r
+               /* Read bank status of bank 1 */\r
+               // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
+               if (Fls_Read(BankProp[0].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[0], sizeof(FlsBankStatusType)) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AbortStartup(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ *  Check job result of bank 1 status read, if ok request for bank 2 status read\r
+ */\r
+static void StartupReadBank1Status(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS_REQUESTED;\r
+               } else {\r
+                       AbortStartup(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of bank status 2 read\r
+ */\r
+static void StartupReadBank2StatusRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               /* Read bank status of bank 2 */\r
+               CurrentJob.State = FEE_STARTUP_READ_BANK2_STATUS;\r
+               // PC-Lint exception (MISRA 11.4) - Pointer to pointer conversion ok by AUTOSAR\r
+               if (Fls_Read(BankProp[1].End - BANK_CTRL_PAGE_SIZE, /*lint -e(926)*/(uint8*)&AdminFls.BankStatus[1], sizeof(FlsBankStatusType)) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AbortStartup(Fls_GetJobResult());\r
                }\r
        }\r
 }\r
 \r
 \r
-void ReadStartJob(void)\r
+/*\r
+ * Check job result of bank status 2 read - request for block status reading\r
+ */\r
+static void StartupReadBank2Status(void)\r
+{\r
+       MemIf_JobResultType jobResult;\r
+\r
+       if (CheckFlsJobFinnished()) {\r
+               jobResult = Fls_GetJobResult();\r
+               if (jobResult == MEMIF_JOB_OK) {\r
+                       /* Select which bank to start with */\r
+                       if ((AdminFls.BankStatus[0] != BANK_STATUS_OLD) && (AdminFls.BankStatus[1] != BANK_STATUS_OLD)){\r
+                               /* None is marked as old, just start with one of them */\r
+                               CurrentJob.Op.Startup.BankNumber = 0;\r
+                               CurrentJob.Op.Startup.NrOfBanks = 2;\r
+                       } else if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) && (AdminFls.BankStatus[1] == BANK_STATUS_OLD) ) {\r
+                               /* Both banks are marked as old, this shall not be possible */\r
+                               DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
+                               jobResult = MEMIF_JOB_FAILED;\r
+                       } else if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
+                               CurrentJob.Op.Startup.BankNumber = 0;\r
+                               CurrentJob.Op.Startup.NrOfBanks = 2;\r
+                       } else {\r
+                               CurrentJob.Op.Startup.BankNumber = 1;\r
+                               CurrentJob.Op.Startup.NrOfBanks = 2;\r
+                       }\r
+               }\r
+\r
+               if (jobResult != MEMIF_JOB_OK) {\r
+                       AbortStartup(jobResult);\r
+               } else {\r
+                       CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+                       CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+ * Start of block admin read\r
+ */\r
+static void StartupReadBlockAdminRequested(void)\r
 {\r
-       if (FlsAdmin.State == FEE_FLS_STATE_IDLE) {\r
-               FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-               CurrentJob.State = FEE_READ_BLOCK_ADMIN_PENDING;\r
-               // Start by reading the admin block\r
-               if (Fls_Read(CurrentJob.FlsBlockAdminAddr, (uint8*)&FlsBlockAdmin, BLOCK_ADMIN_LEN) != E_OK) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                       FlsAdmin.JobResult = Fls_GetJobResult();\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               /* Start reading the banks */\r
+               CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN;\r
+               if (Fls_Read(CurrentJob.Op.Startup.BlockAdminAddress, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AbortStartup(Fls_GetJobResult());\r
                }\r
        }\r
 }\r
 \r
-void ReadCheckBlockAdminJob(void)\r
+\r
+/*\r
+ * Check job result of block admin read, if all block processed finish\r
+ * otherwise request for a new block admin read\r
+ */\r
+static void StartupReadBlockAdmin(void)\r
 {\r
-       if (FlsAdmin.ErrorStatus == E_OK) {\r
-               if (memcmp(FlsBlockAdmin.Magic, MagicMaster, BLOCK_ADMIN_MAGIC_LEN) == 0) {\r
-                       if (FlsBlockAdmin.Status & BLOCK_ADMIN_STATUS_VALID) {\r
-                               if (FlsAdmin.State != FEE_FLS_STATE_PENDING) {\r
-                                       FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-                                       CurrentJob.State = FEE_READ_PENDING;\r
-                                       // Read the actual data\r
-                                       if (Fls_Read(CurrentJob.FlsBlockAddr + CurrentJob.Offset, CurrentJob.RamPtr, CurrentJob.Length) != E_OK) {\r
-                                               FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                                               FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                                               FlsAdmin.JobResult = Fls_GetJobResult();\r
-                                               FinnishJob();\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       if (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_EMPTY) {\r
+                               DET_VALIDATE(CurrentJob.Op.Startup.NrOfBanks != 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
+                               CurrentJob.Op.Startup.NrOfBanks--;\r
+                               CurrentJob.Op.Startup.BankNumber = (CurrentJob.Op.Startup.BankNumber + 1) % 2;\r
+                               CurrentJob.Op.Startup.BlockAdminAddress = BankProp[CurrentJob.Op.Startup.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+                       } else { /* Block not empty */\r
+                               if ((memcmp(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN) == 0) &&\r
+                                               ((RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INUSE) || (RWBuffer.BlockCtrl.DataPage.Data.Status == BLOCK_STATUS_INVALIDATED))) {\r
+                                       /* This is a valid admin block */\r
+                                       uint16 blockIndex;\r
+                                       uint16 dataSet;\r
+\r
+                                       blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
+                                       dataSet = GET_DATASET_FROM_BLOCK_NUMBER(RWBuffer.BlockCtrl.DataPage.Data.BlockNo);\r
+\r
+                                       if ((blockIndex < FEE_NUM_OF_BLOCKS) && (dataSet < FEE_MAX_NUM_SETS)) {\r
+                                               AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
+                                               AdminFls.BlockDescrTbl[blockIndex][dataSet].BlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress;\r
+                                               AdminFls.BlockDescrTbl[blockIndex][dataSet].Status = RWBuffer.BlockCtrl.DataPage.Data.Status;\r
+\r
+                                               AdminFls.BankNumber = CurrentJob.Op.Startup.BankNumber;\r
+                                               AdminFls.NewBlockDataAddress = RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress + RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength;\r
+                                               if (CurrentJob.Op.Startup.BlockAdminAddress <= AdminFls.NewBlockDataAddress) {\r
+                                                       /* This shall never happen */\r
+                                                       DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_STARTUP_ID, FEE_FLASH_CORRUPT);\r
+                                               }\r
                                        }\r
                                }\r
+                               // TODO Check wrap around here\r
+                               CurrentJob.Op.Startup.BlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
+                               AdminFls.NewBlockAdminAddress = CurrentJob.Op.Startup.BlockAdminAddress;\r
+                       }\r
+\r
+                       if (CurrentJob.Op.Startup.NrOfBanks == 0) {\r
+                               /* If current bank is marked as old we need to switch to a new bank */\r
+                               if (AdminFls.BankStatus[AdminFls.BankNumber] == BANK_STATUS_OLD) {\r
+                                       AdminFls.BankNumber = (AdminFls.BankNumber + 1) % 2;\r
+                                       AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+                                       AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
+                               }\r
+                               /* We are done! */\r
+                               FinnishStartup();\r
+                       } else {\r
+                               CurrentJob.State = FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED;\r
+                       }\r
+\r
+\r
+               } else { /* ErrorStatus not E_OK */\r
+                       AbortStartup(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of read block data\r
+ */\r
+static void ReadStartJob(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_EMPTY) {\r
+                       if (CurrentJob.AdminFlsBlockPtr->Status != BLOCK_STATUS_INVALIDATED) {\r
+                               CurrentJob.State = FEE_READ;\r
+                               /* Read the actual data */\r
+                               if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.Read.Offset, CurrentJob.Op.Read.RamPtr, CurrentJob.Length) == E_OK) {\r
+                                       SetFlsJobBusy();\r
+                               } else {\r
+                                       AbortJob(Fls_GetJobResult());\r
+                               }\r
                        } else {\r
-                               FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                               FlsAdmin.JobResult = MEMIF_BLOCK_INVALID;\r
-                               FinnishJob();\r
+                               /* Invalid */\r
+                               AbortJob(MEMIF_BLOCK_INVALID);\r
                        }\r
                } else {\r
-                       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                       FlsAdmin.JobResult = MEMIF_BLOCK_INCONSISTENT;\r
+                       /* Inconsistent */\r
+                       AbortJob(MEMIF_BLOCK_INCONSISTENT);\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+ * Check job result of block data read\r
+ */\r
+static void Reading(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
                        FinnishJob();\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
                }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Write bank header\r
+ */\r
+static void BankHeaderOldWrite(uint8 bank)\r
+{\r
+       /* Need to collect garbage */\r
+       AdminFls.ForceGarbageCollect = 1;\r
+       /* Mark the bank as old */\r
+       memset(RWBuffer.BankCtrl.Data, 0xff, BANK_CTRL_PAGE_SIZE);\r
+       RWBuffer.BankCtrl.BankStatus = BANK_STATUS_OLD;\r
+       if (Fls_Write(BankProp[bank].End - BANK_CTRL_PAGE_SIZE, RWBuffer.BankCtrl.Data, BANK_CTRL_PAGE_SIZE) == E_OK) {\r
+               SetFlsJobBusy();\r
+       } else {\r
+               AbortJob(Fls_GetJobResult());\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Write block header\r
+ */\r
+static void BlockHeaderDataWrite(void)\r
+{\r
+       /* Write the header excluding the magic */\r
+       memset(RWBuffer.BlockCtrl.DataPage.Byte, 0xff, BLOCK_CTRL_DATA_PAGE_SIZE);\r
+       RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INUSE;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = CurrentJob.Length;\r
+       if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_DATA_PAGE_SIZE) == E_OK) {\r
+               SetFlsJobBusy();\r
+               AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
+               AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
        } else {\r
-               FinnishJob();\r
+               AbortJob(Fls_GetJobResult());\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check if bank switch needed:\r
+ * - Yes, start mark current bank as old\r
+ * - No, start of header write\r
+ */\r
+static void WriteStartJob(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
+                       /* Bank switch needed, mark current bank as "old" */\r
+                       CurrentJob.State = FEE_WRITE_MARK_BANK_OLD;\r
+                       BankHeaderOldWrite(AdminFls.BankNumber);\r
+               } else {\r
+                       CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
+                       CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
+\r
+                       CurrentJob.State = FEE_WRITE_HEADER;\r
+                       BlockHeaderDataWrite();\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check job result of mark bank as old, if ok request for header write\r
+ */\r
+static void WriteMarkBankOldState(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       /* Mark for garbage collection */\r
+                       AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
+\r
+                       /* Change of bank */\r
+                       AdminFls.BankNumber ^= 0x1u;\r
+                       AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
+                       AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+\r
+                       CurrentJob.Op.Write.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
+                       CurrentJob.Op.Write.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
+\r
+                       CurrentJob.State = FEE_WRITE_HEADER_REQUESTED;\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of header write\r
+ */\r
+static void WriteHeaderRequested()\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_WRITE_HEADER;\r
+               BlockHeaderDataWrite();\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check job result of write header, if ok request for block data write\r
+ */\r
+static void WriteHeaderState(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       CurrentJob.State = FEE_WRITE_DATA_REQUESTED;\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start block data write\r
+ */\r
+static void WriteDataRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_WRITE_DATA;\r
+               /* Write the actual data */\r
+               DEBUG_PRINTF("WriteDataRequested: 0x%x 0x%x %d  ",CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length );\r
+\r
+               if (Fls_Write(CurrentJob.Op.Write.WriteDataAddress, CurrentJob.Op.Write.RamPtr, CurrentJob.Length) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check job result of data write - request for magic write\r
+ */\r
+static void WriteDataState(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       CurrentJob.State = FEE_WRITE_MAGIC_REQUESTED;\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
        }\r
 }\r
 \r
 \r
-void WriteStartJob(void)\r
+/*\r
+ * Start magic write\r
+ */\r
+static void WriteMagicRequested(void)\r
 {\r
-       if (FlsAdmin.State == FEE_FLS_STATE_IDLE) {\r
-               FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-               CurrentJob.State = FEE_WRITE_MAGIC_EREASE_PENDING;\r
-               // Start by erasing the magic\r
-               if (Fls_Erase(CurrentJob.FlsBlockAdminAddr + BLOCK_ADMIN_MAGIC_POS, BLOCK_ADMIN_MAGIC_LEN) != E_OK) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                       FlsAdmin.JobResult = Fls_GetJobResult();\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_WRITE_MAGIC;\r
+               memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
+               memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
+               if (Fls_Write(CurrentJob.Op.Write.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
                }\r
        }\r
 }\r
 \r
 \r
-void WriteCheckMagicEraseJob(void)\r
+/*\r
+ * Check job result of write magic, if ok update the block admin table and finish\r
+ */\r
+static void WriteMagicState(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       /* Update the block admin table */\r
+                       CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INUSE;\r
+                       CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Write.WriteAdminAddress;\r
+                       CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Write.WriteDataAddress;\r
+\r
+                       FinnishJob();\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check if any bank is marked as old\r
+ */\r
+static void CheckIfGarbageCollectionNeeded(void)\r
+{\r
+       if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
+               ModuleStatus = MEMIF_BUSY_INTERNAL;\r
+               JobResult = MEMIF_JOB_PENDING;\r
+\r
+               CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Checks if any blocks needs to be moved if so start with writing a new header\r
+ * or if no blocks needs to be moved request for bank erase.\r
+ */\r
+static void GarbageCollectStartJob(void)\r
 {\r
-       if (FlsAdmin.ErrorStatus == E_OK) {\r
-               if (FlsAdmin.State != FEE_FLS_STATE_PENDING) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-                       CurrentJob.State = FEE_WRITE_EREASE_PENDING;\r
-                       // Erase the rest of the block\r
-                       if (Fls_Erase(CurrentJob.FlsBlockAddr, CurrentJob.BlockConfigPtr->BlockSize + BLOCK_ADMIN_LEN - BLOCK_ADMIN_MAGIC_LEN) != E_OK) {\r
-                               FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                               FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                               FlsAdmin.JobResult = Fls_GetJobResult();\r
-                               FinnishJob();\r
+       uint16 blockIndex;\r
+       uint16 set;\r
+       boolean found = FALSE;\r
+       uint8 sourceBank;\r
+\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               if ((AdminFls.BankStatus[0] == BANK_STATUS_OLD) || (AdminFls.BankStatus[1] == BANK_STATUS_OLD)) {\r
+                       if (AdminFls.BankStatus[0] == BANK_STATUS_OLD) {\r
+                               sourceBank = 0;\r
+                       } else {\r
+                               sourceBank = 1;\r
+                       }\r
+\r
+                       for (blockIndex = 0; (blockIndex < FEE_NUM_OF_BLOCKS) && (!found); blockIndex++) {\r
+                               for (set = 0; (set < FEE_MAX_NUM_SETS) && (!found); set++) {\r
+                                       if (AdminFls.BlockDescrTbl[blockIndex][set].Status != BLOCK_STATUS_EMPTY) {\r
+                                               if ((AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress >= BankProp[sourceBank].Start) && (AdminFls.BlockDescrTbl[blockIndex][set].BlockAdminAddress < (BankProp[sourceBank].End))) {\r
+                                                       CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][set];\r
+                                                       CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
+                                                       CurrentJob.BlockNumber = Fee_Config.BlockConfig[blockIndex].BlockNumber;\r
+                                                       if (AdminFls.BlockDescrTbl[blockIndex][set].Status == BLOCK_STATUS_INVALIDATED) {\r
+                                                               CurrentJob.Length = 0;\r
+                                                       } else {\r
+                                                               CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
+                                                       }\r
+\r
+                                                       found = TRUE;\r
+                                               }\r
+                                       }\r
+                               }\r
                        }\r
+\r
+                       if (found) {\r
+                               CurrentJob.Op.GarbageCollect.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
+                               CurrentJob.Op.GarbageCollect.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
+\r
+                               CurrentJob.State = FEE_GARBAGE_COLLECT_HEADER_WRITE;\r
+                               BlockHeaderDataWrite();\r
+                       } else {\r
+                               if (Fls_Erase(BankProp[sourceBank].Start, BankProp[sourceBank].End - BankProp[sourceBank].Start) == E_OK) {\r
+                                       SetFlsJobBusy();\r
+                                       CurrentJob.Op.GarbageCollect.BankNumber = sourceBank;\r
+                                       CurrentJob.State = FEE_GARBAGE_COLLECT_ERASE;\r
+                               } else {\r
+                                       AdminFls.NofFailedGarbageCollect++;\r
+                                       AbortJob(Fls_GetJobResult());\r
+                               }\r
+                       }\r
+               } else {\r
+                       CurrentJob.State = FEE_IDLE;\r
                }\r
-       } else {\r
-               FinnishJob();\r
        }\r
 }\r
 \r
 \r
-void WriteCheckEraseJob(void)\r
+/*\r
+ * Check job result of write header, if ok request for read block data\r
+ */\r
+static void GarbageCollectWriteHeader(void)\r
 {\r
-       if (FlsAdmin.ErrorStatus == E_OK) {\r
-               if (FlsAdmin.State != FEE_FLS_STATE_PENDING) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-                       CurrentJob.State = FEE_WRITE_PENDING;\r
-                       // Write the actual data\r
-                       if (Fls_Write(CurrentJob.FlsBlockAddr, CurrentJob.RamPtr, CurrentJob.Length) != E_OK) {\r
-                               FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                               FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                               FlsAdmin.JobResult = Fls_GetJobResult();\r
-                               FinnishJob();\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       if (CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INUSE) {\r
+                               CurrentJob.Op.GarbageCollect.BytesLeft = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
+                               CurrentJob.Op.GarbageCollect.DataOffset = 0;\r
+                               CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
+                       } else {\r
+                               /* Yes, we are finished */\r
+                               DET_VALIDATE_NO_RV(CurrentJob.AdminFlsBlockPtr->Status == BLOCK_STATUS_INVALIDATED, FEE_GARBAGE_WRITE_HEADER_ID, FEE_UNEXPECTED_STATUS);\r
+                               CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
                        }\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of read block data, if data length is more than buffer size\r
+ * the reading is segmented.\r
+ */\r
+static void GarbageCollectReadDataRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ;\r
+               if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
+                       CurrentJob.Length = CurrentJob.Op.GarbageCollect.BytesLeft;\r
+               } else {\r
+                       CurrentJob.Length = RWBUFFER_SIZE;\r
+               }\r
+               if (Fls_Read(CurrentJob.AdminFlsBlockPtr->BlockDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check job result of read block data, if ok request for a data write\r
+ */\r
+static void GarbageCollectReadData(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED;\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start of write block data\r
+ */\r
+static void GarbageCollectWriteDataRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_WRITE;\r
+               /* Write the actual data */\r
+               if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteDataAddress + CurrentJob.Op.GarbageCollect.DataOffset, RWBuffer.Byte, CurrentJob.Length) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
                }\r
        } else {\r
-               FinnishJob();\r
+               AdminFls.NofFailedGarbageCollect++;\r
+               AbortJob(Fls_GetJobResult());\r
        }\r
 }\r
 \r
 \r
-void WriteCheckWriteJob(void)\r
+/*\r
+ * Check job result of write data, if ok request for write magic or\r
+ * next data read depending on if there are more block data to move.\r
+ */\r
+static void GarbageCollectWriteData(void)\r
 {\r
-       if (FlsAdmin.ErrorStatus == E_OK) {\r
-               if (FlsAdmin.State != FEE_FLS_STATE_PENDING) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-                       CurrentJob.State = FEE_WRITE_BLOCK_ADMIN_PENDING;\r
-                       // Write the block admin (mark it as consistent, valid and not empty)\r
-                       if (Fls_Write(CurrentJob.FlsBlockAdminAddr, (uint8*)&FlsBlockAdminMaster, BLOCK_ADMIN_LEN) != E_OK) {\r
-                               FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                               FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                               FlsAdmin.JobResult = Fls_GetJobResult();\r
-                               FinnishJob();\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       if (CurrentJob.Op.GarbageCollect.BytesLeft <= RWBUFFER_SIZE) {\r
+                               /* Yes, we are finished */\r
+                               CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED;\r
+                       } else {\r
+                               /* More data to move */\r
+                               CurrentJob.Op.GarbageCollect.DataOffset += RWBUFFER_SIZE;\r
+                               CurrentJob.Op.GarbageCollect.BytesLeft -= RWBUFFER_SIZE;\r
+                               CurrentJob.State = FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED;\r
                        }\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Start write magic\r
+ */\r
+static void GarbageCollectWriteMagicRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_GARBAGE_COLLECT_MAGIC_WRITE;\r
+               memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
+               memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
+               if (Fls_Write(CurrentJob.Op.GarbageCollect.WriteAdminAddress + BLOCK_CTRL_MAGIC_POS_OFFSET, RWBuffer.BlockCtrl.MagicPage.Byte, BLOCK_CTRL_MAGIC_PAGE_SIZE) == E_OK) {\r
+                       SetFlsJobBusy();\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check the job result of write magic, if ok update the admin table with the new position of data.\r
+ */\r
+static void GarbageCollectWriteMagic(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.GarbageCollect.WriteAdminAddress;\r
+                       CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.GarbageCollect.WriteDataAddress;\r
+                       CurrentJob.State = FEE_GARBAGE_COLLECT_REQUESTED;\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
                }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check the result of the erase job\r
+ */\r
+static void GarbageCollectErase(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       AdminFls.BankStatus[CurrentJob.Op.GarbageCollect.BankNumber] = BANK_STATUS_NEW;\r
+                       AdminFls.ForceGarbageCollect = 0;\r
+                       AdminFls.NofFailedGarbageCollect = 0;\r
+                       FinnishJob();\r
+               } else {\r
+                       AdminFls.NofFailedGarbageCollect++;\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Write an "Invalidated" block header\r
+ */\r
+static void BlockHeaderInvalidWrite(void)\r
+{\r
+       // Write the header including the magic\r
+       memset(RWBuffer.Byte, 0xff, BLOCK_CTRL_PAGE_SIZE);\r
+       RWBuffer.BlockCtrl.DataPage.Data.Status = BLOCK_STATUS_INVALIDATED;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockNo = CurrentJob.BlockNumber;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockDataAddress = AdminFls.NewBlockDataAddress;\r
+       RWBuffer.BlockCtrl.DataPage.Data.BlockDataLength = 0;\r
+       memset(RWBuffer.BlockCtrl.MagicPage.Byte, 0xff, BLOCK_CTRL_MAGIC_PAGE_SIZE);\r
+       memcpy(RWBuffer.BlockCtrl.MagicPage.Magic, BlockMagicMaster, BLOCK_MAGIC_LEN);\r
+\r
+       if (Fls_Write(CurrentJob.Op.Invalidate.WriteAdminAddress + BLOCK_CTRL_DATA_POS_OFFSET, RWBuffer.Byte, BLOCK_CTRL_PAGE_SIZE) == E_OK) {\r
+               SetFlsJobBusy();\r
+               AdminFls.NewBlockDataAddress += CurrentJob.Length;\r
+               AdminFls.NewBlockAdminAddress -= BLOCK_CTRL_PAGE_SIZE;\r
        } else {\r
-               FinnishJob();\r
+               AbortJob(Fls_GetJobResult());\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check if bank switch is needed, if yes request for marking current bank as old,\r
+ * if no request for writing a header with "Invalid" status set.\r
+ */\r
+static void InvalidateStartJob(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               if (AdminFls.NewBlockDataAddress + CurrentJob.BlockConfigPtr->BlockSize > AdminFls.NewBlockAdminAddress - BLOCK_CTRL_PAGE_SIZE) {\r
+                       /* Bank switch needed, mark current bank as "old" */\r
+                       CurrentJob.State = FEE_INVALIDATE_MARK_BANK_OLD;\r
+                       BankHeaderOldWrite(AdminFls.BankNumber);\r
+               } else {\r
+                       CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
+                       CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
+\r
+                       CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
+                       BlockHeaderInvalidWrite();\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*\r
+ * Check job result of mark bank old, if ok continue with request for writing\r
+ * a header with "Invalid" status set.\r
+ */\r
+static void InvalidateMarkBankOld(void)\r
+{\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       // Mark for garbage collection\r
+                       AdminFls.BankStatus[AdminFls.BankNumber] = BANK_STATUS_OLD;\r
+\r
+                       // Change of bank\r
+                       AdminFls.BankNumber ^= 0x1u;\r
+                       AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
+                       AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+\r
+                       CurrentJob.Op.Invalidate.WriteDataAddress = AdminFls.NewBlockDataAddress;\r
+                       CurrentJob.Op.Invalidate.WriteAdminAddress = AdminFls.NewBlockAdminAddress;\r
+\r
+                       CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER_REQUESTED;\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+ * Start the writing of the "Invalid" header.\r
+ */\r
+static void InvalidateWriteInvalidateHeaderRequested(void)\r
+{\r
+       if (Fls_GetStatus() == MEMIF_IDLE) {\r
+               CurrentJob.State = FEE_WRITE_INVALIDATE_HEADER;\r
+               BlockHeaderInvalidWrite();\r
        }\r
 }\r
 \r
 \r
-void InvalidateStartJob(void)\r
+/*\r
+ * Check the job result of "Invalid" header write, if ok update the block admin table\r
+ */\r
+static void InvalidateWriteInvalidateHeader(void)\r
 {\r
-       static const uint8 zero = 0;\r
+       if (CheckFlsJobFinnished()) {\r
+               if (Fls_GetJobResult() == MEMIF_JOB_OK) {\r
+                       // Update the block admin table\r
+                       CurrentJob.AdminFlsBlockPtr->Status =  BLOCK_STATUS_INVALIDATED;\r
+                       CurrentJob.AdminFlsBlockPtr->BlockAdminAddress = CurrentJob.Op.Invalidate.WriteAdminAddress;\r
+                       CurrentJob.AdminFlsBlockPtr->BlockDataAddress = CurrentJob.Op.Invalidate.WriteDataAddress;\r
 \r
-       if (FlsAdmin.State == FEE_FLS_STATE_IDLE) {\r
-               FlsAdmin.State = FEE_FLS_STATE_PENDING;\r
-               CurrentJob.State = FEE_INVALIDATE_PENDING;\r
-               // Write a zero to the Validate flag\r
-               if (Fls_Write(CurrentJob.FlsBlockAdminAddr + BLOCK_ADMIN_VALIDATE_POS, &zero, 1) != E_OK) {\r
-                       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-                       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-                       FlsAdmin.JobResult = Fls_GetJobResult();\r
+                       FinnishJob();\r
+               } else {\r
+                       AbortJob(Fls_GetJobResult());\r
                }\r
        }\r
 }\r
 \r
 \r
 /***************************************\r
- *    External accessible functions    *
+ *    External accessible functions    *\r
  ***************************************/\r
 /*\r
  * Procedure:  Fee_Init\r
@@ -347,15 +1183,35 @@ void InvalidateStartJob(void)
  */\r
 void Fee_Init(void)\r
 {\r
-       // Reporting information\r
-       ModuleStatus = MEMIF_IDLE;\r
+       uint16 i,j;\r
+\r
+       /* Reporting information */\r
+       ModuleStatus = MEMIF_BUSY_INTERNAL;\r
        JobResult = MEMIF_JOB_OK;\r
 \r
-       // State of device\r
-       CurrentJob.State = FEE_IDLE;\r
-       FlsAdmin.State = FEE_FLS_STATE_IDLE;\r
-       FlsAdmin.ErrorStatus = E_OK;\r
-       FlsAdmin.JobResult = MEMIF_JOB_OK;\r
+       /* State of device */\r
+       CurrentJob.State = FEE_STARTUP_REQUESTED;\r
+#if (FEE_POLLING_MODE == STD_OFF)\r
+       FlsJobReady = TRUE;\r
+#endif\r
+\r
+       AdminFls.BankNumber = 0;\r
+       AdminFls.ForceGarbageCollect = 0;\r
+       AdminFls.NofFailedGarbageCollect = 0;\r
+       AdminFls.NewBlockDataAddress = BankProp[AdminFls.BankNumber].Start;\r
+       AdminFls.NewBlockAdminAddress = BankProp[AdminFls.BankNumber].End - (BLOCK_CTRL_PAGE_SIZE + BANK_CTRL_PAGE_SIZE);\r
+\r
+       for (i = 0; i < NUM_OF_BANKS; i++) {\r
+               AdminFls.BankStatus[i] = BANK_STATUS_NEW;\r
+       }\r
+\r
+       for (i = 0; i < FEE_NUM_OF_BLOCKS; i++) {\r
+               for (j = 0; j < FEE_MAX_NUM_SETS; j++) {\r
+                       AdminFls.BlockDescrTbl[i][j].Status = BLOCK_STATUS_EMPTY;\r
+                       AdminFls.BlockDescrTbl[i][j].BlockAdminAddress= 0;\r
+                       AdminFls.BlockDescrTbl[i][j].BlockDataAddress = 0;\r
+               }\r
+       }\r
 }\r
 \r
 \r
@@ -368,6 +1224,7 @@ void Fee_SetMode(MemIf_ModeType mode)
 #if ( FLS_SET_MODE_API == STD_ON )\r
        Fls_SetMode(mode);\r
 #else\r
+       //lint --e{715} PC-Lint (715) - variable "mode" not used in this case\r
        DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_SET_MODE_ID, FEE_E_NOT_SUPPORTED);\r
 #endif\r
 }\r
@@ -379,28 +1236,37 @@ void Fee_SetMode(MemIf_ModeType mode)
 Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBufferPtr, uint16 length)\r
 {\r
        uint16 blockIndex;\r
+       uint16 dataset;\r
 \r
-       VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
-       VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
+       DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_READ_ID, FEE_E_UNINIT, E_NOT_OK);\r
+       if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
+               return E_NOT_OK;\r
+       }\r
+       if( !(ModuleStatus == MEMIF_IDLE) ) {\r
+               DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
+               return E_NOT_OK;\r
+       }\r
 \r
-       VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
        blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
-       VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
-       VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
-       VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
-       VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
+       DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
+       DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_READ_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
+       DET_VALIDATE_RV(blockOffset < Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_OFS, E_NOT_OK);\r
+       DET_VALIDATE_RV(blockOffset + length <= Fee_Config.BlockConfig[blockIndex].BlockSize, FEE_READ_ID, FEE_E_INVALID_BLOCK_LEN, E_NOT_OK);\r
+\r
+       dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
+       DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_READ_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
 \r
 \r
        /** @req FEE022 */\r
        ModuleStatus = MEMIF_BUSY;\r
        JobResult = MEMIF_JOB_PENDING;\r
 \r
+       CurrentJob.BlockNumber = blockNumber;\r
        CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
+       CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
        CurrentJob.Length = length;\r
-       CurrentJob.Offset = blockOffset;\r
-       CurrentJob.FlsBlockAddr = CurrentJob.BlockConfigPtr->PhysBaseAddress + GET_DATASET_FROM_BLOCK_NUMBER(blockNumber) * CurrentJob.BlockConfigPtr->BlockSize;               /** @req FEE021 */\r
-       CurrentJob.FlsBlockAdminAddr = CurrentJob.FlsBlockAddr + CurrentJob.BlockConfigPtr->BlockSize;\r
-       CurrentJob.RamPtr = dataBufferPtr;\r
+       CurrentJob.Op.Read.Offset = blockOffset;\r
+       CurrentJob.Op.Read.RamPtr = dataBufferPtr;\r
        CurrentJob.State = FEE_READ_REQUESTED;\r
 \r
        return E_OK;\r
@@ -414,14 +1280,23 @@ Std_ReturnType Fee_Read(uint16 blockNumber, uint16 blockOffset, uint8* dataBuffe
 Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)\r
 {\r
        uint16 blockIndex;\r
+       uint16 dataset;\r
 \r
-       VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
-       VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_WRITE_ID, FEE_E_BUSY, E_NOT_OK);\r
+       DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_WRITE_ID, FEE_E_UNINIT, E_NOT_OK);\r
+       if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
+               return E_NOT_OK;\r
+       }\r
+       if( !(ModuleStatus == MEMIF_IDLE) ) {\r
+               DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
+               return E_NOT_OK;\r
+       }\r
 \r
-       VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
        blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
-       VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
-       VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
+       DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
+       DET_VALIDATE_RV(dataBufferPtr != NULL, FEE_WRITE_ID, FEE_E_INVALID_DATA_PTR, E_NOT_OK);\r
+\r
+       dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
+       DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_WRITE_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
 \r
 \r
        /** @req FEE025 */\r
@@ -429,10 +1304,10 @@ Std_ReturnType Fee_Write(uint16 blockNumber, uint8* dataBufferPtr)
        JobResult = MEMIF_JOB_PENDING;\r
 \r
        CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
-       CurrentJob.Length = CurrentJob.BlockConfigPtr->BlockSize;\r
-       CurrentJob.FlsBlockAddr = CurrentJob.BlockConfigPtr->PhysBaseAddress + GET_DATASET_FROM_BLOCK_NUMBER(blockNumber) * CurrentJob.BlockConfigPtr->BlockSize;               /** @req FEE024 */\r
-       CurrentJob.FlsBlockAdminAddr = CurrentJob.FlsBlockAddr + CurrentJob.BlockConfigPtr->BlockSize;\r
-       CurrentJob.RamPtr = dataBufferPtr;\r
+       CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
+       CurrentJob.BlockNumber = blockNumber;\r
+       CurrentJob.Length = PAGE_ALIGN(CurrentJob.BlockConfigPtr->BlockSize);\r
+       CurrentJob.Op.Write.RamPtr = dataBufferPtr;\r
        CurrentJob.State = FEE_WRITE_REQUESTED;\r
 \r
        return E_OK;\r
@@ -455,7 +1330,11 @@ void Fee_Cancel(void)
  */\r
 MemIf_StatusType Fee_GetStatus(void)\r
 {\r
-       return ModuleStatus;\r
+       if(AdminFls.ForceGarbageCollect && (FEE_IDLE == CurrentJob.State)){\r
+               return MEMIF_BUSY_INTERNAL;\r
+       } else {\r
+               return ModuleStatus;\r
+       }\r
 }\r
 \r
 \r
@@ -476,23 +1355,30 @@ MemIf_JobResultType Fee_GetJobResult(void)
 Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)\r
 {\r
        uint16 blockIndex;\r
+       uint16 dataset;\r
 \r
-       VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
-       VALIDATE_RV(ModuleStatus == MEMIF_IDLE, FEE_INVALIDATE_BLOCK_ID, FEE_E_BUSY, E_NOT_OK);\r
+       DET_VALIDATE_RV(ModuleStatus != MEMIF_UNINIT, FEE_INVALIDATE_BLOCK_ID, FEE_E_UNINIT, E_NOT_OK);\r
+       if(AdminFls.ForceGarbageCollect || (FEE_CORRUPTED == CurrentJob.State)){\r
+               return E_NOT_OK;\r
+       }\r
+       if( !(ModuleStatus == MEMIF_IDLE) ) {\r
+               DET_REPORTERROR(MODULE_ID_FEE, FEE_READ_ID, FEE_E_BUSY, E_NOT_OK);\r
+               return E_NOT_OK;\r
+       }\r
 \r
-       VALIDATE_RV(blockNumber >= (1 << NVM_DATASET_SELECTION_BITS), FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
        blockIndex = GET_BLOCK_INDEX_FROM_BLOCK_NUMBER(blockNumber);\r
-       VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
+       DET_VALIDATE_RV(blockIndex < FEE_NUM_OF_BLOCKS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
+\r
+       dataset = GET_DATASET_FROM_BLOCK_NUMBER(blockNumber);\r
+       DET_VALIDATE_RV(dataset < FEE_MAX_NUM_SETS, FEE_INVALIDATE_BLOCK_ID, FEE_E_INVALID_BLOCK_NO, E_NOT_OK);\r
 \r
 \r
        ModuleStatus = MEMIF_BUSY;\r
        JobResult = MEMIF_JOB_PENDING;\r
 \r
        CurrentJob.BlockConfigPtr = &Fee_Config.BlockConfig[blockIndex];\r
-       CurrentJob.Length = 0;\r
-       CurrentJob.FlsBlockAddr = CurrentJob.BlockConfigPtr->PhysBaseAddress + GET_DATASET_FROM_BLOCK_NUMBER(blockNumber) * CurrentJob.BlockConfigPtr->BlockSize;               /** @req FEE024 */\r
-       CurrentJob.FlsBlockAdminAddr = CurrentJob.FlsBlockAddr + CurrentJob.BlockConfigPtr->BlockSize;\r
-       CurrentJob.RamPtr = NULL;\r
+       CurrentJob.AdminFlsBlockPtr = &AdminFls.BlockDescrTbl[blockIndex][dataset];\r
+       CurrentJob.BlockNumber = blockNumber;\r
        CurrentJob.State = FEE_INVALIDATE_REQUESTED;\r
 \r
        return E_OK;\r
@@ -505,14 +1391,17 @@ Std_ReturnType Fee_InvalidateBlock(uint16 blockNumber)
  */\r
 Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)\r
 {\r
+       //lint --e{715} PC-Lint (715) - function is not implemented and thus variable "blockNumber" is not used yet\r
+\r
        DET_REPORTERROR(MODULE_ID_FEE, 0, FEE_ERASE_IMMEDIATE_ID, FEE_E_NOT_IMPLEMENTED_YET);\r
 \r
+\r
        return E_NOT_OK;\r
 }\r
 \r
 \r
 /***************************************\r
- *         Scheduled functions         *
+ *         Scheduled functions         *\r
  ***************************************/\r
 /*\r
  * Procedure:  Fee_MainFunction\r
@@ -520,76 +1409,157 @@ Std_ReturnType Fee_EraseImmediateBlock(uint16 blockNumber)
  */\r
 void Fee_MainFunction(void)\r
 {\r
+\r
        switch (CurrentJob.State) {\r
        case FEE_UNINITIALIZED:\r
+               break;\r
+\r
        case FEE_IDLE:\r
+               if (AdminFls.ForceGarbageCollect) {\r
+                       CheckIfGarbageCollectionNeeded();\r
+               }\r
                break;\r
 \r
-       // Read states\r
-       case FEE_READ_REQUESTED:\r
-               ReadStartJob();\r
+               /*\r
+                * Startup states\r
+                */\r
+       case FEE_STARTUP_REQUESTED:\r
+               StartupStartJob();\r
                break;\r
 \r
-       case FEE_READ_BLOCK_ADMIN_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       ReadCheckBlockAdminJob();\r
-               }\r
+       case FEE_STARTUP_READ_BANK1_STATUS:\r
+               StartupReadBank1Status();\r
                break;\r
 \r
-       case FEE_READ_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       FinnishJob();\r
-               }\r
+       case FEE_STARTUP_READ_BANK2_STATUS_REQUESTED:\r
+               StartupReadBank2StatusRequested();\r
+               break;\r
+\r
+       case FEE_STARTUP_READ_BANK2_STATUS:\r
+               StartupReadBank2Status();\r
+               break;\r
+\r
+       case FEE_STARTUP_READ_BLOCK_ADMIN_REQUESTED:\r
+               StartupReadBlockAdminRequested();\r
+               break;\r
+\r
+       case FEE_STARTUP_READ_BLOCK_ADMIN:\r
+               StartupReadBlockAdmin();\r
                break;\r
 \r
-       // Write states\r
+       /*\r
+        *  Read states\r
+        */\r
+       case FEE_READ_REQUESTED:\r
+               ReadStartJob();\r
+               break;\r
+\r
+       case FEE_READ:\r
+               Reading();\r
+               break;\r
+\r
+       /*\r
+        * Write states\r
+        */\r
        case FEE_WRITE_REQUESTED:\r
                WriteStartJob();\r
                break;\r
 \r
-       case FEE_WRITE_MAGIC_EREASE_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       WriteCheckMagicEraseJob();\r
-               }\r
+       case FEE_WRITE_MARK_BANK_OLD:\r
+               WriteMarkBankOldState();\r
                break;\r
 \r
-       case FEE_WRITE_EREASE_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       WriteCheckEraseJob();\r
-               }\r
+       case FEE_WRITE_HEADER_REQUESTED:\r
+               WriteHeaderRequested();\r
                break;\r
 \r
-       case FEE_WRITE_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       WriteCheckWriteJob();\r
-               }\r
+       case FEE_WRITE_HEADER:\r
+               WriteHeaderState();\r
                break;\r
 \r
-       case FEE_WRITE_BLOCK_ADMIN_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       FinnishJob();\r
-               }\r
+       case FEE_WRITE_DATA_REQUESTED:\r
+               WriteDataRequested();\r
+               break;\r
+\r
+       case FEE_WRITE_DATA:\r
+               WriteDataState();\r
+               break;\r
+\r
+       case FEE_WRITE_MAGIC_REQUESTED:\r
+               WriteMagicRequested();\r
                break;\r
 \r
-       // Invalidate states\r
+       case FEE_WRITE_MAGIC:\r
+               WriteMagicState();\r
+               break;\r
+\r
+       /*\r
+        * Garbage collection states\r
+        */\r
+       case FEE_GARBAGE_COLLECT_REQUESTED:\r
+               GarbageCollectStartJob();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_HEADER_WRITE:\r
+               GarbageCollectWriteHeader();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_DATA_READ_REQUESTED:\r
+               GarbageCollectReadDataRequested();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_DATA_READ:\r
+               GarbageCollectReadData();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_DATA_WRITE_REQUESTED:\r
+               GarbageCollectWriteDataRequested();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_DATA_WRITE:\r
+               GarbageCollectWriteData();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_MAGIC_WRITE_REQUESTED:\r
+               GarbageCollectWriteMagicRequested();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_MAGIC_WRITE:\r
+               GarbageCollectWriteMagic();\r
+               break;\r
+\r
+       case FEE_GARBAGE_COLLECT_ERASE:\r
+               GarbageCollectErase();\r
+               break;\r
+\r
+       /*\r
+        * Invalidate states\r
+        */\r
        case FEE_INVALIDATE_REQUESTED:\r
                InvalidateStartJob();\r
                break;\r
 \r
-       case FEE_INVALIDATE_PENDING:\r
-               PollFlsJobResult();\r
-               if (FLASH_READY) {\r
-                       FinnishJob();\r
-               }\r
+       case FEE_INVALIDATE_MARK_BANK_OLD:\r
+               InvalidateMarkBankOld();\r
                break;\r
 \r
-       // Other\r
+       case FEE_WRITE_INVALIDATE_HEADER_REQUESTED:\r
+               InvalidateWriteInvalidateHeaderRequested();\r
+               break;\r
+\r
+       case FEE_WRITE_INVALIDATE_HEADER:\r
+               InvalidateWriteInvalidateHeader();\r
+               break;\r
+\r
+       /*\r
+        * Corrupted state\r
+        */\r
+       case FEE_CORRUPTED:\r
+               break;\r
+\r
+       /*\r
+        * Other\r
+        */\r
        default:\r
                break;\r
        }\r
@@ -597,7 +1567,7 @@ void Fee_MainFunction(void)
 \r
 \r
 /***************************************\r
- *  Call-back notifications functions  *
+ *  Call-back notifications functions  *\r
  ***************************************/\r
 #if (FEE_POLLING_MODE == STD_OFF)\r
 /*\r
@@ -606,9 +1576,7 @@ void Fee_MainFunction(void)
  */\r
 void Fee_JobEndNotification(void)\r
 {\r
-       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-       FlsAdmin.ErrorStatus = E_OK;\r
-       FlsAdmin.JobResult = Fls_GetJobResult();\r
+       FlsJobReady = TRUE;\r
 }\r
 \r
 \r
@@ -618,10 +1586,6 @@ void Fee_JobEndNotification(void)
  */\r
 void Fee_JobErrorNotification(void)\r
 {\r
-       FlsAdmin.State = FEE_FLS_STATE_READY;\r
-       FlsAdmin.ErrorStatus = E_NOT_OK;\r
-       FlsAdmin.JobResult = Fls_GetJobResult();\r
+       FlsJobReady = TRUE;\r
 }\r
 #endif\r
-\r
-\r