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
18 * Author: Peter+mahi
\r
24 * Implements the NVRAM Manager module.
\r
27 * General Have Support
\r
28 * -------------------------------------------
\r
29 * NVM_API_CONFIG_CLASS Y NVM_API_CONFIG_CLASS_1 and NVM_API_CONFIG_CLASS_2
\r
30 * NVM_COMPILED_CONFIG_ID N
\r
31 * NVM_CRC_NUM_OF_BYTES N
\r
32 * NVM_DATASET_SELECTION_BITS Y
\r
33 * NVM_DEV_ERROR_DETECT Y
\r
34 * NVM_DRV_MODE_SWITCH N
\r
35 * NVM_DYNAMIC_CONFIGURATION N
\r
36 * NVM_JOB_PRIORITIZATION N
\r
37 * NVM_MULTI_BLOCK_CALLBACK Y
\r
38 * NVM_POLLING_MODE N
\r
39 * NVM_SET_RAM_BLOCK_STATUS_API Y
\r
40 * NVM_SIZE_IMMEDIATE_JOB_QUEUE N
\r
41 * NVM_SIZE_STANDARD_JOB_QUEUE Y
\r
42 * NVM_VERSION_INFO_API Y
\r
44 * NvmBlockDescriptor Have Support
\r
45 * -------------------------------------------
\r
47 * NvmBlockJobPriority N
\r
48 * NvmBlockManagementType Y, All blocks supported
\r
50 * NvmBlockWriteProt N
\r
51 * NvmCalcRamBlockCrc Y
\r
52 * NvmInitBlockCallback Y
\r
53 * NvmNvBlockBaseNumber Y
\r
54 * NvmNvBlockLength Y
\r
56 * NvmNvramBlockIdentifier Y
\r
57 * NvmNvramDeviceId N (always device Id 0)
\r
58 * NvmResistantToChangedSw N
\r
59 * NvmRomBlockDataAddress Y
\r
61 * NvmSelectBlockForReadall Y
\r
62 * NvmSingleBlockCallback Y
\r
63 * NvmWriteBlockOnce N
\r
65 * Implementation notes:
\r
66 * - The Configuration ID NV Block is generated to the configuration but can't be configured.
\r
67 * The Editor should really force you to pick a block in Ea/Fee that should hold the configuration
\r
68 * ID. The NVM_COMPILED_CONFIG_ID is always generated as 0 now.
\r
69 * - You can ONLY configure one block type for the entire NvM since NvmNvramDeviceId is not supported.
\r
70 * ie "Target Block" must all be eihter FEE or EA blocks.
\r
71 * - Differences from 3.1.5 Release (Follow release 4.0.2 here)
\r
72 * NvM_SetDataIndex(), NvM_GetDataIndex, NvM_SetBlockProtection, NvM_GetErrorStatus, NvM_SetRamBlockStatus,
\r
73 * etc....all return Std_ReturnType instead of void since the RTE expects it.
\r
74 * - NvM_GetErrorStatus() uses NvM_GetErrorStatus instead of uint8 *
\r
78 * RamBlockDataAddress
\r
79 * NULL is no permanent RAM block. Otherwise allocate the number of bytes in space (like the stack)
\r
82 * Understanding block numbering:
\r
84 * NVM_DATASET_SELECTION_BIT=2
\r
87 * 0 Reserved (NVM478)
\r
88 * 1 NVM_BLOCK_NATIVE, NvBlockNum=1
\r
89 * 2 NVM_BLOCK_REDUNDANT, NvBlockNum=2
\r
90 * 3 NVM_BLOCK_DATASET, NvBlockNum=4
\r
92 * NvM_ReadBlock( 0, ... ) - Reserved for "multi block requests"
\r
93 * NvM_ReadBlock( 1, ... ) - Reserved for redundant NVRAM block which holds the configuration ID.
\r
94 * NvM_ReadBlock( 2--x, ... ) - "Normal" blocks
\r
97 * NvM_BlockIdType*) NvBlockBaseNumber EA_BLOCK_NUMBER
\r
100 * 2 1 4, (5,6,7) ****)
\r
101 * 3 2 8, R9,(10,11) ****)
\r
102 * 4 3 12, D13,D14,D15 ****)
\r
107 * *) Type used in the API.
\r
108 * **) Reserved ID's ( 0 - multiblock, 1 - redundant NVRAM block which hold configuration ID)
\r
110 * ****) FEE/EA_BLOCK_NUMBER = NvBlockBaseNumber << NvmDatasetSelectionBits = NvBlockBaseNumber * 4
\r
111 * () - Cannot be accesses due to NvBlockNum
\r
112 * R9 - Redundant block
\r
116 * Both NvM and EA/FEE have block sizes. NvM have NvNvmBlockLength (NVM479) and FEE/EA have EaBlockSize.
\r
117 * FEE/EA also have virtual page that is the alignment of a block, with the smallest block=size of the virtual page.
\r
119 * So, who allocates space for this. FEE/EA only have EaBlockSize.
\r
120 * NvM have NvmRamBlockDataAddress, NvmRomBlockDataAddress and mapping to a MemIf Blocks (FEE/EA blocks)
\r
122 * ASSUME: I can't really see a point for the FEE/EA EaBlockSize.. it will just a multiple of NvNvmBlockLength*NvBlockNum + overhead?
\r
123 * Click-box in EA/FEE that leaves the size calculation to NvM?
\r
124 * This also means that enabling NvmBlockUseCrc or set a block from NVM_BLOCK_NATIVE to NVM_BLOCK_DATASET would be "automatic"
\r
125 * in calculation of the EaBlockSize.
\r
127 * So how much data should be read from MemIf if a CRC checksum is used. Assuming that we use a physical layout where the CRC is located
\r
128 * after the NV Block it would be BALIGN(NvNvmBlockLength,4) + 4 bytes. The same applies to the RAM block (ROM block to not have CRC, NVM127)
\r
131 * NVM121: NvM_SetRamBlockStatus(), calculate CRC in background if NvmCalcRamBlockCrc==TRUE
\r
132 * NVM362: NvM_ReadAll() , if (NvmCalcRamBlockCrc == TRUE && permanent RAM block) re-calc CRC.
\r
134 * NvmBlockUseCrc - Global CRC switch. Space is allocated in both RAM and NV block
\r
135 * NvmCalcRamBlockCrc - CRC re-calculation. For example during startup, you may don't want
\r
136 * to verify all the checksums again, but instead just copy from NV
\r
139 * There is also explicit RAM checksum calculations for example NVM253 (Nvm_WriteAll()) where a CRC calculation
\r
140 * is requested (although not stated should be dependent on NvmBlockUseCrc only, not NvmCalcRamBlockCrc).
\r
141 * You have to calculate the checksum at some point....
\r
144 * NVM185: Says "successful enqueueing a request".."set to NVM_REQ_PENDING"
\r
145 * NVM380: The queue length for multi block request shall be one (NvM_ReadAll, NvM_WriteAll)
\r
146 * NVM381+NVM567 : Multi block requests shall not be interrupted.
\r
147 * NVM243+NVM245: Do not unqueue the multi block request until all single block queues are empty.
\r
148 * So, when NvmState==IDLE and we have a multi-request
\r
155 * To get some speed into this multiple thing must be done in the same MainFunction loop.
\r
158 * The interface is actually quite strange, so you may read from any address (through MemIf_Read())
\r
159 * but MemIf_Write(..) only takes a logical block and a pointer to the data to write.
\r
161 * See two alternatives here:
\r
162 * 1. If the NVBlock also contains the checksum after the data then writing the data needs a
\r
163 * RAM that is as big as the biggest RAM block + room for checksum.
\r
164 * 2. If checksums would be kept in a separate EA/FEE block the ALL the checksum need to be written.
\r
165 * For example after a NvM_WriteBlock() the checksum block would need to be written. This
\r
166 * will probably lead consistency problems also... what happens if we fail to write the checksum
\r
175 * Provide Data for the first/initial read
\r
176 * When a block have no
\r
183 * BlockUseCrc (A): If the block (both RAM and NV) should use CRC
\r
184 * CalcRamBlockCrc (B): If the permanent RAM block should re-calculate it's CRC.
\r
188 * 0 0 No error detection or recovery
\r
193 * RAM BLOCK VALID/UNCHANGED
\r
194 * Figure 8 and 9 in 3.1.5/NVM is more confusing than good.
\r
195 * What we have to know is:
\r
196 * 1. Initially the RAM block is in INVALID/UNCHANGED
\r
197 * ALT 2. After a NvM_ReadAll() and all is well the state goes to VALID/UNCHANGED
\r
198 * ALT 2. If ROM values are used we go to VALID/CHANGED (We failed to read from NVRAM)
\r
200 * For NvM_WriteAll()
\r
201 * 1. A block that is INVALID can't be written
\r
202 * 2. A block that is UNCHANGED should not be written.
\r
203 * -> Write only blocks that are VALID/CHANGED.
\r
205 * VALID/UNCHANGED - RAM == NV
\r
206 * VALID/CHANGED - RAM != NV (analog to cache memories, "dirty")
\r
209 * VALID/CHANGED state - Dirty (since RAM != NV)
\r
210 * WriteBlock - Flush (Flush the RAM block to NV)
\r
211 * ReadBlock - Invalidate (NV block is read to RAM)
\r
216 * General requirements
\r
224 * NB! Even though some code exist for handling RamCrc, the functionality is not complete
\r
225 * and shall not be used.
228 //lint -esym(522,CalcCrc) // 522 PC-Lint exception for empty functions
\r
229 //lint -emacro(904,VALIDATE_RV,VALIDATE_NO_RV) //904 PC-Lint exception to MISRA 14.7 (validate macros).
\r
231 // Exception made as a result of that NVM_DATASET_SELECTION_BITS can be zero
\r
232 //lint -emacro(835, BLOCK_BASE_AND_SET_TO_BLOCKNR) // 835 PC-lint: A zero has been given as right argument to operator '<<' or '>>'
\r
235 /* ----------------------------[includes]------------------------------------*/
\r
237 #include <assert.h>
\r
239 #include "NvM_Cbk.h"
\r
240 #if defined(CFG_NVM_USE_SERVICE_PORTS)
\r
241 #include "Rte.h" // ???
\r
243 #if defined(USE_DEM)
\r
247 //#include "SchM_NvM.h"
\r
248 #include "MemMap.h"
\r
249 #include "cirq_buffer.h"
\r
250 #include "Modules.h"
\r
254 #include <string.h>
\r
259 //#define DEBUG_BLOCK 1
\r
260 #if defined(DEBUG_BLOCK)
\r
261 #define DEBUG_BLOCK_STATE(_str,_block,_state) printf("%s BLOCK NR:%d STATE:%d\n",_str,_block, _state); fflush(stdout);
\r
262 #define DEBUG_STATE(_state,_substate) printf("MAIN_STATE:%s/%d\n",StateToStr[_state],_substate); fflush(stdout);
\r
263 #define DEBUG_PRINTF(format,...) printf(format,## __VA_ARGS__ ); fflush(stdout);
\r
264 #define DEBUG_CHECKSUM(_str,_crc) printf("%s crc=%x\n",_str,_crc);
\r
266 #define DEBUG_BLOCK_STATE(_str,_block,_state)
\r
267 #define DEBUG_STATE(_state,_substate)
\r
268 #define DEBUG_PRINTF(format,...)
\r
269 #define DEBUG_CHECKSUM(_str,_crc)
\r
273 /* ----------------------------[private define]------------------------------*/
\r
277 #define NVM_BLOCK_ALIGNMENT 4
\r
278 #define NVM_CHECKSUM_LENGTH 4
\r
280 #define NVM_BLOCK_OFFSET 2
\r
286 /* ----------------------------[private macro]-------------------------------*/
\r
288 #if defined(DEBUG_BLOCK)
\r
289 #define NVM_ASSERT(_exp) if( !(_exp) ) { assert(_exp); } //
\r
291 #define NVM_ASSERT(_exp) if( !(_exp) ) { while(1) {}; } //assert(_exp)
\r
295 #if ( NVM_DEV_ERROR_DETECT == STD_ON )
\r
296 #define DET_REPORT_ERROR( _api, _err) Det_ReportError(MODULE_ID_NVM, 0, _api, _err);
\r
298 #define DET_REPORT_ERROR( _api, _err)
\r
301 #if ( NVM_DEV_ERROR_DETECT == STD_ON )
\r
303 #define VALIDATE(_exp,_api,_err ) \
\r
305 Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \
\r
309 #define VALIDATE_RV(_exp,_api,_err,_rv ) \
\r
311 Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \
\r
315 #define VALIDATE_NO_RV(_exp,_api,_err ) \
\r
317 Det_ReportError(MODULE_ID_NVM, 0, _api, _err); \
\r
320 #define DET_REPORTERROR(_module,_instance,_api,_err) Det_ReportError(_module,_instance,_api,_err)
\r
323 #define VALIDATE(_exp,_api,_err )
\r
324 #define VALIDATE_RV(_exp,_api,_err,_rv )
\r
325 #define VALIDATE_NO_RV(_exp,_api,_err )
\r
326 #define DET_REPORTERROR(_module,_instance,_api,_err)
\r
329 #define BLOCK_BASE_AND_SET_TO_BLOCKNR(_blockbase, _set) ((uint16)(_blockbase) | _set)
\r
331 #if defined(USE_DEM)
\r
332 #define DEM_REPORTERRORSTATUS(_err,_ev ) Dem_ReportErrorStatus(_err, DEM_EVENT_STATUS_FAILED);
\r
334 #define DEM_REPORTERRORSTATUS(_err,_ev )
\r
338 #define BLOCK_NR_FROM_PTR(_bptr) (((_bptr) - NvM_Config.BlockDescriptor + 1)) // sizeof(NvM_BlockDescriptorType))
\r
340 #define CREATE_ENTRY(_val) [_val] = #_val
\r
345 /* ----------------------------[private typedef]-----------------------------*/
\r
349 NVM_UNINITIALIZED = 0,
\r
355 NVM_RESTORE_BLOCK_DEFAULTS,
\r
358 NVM_SETRAMBLOCKSTATUS,
\r
361 char *StateToStr[20] = {
\r
362 CREATE_ENTRY(NVM_UNINITIALIZED),
\r
363 CREATE_ENTRY(NVM_IDLE),
\r
364 CREATE_ENTRY(NVM_READ_ALL),
\r
365 CREATE_ENTRY(NVM_WRITE_ALL),
\r
366 CREATE_ENTRY(NVM_READ_BLOCK),
\r
367 CREATE_ENTRY(NVM_WRITE_BLOCK),
\r
368 CREATE_ENTRY(NVM_RESTORE_BLOCK_DEFAULTS),
\r
369 CREATE_ENTRY(NVM_SETDATAINDEX),
\r
370 CREATE_ENTRY(NVM_GETDATAINDEX),
\r
371 CREATE_ENTRY(NVM_SETRAMBLOCKSTATUS),
\r
376 BLOCK_STATE_MEMIF_REQ,
\r
377 // BLOCK_STATE_START,
\r
378 BLOCK_STATE_MEMIF_PROCESS,
\r
379 // BLOCK_STATE_MEMIF_CRC_PROCESS,
\r
380 BLOCK_STATE_CALC_CRC,
\r
381 // BLOCK_STATE_MEMIF_PROCESS_CRC,
\r
382 BLOCK_STATE_CALC_CRC_WRITE,
\r
383 BLOCK_STATE_CALC_CRC_READ,
\r
384 // BLOCK_STATE_LOAD_FROM_NV,
\r
391 } BlockSubStateType;
\r
408 NvM_RequestResultType ErrorStatus; // Status from multi block requests i.e. Read/Write/CancelWrite-all
\r
409 } AdministrativeMultiBlockType;
\r
412 BlockStateType BlockState;
\r
413 BlockSubStateType BlockSubState;
\r
414 uint8 DataIndex; // Selected data index if "Data Set" type
\r
415 boolean BlockWriteProtected; // Block write protected?
\r
416 NvM_RequestResultType ErrorStatus; // Status of block
\r
417 boolean BlockChanged; // Block changed?
\r
418 boolean BlockValid; // Block valid? (RAM block only?)
\r
419 uint8 NumberOfWriteFailed; // Current write retry cycle
\r
420 union Nvm_CRC RamCrc;
\r
421 union Nvm_CRC NvCrc; // The CRC of this block, read from NV
\r
422 void * savedDataPtr; //
\r
424 uint8 flags; // Used for all sorts of things.
\r
425 } AdministrativeBlockType;
\r
430 NVM_OP_WRITE_BLOCK,
\r
431 NVM_OP_RESTORE_BLOCK_DEFAULTS,
\r
436 #define NO_MULTIBLOCK 0
\r
437 #define MULTIBLOCK 1
\r
442 NvM_BlockIdType blockId;
\r
443 uint8 * dataPtr; /* Src or Dest ptr */
\r
445 boolean blockChanged;
\r
450 /* ----------------------------[private function prototypes]-----------------*/
\r
451 /* ----------------------------[private variables]---------------------------*/
\r
453 static NvmStateType nvmState = NVM_UNINITIALIZED;
\r
456 #define RB_WAIT_READ 1
\r
457 #define RB_CALC_CHECKSUM 2
\r
459 static int nvmSubState = 0;
\r
460 //static int nvmSetNr;
\r
461 static AdministrativeBlockType AdminBlock[NVM_NUM_OF_NVRAM_BLOCKS];
\r
462 static AdministrativeMultiBlockType AdminMultiBlock;
\r
465 //static Nvm_QueueType nvmQueueImmData[NVM_SIZE_IMMEDIATE_JOB_QUEUE];
\r
466 static Nvm_QueueType nvmQueueData[NVM_SIZE_STANDARD_JOB_QUEUE];
\r
468 uint8 Nvm_WorkBuffer[NVM_MAX_BLOCK_LENGTH+4]; /* +4 to make place for max crc length */
\r
470 #if (NVM_SIZE_STANDARD_JOB_QUEUE == 0)
\r
471 #error NVM_SIZE_STANDARD_JOB_QUEUE have size 0
\r
475 CirqBufferType nvmQueue;
\r
478 /* ----------------------------[private functions]---------------------------*/
\r
480 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,
\r
481 AdministrativeBlockType *adminBlock,
\r
483 uint8 *sourceAddress);
\r
485 static void setRamBlockStatus( const NvM_BlockDescriptorType *bPtr,
\r
486 AdministrativeBlockType *admPtr,
\r
487 boolean blockChanged );
\r
490 /* ----------------------------[public functions]----------------------------*/
\r
495 * This function needs to be implemented!
497 static void CalcCrc(void)
\r
499 // TODO: Calculate CRC
\r
503 boolean JobFinished;
\r
504 Std_ReturnType JobStatus;
\r
505 MemIf_JobResultType JobResult;
\r
506 const NvM_BlockDescriptorType * BlockDescriptor;
\r
507 AdministrativeBlockType * BlockAdmin;
\r
508 } MemIfJobAdminType;
\r
510 static MemIfJobAdminType MemIfJobAdmin = {
\r
511 .JobFinished = TRUE,
\r
513 .JobResult = MEMIF_JOB_OK,
\r
514 .BlockDescriptor = NULL,
\r
518 enum Nvm_MultiBlockReq {
\r
525 NvmStateType state;
\r
526 uint16 currBlockIndex; // Keeps track of next unfinished block
\r
527 NvM_RequestResultType PendingErrorStatus; // Status from multi block requests i.e. Read/Write/CancelWrite-all
\r
528 } AdminMultiReqType;
\r
530 static AdminMultiReqType AdminMultiReq;
\r
534 * Set the MemIf job as busy
536 static void SetMemifJobBusy()
\r
538 MemIfJobAdmin.JobFinished = FALSE;
\r
542 #if (NVM_POLLING_MODE == STD_ON)
\r
544 * Check if the MemIf job is finished
546 static boolean CheckMemIfJobFinished(void)
\r
548 MemIf_JobResultType jobResult;
\r
550 if (!MemIfJobAdmin.JobFinished) {
\r
551 jobResult = MemIf_GetJobResult(FIXME);
\r
553 if (jobResult == MEMIF_JOB_OK) {
\r
554 MemIfJobAdmin.JobFinished = TRUE;
\r
555 MemIfJobAdmin.JobStatus = E_OK;
\r
556 MemIfJobAdmin.JobResult = jobResult;
\r
557 } else if (jobResult != MEMIF_JOB_PENDING) {
\r
558 MemIfJobAdmin.JobFinished = TRUE;
\r
559 MemIfJobAdmin.JobStatus = E_NOT_OK;
\r
560 MemIfJobAdmin.JobResult = jobResult;
\r
564 return MemIfJobAdmin.JobFinished;
\r
568 * Check if the MemIf job is finished
\r
571 static boolean CheckMemIfJobFinished(void)
\r
573 return MemIfJobAdmin.JobFinished;
\r
580 * Abort the MemIf job with E_NOT_OK
\r
582 static void AbortMemIfJob(MemIf_JobResultType jobResult)
\r
584 MemIfJobAdmin.JobFinished = TRUE;
\r
585 MemIfJobAdmin.JobStatus = E_NOT_OK;
\r
586 MemIfJobAdmin.JobResult = jobResult;
\r
590 static boolean CheckJobFailed( void ) {
\r
591 return CheckMemIfJobFinished() && (MemIfJobAdmin.JobResult == MEMIF_JOB_FAILED);
\r
596 * Request a read of a block from MemIf
598 static Std_ReturnType ReadBlock(const NvM_BlockDescriptorType *blockDescriptor,
\r
599 AdministrativeBlockType *adminBlock,
\r
601 uint16 blockOffset,
\r
602 uint8 *destAddress,
\r
605 Std_ReturnType returnCode;
\r
607 if (setNumber < blockDescriptor->NvBlockNum) {
\r
609 MemIfJobAdmin.BlockAdmin = adminBlock;
\r
610 MemIfJobAdmin.BlockDescriptor = blockDescriptor;
\r
611 returnCode = MemIf_Read(blockDescriptor->NvramDeviceId, BLOCK_BASE_AND_SET_TO_BLOCKNR(blockDescriptor->NvBlockBaseNumber, setNumber), blockOffset, destAddress, length );
\r
612 if (returnCode != E_OK) {
\r
613 AbortMemIfJob(MEMIF_JOB_FAILED);
\r
615 } else if (setNumber < blockDescriptor->NvBlockNum + blockDescriptor->RomBlockNum) {
\r
616 // TODO: Read from ROM
\r
618 // Error: setNumber out of range
\r
619 returnCode = E_NOT_OK;
\r
620 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_READ_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);
\r
628 * Initiate the read all job
630 static boolean ReadAllInit(void)
\r
633 * Initiate the read all job
635 const NvM_BlockDescriptorType *BlockDescriptorList = NvM_Config.BlockDescriptor;
\r
636 AdministrativeBlockType *AdminBlockTable = AdminBlock;
\r
638 boolean needsProcessing = FALSE;
\r
640 // Set status to pending in the administration blocks
\r
641 AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING; /** @req 3.1.5/NVM304 */
\r
642 AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;
\r
643 AdminMultiReq.currBlockIndex = 0;
\r
645 for (i = 0; i < ( NVM_NUM_OF_NVRAM_BLOCKS ); i++) {
\r
646 if ((BlockDescriptorList->SelectBlockForReadall)
\r
647 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON) /** @req NVM345 */
\r
648 && ((!AdminBlockTable->BlockValid) // TODO: Check if this is to be done like this
\r
649 || (!AdminBlockTable->BlockChanged)) // TODO: Check if this is to be done like this
\r
652 NVM_ASSERT(BlockDescriptorList->RamBlockDataAddress != NULL);
\r
653 VALIDATE_RV(BlockDescriptorList->RamBlockDataAddress != NULL, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG, FALSE );
\r
655 NVM_ASSERT(BlockDescriptorList->BlockManagementType != NVM_BLOCK_DATASET);
\r
656 VALIDATE_RV(BlockDescriptorList->BlockManagementType != NVM_BLOCK_DATASET, NVM_READ_ALL_ID, NVM_E_WRONG_CONFIG, FALSE );
\r
658 AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;
\r
659 AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
660 needsProcessing = TRUE;
\r
662 AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED; /* @req 3.1.5/NVM287 */
\r
666 BlockDescriptorList++;
\r
669 return needsProcessing;
\r
673 static void writeCrcToBuffer( void *bufPtr,
\r
674 const NvM_BlockDescriptorType *bPtr,
\r
675 AdministrativeBlockType *admPtr )
\r
677 if( bPtr->BlockUseCrc ) {
\r
678 if(bPtr->BlockCRCType == NVM_CRC16) {
\r
679 WRITE16_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc16);
\r
681 WRITE32_NA(bufPtr + bPtr->NvBlockLength,admPtr->RamCrc.crc32);
\r
688 * Drive the read state-machine
\r
694 static void DriveBlock( const NvM_BlockDescriptorType *bPtr,
\r
695 AdministrativeBlockType *admPtr,
\r
698 boolean multiBlock,
\r
699 boolean restoreFromRom )
\r
701 bool blockDone = 0;
\r
703 DEBUG_BLOCK_STATE("DriveBlock", BLOCK_NR_FROM_PTR(bPtr), admPtr->BlockState );
\r
705 NVM_ASSERT( admPtr->ErrorStatus == NVM_REQ_PENDING);
\r
707 switch (admPtr->BlockState) {
\r
708 case BLOCK_STATE_MEMIF_REQ:
\r
710 void *ramData = (dataPtr != NULL) ? dataPtr : bPtr->RamBlockDataAddress;
\r
712 admPtr->savedDataPtr = ramData;
\r
715 if( multiBlock && (dataPtr!=NULL)) {
\r
718 /* Copy to work buffer */
\r
719 memcpy( Nvm_WorkBuffer, ramData, bPtr->NvBlockLength );
\r
720 /* Add the CRC to write */
\r
721 writeCrcToBuffer(Nvm_WorkBuffer, bPtr, admPtr );
\r
722 WriteBlock(bPtr, admPtr, admPtr->DataIndex, Nvm_WorkBuffer);
\r
725 /* Read to workbuffer */
\r
726 if( bPtr->BlockUseCrc ) {
\r
727 crcLen = (bPtr->BlockCRCType == NVM_CRC16) ? 2: 4;
\r
730 if( restoreFromRom ) {
\r
731 NVM_ASSERT( bPtr->RomBlockDataAdress != NULL );
\r
732 /* No CRC on the ROM block */
\r
733 memcpy(ramData,bPtr->RomBlockDataAdress,bPtr->NvBlockLength);
\r
735 admPtr->ErrorStatus = NVM_REQ_OK;
\r
737 break; /* Do NOT advance to next state */
\r
740 if( ReadBlock(bPtr, admPtr, admPtr->DataIndex, 0, Nvm_WorkBuffer, bPtr->NvBlockLength+crcLen) != E_OK ) {
\r
742 admPtr->ErrorStatus = NVM_REQ_NOT_OK;
\r
744 break; /* Do NOT advance to next state */
\r
749 admPtr->BlockState = BLOCK_STATE_MEMIF_PROCESS;
\r
753 case BLOCK_STATE_MEMIF_PROCESS:
\r
756 MemIf_JobResultType jobResult = MemIf_GetJobResult(FIXME);
\r
758 if( MEMIF_JOB_PENDING == jobResult ) {
\r
759 /* Keep on waiting */
\r
760 } else if( MEMIF_JOB_OK == jobResult ) {
\r
764 if( BLOCK_STATE_MEMIF_CRC_PROCESS == admPtr->BlockState ) {
\r
765 /* @req 3.1.5/NVM362 NvM_ReadAll*/
\r
766 DEBUG_CHECKSUM("RAM CRC", (bPtr->BlockCRCType == NVM_CRC16) ? admPtr->RamCrc.crc16 : admPtr->RamCrc.crc32);
\r
767 admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;
\r
773 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
774 admPtr->ErrorStatus = NVM_REQ_OK;
\r
778 if( bPtr->BlockUseCrc ) {
\r
779 /* Explicit CRC calc (not dependent on NvmCalcRamBlockCrc) */
\r
780 /* @req 3.1.5/NVM212 NvM_WriteBlock */
\r
781 /* @req 3.1.5/NVM253 NvM_WriteAll */
\r
782 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;
\r
785 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
786 admPtr->ErrorStatus = NVM_REQ_OK;
\r
793 if( bPtr->BlockUseCrc ) {
\r
795 /* The read data is in the work buffer, read the CRC */
\r
796 if( bPtr->BlockCRCType == NVM_CRC16) {
\r
797 admPtr->NvCrc.crc16 = READ16_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );
\r
799 DEBUG_PRINTF(">> Nv CRC %04x\n",admPtr->NvCrc.crc16);
\r
800 admPtr->RamCrc.crc16 = admPtr->NvCrc.crc16; /* Set RAM CRC = NvRAM CRC */
\r
802 admPtr->NvCrc.crc32 = READ32_NA( Nvm_WorkBuffer + bPtr->NvBlockLength );
\r
804 DEBUG_PRINTF(">> Nv CRC %08x\n",admPtr->NvCrc.crc16);
\r
805 admPtr->RamCrc.crc32 = admPtr->NvCrc.crc32; /* Set RAM CRC = NvRAM CRC */
\r
808 /* 3.1.5/NVM201 + 3.1.5/NVM292 NvM_ReadBlock() + NvM_ReadAll() should request
\r
809 * recalculation of the RAM block data if configured with CRC.
\r
812 /* savedDataPtr points to the real data buffers and they do no contain the
\r
814 memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength );
\r
816 /* Check if we should re-calculate the RAM checksum now when it's in RAM
\r
818 if( bPtr->CalcRamBlockCrc ) {
\r
819 /* This block want its RAM block CRC checked */
\r
820 DEBUG_PRINTF(">> Recalculation of RAM checksum \n",admPtr->NvCrc.crc16);
\r
821 assert( bPtr->BlockUseCrc == 1);
\r
822 admPtr->BlockState = BLOCK_STATE_CALC_CRC_READ;
\r
823 admPtr->BlockSubState = BLOCK_SUBSTATE_0;
\r
826 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
827 admPtr->ErrorStatus = NVM_REQ_OK;
\r
832 DEBUG_PRINTF(">> Block have NO CRC\n");
\r
834 memcpy(admPtr->savedDataPtr, Nvm_WorkBuffer, bPtr->NvBlockLength + crcLen );
\r
836 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
837 admPtr->ErrorStatus = NVM_REQ_OK;
\r
841 /* Copy from Workbuffer to the real buffer */
\r
846 /* Something failed */
\r
848 DEBUG_PRINTF(">> Write FAILED\n");
\r
849 admPtr->NumberOfWriteFailed++;
\r
850 if( admPtr->NumberOfWriteFailed > NVM_MAX_NUMBER_OF_WRITE_RETRIES ) {
\r
851 DEBUG_PRINTF(">> Write FAILED COMPLETELY (all retries)\n");
\r
858 if( blockDone == 1 ) {
\r
859 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ; /* TODO, this really true for all result below */
\r
860 AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;
\r
862 switch( jobResult ) {
\r
863 case MEMIF_BLOCK_INVALID:
\r
864 /* @req 3.1.5/NVM342 */
\r
865 admPtr->ErrorStatus = NVM_REQ_NV_INVALIDATED;
\r
867 case MEMIF_BLOCK_INCONSISTENT:
\r
868 /* @req 3.1.5/NVM360 */
\r
869 admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;
\r
870 DEM_REPORTERRORSTATUS(NVM_E_REQ_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);
\r
872 case MEMIF_JOB_FAILED:
\r
873 /* @req 3.1.5/NVM361 */
\r
874 admPtr->ErrorStatus = NVM_REQ_NOT_OK;
\r
875 DEM_REPORTERRORSTATUS(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);
\r
878 DEBUG_PRINTF("## Unexpected jobResult:%d\n",jobResult);
\r
887 case BLOCK_STATE_CALC_CRC:
\r
891 case BLOCK_STATE_CALC_CRC_WRITE:
\r
897 if( bPtr->RamBlockDataAddress == NULL ) {
\r
898 /* If we have no buffer to work with something is very very wrong */
\r
899 NVM_ASSERT(dataPtr != NULL );
\r
902 ramData = bPtr->RamBlockDataAddress;
\r
905 admPtr->savedDataPtr = ramData;
\r
907 /* Calculate RAM CRC checksum */
\r
908 if( bPtr->BlockCRCType == NVM_CRC16 ) {
\r
910 crc16 = Crc_CalculateCRC16(ramData,bPtr->NvBlockLength,0xffff);
\r
911 DEBUG_CHECKSUM("RAM",crc16);
\r
913 /* Just save the checksum */
\r
914 admPtr->RamCrc.crc16 = crc16;
\r
916 /* Write the block */
\r
917 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
919 /* @req 3.1.5/NVM253 */
\r
920 crc32 = Crc_CalculateCRC32(ramData,bPtr->NvBlockLength,0xffffffffUL);
\r
921 DEBUG_CHECKSUM("RAM",crc32);
\r
923 admPtr->RamCrc.crc32 = crc32;
\r
925 /* Write the block */
\r
926 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
930 case BLOCK_STATE_CALC_CRC_READ:
\r
932 //NVM_ASSERT(bPtr->RamBlockDataAddress != NULL );
\r
933 NVM_ASSERT(bPtr->CalcRamBlockCrc == true );
\r
936 boolean checksumOk;
\r
939 /* @req 3.1.5/NVM253 */
\r
940 /* Calculate CRC on the data we just read to RAM. Compare with CRC that is located in NV block */
\r
942 if( bPtr->BlockCRCType == NVM_CRC16 ) {
\r
943 crc16 = Crc_CalculateCRC16(admPtr->savedDataPtr,bPtr->NvBlockLength,0xffff);
\r
945 crc32 = Crc_CalculateCRC32(admPtr->savedDataPtr,bPtr->NvBlockLength,0xffffffffUL);
\r
948 switch( admPtr->BlockSubState ) {
\r
949 case BLOCK_SUBSTATE_0:
\r
951 checksumOk = ( bPtr->BlockCRCType == NVM_CRC16 ) ? ( crc16 == admPtr->RamCrc.crc16 ) : ( crc32 == admPtr->RamCrc.crc32 );
\r
953 /* @req 3.1.5/NVM387 */
\r
955 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
957 DEBUG_CHECKSUM("RAM checksum ok with ", ( bPtr->BlockCRCType == NVM_CRC16 ) ? crc16 : crc32 );
\r
958 admPtr->ErrorStatus = NVM_REQ_OK;
\r
959 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
964 * Corrupt CRC, what choices are there:
\r
965 * 1. Default data (=ROM) configured, just copy it.
\r
966 * 2. Data redundancy, get it.
\r
967 * 3. None of the above. Catastrophic failure. (NVM203)
\r
970 if( (admPtr->flags != 2) && bPtr->BlockManagementType == NVM_BLOCK_REDUNDANT ) {
\r
971 /* According to 3.1.5/NVM137 we have 2 NV Blocks and 0..1 ROM Blocks */
\r
972 /* Req 3.1.5/NVM199 , 3.1.5/NVM279 , 3.1.5/NVM317
\r
973 * 3.1.5/NVM288, 3.1.5/NVM315
\r
975 NVM_ASSERT(bPtr->NvBlockNum == 2); /* Configuration error */
\r
976 if( admPtr->DataIndex == 0) {
\r
977 admPtr->DataIndex = 1;
\r
979 admPtr->DataIndex = 0;
\r
982 if( admPtr->flags == 2 ) {
\r
983 /* We have failed both NV Blocks */
\r
984 DEBUG_PRINTF(" # Both redundant NV blocks failed\n");
\r
987 /* Start over again with the other NV block */
\r
988 DEBUG_PRINTF(" # First redundant NV block failed\n");
\r
989 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
990 break; /* Break from BLOCK_SUBSTATE_0 */
\r
994 if( bPtr->RomBlockDataAdress != NULL ) {
\r
995 DEBUG_PRINTF("Copying ROM data to block\n");
\r
996 memcpy(bPtr->RamBlockDataAddress, bPtr->RomBlockDataAdress,bPtr->NvBlockLength);
\r
997 admPtr->BlockSubState = BLOCK_SUBSTATE_1;
\r
1000 /* @req 3.1.5/NVM469 */
\r
1001 if( bPtr->InitBlockCallback != NULL ) {
\r
1003 DEBUG_PRINTF("Filling block with default data\n");
\r
1004 bPtr->InitBlockCallback();
\r
1005 admPtr->BlockSubState = BLOCK_SUBSTATE_1;
\r
1007 /* NVM085 is very vague here, but the says the application should be
\r
1008 * able distinguish between when the init-callback have been called
\r
1009 * or CRC is corrupt.
\r
1012 /* The RAM CRC is at this point not calculated...so we must do this
\r
1013 * .. so just stay in this state one more MainFunction.
\r
1018 DEBUG_PRINTF("### Block FAILED with NVM_REQ_INTEGRITY_FAILED\n");
\r
1021 /* @req 3.1.5/NVM203 */
\r
1022 DEM_REPORTERRORSTATUS(NVM_E_INTEGRITY_FAILED,DEM_EVENT_STATUS_FAILED);
\r
1023 /* @req 3.1.5/NVM204 */
\r
1024 admPtr->ErrorStatus = NVM_REQ_INTEGRITY_FAILED;
\r
1025 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1031 case BLOCK_SUBSTATE_1:
\r
1032 /* The checksum is on the ROM data so just save it */
\r
1033 DEBUG_CHECKSUM("RAM checksum after ROM copy ", ( bPtr->BlockCRCType == NVM_CRC16 ) ? crc16 : crc32 );
\r
1035 if( bPtr->BlockCRCType == NVM_CRC16 ) {
\r
1036 admPtr->RamCrc.crc16 = crc16;
\r
1038 admPtr->RamCrc.crc32 = crc32;
\r
1040 admPtr->BlockSubState = BLOCK_SUBSTATE_0;
\r
1041 admPtr->ErrorStatus = NVM_REQ_OK;
\r
1042 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1058 DEBUG_PRINTF("# Block Done\n");
\r
1060 if( admPtr->ErrorStatus == NVM_REQ_OK ) {
\r
1061 admPtr->BlockChanged = FALSE;
\r
1062 admPtr->BlockValid = TRUE;
\r
1066 /* @req 3.1.5/NVM281 */
\r
1067 if( bPtr->SingleBlockCallback != NULL ) {
\r
1068 bPtr->SingleBlockCallback(NVM_READ_ALL_ID, admPtr->ErrorStatus);
\r
1071 if( multiBlock ) {
\r
1072 AdminMultiReq.currBlockIndex++;
\r
1073 if( AdminMultiReq.currBlockIndex >= NVM_NUM_OF_NVRAM_BLOCKS ) {
\r
1074 AdminMultiReq.currBlockIndex = 0;
\r
1076 /* @req 3.1.5/NVM301 */
\r
1077 if( NVM_REQ_NOT_OK == AdminMultiReq.PendingErrorStatus ) {
\r
1078 AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;
\r
1080 AdminMultiBlock.ErrorStatus = NVM_REQ_OK;
\r
1082 nvmState = NVM_IDLE;
\r
1086 nvmState = NVM_IDLE;
\r
1094 * Main function for the read all job
1096 static void ReadAllMain(void)
\r
1100 * 1. We process each block until it's finished
\r
1101 * 2. We start to process a lot of blocks. The blocks may use different devices
\r
1102 * and should be able to read a lot of them. This includes CRC.
\r
1104 * 1) is much simpler and 2) probably much faster.
\r
1105 * This implementation will use 1) since it's simpler and maximum time that is
\r
1106 * spent in MainFunction() can be controlled much better.
\r
1109 /* Skip blocks that are skipped */
\r
1111 while ( (AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus == NVM_REQ_BLOCK_SKIPPED) ) {
\r
1112 if( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {
\r
1113 AdminMultiReq.currBlockIndex++;
\r
1119 DriveBlock( &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],
\r
1120 &AdminBlock[AdminMultiReq.currBlockIndex],
\r
1128 * Request writing of a block to MemIf
1130 static void WriteBlock( const NvM_BlockDescriptorType *blockDescriptor,
\r
1131 AdministrativeBlockType *adminBlock,
\r
1133 uint8 *sourceAddress)
\r
1135 Std_ReturnType returnCode;
\r
1137 if (setNumber < blockDescriptor->NvBlockNum) {
\r
1138 SetMemifJobBusy();
\r
1139 MemIfJobAdmin.BlockAdmin = adminBlock;
\r
1140 MemIfJobAdmin.BlockDescriptor = blockDescriptor;
\r
1141 returnCode = MemIf_Write(blockDescriptor->NvramDeviceId, BLOCK_BASE_AND_SET_TO_BLOCKNR(blockDescriptor->NvBlockBaseNumber, setNumber), sourceAddress);
\r
1142 if (returnCode != E_OK) {
\r
1143 AbortMemIfJob(MEMIF_JOB_FAILED);
\r
1146 // Error: setNumber out of range
\r
1147 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_LOC_WRITE_BLOCK_ID, NVM_PARAM_OUT_OF_RANGE);
\r
1154 * Initiate the write all job
\r
1156 static boolean WriteAllInit(void)
\r
1158 const NvM_BlockDescriptorType *BlockDescriptorList = NvM_Config.BlockDescriptor;
\r
1159 AdministrativeBlockType *AdminBlockTable = AdminBlock;
\r
1161 boolean needsProcessing = FALSE;
\r
1163 // nvmState = NVM_WRITE_ALL_PROCESSING;
\r
1164 AdminMultiReq.PendingErrorStatus = NVM_REQ_OK;
\r
1165 AdminMultiReq.currBlockIndex = 0;
\r
1167 for (i = 0; i < NVM_NUM_OF_NVRAM_BLOCKS; i++) {
\r
1168 if ((BlockDescriptorList->RamBlockDataAddress != NULL)
\r
1169 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON) /** @req NVM344 */
\r
1170 && (AdminBlockTable->BlockValid) /** @req NVM682 */
\r
1171 && (AdminBlockTable->BlockChanged) /** @req NVM682 */
\r
1173 && (!AdminBlockTable->BlockWriteProtected)) /** @req NVM432 *//** @req NVM433 */
\r
1175 AdminBlockTable->ErrorStatus = NVM_REQ_PENDING;
\r
1177 if (BlockDescriptorList->BlockUseCrc) {
\r
1178 AdminBlockTable->BlockState = BLOCK_STATE_CALC_CRC_WRITE; /** @req NVM253 */
\r
1180 AdminBlockTable->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1181 AdminBlockTable->NumberOfWriteFailed = 0;
\r
1183 needsProcessing = TRUE;
\r
1185 AdminBlockTable->ErrorStatus = NVM_REQ_BLOCK_SKIPPED; /** @req NVM298 */
\r
1188 AdminBlockTable++;
\r
1189 BlockDescriptorList++;
\r
1191 return needsProcessing;
\r
1197 * Main function for the write all job
\r
1199 static void WriteAllMain(void)
\r
1202 while ( (AdminBlock[AdminMultiReq.currBlockIndex].ErrorStatus == NVM_REQ_BLOCK_SKIPPED) ) {
\r
1203 if( (AdminMultiReq.currBlockIndex < NVM_NUM_OF_NVRAM_BLOCKS) ) {
\r
1204 AdminMultiReq.currBlockIndex++;
\r
1210 DriveBlock( &NvM_Config.BlockDescriptor[AdminMultiReq.currBlockIndex],
\r
1211 &AdminBlock[AdminMultiReq.currBlockIndex],
\r
1221 * Handles the result of one MemIf block write
\r
1223 static void WriteAllCheckWriteResult(void)
\r
1225 if (MemIfJobAdmin.JobStatus == E_OK) {
\r
1226 // TODO: Check if redundant block shall be written NVM337
\r
1228 if (MemIfJobAdmin.BlockDescriptor->WriteBlockOnce) {
\r
1229 MemIfJobAdmin.BlockAdmin->BlockWriteProtected = TRUE; /** @req NVM329 */
\r
1231 MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1232 MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_OK;
\r
1234 if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {
\r
1235 (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);
\r
1238 MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed++;
\r
1239 if (MemIfJobAdmin.BlockAdmin->NumberOfWriteFailed > NVM_MAX_NUMBER_OF_WRITE_RETRIES) {
\r
1240 // TODO: Check if redundant block shall be written NVM337
\r
1242 // Write has failed
\r
1243 AdminMultiReq.PendingErrorStatus = NVM_REQ_NOT_OK;
\r
1245 MemIfJobAdmin.BlockAdmin->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1246 MemIfJobAdmin.BlockAdmin->ErrorStatus = NVM_REQ_NOT_OK; /** @req NVM296 */
\r
1247 #if defined(USE_DEM)
\r
1248 Dem_ReportErrorStatus(NVM_E_REQ_FAILED,DEM_EVENT_STATUS_FAILED);
\r
1251 if (MemIfJobAdmin.BlockDescriptor->SingleBlockCallback != NULL) {
\r
1252 (void)MemIfJobAdmin.BlockDescriptor->SingleBlockCallback(NVM_SERVICE_ID, MemIfJobAdmin.BlockAdmin->ErrorStatus);
\r
1256 nvmState = NVM_WRITE_ALL_PROCESSING;
\r
1262 /***************************************
\r
1263 * External accessible functions *
\r
1264 ***************************************/
\r
1266 * Procedure: NvM_Init
\r
1269 void NvM_Init(void)
\r
1271 /** @req NVM399 *//** @req NVM193 */
\r
1272 const NvM_BlockDescriptorType *BlockDescriptorList = NvM_Config.BlockDescriptor;
\r
1273 AdministrativeBlockType *AdminBlockTable = AdminBlock;
\r
1277 CirqBuff_Init(&nvmQueue,nvmQueueData,sizeof(nvmQueueData)/sizeof(Nvm_QueueType),sizeof(Nvm_QueueType));
\r
1279 // Initiate the administration blocks
\r
1280 for (i = 0; i< NVM_NUM_OF_NVRAM_BLOCKS; i++) {
\r
1281 if (BlockDescriptorList->BlockManagementType == NVM_BLOCK_DATASET) {
\r
1282 AdminBlockTable->DataIndex = 0; /** @req NVM192 */
\r
1284 AdminBlockTable->BlockWriteProtected = BlockDescriptorList->BlockWriteProt;
\r
1285 AdminBlockTable->ErrorStatus = NVM_REQ_NOT_OK;
\r
1286 AdminBlockTable->BlockChanged = FALSE;
\r
1287 AdminBlockTable->BlockValid = FALSE;
\r
1288 AdminBlockTable->NumberOfWriteFailed = 0;
\r
1290 AdminBlockTable++;
\r
1291 BlockDescriptorList++;
\r
1294 AdminMultiBlock.ErrorStatus = NVM_REQ_NOT_OK;
\r
1296 // Set status to initialized
\r
1297 nvmState = NVM_IDLE; /** @req 3.1.5/NVM399 */
\r
1304 * NvM_ReadAll() does not set status here or need to check status of the
\r
1305 * any blocks since it's done after all single reads are done.
\r
1307 void NvM_ReadAll(void)
\r
1310 VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);
\r
1312 NVM_ASSERT(nvmState == NVM_IDLE);
\r
1315 AdminMultiReq.state = NVM_READ_ALL;
\r
1316 AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;
\r
1317 Irq_Restore(state);
\r
1323 * Procedure: NvM_WriteAll
\r
1326 void NvM_WriteAll(void)
\r
1329 VALIDATE_NO_RV(nvmState != NVM_UNINITIALIZED, NVM_READ_ALL_ID, NVM_E_NOT_INITIALIZED);
\r
1331 NVM_ASSERT(nvmState == NVM_IDLE);
\r
1334 AdminMultiReq.state = NVM_WRITE_ALL;
\r
1335 AdminMultiBlock.ErrorStatus = NVM_REQ_PENDING;
\r
1336 Irq_Restore(state);
\r
1341 * Procedure: NvM_CancelWriteAll
\r
1344 void NvM_CancelWriteAll(void)
\r
1351 * Procedure: NvM_GetErrorStatus
\r
1354 Std_ReturnType NvM_GetErrorStatus(NvM_BlockIdType blockId, uint8 *requestResultPtr)
\r
1356 VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_GET_ERROR_STATUS_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK );
\r
1357 VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_GET_ERROR_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK );
\r
1359 if (blockId == 0) {
\r
1361 *requestResultPtr = AdminMultiBlock.ErrorStatus;
\r
1362 } else if (blockId == 1) {
\r
1363 /* TODO Configuration ID */
\r
1364 *requestResultPtr = NVM_REQ_OK;
\r
1366 *requestResultPtr = AdminBlock[blockId-1].ErrorStatus;
\r
1372 #if (NVM_SET_RAM_BLOCK_STATUS_API == STD_ON) /** @req NVM408 */
\r
1374 * Procedure: Nvm_SetRamBlockStatus
\r
1377 Std_ReturnType NvM_SetRamBlockStatus(NvM_BlockIdType blockId, boolean blockChanged)
\r
1379 const NvM_BlockDescriptorType * bPtr;
\r
1380 AdministrativeBlockType * admPtr;
\r
1381 Nvm_QueueType qEntry;
\r
1384 VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK);
\r
1386 bPtr = &NvM_Config.BlockDescriptor[blockId-1];
\r
1387 admPtr = &AdminBlock[blockId-1];
\r
1389 VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK); /** @req NVM497 */
\r
1390 VALIDATE_RV(blockId > 1, NVM_SET_RAM_BLOCK_STATUS_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK );
\r
1391 VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );
\r
1393 qEntry.blockId = blockId;
\r
1394 qEntry.op = NVM_SETRAMBLOCKSTATUS;
\r
1395 qEntry.blockChanged = blockChanged;
\r
1396 rv = CirqBuffPush(&nvmQueue,&qEntry);
\r
1397 NVM_ASSERT(rv == 0 );
\r
1399 /* req 3.1.5/NVM185 */
\r
1400 admPtr->ErrorStatus = NVM_REQ_PENDING;
\r
1406 static void setRamBlockStatus( const NvM_BlockDescriptorType *bPtr, AdministrativeBlockType *admPtr, boolean blockChanged ) {
\r
1408 if (bPtr->RamBlockDataAddress != NULL) { /** @req NVM240 */
\r
1409 if (blockChanged) {
\r
1410 admPtr->BlockChanged = TRUE; /** @req NVM406 */
\r
1411 admPtr->BlockValid = TRUE; /** @req NVM241 */
\r
1412 // TODO? if (bPtr->BlockUseCrc) {
\r
1413 // admPtr->BlockState = BLOCK_STATE_CALC_CRC; /** @req NVM121 */
\r
1416 admPtr->BlockChanged = FALSE; /** @req NVM405 */
\r
1417 admPtr->BlockValid = FALSE;
\r
1418 } // else blockChanged
\r
1419 } // if permanent block
\r
1422 void NvM_SetBlockLockStatus( NvM_BlockIdType blockId, boolean blockLocked ) {
\r
1424 (void)blockLocked;
\r
1429 * Restore default data to its corresponding RAM block.
\r
1431 * @param BlockId NVRAM block identifier.
1432 * @param NvM_DestPtr Pointer to the RAM block
1435 Std_ReturnType NvM_RestoreBlockDefaults( NvM_BlockIdType blockId, uint8* NvM_DestPtr )
\r
1437 /* !req 3.1.5/NVM012 */ /* !req 3.1.5/NVM267 */ /* !req 3.1.5/NVM266 */
\r
1438 /* !req 3.1.5/NVM353 */ /* !req 3.1.5/NVM435 */ /* !req 3.1.5/NVM436 */ /* !req 3.1.5/NVM227 */
\r
1439 /* !req 3.1.5/NVM228 */ /* !req 3.1.5/NVM229 */ /* !req 3.1.5/NVM413 */
\r
1441 const NvM_BlockDescriptorType * bPtr;
\r
1442 AdministrativeBlockType * admPtr;
\r
1443 Nvm_QueueType qEntry;
\r
1446 NVM_ASSERT( blockId >= 2 ); /* No support for lower numbers, yet */
\r
1448 /* @req 3.1.5/NVM618 */
\r
1449 VALIDATE_RV( blockId <= NVM_NUM_OF_NVRAM_BLOCKS,
\r
1450 NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );
\r
1452 bPtr = &NvM_Config.BlockDescriptor[blockId-1];
\r
1453 admPtr = &AdminBlock[blockId-1];
\r
1455 /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */ /** @req 3.1.5/NVM210 */
\r
1456 /* It must be a permanent RAM block but no RamBlockDataAddress -> error */
\r
1457 VALIDATE_RV( !((NvM_DestPtr == NULL) && ( bPtr->RamBlockDataAddress == NULL )),
\r
1458 NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );
\r
1460 VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );
\r
1462 /* @req 3.1.5/NVM195 */
\r
1463 qEntry.blockId = blockId;
\r
1464 qEntry.op = NVM_RESTORE_BLOCK_DEFAULTS;
\r
1465 qEntry.blockId = blockId;
\r
1466 qEntry.dataPtr = (uint8_t *)NvM_DestPtr;
\r
1467 rv = CirqBuffPush(&nvmQueue,&qEntry);
\r
1468 NVM_ASSERT(rv == 0 );
\r
1470 /* req 3.1.5/NVM185 */
\r
1471 admPtr->ErrorStatus = NVM_REQ_PENDING;
\r
1473 if( bPtr->BlockUseCrc) {
\r
1474 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;
\r
1476 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1484 * Service to copy the data NV block to the RAM block
\r
1486 * @param blockId 0 and 1 reserved. The block ID are sequential.
1492 Std_ReturnType NvM_ReadBlock( NvM_BlockIdType blockId, uint8* NvM_DstPtr )
\r
1494 /* !req 3.1.5/NVM010 */
\r
1497 /* !req 3.1.5/NVM278 */
\r
1498 /* !req 3.1.5/NVM340 */
\r
1499 /* !req 3.1.5/NVM354 */
\r
1500 /* !req 3.1.5/NVM200 */
\r
1501 /* !req 3.1.5/NVM366 */
\r
1502 /* !req 3.1.5/NVM206 */
\r
1503 /* !req 3.1.5/NVM341 */
\r
1504 /* !req 3.1.5/NVM358 */
\r
1505 /* !req 3.1.5/NVM359 */
\r
1506 /* !req 3.1.5/NVM279 */
\r
1507 /* !req 3.1.5/NVM316 */
\r
1508 /* !req 3.1.5/NVM317 */
\r
1509 /* !req 3.1.5/NVM201 */
\r
1510 /* !req 3.1.5/NVM202 */
\r
1511 /* !req 3.1.5/NVM203 */
\r
1512 /* !req 3.1.5/NVM204 */
\r
1513 /* !req 3.1.5/NVM409 */
\r
1519 * |5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0|
\r
1520 * b b b b b b b b b b d d d d d d
\r
1522 * Here we have 10 bits for block id, 16-5 for DataSetSelection bits.
\r
1523 * - 2^10, 1024 blocks
\r
1524 * - 64 datasets for each NVRAM block
\r
1526 * How are the block numbers done in EA? Assume virtual page=8
\r
1537 * How can NVM/NvmNvBlockLength and EA/EaBlockSize be different?
\r
1538 * It seems that EA/FEE does not care about that logical block 2 above is
\r
1542 Nvm_QueueType qEntry;
\r
1545 /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */
\r
1546 VALIDATE_RV( !(( NvM_DstPtr == NULL) &&
\r
1547 ( NvM_Config.BlockDescriptor[blockId-1].RamBlockDataAddress == NULL )),
\r
1548 0, NVM_E_PARAM_ADDRESS , E_NOT_OK );
\r
1549 VALIDATE_RV( (AdminBlock[blockId-1].ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );
\r
1551 /* @req 3.1.5/NVM195 */
\r
1552 qEntry.blockId = blockId;
\r
1553 qEntry.op = NVM_READ_BLOCK;
\r
1554 qEntry.blockId = blockId;
\r
1555 qEntry.dataPtr = NvM_DstPtr;
\r
1556 rv = CirqBuffPush(&nvmQueue,&qEntry);
\r
1557 NVM_ASSERT(rv == 0 );
\r
1560 /* req 3.1.5/NVM185 */
\r
1561 AdminBlock[blockId-1].ErrorStatus = NVM_REQ_PENDING;
\r
1568 * Service to copy a RAM block to its correspnding NVRAM block
\r
1574 Std_ReturnType NvM_WriteBlock( NvM_BlockIdType blockId, const uint8* NvM_SrcPtr ) {
\r
1576 const NvM_BlockDescriptorType * bPtr;
\r
1577 AdministrativeBlockType * admPtr;
\r
1578 Nvm_QueueType qEntry;
\r
1581 NVM_ASSERT( blockId >= 2 ); /* No support for lower numbers, yet */
\r
1583 /* @req 3.1.5/NVM618 */
\r
1584 VALIDATE_RV( blockId <= NVM_NUM_OF_NVRAM_BLOCKS,
\r
1585 NVM_WRITE_BLOCK_ID,NVM_E_PARAM_BLOCK_ID,E_NOT_OK );
\r
1587 bPtr = &NvM_Config.BlockDescriptor[blockId-1];
\r
1588 admPtr = &AdminBlock[blockId-1];
\r
1590 /** @req 3.1.5/NVM196 */ /** @req 3.1.5/NVM278 */
\r
1591 VALIDATE_RV( !((NvM_SrcPtr == NULL) && ( bPtr->RamBlockDataAddress == NULL )),
\r
1592 0, NVM_E_PARAM_ADDRESS, E_NOT_OK );
\r
1593 VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), 0, NVM_E_BLOCK_PENDING , E_NOT_OK );
\r
1595 /* @req 3.1.5/NVM195 */
\r
1596 qEntry.blockId = blockId;
\r
1597 qEntry.op = NVM_WRITE_BLOCK;
\r
1598 qEntry.blockId = blockId;
\r
1599 qEntry.dataPtr = (uint8_t *)NvM_SrcPtr;
\r
1600 rv = CirqBuffPush(&nvmQueue,&qEntry);
\r
1601 NVM_ASSERT(rv == 0 );
\r
1603 /* req 3.1.5/NVM185 */
\r
1604 admPtr->ErrorStatus = NVM_REQ_PENDING;
\r
1606 if( bPtr->BlockUseCrc) {
\r
1607 admPtr->BlockState = BLOCK_STATE_CALC_CRC_WRITE;
\r
1609 admPtr->BlockState = BLOCK_STATE_MEMIF_REQ;
\r
1616 /* Missing from Class 2
\r
1617 * - NvM_CancelWriteAll
\r
1620 //#if (NVM_API_CONFIG_CLASS > NVM_API_CONFIG_CLASS_1)
\r
1624 * This function returns void in 3.1.5 and in 4.0 it returns Std_ReturnType.
\r
1628 * x NVM_E_NOT_INITIALIZED
\r
1629 * x NVM_E_BLOCK_PENDING
\r
1630 * NVM_E_PARAM_BLOCK_DATA_IDX
\r
1631 * NVM_E_PARAM_BLOCK_TYPE
\r
1632 * x NVM_E_PARAM_BLOCK_ID
\r
1635 Std_ReturnType NvM_SetDataIndex( NvM_BlockIdType blockId, uint8 dataIndex ) {
\r
1636 #if ( NVM_DEV_ERROR_DETECT == STD_ON )
\r
1637 const NvM_BlockDescriptorType * bPtr = &NvM_Config.BlockDescriptor[blockId-1];
\r
1638 AdministrativeBlockType * admPtr = &AdminBlock[blockId-1];
\r
1640 Nvm_QueueType qEntry;
\r
1643 NVM_ASSERT( blockId >= 2 ); /* No support for lower numbers, yet */
\r
1645 VALIDATE_RV(nvmState != NVM_UNINITIALIZED, NVM_SET_DATA_INDEX_ID, NVM_E_NOT_INITIALIZED, E_NOT_OK);
\r
1646 VALIDATE_RV(blockId < NVM_NUM_OF_NVRAM_BLOCKS+1, NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_ID, E_NOT_OK);
\r
1647 VALIDATE_RV(bPtr->BlockManagementType != NVM_BLOCK_NATIVE , NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_TYPE , E_NOT_OK);
\r
1648 VALIDATE_RV(dataIndex < bPtr->NvBlockNum + bPtr->RomBlockNum , NVM_SET_DATA_INDEX_ID, NVM_E_PARAM_BLOCK_DATA_IDX ,E_NOT_OK);
\r
1649 VALIDATE_RV( (admPtr->ErrorStatus != NVM_REQ_PENDING), NVM_SET_DATA_INDEX_ID, NVM_E_BLOCK_PENDING , E_NOT_OK);
\r
1651 qEntry.blockId = blockId;
\r
1652 qEntry.op = NVM_SETDATAINDEX;
\r
1653 qEntry.blockId = blockId;
\r
1654 qEntry.dataIndex = dataIndex;
\r
1655 rv = CirqBuffPush(&nvmQueue,&qEntry);
\r
1656 NVM_ASSERT(rv == 0 );
\r
1658 /* req 3.1.5/NVM185 */
\r
1659 admPtr->ErrorStatus = NVM_REQ_PENDING;
\r
1664 const NvM_BlockDescriptorType * nvmBlock;
\r
1665 AdministrativeBlockType *admBlock;
\r
1670 void NvM_MainFunction(void)
\r
1673 Nvm_QueueType qEntry;
\r
1674 const NvM_BlockDescriptorType * bList = NvM_Config.BlockDescriptor;
\r
1675 // const NvM_BlockDescriptorType * currBlock;
\r
1676 // static uint32 crc32;
\r
1677 // static uint32 crc32Left;
\r
1679 /* Check for new requested state changes */
\r
1680 if( nvmState == NVM_IDLE ) {
\r
1681 rv = CirqBuffPop( &nvmQueue, &qEntry );
\r
1683 /* Found something in buffer */
\r
1684 nvmState = qEntry.op;
\r
1685 nvmBlock = &bList[qEntry.blockId-1];
\r
1686 admBlock = &AdminBlock[qEntry.blockId-1];
\r
1688 admBlock->ErrorStatus = NVM_REQ_PENDING;
\r
1689 DEBUG_PRINTF("### Popped Single FIFO : %s\n",StateToStr[qEntry.op]);
\r
1690 DEBUG_PRINTF("### CRC On:%d Ram:%d Type:%d\n",nvmBlock->BlockUseCrc, nvmBlock->CalcRamBlockCrc, nvmBlock->BlockCRCType );
\r
1691 DEBUG_PRINTF("### RAM:%x ROM:%x\n", nvmBlock->RamBlockDataAddress, nvmBlock->RomBlockDataAdress );
\r
1693 /* Check multiblock req and do after all single block reads (3.1.5/NVM243) */
\r
1694 if( AdminMultiReq.state != NVM_UNINITIALIZED ) {
\r
1695 nvmState = AdminMultiReq.state ;
\r
1699 AdminMultiReq.state = NVM_UNINITIALIZED;
\r
1701 DEBUG_PRINTF("### Popped MULTI\n");
\r
1706 DEBUG_STATE(nvmState,nvmSubState);
\r
1708 switch (nvmState) {
\r
1709 case NVM_UNINITIALIZED:
\r
1717 case NVM_READ_ALL:
\r
1718 if( NS_INIT == nvmSubState ) {
\r
1719 if( ReadAllInit() ) {
\r
1720 nvmSubState = NS_PROSSING;
\r
1722 /* Nothing to do, everything is OK */
\r
1723 AdminMultiBlock.ErrorStatus = NVM_REQ_OK;
\r
1724 nvmState = NVM_IDLE;
\r
1727 } else if( NS_PROSSING == nvmSubState ) {
\r
1732 case NVM_READ_BLOCK:
\r
1733 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, false );
\r
1736 case NVM_RESTORE_BLOCK_DEFAULTS:
\r
1737 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, false, false, true );
\r
1740 case NVM_WRITE_BLOCK:
\r
1741 DriveBlock(nvmBlock,admBlock, qEntry.dataPtr, true /*write*/, false , false );
\r
1744 case NVM_WRITE_ALL:
\r
1745 if( NS_INIT == nvmSubState ) {
\r
1746 if( WriteAllInit() ) {
\r
1747 nvmSubState = NS_PROSSING;
\r
1749 /* Nothing to do, everything is OK */
\r
1750 AdminMultiBlock.ErrorStatus = NVM_REQ_OK;
\r
1751 nvmState = NVM_IDLE;
\r
1754 } else if( NS_PROSSING == nvmSubState ) {
\r
1758 case NVM_SETDATAINDEX:
\r
1759 admBlock->DataIndex = qEntry.dataIndex;
\r
1760 nvmState = NVM_IDLE;
\r
1762 admBlock->ErrorStatus = NVM_REQ_OK;
\r
1764 case NVM_GETDATAINDEX:
\r
1766 nvmState = NVM_IDLE;
\r
1768 admBlock->ErrorStatus = NVM_REQ_OK;
\r
1770 case NVM_SETRAMBLOCKSTATUS:
\r
1771 setRamBlockStatus(nvmBlock,admBlock,qEntry.blockChanged );
\r
1772 nvmState = NVM_IDLE;
\r
1774 admBlock->ErrorStatus = NVM_REQ_OK;
\r
1777 DET_REPORTERROR(MODULE_ID_NVM, 0, NVM_MAIN_FUNCTION_ID, NVM_UNEXPECTED_STATE);
\r
1783 /***************************************
\r
1784 * Call-back notifications functions *
\r
1785 ***************************************/
\r
1786 #if (NVM_POLLING_MODE == STD_OFF)
\r
1788 * Procedure: NvM_JobEndNotification
\r
1791 void NvM_JobEndNotification(void)
\r
1793 MemIfJobAdmin.JobFinished = TRUE;
\r
1794 MemIfJobAdmin.JobStatus = E_OK;
\r
1795 MemIfJobAdmin.JobResult = MemIf_GetJobResult(FIXME);
\r
1799 * Procedure: NvM_JobErrorNotification
\r
1802 void NvM_JobErrorNotification(void)
\r
1804 MemIfJobAdmin.JobFinished = TRUE;
\r
1805 MemIfJobAdmin.JobStatus = E_NOT_OK;
\r
1806 MemIfJobAdmin.JobResult = MemIf_GetJobResult(FIXME);
\r