Index: firmware/App/Controllers/DialysatePumps.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Controllers/DialysatePumps.c (.../DialysatePumps.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Controllers/DialysatePumps.c (.../DialysatePumps.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -633,8 +633,11 @@ // if ( TRUE == isNewCalibrationRecordAvailable() ) // { // get updated record - //getNVRecord2Driver( GET_CAL_DIALYSATE_PUMP_RECORD, (U08*)&dialysatePumpCalRecord, sizeof( DD_DIALYSATE_PUMP_CAL_RECORD_T ), 0, - // ALARM_ID_DD_D12_PUMP_INVALID_CAL_RECORD ); +// getNVRecord2Driver( GET_CAL_D12_PUMP_RECORD, (U08*)&dialysatePumpD12CalRecord, sizeof( DD_D12_DIALYSATE_PUMP_RECORD_T ), 0, +// ALARM_ID_DD_D12_PUMP_INVALID_CAL_RECORD ); +// +// getNVRecord2Driver( GET_CAL_D48_PUMP_RECORD, (U08*)&dialysatePumpD48CalRecord, sizeof( DD_D48_DIALYSATE_PUMP_RECORD_T ), 0, +// ALARM_ID_DD_D48_PUMP_INVALID_CAL_RECORD ); // } for ( pumpId = DIALYSATE_PUMPS_FIRST; pumpId < NUM_OF_DIALYSATE_PUMPS; pumpId++ ) @@ -674,13 +677,10 @@ BOOL calStatus = TRUE; // TODO:initialize to false when calibration records avialble // This is only one record the number of items to check is 0 since the get NV data function does not do a for loop to check the calibration time -// calStatus |= getNVRecord2Driver( GET_CAL_D12_PUMP_RECORD, (U08*)&freshDialysatePumpRecord, sizeof( DD_D12_PUMP_RECORD_T ), 0, +// calStatus |= getNVRecord2Driver( GET_CAL_D12_PUMP_RECORD, (U08*)&freshDialysatePumpRecord, sizeof( DD_D12_DIALYSATE_PUMP_RECORD_T ), 0, // ALARM_ID_DD_D12_PUMP_INVALID_CAL_RECORD ); -// calStatus |= getNVRecord2Driver( GET_CAL_D48_PUMP_RECORD, (U08*)&spentDialysatePumpRecord, sizeof( DD_D48_PUMP_RECORD_T ), 0, +// calStatus |= getNVRecord2Driver( GET_CAL_D48_PUMP_RECORD, (U08*)&spentDialysatePumpRecord, sizeof( DD_D48_DIALYSATE_PUMP_RECORD_T ), 0, // ALARM_ID_DD_D48_PUMP_INVALID_CAL_RECORD ); -// -// calStatus |= getNVRecord2Driver( GET_CAL_DIALYSATE_PUMP_RECORD, (U08*)&dialysatePumpCalRecord, sizeof( DD_DIALYSATE_PUMP_CAL_RECORD_T ), 0, -// ALARM_ID_NO_ALARM ); if ( TRUE == calStatus ) { Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -24,7 +24,7 @@ //#include "Integrity.h" #include "Messaging.h" #include "ModeInitPOST.h" -//#include "NVMgmtDD.h" +#include "NVMgmtDD.h" #include "OperationModes.h" #include "Pressure.h" #include "SafetyShutdown.h" @@ -133,7 +133,7 @@ break; case DD_POST_STATE_NVDATAMGMT: - //testStatus = execNVMSelfTest(); + testStatus = execNVMSelfTest(); postState = handlePOSTStatus( testStatus ); break; Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r0face6417892ea9de28d146bf88d44a9f30cf2a4 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 0face6417892ea9de28d146bf88d44a9f30cf2a4) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -15,6 +15,7 @@ * ***************************************************************************/ + #include // for memcpy() #include "reg_system.h" @@ -46,7 +47,7 @@ #include "ModePreGenPermeateDefeatured.h" #include "ModePostGenDialysate.h" #include "ModeStandby.h" -#include "NVMsgQ.h" +#include "NVMessaging.h" #include "OperationModes.h" #include "PAL.h" #include "PermeateTank.h" @@ -273,6 +274,7 @@ { MSG_ID_DD_NVM_SET_CALIBRATION_RECORD, &testDDSetNVCalibrationRecord }, { MSG_ID_DD_NVM_SET_INSTITUTIONAL_RECORD, &testDDSetNVInstitutionalRecord }, { MSG_ID_DD_NVM_SET_USAGE_INFO_RECORD, &testDDSetNVUsageInfoRecord }, + { MSG_ID_DD_NVM_RECORD_CRC_OVERRIDE_REQUEST, &testDDSetNVUsageInfoRecord }, { MSG_ID_FP_RO_REJECTION_RATIO_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testRORejectionRatioDataPublishIntervalOverride }, { MSG_ID_FP_RO_FILTERED_REJECTION_RATIO_OVERRIDE_REQUEST, &testRORejectionRatioFilteredOverride }, { MSG_ID_FP_SET_TEST_CONFIGURATION, &testSetTestConfiguration }, Index: firmware/App/Services/NVJobQ.c =================================================================== diff -u --- firmware/App/Services/NVJobQ.c (revision 0) +++ firmware/App/Services/NVJobQ.c (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -0,0 +1,320 @@ +/************************************************************************** +* +* Copyright (c) 2026-2027 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file NVJobQ.c +* +* @author (original) Arpita Srivastava +* @date (original) 31-Mar-2026 +* +***************************************************************************/ + +#include // For memcpy +#include "Common.h" +#include "MsgDefs.h" +#include "NVJobQ.h" +#include "NVRecordsDD.h" + + + + +/** + * @addtogroup NVJobQ + * @{ + */ + +// ********** private definitions ********** + +// Once a new calibration data is available the driver, sets a signal for the defined time. Once the time is out, it turns the signal off. + +#define QUEUE_MAX_SIZE 20U ///< Max queue size. +#define QUEUE_START_INDEX 0U ///< Queue start index. +#define MAX_JOB_DATA_SIZE_BYTES 32U ///< Max bytes per job (32 bytes). + +/// DD institutional values structure. +typedef struct +{ + U32 minRORejectionRatioPCT; ///< Min RO rejection ratio in percent. + F32 minInletWaterCondAlarmLimitUSPCM; ///< Min inlet water conductivity alarm limit in uS/cm. +} DD_INSTITUTIONAL_VALUES_T; + +// ********** private data ********** + +static PROCESS_RECORD_JOB_T recordJobQueue[ QUEUE_MAX_SIZE ]; ///< Record queue jobs. +static U08 recordQueueRearIndex; ///< Record queue rear index. +static U08 recordQueueFrontIndex; ///< Record queue front index. +static U08 recordQueueCount; ///< Record queue count. +static PROCESS_RECORD_JOB_T recordCurrentJob; ///< Record queue current job. +static NVM_RECORDS_READ_STATUS_T recordsReadStatus; ///< NVM records read status. + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The initNVJobQ function initializes the NV message queue and related + * state variables. + * @details \b Inputs: none + * @details \b Outputs: recordQueueRearIndex, + * recordQueueFrontIndex, recordQueueCount, recordsReadStatus, + * @return none + *************************************************************************/ +void initNVJobQ ( void ) +{ + recordQueueRearIndex = QUEUE_START_INDEX; + recordQueueFrontIndex = QUEUE_START_INDEX; + recordQueueCount = 0; + recordsReadStatus = NVM_RECORDS_NOT_STARTED; +} + +/*********************************************************************//** + * @brief + * The enqueueRecordJob function enqueues a new record job into the + * record queue. It updates the queue with the new job and advances + * the rear index. + * @details \b Inputs: recordQueueRearIndex, recordQueueCount + * @details \b Outputs: recordJobQueue, recordQueueRearIndex, + * recordQueueCount + * @param ops memory operation (i.e write, read) + * @param job type of job (i.e write calibration data) + * @return none + *************************************************************************/ +void enqueueRecordJob( NVM_OPERATION_T ops, NVM_RECORD_TYPE_T job ) +{ + PROCESS_RECORD_JOB_T currentJob; + + currentJob.memoryOperation = ops; + currentJob.recordJob = job; + recordJobQueue[ recordQueueRearIndex ] = currentJob; + + recordQueueCount++; + recordQueueRearIndex = INC_WRAP( recordQueueRearIndex, 0, QUEUE_MAX_SIZE - 1 ); +} + +/*********************************************************************//** + * @brief + * The dequeueRecordJob function removes a record job from the queue. + * It updates the front index, retrieves the job, and updates the + * queue count. + * @details \b Inputs: recordQueueFrontIndex, recordQueueCount, + * recordJobQueue + * @details \b Outputs: recordQueueFrontIndex, recordQueueCount, + * recordCurrentJob + * @return none + *************************************************************************/ +void dequeueRecordJob( void ) +{ + U32 tempIndex; + + _disable_IRQ(); + tempIndex = recordQueueFrontIndex; + + if ( FALSE == isRecordQueueEmpty() ) + { + recordQueueFrontIndex = INC_WRAP( recordQueueFrontIndex, 0, QUEUE_MAX_SIZE - 1 ); + recordCurrentJob = recordJobQueue[ tempIndex ]; + } + if ( recordQueueCount > 0 ) + { + recordQueueCount--; + } + _enable_IRQ(); +} + +/*********************************************************************//** + * @brief + * The isRecordQueueEmpty function checks whether the record queue is + * empty. It returns the status based on the queue count. + * @details \b Inputs: recordQueueCount + * @details \b Outputs: none + * @return TRUE if queue is empty otherwise FALSE + *************************************************************************/ +BOOL isRecordQueueEmpty( void ) +{ + BOOL isEmpty = TRUE; + + if ( recordQueueCount > 0 ) + { + isEmpty = FALSE; + } + + return isEmpty; +} + +/*********************************************************************//** + * @brief + * The isRecordQueueFull function checks whether the record queue is + * full based on the maximum queue size. + * @details \b Inputs: recordQueueCount + * @details \b Outputs: none + * @return TRUE if queue is full otherwise FALSE + *************************************************************************/ +BOOL isRecordQueueFull( void ) +{ + BOOL isFull = FALSE; + + if ( recordQueueCount >= ( QUEUE_MAX_SIZE - 1 ) ) + { + isFull = TRUE; + } + + return isFull; +} + +/*********************************************************************//** + * @brief + * The getAvailableRecordQueueCount function returns the number of + * available record queue slots based on the current queue count. + * @details \b Inputs: recordQueueCount + * @details \b Outputs: none + * @return available record queues + *************************************************************************/ + +U32 getAvailableRecordQueueCount( void ) +{ + return QUEUE_MAX_SIZE - recordQueueCount; +} + +/*********************************************************************//** + * @brief + * The enqueueEraseAndWriteSector function enqueues erase and write + * operations for the given record type. + * @details \b Inputs: none + * @details \b Outputs: none + * @param job Record type for which erase and write operations are scheduled + * @return TRUE if the operations were successfully enqueued otherwise FALSE + *************************************************************************/ +BOOL enqueueEraseAndWriteSector( NVM_RECORD_TYPE_T job ) +{ + BOOL status = FALSE; + + if ( getAvailableRecordQueueCount() >= MIN_JOBS_NEEDED_TO_WRITE_A_RECORD ) + { + // Service and Calibration record are stored in the same sector. + if ( ( job == NVM_SERVICE_RECORD ) || ( job == NVM_CALIBRATION_RECORD ) ) + { + enqueueRecordJob( NVM_OPERATION_ERASE, NVM_SERVICE_RECORD ); + enqueueRecordJob( NVM_OPERATION_WRITE, NVM_SERVICE_RECORD ); + enqueueRecordJob( NVM_OPERATION_WRITE, NVM_CALIBRATION_RECORD ); + } + else + { + enqueueRecordJob( NVM_OPERATION_ERASE, job ); + enqueueRecordJob( NVM_OPERATION_WRITE, job ); + } + + status = TRUE; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The enqueuewriteAllRecords function enqueues erase and write + * operations for all records. It schedules jobs for all record types + * if sufficient queue space is available. + * @details \b Inputs: none + * @details \b Outputs: none + * @return TRUE if all operations were successfully enqueued otherwise FALSE + *************************************************************************/ +BOOL enqueuewriteAllRecords( void ) +{ + BOOL status = FALSE; + + if ( getAvailableRecordQueueCount() >= MIN_JOBS_NEEDED_TO_WRITE_ALL_RECORDS ) + { + NVM_RECORD_TYPE_T record; + + // Erase all the sectors + for ( record = NVM_SYSTEM_RECORD; record < NUM_OF_NVM_RECORD_TYPES; record++ ) + { + enqueueRecordJob( NVM_OPERATION_ERASE, record ); + } + + // Write all the records + for ( record = NVM_SYSTEM_RECORD; record < NUM_OF_NVM_RECORD_TYPES; record++ ) + { + enqueueRecordJob( NVM_OPERATION_WRITE, record ); + } + + status = TRUE; + } + + return status; +} + +/*********************************************************************//** + * @brief + * The enqueueReadAllRecords function enqueues all NV records to be read + * during POST. It schedules read jobs for all record types if sufficient + * queue space is available. + * @details \b Inputs: none + * @details \b Outputs: recordsReadStatus + * @return TRUE if records were successfully enqueued otherwise FALSE + *************************************************************************/ +BOOL enqueueReadAllRecords( void ) +{ + BOOL status = FALSE; + NVM_RECORD_TYPE_T record; + + if ( getAvailableRecordQueueCount() >= MIN_JOBS_NEEDED_TO_READ_ALL_RECORDS ) + { + for ( record = NVM_SYSTEM_RECORD; record < NUM_OF_NVM_RECORD_TYPES; record++ ) + { + enqueueRecordJob( NVM_OPERATION_READ, record ); + } + + status = TRUE; + } + + // Set the status to records were queued successfully + recordsReadStatus = NVM_RECORDS_QUEUED; + + return status; +} + +/*********************************************************************//** + * @brief + * The getNVRecordsReadStatus function returns the current NV records + * read status of the POST process. + * @details \b Inputs: recordsReadStatus + * @details \b Outputs: none + * @return recordsReadStatus + *************************************************************************/ +NVM_RECORDS_READ_STATUS_T getNVRecordsReadStatus( void ) +{ + return recordsReadStatus; +} + +/*********************************************************************//** + * @brief + * The updateRecordReadStatus function updates the NV records read + * status with the provided value. + * @details \b Inputs: none + * @details \b Outputs: recordsReadStatus + * @param status Record read status to be updated + * @return none + *************************************************************************/ +void updateRecordReadStatus( NVM_RECORDS_READ_STATUS_T status ) +{ + recordsReadStatus = status; +} + +/*********************************************************************//** + * @brief + * The getCurrentProcessRecordJob function gets the current record job + * from the processing queue. + * @details \b Inputs: recordCurrentJob + * @details \b Outputs: none + * @return recordCurrentJob + *************************************************************************/ +PROCESS_RECORD_JOB_T getCurrentProcessRecordJob ( void ) +{ + return recordCurrentJob; +} + + +/**@}*/ Index: firmware/App/Services/NVJobQ.h =================================================================== diff -u --- firmware/App/Services/NVJobQ.h (revision 0) +++ firmware/App/Services/NVJobQ.h (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -0,0 +1,81 @@ +/************************************************************************** +* +* Copyright (c) 2026-2027 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file NVJobQ.h +* +* @author (original) Arpita Srivastava +* @date (original) 31-Mar-2026 +* +***************************************************************************/ + +#ifndef _NV_JOB_Q_H_ +#define _NV_JOB_Q_H_ + +#include "Common.h" +#include "DDDefs.h" +#include "NVDriver.h" + +/** + * @defgroup NVJobQ NVJobQ + * @brief This module manages the NV record job queue. It provides interfaces + * to enqueue, dequeue, and monitor record operations such as read, + * write, and erase. It also maintains queue state, availability, and + * current job tracking for NV data processing. + * + * @addtogroup NVJobQ + * @{ + */ + +// ********** public definitions ********** + +#define NV_RECORD_SLOT_SIZE 4096 ///< Size of each NV record slot (4KB) + +#define SYSTEM_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of system record within sector +#define SERVICE_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of service record within sector +#define CAL_RECORD_OFFSET (1U * NV_RECORD_SLOT_SIZE) ///< Offset of calibration record within sector +#define INSTIT_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of institutional record within sector +#define USAGE_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of usage record within sector + +#define SYSTEM_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR0_START_ADDRESS + SYSTEM_RECORD_OFFSET ) ///< Start address of system record in NV memory +#define SERVICE_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR1_START_ADDRESS + SERVICE_RECORD_OFFSET ) ///< Start address of service record in NV memory +#define CAL_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR1_START_ADDRESS + CAL_RECORD_OFFSET ) ///< Start address of calibration record in NV memory +#define INSTIT_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR2_START_ADDRESS + INSTIT_RECORD_OFFSET ) ///< Start address of institutional record in NV memory +#define USAGE_INFO_START_ADDRESS ( BANK7_SECTOR3_START_ADDRESS + USAGE_RECORD_OFFSET ) ///< Start address of usage info record in NV memory + +#define MAX_NUM_OF_RECORD_IN_A_SECTOR 2 ///< Maximum number of records stored in one sector +#define MIN_JOBS_NEEDED_TO_WRITE_A_RECORD ( MAX_NUM_OF_RECORD_IN_A_SECTOR * 2 ) ///< Minimum queue jobs to erase and write one record +#define MIN_JOBS_NEEDED_TO_WRITE_ALL_RECORDS ( NUM_OF_NVM_RECORD_TYPES * 2 ) ///< Minimum queue jobs to erase and write all records +#define MIN_JOBS_NEEDED_TO_READ_ALL_RECORDS ( NUM_OF_NVM_RECORD_TYPES ) ///< Minimum queue jobs to read all records + +/// NVM records read status +typedef enum NVM_NV_Records_Read_Status +{ + NVM_RECORDS_NOT_STARTED = 0, ///< NVM records not started. + NVM_RECORDS_QUEUED, ///< NVM records queued. + NVM_RECORDS_READ, ///< NVM records read. + NVM_RECORDS_CRC_CHECKED, ///< NVM records CRC checked. + NUM_OF_NVM_READ_RECORDS_STATES, ///< Number of NVM read records states. +} NVM_RECORDS_READ_STATUS_T; + +// ********** public function prototypes ********** + +void initNVJobQ( void ); +// Record operations queue functions +void enqueueRecordJob( NVM_OPERATION_T ops, NVM_RECORD_TYPE_T job ); +void dequeueRecordJob( void ); +BOOL isRecordQueueEmpty( void ); +BOOL isRecordQueueFull( void ); +U32 getAvailableRecordQueueCount( void ); +BOOL enqueueEraseAndWriteSector( NVM_RECORD_TYPE_T job ); +BOOL enqueuewriteAllRecords( void ); +BOOL enqueueReadAllRecords( void ); +void updateRecordReadStatus( NVM_RECORDS_READ_STATUS_T status ); +PROCESS_RECORD_JOB_T getCurrentProcessRecordJob ( void ); + +/**@}*/ + +#endif /* _NV_JOB_Q_H_ */ Index: firmware/App/Services/NVMessaging.c =================================================================== diff -u --- firmware/App/Services/NVMessaging.c (revision 0) +++ firmware/App/Services/NVMessaging.c (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -0,0 +1,764 @@ +/************************************************************************** +* +* Copyright (c) 2026-2027 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file NVMessaging.c +* +* @author (original) Arpita Srivastava +* @date (original) 31-Mar-2026 +* +***************************************************************************/ + +#include // For ceilf function +#include "NVJobQ.h" +#include "NVMessaging.h" +#include "NVRecordsDD.h" +#include "OperationModes.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "Utilities.h" // For crc calculation + +/** + * @addtogroup NVMessaging + * @{ + */ + +// ********** private definitions ********** + +#define NEW_CAL_AVAILABLE_SIGNAL_TIMEOUT_MS (1 * MS_PER_SECOND) ///< New calibration available signal timeout in milliseconds. +#define NUM_OF_BYTES_PER_RECORD_PAYLOAD ( MAX_MSG_PAYLOAD_SIZE - ( sizeof( U32 ) * 3 ) ) ///< Number of bytes per calibration payload. +#define RECORD_DATA_SEND_INTERVAL_COUNT (MS_PER_SECOND / (5 * TASK_GENERAL_INTERVAL)) ///< Calibration data send time interval in counts. +#define RECORD_DATA_RECEIVE_TIMEOUT_MS (4 * MS_PER_SECOND) ///< Record data receive all the data packets timeout in ms. +#define RECORD_DATA_MAX_MESSAGE_DFFIRENCE 1 ///< Calibration data receive message different from the previous message. +#define RECORD_DATA_FIRST_RECEIVING_MSG_NUM 1 ///< Calibration data first receiving message number. + +/// NVM send records states +typedef enum NVM_Send_Records_States +{ + NVM_SEND_RECORD_STATE_IDLE = 0, ///< NVM process record idle state. + NVM_SEND_RECORD_STATE_SEND, ///< NVM process record send record state. + NUM_OF_NVM_SEND_RECORD_STATES ///< Number of NVM process records state. +} SEND_RECORD_STATE_T; + +/// NVM receive records states +typedef enum NVM_Receive_Records_States +{ + NVM_RECEIVE_RECORD_STATE_IDLE = 0, ///< NVM receive record idle. + NVM_RECEIVE_RECORD_STATE_RECEIVE, ///< NVM receive record receive. + NUM_OF_NVM_RECEIVE_RECORD_STATES ///< Number of NVM receive record. +} RECEIVE_RECORD_STATE_T; + +/// DD NVM Record Payload +typedef struct +{ + U32 payloadCurrNum; ///< Current Chunk number out of total number number of chunks + U32 payloadTotalNum; ///< Total number of chunks in which data is broken be sent + U32 length; ///< Length of data in the current chunk + U08 data[NUM_OF_BYTES_PER_RECORD_PAYLOAD]; ///< Data to be sent +} DD_NVM_SEND_RECORD_PAYLOAD_T; + +// ********** private data ********** + +static SEND_RECORD_STATE_T nvMExecSendRecordState; ///< NVM exec process record state. +static RECEIVE_RECORD_STATE_T nvmExecReceiveRecordState; ///< NVM exec receive record state. +static U32 newRecordStartTimer; ///< New record availability start timer. +static BOOL isNewCalRecordAvailable; ///< Signal to indicate whether a new NVM data is available. +static NVM_RECORD_TYPE_T recordToPublish; ///< Record type which is being processed currently for sending +static NVM_RECORD_TYPE_T nvPublishRecordType; ///< Used to index over isPublishRecordRequested in the idle state +static NVM_RECORD_TYPE_T currentRxRecordType; ///< Record type which is being processed currently for receiving +static U32 recordPublishMsgCount; ///< Record data publish message counter. +static U32 recordPublishTotalMsgs; ///< Record data total number of messages to be sent. +static U32 recordSendDataIntervalCounter; ///< Record data send to CAN bust interval counter. +static U32 previousRecordMessageNum; ///< Record previous message number. +static U32 recordUpdateAddress; ///< DD record update address for all the write operations. +static U32 recordReceiveStartTime; ///< Time stamp the calibration/service was received. +static BOOL isPublishRecordRequested[ NUM_OF_NVM_RECORD_TYPES ]; ///< Record state machine publish request flag. + +// ********** private function prototypes ********** + +// Process record functions +static SEND_RECORD_STATE_T handleExecSendRecordIdleState( void ); +static SEND_RECORD_STATE_T handleExecSendRecordSendState( void ); +static BOOL sendDDRecord( MSG_ID_T msgId, U32 payloadCurrNum, U32 payloadTotalNum, + U32 length, U08* calRcrdAddress ); +static BOOL receiveDDRecord( MESSAGE_T *message ); +static BOOL verifyAndSaveReceivedRecord( NVM_RECORD_TYPE_T job, U32 currentMessage, + U32 totalMessages, U32 length, U08 *addressPtr ); +static NVM_RECORD_TYPE_T getNVMRecordJobState( MSG_ID_T msgID ); +static MSG_ID_T getNVMRecordResponseMsgId (NVM_RECORD_TYPE_T job ); +static void monitorNewCalSignal( void ); + +/*********************************************************************//** + * @brief + * The initNVMessaging function initializes NV messaging related + * states and variables. It resets send and receive states, flags, + * counters, and timing values. + * @details \b Inputs: none + * @details \b Outputs: nvMExecSendRecordState, + * nvmExecReceiveRecordState, newRecordStartTimer, + * isNewCalRecordAvailable, nvPublishRecordType, + * isPublishRecordRequested, recordPublishMsgCount, + * recordPublishTotalMsgs, recordSendDataIntervalCounter, + * previousRecordMessageNum, recordReceiveStartTime + * @return none + *************************************************************************/ +void initNVMessaging( void ) +{ + nvMExecSendRecordState = NVM_SEND_RECORD_STATE_IDLE; + nvmExecReceiveRecordState = NVM_RECEIVE_RECORD_STATE_IDLE; + newRecordStartTimer = 0; + isNewCalRecordAvailable = FALSE; + nvPublishRecordType = NVM_SYSTEM_RECORD; + isPublishRecordRequested[ NVM_SYSTEM_RECORD ] = FALSE; + isPublishRecordRequested[ NVM_SERVICE_RECORD ] = FALSE; + isPublishRecordRequested[ NVM_CALIBRATION_RECORD ] = FALSE; + isPublishRecordRequested[ NVM_INSTITUTIONAL_RECORD ] = FALSE; + isPublishRecordRequested[ NVM_USAGE_INFO_RECORD ] = FALSE; + recordPublishMsgCount = 1; + recordPublishTotalMsgs = 1; + recordSendDataIntervalCounter = 0; + previousRecordMessageNum = 0; + recordReceiveStartTime = 0; +} + +/*********************************************************************//** + * @brief + * The execNVMPSendReceiveRecord function executes the NV record processing + * state machines. It handles send and receive operations and monitors + * for timeouts and calibration signals. + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid send state + * @details \b Inputs: nvMExecSendRecordState, + * nvmExecReceiveRecordState, recordReceiveStartTime + * @details \b Outputs: nvMExecSendRecordState, + * nvmExecReceiveRecordState + * @return none + *************************************************************************/ +void execNVMPSendReceiveRecord( void ) +{ + switch ( nvMExecSendRecordState ) + { + case NVM_SEND_RECORD_STATE_IDLE: + nvMExecSendRecordState = handleExecSendRecordIdleState(); + break; + + case NVM_SEND_RECORD_STATE_SEND: + nvMExecSendRecordState = handleExecSendRecordSendState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVM_INVALID_EXEC_SEND_STATE, ( U32 )nvMExecSendRecordState ); + nvMExecSendRecordState = NVM_SEND_RECORD_STATE_IDLE; + break; + } + + // Check if the exec receive records is not idle + // This section checks the status of the asynchronous state machine that receives + // data from Dialin. + if ( nvmExecReceiveRecordState != NVM_RECEIVE_RECORD_STATE_IDLE ) + { + // Check if the data receiving process has timed out. The exec receive record + // state machine is asynchronous so it is checked in this state machine + if ( TRUE == didTimeout( recordReceiveStartTime, RECORD_DATA_RECEIVE_TIMEOUT_MS ) ) + { + // Exec receive state machine timed out. Schedule a read to update the structure + enqueueRecordJob( NVM_OPERATION_READ, currentRxRecordType ); + nvmExecReceiveRecordState = NVM_RECEIVE_RECORD_STATE_IDLE; + } + } + + // Check the calibration signal + monitorNewCalSignal(); +} + +/*********************************************************************//** + * @brief + * The setNewCalibrationRecordAvailable function updates the flag + * indicating new NV record availability. + * @details \b Inputs: none + * @details \b Outputs: isNewCalRecordAvailable + * @param value Flag value to be updated + * @return none + *************************************************************************/ +void setNewCalibrationRecordAvailable( BOOL isAvailable) +{ + isNewCalRecordAvailable = isAvailable; +} + +/*********************************************************************//** + * @brief + * The getNewCalRecordAvalability function gets the status of new + * calibration record availability. + * @details \b Inputs: isNewCalRecordAvailable + * @details \b Outputs: none + * @return TRUE if new calibration record is available otherwise FALSE + *************************************************************************/ +BOOL getNewCalRecordAvalability( void ) +{ + return isNewCalRecordAvailable; +} + +/*********************************************************************//** + * @brief + * The startNewCalRecordAvailableTimer function starts the time for + * new calibration record availability. + * @details \b Inputs: none + * @details \b Outputs: newRecordStartTimer + * @return none + *************************************************************************/ +void startNewCalRecordAvailableTimer( void ) +{ + newRecordStartTimer = getMSTimerCount(); +} +/*********************************************************************//** + * @brief + * The handleExecSendRecordIdleState function handles the idle state of + * the exec send record state machine. It prepares record data for + * publishing when requested. + * @details \b Inputs: isPublishRecordRequested, + * nvPublishRecordType + * @details \b Outputs: isPublishRecordRequested, + * recordPublishTotalMsgs, recordPublishMsgCount, + * recordSendDataIntervalCounter, nvPublishRecordType, + * recordToPublish + * @return state next state of the state machine + *************************************************************************/ +static SEND_RECORD_STATE_T handleExecSendRecordIdleState( void ) +{ + SEND_RECORD_STATE_T state = NVM_SEND_RECORD_STATE_IDLE; + + if ( TRUE == isPublishRecordRequested[ nvPublishRecordType ] ) + { + recordToPublish = ( NVM_RECORD_TYPE_T )nvPublishRecordType; + + // Set the publish flag to FALSE + isPublishRecordRequested[ recordToPublish ] = FALSE; + + // Get the record specifications to find the size of the job + PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( recordToPublish ); + + // Calculate the total number of messages required to be sent using ceilf function. This function rounds up the + // value and its result is converted to U32. + recordPublishTotalMsgs = (U32)ceilf( (F32)recordSpec.sizeofRecord / (F32)NUM_OF_BYTES_PER_RECORD_PAYLOAD ); + recordPublishMsgCount = 0; + + // Time interval in between data to be sent. It is set to the interval count so on the first call + // of the send calibration record function, the first packet of data is sent + recordSendDataIntervalCounter = RECORD_DATA_SEND_INTERVAL_COUNT; + + state = NVM_SEND_RECORD_STATE_SEND; + } + + nvPublishRecordType = ( NVM_RECORD_TYPE_T )( nvPublishRecordType + 1 ); + if( nvPublishRecordType >= NUM_OF_NVM_RECORD_TYPES ) + { + nvPublishRecordType = NVM_SYSTEM_RECORD; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleExecSendRecordSendState function handles the send state of + * the exec send record state machine. It sends record data in chunks + * based on timing and message count. + * @details \b Inputs: recordPublishTotalMsgs, + * recordPublishMsgCount, recordSendDataIntervalCounter, + * recordToPublish + * @details \b Outputs: recordPublishMsgCount, + * recordSendDataIntervalCounter + * @return state next state of the state machine + *************************************************************************/ +static SEND_RECORD_STATE_T handleExecSendRecordSendState( void ) +{ + SEND_RECORD_STATE_T state = NVM_SEND_RECORD_STATE_SEND; + MSG_ID_T msgId; + + // If the current message number is less than the total, keep sending + if ( recordPublishMsgCount < recordPublishTotalMsgs ) + { + // If it is time to send data + if ( ++recordSendDataIntervalCounter >= RECORD_DATA_SEND_INTERVAL_COUNT ) + { + // Set to default cal data payload length + U32 length = NUM_OF_BYTES_PER_RECORD_PAYLOAD; + + PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( recordToPublish ); + U08* startPtr = recordSpec.structAddressPtr; + + // If this is the last calibration data payload, calculate the remainder of the bytes to send + if ( ( recordPublishMsgCount + 1 ) == recordPublishTotalMsgs ) + { + length = recordSpec.sizeofRecord - ( recordPublishMsgCount * NUM_OF_BYTES_PER_RECORD_PAYLOAD ); + } + + // Find the new location of the pointer which is the start of the calibration payload to be sent + startPtr += recordPublishMsgCount * NUM_OF_BYTES_PER_RECORD_PAYLOAD; + + // Get th message id of the NVM record response + msgId = getNVMRecordResponseMsgId( recordToPublish ); + + // Send the NVM record + sendDDRecord( msgId, recordPublishMsgCount + 1, recordPublishTotalMsgs, length, startPtr ); + + recordPublishMsgCount++; + recordSendDataIntervalCounter = 0; + } + } + else + { + state = NVM_SEND_RECORD_STATE_IDLE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The sendDDRecord function sends a DD record payload over communication. + * It prepares the payload and queues it for transmission. + * @details \b Inputs: none + * @details \b Outputs: none + * @param msgId Message Id for response record + * @param payloadCurrNum Current payload number + * @param payloadTotalNum Total number of payloads + * @param length Buffer length to be written + * @param recordAddress Start address of the record data + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +static BOOL sendDDRecord( MSG_ID_T msgId, U32 payloadCurrNum, U32 payloadTotalNum, + U32 length, U08* recordAddress ) +{ + BOOL result = FALSE; + U08 payloadLen = 0; + DD_NVM_SEND_RECORD_PAYLOAD_T payload; + + payloadLen = sizeof( U32 ) + sizeof( U32 ) + sizeof( U32 ) + length; + payload.payloadCurrNum = payloadCurrNum; + payload.payloadTotalNum = payloadTotalNum; + payload.length = length; + memcpy( payload.data, recordAddress, length ); + result = sendMessage( msgId, COMM_BUFFER_OUT_DD_CAN_PC, (U08 *)&payload, payloadLen ); + + return result; +} + +/*********************************************************************//** + * @brief + * The receiveDDRecord function processes a received DD record message. + * It extracts payload information and verifies the received data before + * saving it. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to received message structure + * @return TRUE if the record is successfully verified and saved, + * otherwise FALSE + *************************************************************************/ +static BOOL receiveDDRecord( MESSAGE_T *message ) +{ + BOOL status = FALSE; + U32 currentMessage; + U32 totalMessages; + U32 payloadLength; + + U08* payloadPtr = message->payload; + U08 minPayloadLen = ( sizeof(currentMessage) + sizeof(totalMessages) + sizeof(payloadLength) ); + MSG_ID_T msgID = (MSG_ID_T)message->hdr.msgID; + NVM_RECORD_TYPE_T job = getNVMRecordJobState( msgID ); + + // To proceed, the payload length should be valid. And, if it is a service job, then DD mode should also be in service. + if ( message->hdr.payloadLen >= minPayloadLen ) + { + memcpy(¤tMessage, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + memcpy(&totalMessages, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + memcpy(&payloadLength, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + status = verifyAndSaveReceivedRecord( job, currentMessage, totalMessages, payloadLength, payloadPtr ); + } + + return status; +} + +/*********************************************************************//** + * @brief + * The verifyAndSaveReceivedRecord function receives the record sent + * from Dialin, assembles it, validates it using CRC, and schedules a + * write to NV memory if valid. + * @details \b Inputs: nvmExecReceiveRecordState, + * @details \b Outputs: nvmExecReceiveRecordState, + * recordReceiveStartTime, previousRecordMessageNum, + * recordUpdateAddress, currentRxRecordType, + * @param job The job that has to be received and written + * @param currentMessage Current message number received from Dialin + * @param totalMessages Total number of messages from Dialin + * @param length Message length in bytes + * @param addressPtr Address to the beginning of received data from Dialin + * @return TRUE if the request was successfully registered + *************************************************************************/ +static BOOL verifyAndSaveReceivedRecord( NVM_RECORD_TYPE_T job, U32 currentMessage, + U32 totalMessages, U32 length, U08 *addressPtr ) +{ + BOOL status = TRUE; + + // If the calibration message number is the first message number and receive exec state is idle, switch to idle + if ( ( RECORD_DATA_FIRST_RECEIVING_MSG_NUM == currentMessage ) && + ( NVM_RECEIVE_RECORD_STATE_IDLE == nvmExecReceiveRecordState ) ) + { + nvmExecReceiveRecordState = NVM_RECEIVE_RECORD_STATE_RECEIVE; + currentRxRecordType = job; + recordReceiveStartTime = getMSTimerCount(); + previousRecordMessageNum = 0; + recordUpdateAddress = 0; + } + + // Check if there is still a message left to be received + if ( ( NVM_RECEIVE_RECORD_STATE_RECEIVE == nvmExecReceiveRecordState ) && + ( currentMessage <= totalMessages ) ) + { + // Check if the current message is different from the previous message by 1 + if ( RECORD_DATA_MAX_MESSAGE_DFFIRENCE == ( currentMessage - previousRecordMessageNum ) ) + { + // Define a pointer that points to the temporary receive record + PROCESS_RECORD_SPECS_T tempRxSpec = getTemporaryRxRecord( job ); + U08* tempRxPtr = tempRxSpec.structAddressPtr; + + // Get the DD main nvm record + PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( job ); + + // Offset the pointer to length that we should start writing from + tempRxPtr += recordUpdateAddress; + + memcpy( tempRxPtr, addressPtr, length ); + + // Check if the current message is total messages + // and 0 everything out since we are done writing + if ( currentMessage == totalMessages ) + { + U16 calcCRC = crc16 ( tempRxSpec.structAddressPtr, + tempRxSpec.sizeofRecord - sizeof(U16) ); + // Get the CRC of the structure without the last 16 bits which is the CRC as well as the padding values + U16 recordCRC = *(U16*)tempRxSpec.structCRCPtr; + + // Check if calculated CRC matches the Stored CRC + if ( ( calcCRC == recordCRC ) ) + { + _disable_IRQ(); + // Copy the valid temporary record into the main record spec + memcpy(recordSpec.structAddressPtr, tempRxSpec.structAddressPtr, tempRxSpec.sizeofRecord); + _enable_IRQ(); + + // Enqueue an erase and write of the nvm record + status = enqueueEraseAndWriteSector( job ); + + if( NVM_CALIBRATION_RECORD == job ) + { + // Signal that there is a new calibration record available. + // NOTE: as of now, this signal will be sent even after the system record is sent + startNewCalRecordAvailableTimer(); + setNewCalibrationRecordAvailable( TRUE ); + } + + // Update the event of the received record that has been accepted + SEND_EVENT_WITH_2_U32_DATA( recordSpec.nvEvent, 0, 0 ); + + // Done with receiving data, go back to idle + nvmExecReceiveRecordState = NVM_RECEIVE_RECORD_STATE_IDLE; + } + else + { + // CRC match failed, go to idle + nvmExecReceiveRecordState = NVM_RECEIVE_RECORD_STATE_IDLE; + status = FALSE; + } + } + else + { + // Update the length as it has successfully been written + recordUpdateAddress += length; + + // Now the current message is the previous message + previousRecordMessageNum = currentMessage; + } + } + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getNVMRecordJobState function maps the received message ID to + * the corresponding NV record job type. + * @details \b Inputs: none + * @details \b Outputs: none + * @param msgID Message ID received + * @return job corresponding NV record type + *************************************************************************/ +static NVM_RECORD_TYPE_T getNVMRecordJobState( MSG_ID_T msgID ) +{ + NVM_RECORD_TYPE_T job; + + switch ( msgID ) + { + case MSG_ID_DD_NVM_SET_CALIBRATION_RECORD: + job = NVM_CALIBRATION_RECORD; + break; + + case MSG_ID_DD_NVM_SET_SYSTEM_RECORD: + job = NVM_SYSTEM_RECORD; + break; + + case MSG_ID_DD_NVM_SET_SERVICE_RECORD: + job = NVM_SERVICE_RECORD; + break; + + case MSG_ID_DD_NVM_SET_INSTITUTIONAL_RECORD: + job = NVM_INSTITUTIONAL_RECORD; + break; + + case MSG_ID_DD_NVM_SET_USAGE_INFO_RECORD: + job = NVM_USAGE_INFO_RECORD; + break; + + default: + // Do nothing for Invalid Input from Dialin + break; + } + + return job; +} + +/*********************************************************************//** + * @brief + * The getNVMRecordResponseMsgId function maps the NV record type to + * the corresponding response message ID. + * provided + * @details \b Inputs: none + * @details \b Outputs: none + * @param job NV record type + * @return msgID corresponding response message ID + *************************************************************************/ +static MSG_ID_T getNVMRecordResponseMsgId( NVM_RECORD_TYPE_T job ) +{ + MSG_ID_T msgID; + + switch( job ) + { + case NVM_CALIBRATION_RECORD: + msgID = MSG_ID_DD_NVM_SEND_CALIBRATION_RECORD; + break; + + case NVM_SYSTEM_RECORD: + msgID = MSG_ID_DD_NVM_SEND_SYSTEM_RECORD; + break; + + case NVM_SERVICE_RECORD: + msgID = MSG_ID_DD_NVM_SEND_SERVICE_RECORD; + break; + + case NVM_INSTITUTIONAL_RECORD: + msgID = MSG_ID_DD_NVM_SEND_INSTITUTIONAL_RECORD; + break; + + case NVM_USAGE_INFO_RECORD: + msgID = MSG_ID_DD_NVM_SEND_USAGE_INFO_RECORD; + break; + + default: + // Do nothing for Invalid Input from Dialin + break; + } + + return msgID; +} + +/*********************************************************************//** + * @brief + * The monitorNewCalSignal function monitors the new calibration signal + * and clears it when the timeout has elapsed. + * @details \b Inputs: isNewCalRecordAvailable, + * newRecordStartTimer + * @details \b Outputs: isNewCalRecordAvailable + * @return none + *************************************************************************/ + +static void monitorNewCalSignal( void ) +{ + // Check if new calibration record is available and + // the timer has elapsed + if ( ( TRUE == didTimeout( newRecordStartTimer, NEW_CAL_AVAILABLE_SIGNAL_TIMEOUT_MS ) ) && + ( TRUE == getNewCalRecordAvalability() ) ) + { + // Clear the new calibration record available flag + setNewCalibrationRecordAvailable( FALSE ); + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testDDGetNVRecord function processes a request to publish an NV + * record. It validates the payload and sets the publish request flag + * for the selected record. + * @details \b Inputs: nvMExecSendRecordState + * @details \b Outputs: isPublishRecordRequested, + * recordToPublish + * @param message Pointer to the received message + * @return TRUE if the request is accepted otherwise FALSE + *************************************************************************/ +BOOL testDDGetNVRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + NVM_RECORD_TYPE_T job; + + // verify payload length + if ( 1 == message->hdr.payloadLen ) + { + job = ( NVM_RECORD_TYPE_T )message->payload[ 0 ]; + + // Accept the request only if the send exec is in the idle state + if ( ( job < NUM_OF_NVM_RECORD_TYPES ) && + ( NVM_SEND_RECORD_STATE_IDLE == nvMExecSendRecordState ) ) + { + isPublishRecordRequested[ job ] = TRUE; + recordToPublish = job; + result = TRUE; + } + + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testDDSetNVSystemRecord function processes a request to update + * the system record. It allows updates only when the system is in + * service mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to the received message + * @return TRUE if the record is successfully processed otherwise FALSE + *************************************************************************/ +BOOL testDDSetNVSystemRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // System record can be updated only in service mode + if ( DD_MODE_SERV == getCurrentOperationMode() ) + { + result = receiveDDRecord( message ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testDDSetNVServiceRecord function processes a request to update + * the service record. It allows updates only when the system is in + * service mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to the received message + * @return TRUE if the record is successfully processed otherwise FALSE + *************************************************************************/ +BOOL testDDSetNVServiceRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Service record can be updated only in service mode + if ( DD_MODE_SERV == getCurrentOperationMode() ) + { + result = receiveDDRecord( message ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testDDSetNVCalibrationRecord function processes a request to + * update the calibration record. It allows updates only when the + * system is in service mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to the received message + * @return TRUE if the record is successfully processed otherwise FALSE + *************************************************************************/ +BOOL testDDSetNVCalibrationRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Calibration record can be updated only in service mode + if ( DD_MODE_SERV == getCurrentOperationMode() ) + { + result = receiveDDRecord( message ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testDDSetNVInstitutionalRecord function processes a request to + * update the institutional record. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to the received message + * @return TRUE if the record is successfully processed otherwise FALSE + *************************************************************************/ +BOOL testDDSetNVInstitutionalRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + result = receiveDDRecord( message ); + return result; +} + +/*********************************************************************//** + * @brief + * The testDDSetNVUsageInfoRecord function processes a request to + * update the usage information record. + * @details \b Inputs: none + * @details \b Outputs: none + * @param message Pointer to the received message + * @return TRUE if the record is successfully processed otherwise FALSE + *************************************************************************/ +BOOL testDDSetNVUsageInfoRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + result = receiveDDRecord( message ); + return result; +} + +/*********************************************************************//** + * @brief + * The testSetNVRecordCRCOverride function overrides the CRC value of + * the selected non-volatile record and schedules it for writing. + * @details \b Inputs: none + * @details \b Outputs: none + * @param job The job whose CRC needs to be overridden + * @param crc The CRC value to be set + * @return TRUE if the job was scheduled successfully otherwise FALSE + *************************************************************************/ +BOOL testSetNVRecordCRCOverride( U32 job, U16 crc ) +{ + BOOL result = FALSE; + result = updateNVRecordCRC( job, crc ); + return result; +} + +/**@}*/ Index: firmware/App/Services/NVMessaging.h =================================================================== diff -u --- firmware/App/Services/NVMessaging.h (revision 0) +++ firmware/App/Services/NVMessaging.h (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -0,0 +1,51 @@ +/************************************************************************** +* +* Copyright (c) 2026-2027 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file NVMessaging.h +* +* @author (original) Arpita Srivastava +* @date (original) 31-Mar-2026 +* +***************************************************************************/ + +#ifndef _NV_MESSAGING_H_ +#define _NV_MESSAGING_H_ + +#include "Common.h" + +/** + * @defgroup NVMessaging NVMessaging + * @brief This module handles NV record messaging including sending and + * receiving records over communication interfaces. It manages + * publish requests, record transmission sequencing, and reception + * of record data from external sources. It also provides support + * for signaling new calibration record availability and includes + * test interfaces for setting and getting different NV records + * + * + * @addtogroup NVMessaging + * @{ + */ + +// ********** public function prototypes ********** + +void initNVMessaging( void ); +void execNVMPSendReceiveRecord( void ); +void setNewCalibrationRecordAvailable( BOOL isAvailable ); +BOOL getNewCalRecordAvalability( void ); +void startNewCalRecordAvailableTimer( void ); + +BOOL testDDGetNVRecord( MESSAGE_T *message ); +BOOL testDDSetNVSystemRecord( MESSAGE_T *message ); +BOOL testDDSetNVServiceRecord( MESSAGE_T *message ); +BOOL testDDSetNVCalibrationRecord( MESSAGE_T *message ); +BOOL testDDSetNVInstitutionalRecord( MESSAGE_T *message ); +BOOL testDDSetNVUsageInfoRecord( MESSAGE_T *message ); + +/**@}*/ + +#endif /* _NV_MESSAGING_H_ */ Index: firmware/App/Services/NVMgmtDD.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Services/NVMgmtDD.c (.../NVMgmtDD.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Services/NVMgmtDD.c (.../NVMgmtDD.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -15,8 +15,9 @@ #include // For memcpy #include "Common.h" #include "NVDriver.h" +#include "NVJobQ.h" #include "NVMgmtDD.h" -#include "NVMsgQ.h" +#include "NVMessaging.h" #include "NVRecordsDD.h" #include "Timers.h" @@ -35,10 +36,10 @@ typedef enum NVM_Exec_State { NVM_EXEC_STATE_IDLE = 0, ///< Exec state Idle. - NVM_EXEC_STATE_WRITE, ///< Exec state write to EEPROM. - NVM_EXEC_STATE_VERIFY_WRITE, ///< Exec state verify EEPROM write. - NVM_EXEC_STATE_READ, ///< Exec state read from EEPROM. - NVM_EXEC_STATE_ERASE, ///< Exec state erase EEPROM. + NVM_EXEC_STATE_WRITE, ///< Exec state write to EEPROM. + NVM_EXEC_STATE_VERIFY_WRITE, ///< Exec state verify EEPROM write. + NVM_EXEC_STATE_READ, ///< Exec state read from EEPROM. + NVM_EXEC_STATE_ERASE, ///< Exec state erase EEPROM. NUM_OF_NVM_EXEC_STATES ///< Total number of exec states. } NVM_EXEC_STATE_T; @@ -92,7 +93,8 @@ recordAddressOffset = 0; initNVDriver(); - initNVMsgQ(); + initNVJobQ(); + initNVMessaging(); initNVRecordsDD(); enqueueReadAllRecords(); } @@ -152,6 +154,89 @@ } /*********************************************************************//** + * @brief + * The resetNVMPOSTState function resets the NV data management POST + * state and sets the self-test to start reading all the records. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ + +void resetNVMPOSTState( void ) +{ + updateNVSelfTestResult( SELF_TEST_STATUS_IN_PROGRESS ); + updateNVSelfTestState( NVM_SELF_TEST_STATE_READ_RECORDS ); +} + +/*********************************************************************//** + * @brief + * The isNewCalibrationRecordAvailable function returns the status of + * new calibration record availability. + * @details \b Inputs: none + * @details \b Outputs: none + * @return TRUE if new calibration is available otherwise FALSE + *************************************************************************/ +BOOL isNewCalibrationRecordAvailable( void ) +{ + return getNewCalRecordAvalability(); +} + +/*********************************************************************//** + * @brief + * The getNVRecord2Driver function retrieves NV data by calling the + * record handler after validating input parameters. + * @details \b Inputs: none + * @details \b Outputs: none + * @param nvData The non-volatile data identifier + * @param bufferAddress Pointer to the buffer where data will be copied + * @param bufferLength Length of the provided buffer + * @param numOfSnsrs2Check Number of sensors to check + * @param nvAlarm Alarm to raise if data is invalid + * @return TRUE if the operation is successful otherwise FALSE + *************************************************************************/ +BOOL getNVRecord2Driver( NV_DATA_T nvData, U08* bufferAddress, U32 bufferLength, + U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ) +{ + BOOL status = FALSE; + + if ( ( nvData < NUM_OF_NV_DD_DATA ) && + ( NULL != bufferAddress ) && + ( bufferLength > 0U ) ) + { + status = getNVMRecord(nvData, bufferAddress, + bufferLength, numOfSnsrs2Check, nvAlarm); + } + + return status; +} + +/*********************************************************************//** + * @brief + * The execNVMProcessRecord function executes the NVM process record + * handler. + * @details \b Inputs: none + * @details \b Outputs: none + * @return none + *************************************************************************/ +void execNVMProcessRecord( void ) +{ + execNVMPSendReceiveRecord(); +} + +/*********************************************************************//** + * @brief + * The execNVMSelfTest function executes the NV management self-test + * handler. + * @details \b Inputs: none + * @details \b Outputs: none + * @return SELF_TEST_STATUS_T self-test result + *************************************************************************/ +SELF_TEST_STATUS_T execNVMSelfTest( void ) +{ + return execNVMRecordsSelfTest(); +} + +/*********************************************************************//** * @brief * The handleExecIdleState function processes the idle state of the * NVM execution state machine. It checks for pending record jobs and @@ -403,78 +488,10 @@ return state; } -/*********************************************************************//** - * @brief - * The resetNVMPOSTState function resets the NV data management POST - * state and sets the self-test to start reading all the records. - * @details \b Inputs: none - * @details \b Outputs: none - * @return none - *************************************************************************/ -void resetNVMPOSTState( void ) -{ - updateNVSelfTestResult( SELF_TEST_STATUS_IN_PROGRESS ); - updateNVSelfTestState( NVM_SELF_TEST_STATE_READ_RECORDS ); -} /*********************************************************************//** * @brief - * The execNVMProcessRecord function executes the NVM process record - * handler. - * @details \b Inputs: none - * @details \b Outputs: none - * @return none - *************************************************************************/ -void execNVMProcessRecord( void ) -{ - execNVMPSendReceiveRecord(); -} - -/*********************************************************************//** - * @brief - * The execNVMSelfTest function executes the NV management self-test - * handler. - * @details \b Inputs: none - * @details \b Outputs: none - * @return SELF_TEST_STATUS_T self-test result - *************************************************************************/ -SELF_TEST_STATUS_T execNVMSelfTest( void ) -{ - execNVMRecordsSelfTest(); -} - -/*********************************************************************//** - * @brief - * The getNVRecord2Driver function retrieves NV data by calling the - * record handler after validating input parameters. - * @details \b Inputs: none - * @details \b Outputs: none - * @param nvData The non-volatile data identifier - * @param bufferAddress Pointer to the buffer where data will be copied - * @param bufferLength Length of the provided buffer - * @param numOfSnsrs2Check Number of sensors to check - * @param nvAlarm Alarm to raise if data is invalid - * @return TRUE if the operation is successful otherwise FALSE - *************************************************************************/ -BOOL getNVRecord2Driver( NV_DATA_T nvData, U08* bufferAddress, U32 bufferLength, - U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ) -{ - BOOL status = FALSE; - - if ( ( nvData < NUM_OF_NV_DD_DATA ) && - ( NULL != bufferAddress ) && - ( bufferLength > 0U ) ) - { - status = getNVMRecord(nvData, bufferAddress, - bufferLength, numOfSnsrs2Check, nvAlarm); - } - - return status; -} - -/*********************************************************************//** - * @brief * The didCommandTimeout function checks whether the command has timed * out. If a timeout occurs, it sets an alarm and returns TRUE. * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if command timeout Index: firmware/App/Services/NVMgmtDD.h =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Services/NVMgmtDD.h (.../NVMgmtDD.h) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Services/NVMgmtDD.h (.../NVMgmtDD.h) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -20,7 +20,11 @@ /** * @defgroup NVMgmtDD NVMgmtDD - * @brief + * @brief This module provides the top-level NV data management interface used + * by other system modules. + * It initializes and executes NV operations, manages POST self-test, + * handles power-off conditions, and provides APIs to access NV records. + * It also integrates lower-level NV messaging and record handling modules. * * @addtogroup NVMgmtDD * @{ @@ -33,12 +37,13 @@ void execNVM( void ); void resetNVMPOSTState( void ); -// Wrapper functions to other NVM files -void execNVMProcessRecord( void ); -SELF_TEST_STATUS_T execNVMSelfTest( void ); +BOOL isNewCalibrationRecordAvailable( void ); BOOL getNVRecord2Driver( NV_DATA_T nvData, U08* bufferAddress, U32 bufferLength, U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ); +// Wrapper functions to other NVM files +void execNVMProcessRecord( void ); +SELF_TEST_STATUS_T execNVMSelfTest( void ); /**@}*/ #endif /* _NV_MGMT_DD_H_ */ Fisheye: Tag 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 refers to a dead (removed) revision in file `firmware/App/Services/NVMsgQ.c'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 refers to a dead (removed) revision in file `firmware/App/Services/NVMsgQ.h'. Fisheye: No comparison available. Pass `N' to diff? Index: firmware/App/Services/NVRecordsDD.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Services/NVRecordsDD.c (.../NVRecordsDD.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Services/NVRecordsDD.c (.../NVRecordsDD.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -15,7 +15,8 @@ #include // For memcpy //#include "Common.h" #include "DDDefs.h" -#include "NVMsgQ.h" +#include "NVJobQ.h" +#include "NVMessaging.h" #include "NVRecordsDD.h" #include "Timers.h" #include "Utilities.h" // For crc calculation @@ -97,42 +98,42 @@ /// DG calibration records structure typedef struct { - DD_CALIBRATION_GROUPS_T ddCalibrationGroups; ///< DD calibration groups. - U08 padding[ RECORD_PADDING_LENGTH(DD_CALIBRATION_GROUPS_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD calibration record padding byte array. - U16 crc; ///< CRC for the DG calibration record structure. + DD_CALIBRATION_GROUPS_T ddCalibrationGroups; ///< DD calibration groups. + U08 padding[ RECORD_PADDING_LENGTH(DD_CALIBRATION_GROUPS_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD calibration record padding byte array. + U16 crc; ///< CRC for the DG calibration record structure. } DD_CALIBRATION_RECORD_T; /// DG system group structure typedef struct { - DD_SYSTEM_RECORD_T ddSystemRecord; ///< DD system record. - U08 padding[ RECORD_PADDING_LENGTH(DD_SYSTEM_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD system group padding byte array. - U16 crc; ///< CRC for the DG system group structure. + DD_SYSTEM_RECORD_T ddSystemRecord; ///< DD system record. + U08 padding[ RECORD_PADDING_LENGTH(DD_SYSTEM_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD system group padding byte array. + U16 crc; ///< CRC for the DG system group structure. } DD_SYSTEM_GROUP_T; /// DG service record structure typedef struct { - DD_SERVICE_RECORD_T ddServiceRecord; ///< DD service record. - U08 padding[ RECORD_PADDING_LENGTH(DD_SERVICE_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD service group padding. - U16 crc; ///< CRC for the DG service structure. + DD_SERVICE_RECORD_T ddServiceRecord; ///< DD service record. + U08 padding[ RECORD_PADDING_LENGTH(DD_SERVICE_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD service group padding. + U16 crc; ///< CRC for the DG service structure. } DD_SERVICE_GROUP_T; /// DD institutional record structure typedef struct { - DD_INSTITUTIONAL_RECORD_T ddInstitutionalRecord; ///< DD institutional record. - U08 padding[ RECORD_PADDING_LENGTH(DD_INSTITUTIONAL_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD institutional group padding. - U16 crc; ///< CRC for the HD institutional structure. + DD_INSTITUTIONAL_RECORD_T ddInstitutionalRecord; ///< DD institutional record. + U08 padding[ RECORD_PADDING_LENGTH(DD_INSTITUTIONAL_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD institutional group padding. + U16 crc; ///< CRC for the HD institutional structure. } DD_INSTITUTIONAL_GROUP_T; /// DG usage record structure typedef struct { - DD_USAGE_INFO_RECORD_T ddUsageInfo; ///< DD usage info record. - U08 padding[ RECORD_PADDING_LENGTH(DD_USAGE_INFO_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD scheduled run group padding. - U16 crc; ///< CRC for the DG usage info structure. + DD_USAGE_INFO_RECORD_T ddUsageInfo; ///< DD usage info record. + U08 padding[ RECORD_PADDING_LENGTH(DD_USAGE_INFO_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DD scheduled run group padding. + U16 crc; ///< CRC for the DG usage info structure. } DD_USAGE_INFO_GROUP_T; #pragma pack(pop) @@ -364,8 +365,8 @@ if ( ( TRUE == hasSystemRecordPassed ) && ( TRUE == hasServiceRecordPassed ) && ( TRUE == haveCalGroupsPassed ) && ( TRUE == hasUsageRecordPassed ) ) { - updateRecordStartTimer( getMSTimerCount() ); - updateNewNVRecordAvailableFlag( TRUE ); + startNewCalRecordAvailableTimer(); + setNewCalibrationRecordAvailable( TRUE ); nvmSelfTestResult = SELF_TEST_STATUS_PASSED; } else @@ -1162,7 +1163,7 @@ /*********************************************************************//** * @brief - * The testSetNVRecordCRCOverride function overrides the CRC value of + * The updateNVRecordCRC function overrides the CRC value of * the selected non-volatile record and schedules it for writing. * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid job is * selected @@ -1173,7 +1174,7 @@ * @param crc The CRC value to be set * @return TRUE if the job was scheduled successfully otherwise FALSE *************************************************************************/ -BOOL testSetNVRecordCRCOverride( U32 job, U16 crc ) +BOOL updateNVRecordCRC( U32 job, U16 crc ) { BOOL status = FALSE; NVM_RECORD_TYPE_T nvJob = (NVM_RECORD_TYPE_T)job; Index: firmware/App/Services/NVRecordsDD.h =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Services/NVRecordsDD.h (.../NVRecordsDD.h) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Services/NVRecordsDD.h (.../NVRecordsDD.h) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -297,7 +297,7 @@ // ********** public function prototypes ********** void initNVRecordsDD( void ); -SELF_TEST_STATUS_T execNVMRecordsSelfTest ( void ); +SELF_TEST_STATUS_T execNVMRecordsSelfTest( void ); PROCESS_RECORD_SPECS_T getProcessRecord( NVM_RECORD_TYPE_T job ); PROCESS_RECORD_SPECS_T getTemporaryRxRecord( NVM_RECORD_TYPE_T job ); void benignPolynomialCalRecord( POLYNOMIAL_CAL_PAYLOAD_T* record ); @@ -306,11 +306,11 @@ U32 getMinRORejectionRatioInInstitRecordPCT( void ); F32 getMinInletWaterConductivityLimitInstitRecordUSPCM( void ); BOOL getNVMRecord( NV_DATA_T nvData, U08* bufferAddress, U32 bufferLength, - U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ); + U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ); void updateNVSelfTestResult( SELF_TEST_STATUS_T result ); void updateNVSelfTestState( NVM_SELF_TEST_STATE_T state ); void updateSelfTestReadRecordsFlag ( BOOL value ); -BOOL testSetNVRecordCRCOverride( U32 job, U16 crc ); +BOOL updateNVRecordCRC( U32 job, U16 crc ); /**@}*/ #endif /* _NV_RECORDS_DD_H_ */ Index: firmware/App/Tasks/TaskBG.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Tasks/TaskBG.c (.../TaskBG.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Tasks/TaskBG.c (.../TaskBG.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -17,7 +17,7 @@ #include "gio.h" -//#include "NVMgmtDD.h" +#include "NVMgmtDD.h" #include "TaskTimer.h" #include "WatchdogMgmt.h" @@ -45,7 +45,7 @@ execWatchdogMgmt(); // Manage Non-volatile data manager - //execNVM(); + execNVM(); } } Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r9a14f69c0f0de343b5664b20753142b50bc4e093 -r6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 9a14f69c0f0de343b5664b20753142b50bc4e093) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 6d1ea33dbe56d63b13802cacd09c263a5ee7e6e0) @@ -25,7 +25,7 @@ #include "Heaters.h" #include "FPOperationModes.h" #include "Messaging.h" -//#include "NVMgmtDD.h" +#include "NVMgmtDD.h" #include "OperationModes.h" #include "PermeateTank.h" #include "RinsePump.h" @@ -124,7 +124,7 @@ // Run non-volatile data management state machine that sends the data record // to Dialin - //execNVMProcessRecord(); + execNVMProcessRecord(); // Run alarm management execAlarmMgmt();