* SPEED\r
* To get some speed into this multiple thing must be done in the same MainFunction loop.\r
*\r
+ * MEMIF\r
+ * The interface is actually quite strange, so you may read from any address (through MemIf_Read())\r
+ * but MemIf_Write(..) only takes a logical block and a pointer to the data to write.\r
+ *\r
+ * See two alternatives here:\r
+ * 1. If the NVBlock also contains the checksum after the data then writing the data needs a\r
+ * RAM that is as big as the biggest RAM block + room for checksum.\r
+ * 2. If checksums would be kept in a separate EA/FEE block the ALL the checksum need to be written.\r
+ * For example after a NvM_WriteBlock() the checksum block would need to be written. This\r
+ * will probably lead consistency problems also... what happens if we fail to write the checksum\r
+ * block?\r
+ *\r
+ *\r
+ *\r
+ * MANUAL\r
+ *\r
+ *\r
+ *\r
+ * Provide Data for the first/initial read\r
+ * When a block have no\r
+ *\r
+ * NVM085\r
+ * NVM061\r
+ * NVM083\r
+ *\r
+ * Configuring CRCs\r
+ * BlockUseCrc (A): If the block (both RAM and NV) should use CRC\r
+ * CalcRamBlockCrc (B): If the permanent RAM block should re-calculate it's CRC.\r
+ *\r
+ * A B\r
+ * ------------\r
+ * 0 0 No error detection or recovery\r
+ * 0 1 N/A\r
+ * 1 0 ?\r
+ * 1 1 ?\r
+ *\r
+ * RAM BLOCK VALID/UNCHANGED\r
+ * Figure 8 and 9 in 3.1.5/NVM is more confusing than good.\r
+ * What we have to know is:\r
+ * 1. Initially the RAM block is in INVALID/UNCHANGED\r
+ * ALT 2. After a NvM_ReadAll() and all is well the state goes to VALID/UNCHANGED\r
+ * ALT 2. If ROM values are used we go to VALID/CHANGED (We failed to read from NVRAM)\r
+ *\r
+ * For NvM_WriteAll()\r
+ * 1. A block that is INVALID can't be written\r
+ * 2. A block that is UNCHANGED should not be written.\r
+ * -> Write only blocks that are VALID/CHANGED.\r
+ *\r
+ * VALID/UNCHANGED - RAM == NV\r
+ * VALID/CHANGED - RAM != NV (analog to cache memories, "dirty")\r
+ *\r
+ * Analog to cache\r
+ * VALID/CHANGED state - Dirty (since RAM != NV)\r
+ * WriteBlock - Flush (Flush the RAM block to NV)\r
+ * ReadBlock - Invalidate (NV block is read to RAM)\r
*/\r
\r
\r
\r
\r
/*\r
- * NB! Even though some code exist for handling crc, the functionality is not complete\r
+ * NB! Even though some code exist for handling RamCrc, the functionality is not complete\r
* and shall not be used.
*/\r
\r
#include <stdio.h>\r
#include "io.h"\r
#include "Crc.h"\r
+#include <string.h>\r
\r
#if NVM_NUM_OF_NVRAM_BLOCKS != 5\r
#error nOOOOO\r
BLOCK_STATE_MEMIF_REQ,\r
// BLOCK_STATE_START,\r
BLOCK_STATE_MEMIF_PROCESS,\r
- BLOCK_STATE_MEMIF_CRC_PROCESS,\r
+// BLOCK_STATE_MEMIF_CRC_PROCESS,\r
BLOCK_STATE_CALC_CRC,\r
// BLOCK_STATE_MEMIF_PROCESS_CRC,\r
BLOCK_STATE_CALC_CRC_WRITE,\r
boolean BlockChanged; // Block changed?\r
boolean BlockValid; // Block valid? (RAM block only?)\r
uint8 NumberOfWriteFailed; // Current write retry cycle\r
- union Nvm_CRC crc;\r
+ union Nvm_CRC RamCrc;\r
+ union Nvm_CRC NvCrc; // The CRC of this block, read from NV\r
+ void * savedDataPtr; //\r
+ uint8 crcLen;\r
+\r
} AdministrativeBlockType;\r
\r
/*\r
static Nvm_QueueType nvmQueueImmData[NVM_SIZE_IMMEDIATE_JOB_QUEUE];\r
static Nvm_QueueType nvmQueueData[NVM_SIZE_STANDARD_JOB_QUEUE];\r
\r
+uint8 Nvm_WorkBuffer[200]; /* TODO */\r
+\r
#if (NVM_SIZE_STANDARD_JOB_QUEUE == 0)\r
#error NVM_SIZE_STANDARD_JOB_QUEUE have size 0\r
#endif\r
}\r
\r
\r
+static void writeCrcToBuffer( void *bufPtr,\r
+ const NvM_BlockDescriptorType *bPtr,\r
+ AdministrativeBlockType *admPtr )\r
+{\r
+ if( bPtr->BlockUseCrc ) {\r
+ if(bPtr->BlockCRCType == NVM_CRC16) {\r
+ WRITE16_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc16);\r
+ } else {\r
+ WRITE32_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc32);\r
+ }\r
+ }\r
+}\r
+\r
\r
/*\r
* Drive the read state-machine\r
boolean multiBlock )\r
{\r
bool blockDone = 0;\r
+ static uint8 driveBlockCnt = 0;\r
\r
\r
NVM_ASSERT( admPtr->ErrorStatus == NVM_REQ_PENDING);\r
switch (admPtr->BlockState) {\r
case BLOCK_STATE_MEMIF_REQ:\r
{\r
+ void *ramData = (dataPtr != NULL) ? dataPtr : bPtr->RamBlockDataAddress;\r
+\r
+ admPtr->savedDataPtr = ramData;\r
+\r
if( write ) {\r
if( multiBlock && (dataPtr!=NULL)) {\r
NVM_ASSERT(0);\r
}\r
-\r
- if (dataPtr != NULL ) {\r
- WriteBlock(bPtr, admPtr, 0, dataPtr);\r
- } else {\r
- WriteBlock(bPtr, admPtr, 0, bPtr->RamBlockDataAddress);\r
- }\r
+ /* Copy to work buffer */\r
+ memcpy( Nvm_WorkBuffer, ramData, bPtr->NvBlockLength );\r
+ /* Add the CRC to write */\r
+ writeCrcToBuffer(Nvm_WorkBuffer, bPtr, admPtr );\r
+ WriteBlock(bPtr, admPtr, 0, Nvm_WorkBuffer);\r
} else {\r
- ReadBlock(bPtr, admPtr, 0, 0, bPtr->RamBlockDataAddress, bPtr->NvBlockLength);\r
+ uint8 crcLen = 0;\r
+ /* Read to workbuffer */\r
+ if( bPtr->BlockUseCrc ) {\r
+ crcLen = (bPtr->BlockCRCType == NVM_CRC16) ? 2: 4;\r
+ }\r
+\r
+ ReadBlock(bPtr, admPtr, 0, 0, bPtr->RamBlockDataAddress, bPtr->NvBlockLength+crcLen);\r
}\r
\r
admPtr->BlockState = BLOCK_STATE_MEMIF_PROCESS;\r
}\r
\r
case BLOCK_STATE_MEMIF_PROCESS:\r
- case BLOCK_STATE_MEMIF_CRC_PROCESS:\r
{\r
/* Check read */\r
MemIf_JobResultType jobResult = MemIf_GetJobResult(0);\r
} else if( MEMIF_JOB_OK == jobResult ) {\r
/* We are done */\r
\r
+#if 0\r
if( BLOCK_STATE_MEMIF_CRC_PROCESS == admPtr->BlockState ) {\r
/* @req 3.1.5/NVM362 NvM_ReadAll*/\r
+ DEBUG_CHECKSUM("RAM CRC", (bPtr->BlockCRCType == NVM_CRC16) ? admPtr->RamCrc.crc16 : admPtr->RamCrc.crc32);\r
admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;\r
break;\r
}\r
+#endif\r
\r
if( write ) {\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
+ admPtr->ErrorStatus = NVM_REQ_OK;\r
+ blockDone = 1;\r
+\r
+#if 0\r
if( bPtr->BlockUseCrc ) {\r
/* Explicit CRC calc (not dependent on NvmCalcRamBlockCrc) */\r
/* @req 3.1.5/NVM212 NvM_WriteBlock */\r
admPtr->ErrorStatus = NVM_REQ_OK;\r
blockDone = 1;\r
}\r
+#endif\r
} else {\r
/* read */\r
+ uint8 crcLen = 0;\r
if( bPtr->BlockUseCrc ) {\r
\r
- /* The CRC does not fit into RAM block so we have to read\r
- * it now.\r
- *\r
- * Note! There is no difference at this point if CalcRamBlockCrc\r
- * is TRUE or not. If CalcRamBlockCrc=FALSE we still need to save\r
- * the NV CRC checksum in the admin block. If CalcRamBlockCrc=TRUE\r
- * we need to re-calculate the RAM CRC and compare it to the one\r
- * in the NV block.\r
- */\r
- ReadBlock(bPtr, admPtr, 0, bPtr->NvBlockLength,\r
- (bPtr->BlockCRCType == NVM_CRC16) ? &admPtr->crc.crc16 : &admPtr->crc.crc32 ,\r
- (bPtr->BlockCRCType == NVM_CRC16) ? 2 : 4 );\r
-\r
- DEBUG_CHECKSUM("RAM CRC", (bPtr->BlockCRCType == NVM_CRC16) ? admPtr->crc.crc16 : admPtr->crc.crc32);\r
- admPtr->BlockState = BLOCK_STATE_MEMIF_CRC_PROCESS;\r
+ /* The read data is in the work buffer, read the CRC */\r
+ if( bPtr->BlockCRCType == NVM_CRC16) {\r
+ admPtr->NvCrc.crc16 = READ16_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
+ crcLen = 2;\r
+ DEBUG_PRINTF(">> Nv CRC %04x\n",admPtr->NvCrc.crc16);\r
+ admPtr->RamCrc.crc16 = admPtr->NvCrc.crc16; /* Set RAM CRC = NvRAM CRC */\r
+ } else {\r
+ admPtr->NvCrc.crc32 = READ32_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );\r
+ crcLen = 4;\r
+ DEBUG_PRINTF(">> Nv CRC %08x\n",admPtr->NvCrc.crc16);\r
+ admPtr->RamCrc.crc32 = admPtr->NvCrc.crc32; /* Set RAM CRC = NvRAM CRC */\r
+ }\r
+\r
+ memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength + crcLen );\r
+\r
+ /* Check if we should re-calculate the RAM checksum now when it's in RAM */\r
+ if( bPtr->CalcRamBlockCrc ) {\r
+ /* This block want its RAM block CRC checked */\r
+ DEBUG_PRINTF(">> Recalculation of RAM checksum \n",admPtr->NvCrc.crc16);\r
+ assert( bPtr->BlockUseCrc == 1);\r
+ admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;\r
+ } else {\r
+ /* Done */\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
+ admPtr->ErrorStatus = NVM_REQ_OK;\r
+ blockDone = 1;\r
+ }\r
\r
} else {\r
+ DEBUG_PRINTF(">> Block have NO CRC\n");\r
+\r
+ memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength + crcLen );\r
/* Done */\r
admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
admPtr->ErrorStatus = NVM_REQ_OK;\r
blockDone = 1;\r
}\r
+\r
+ /* Copy from Workbuffer to the real buffer */\r
+\r
}\r
break;\r
} else {\r
\r
/* Calculate RAM CRC checksum */\r
if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
+\r
crc16 = Crc_CalculateCRC16(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffff);\r
+ DEBUG_CHECKSUM("RAM",crc16);\r
+\r
+ /* Just save the checksum */\r
+ admPtr->RamCrc.crc16 = crc16;\r
\r
+#if 0\r
/* NV CRC in admin block */\r
- if( admPtr->crc.crc16 != crc16 ) {\r
+ if( admPtr->RamCrc.crc16 != crc16 ) {\r
NVM_ASSERT(0); /* TODO: Corrupt CRC */\r
} else {\r
admPtr->BlockChanged = BLOCK_STATE_MEMIF_REQ;\r
}\r
+#endif\r
+\r
+ /* Write the block */\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
} else {\r
/* @req 3.1.5/NVM253 */\r
crc32 = Crc_CalculateCRC32(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffffffffUL);\r
- if( crc32 != admPtr->crc.crc32 ) {\r
+ if( crc32 != admPtr->RamCrc.crc32 ) {\r
/* The checksum is wrong, something have written to the RAM area without\r
* telling the NVM */\r
NVM_ASSERT(0);\r
} else {\r
admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
}\r
- admPtr->crc.crc32 = crc32;\r
+ admPtr->RamCrc.crc32 = crc32;\r
}\r
break;\r
}\r
case BLOCK_STATE_CALC_CRC_READ:\r
{\r
NVM_ASSERT(bPtr->RamBlockDataAddress != NULL );\r
+ NVM_ASSERT(bPtr->CalcRamBlockCrc == true );\r
uint16 crc16;\r
uint32 crc32;\r
\r
/* Calculate RAM CRC checksum */\r
if( bPtr->BlockCRCType == NVM_CRC16 ) {\r
+\r
+\r
crc16 = Crc_CalculateCRC16(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffff);\r
+ DEBUG_CHECKSUM("RAM",crc16);\r
+\r
/* NV CRC in admin block */\r
- if( admPtr->crc.crc16 != crc16 ) {\r
- NVM_ASSERT(0); /* TODO: Corrupt CRC */\r
+\r
+ if( driveBlockCnt == 1) {\r
+ /* The previous "loop" we filled with default data */\r
+ admPtr->RamCrc.crc16 = crc16;\r
+ }\r
+\r
+ /* @req 3.1.5/NVM387 */\r
+ if( admPtr->RamCrc.crc16 != crc16 ) {\r
+\r
+ /* @req 3.1.5/NVM388 Nvm_ReadAll */\r
+\r
+ /* NVM387, NVM388\r
+ *\r
+ * Corrupt CRC, what choices are there:\r
+ * 1. Default data (=ROM) configured, just copy it.\r
+ * 2. Data redundancy, get it.\r
+ * 3. None of the above. Catastrophic failure. (NVM203)\r
+ */\r
+ if( bPtr->RomBlockDataAdress != NULL ) {\r
+ /* TODO: Restore block from ROM */\r
+ NVM_ASSERT(0);\r
+ } else {\r
+ /* @req 3.1.5/NVM469 */\r
+ if( bPtr->InitBlockCallback != NULL ) {\r
+\r
+ DEBUG_PRINTF("Filling block with default data\n");\r
+ bPtr->InitBlockCallback();\r
+ driveBlockCnt++;\r
+ /* NVM085 is very vague here, but the says the application should be\r
+ * able distinguish between when the init-callback have been called\r
+ * or CRC is corrupt.\r
+ */\r
+\r
+ /* The RAM CRC is at this point not calculated...so we must do this\r
+ * .. so just stay in this state one more MainFunction.\r
+ * */\r
+\r
+ } else {\r
+\r
+ /* @req 3.1.5/NVM203 */\r
+ DEM_REPORTERRORSTATUS(NVM_E_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);\r
+ /* @req 3.1.5/NVM204 */\r
+ admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
+ blockDone = 1;\r
+ }\r
+ }\r
} else {\r
- admPtr->BlockChanged = BLOCK_STATE_MEMIF_REQ;\r
+ DEBUG_CHECKSUM("RAM checksum ok with ",crc16);\r
+ admPtr->ErrorStatus = NVM_REQ_OK;\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
+ blockDone = 1;\r
}\r
\r
} else {\r
/* @req 3.1.5/NVM253 */\r
/* Calculate CRC on the data we just read to RAM. Compare with CRC that is located in NV block */\r
crc32 = Crc_CalculateCRC32(bPtr->RamBlockDataAddress,bPtr->NvBlockLength,0xffffffffUL);\r
- if( crc32 != admPtr->crc.crc32 ) {\r
+ if( crc32 != admPtr->RamCrc.crc32 ) {\r
NVM_ASSERT(0); /* TODO: Corrupt CRC */\r
} else {\r
- admPtr->BlockChanged = BLOCK_STATE_MEMIF_REQ;\r
+ admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;\r
}\r
}\r
break;\r
}\r
\r
if( blockDone ) {\r
+\r
+ DEBUG_PRINTF("# Block Done\n");\r
+\r
+ if( admPtr->ErrorStatus == NVM_REQ_OK ) {\r
+ admPtr->BlockChanged = FALSE;\r
+ admPtr->BlockValid = TRUE;\r
+ }\r
+\r
+\r
/* @req 3.1.5/NVM281 */\r
if( bPtr->SingleBlockCallback != NULL ) {\r
bPtr->SingleBlockCallback(NVM_READ_ALL_ID, admPtr->ErrorStatus);\r
DriveBlock( &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],\r
&AdminBlock[AdminMultiReq.currBlockIndex],\r
NULL,\r
- false,\r
+ true,\r
true );\r
\r
}\r
Nvm_QueueType qEntry;\r
const NvM_BlockDescriptorType * bList = NvM_Config.BlockDescriptor;\r
const NvM_BlockDescriptorType * nvmBlock;\r
- const NvM_BlockDescriptorType * currBlock;\r
+// const NvM_BlockDescriptorType * currBlock;\r
AdministrativeBlockType *admBlock;\r
- static uint32 crc32;\r
- static uint32 crc32Left;\r
+// static uint32 crc32;\r
+// static uint32 crc32Left;\r
\r
/* Check for new requested state changes */\r
if( nvmState == NVM_IDLE ) {\r
- DEBUG_PRINTF("### Popping FIFO ###\n");\r
rv = CirqBuffPop( &nvmQueue, &qEntry );\r
if( rv == 0 ) {\r
- /* Buffer not empty */\r
+ /* Found something in buffer */\r
nvmState = qEntry.op;\r
nvmBlock = &bList[qEntry.blockId-1];\r
admBlock = &AdminBlock[qEntry.blockId-1];\r
nvmSubState = 0;\r
admBlock->ErrorStatus = NVM_REQ_PENDING;\r
+ DEBUG_PRINTF("### Popped Single FIFO \n");\r
+ DEBUG_PRINTF("### CRC On:%d Ram:%d Type:%d\n",nvmBlock->BlockUseCrc, nvmBlock->CalcRamBlockCrc, nvmBlock->BlockCRCType );\r
} else {\r
/* Check multiblock req */\r
if( AdminMultiReq.state != NVM_UNINITIALIZED ) {\r
nvmBlock = 0;\r
admBlock = 0;\r
AdminMultiReq.state = NVM_UNINITIALIZED;\r
+\r
+ DEBUG_PRINTF("### Popped MULTI\n");\r
}\r
}\r
}\r