/************************************************************************** * * 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 NVMessagingDD.c * * @author (original) Arpita Srivastava * @date (original) 31-Mar-2026 * ***************************************************************************/ #include // For ceilf function #include "NVJobQ.h" #include "NVMessagingDD.h" #include "NVRecordsDD.h" #include "OperationModes.h" #include "TaskGeneral.h" #include "Timers.h" #include "Utilities.h" // For crc calculation /** * @addtogroup NVMessagingDD * @{ */ // ********** 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 ) ) ) ///< 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 idx; ///< Index of sensor / pump / concentrates 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 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 calRecordReceiveStartTime; ///< Time stamp the calibration record was received. static U32 institRecordReceiveStartTime; ///< Time stamp the institutional record was received. 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 sendDDSystemRecord( void ); static BOOL sendDDServiceRecord( void ); static BOOL sendDDCalibrationRecord( void ); static BOOL sendDDInstitutionalRecord( void ); static BOOL sendDDUsageInfoRecord( void ); static BOOL sendDDRecord( MSG_ID_T msgId, U32 idx, U32 length, U08* recordAddress ); static BOOL receiveDDRecord( MESSAGE_T *message, NVM_RECORD_TYPE_T recordType, U16 recordSize ); static BOOL receiveCalRecord( MESSAGE_T *message, DD_CAL_REC_TYPE calRecordType, U16 recordSize ); static BOOL receiveInstitRecord( 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 initNVMessagingDD 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 initNVMessagingDD( 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; recordSendDataIntervalCounter = 0; previousRecordMessageNum = 0; recordReceiveStartTime = 0; } /*********************************************************************//** * @brief * The execNVMPSendreceiveDDRecord 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; } if( nvmExecreceiveRecordState == NVM_RECEIVE_RECORD_STATE_RECEIVE ) { if ( TRUE == didTimeout( calRecordReceiveStartTime, RECORD_DATA_RECEIVE_TIMEOUT_MS ) ) { // Exec receive state machine timed out. Schedule a read to update the structure enqueueEraseAndWriteSector( NVM_CALIBRATION_RECORD ); startNewCalRecordAvailableTimer(); setNewCalibrationRecordAvailable( TRUE ); PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( NVM_CALIBRATION_RECORD ); sendNVEvent( NVM_CALIBRATION_RECORD , 0, 0 ); nvmExecreceiveRecordState = NVM_RECEIVE_RECORD_STATE_IDLE; } if ( TRUE == didTimeout( institRecordReceiveStartTime, RECORD_DATA_RECEIVE_TIMEOUT_MS ) ) { // Exec receive state machine timed out. Schedule a read to update the structure enqueueEraseAndWriteSector( NVM_INSTITUTIONAL_RECORD ); PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( NVM_INSTITUTIONAL_RECORD ); sendNVEvent( NVM_INSTITUTIONAL_RECORD , 0, 0 ); 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; // 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; // If it is time to send data if ( ++recordSendDataIntervalCounter >= RECORD_DATA_SEND_INTERVAL_COUNT ) { switch(recordToPublish) { case NVM_SYSTEM_RECORD: sendDDSystemRecord(); break; case NVM_SERVICE_RECORD: sendDDServiceRecord(); break; case NVM_CALIBRATION_RECORD: sendDDCalibrationRecord(); break; case NVM_INSTITUTIONAL_RECORD: sendDDInstitutionalRecord(); break; case NVM_USAGE_INFO_RECORD: sendDDUsageInfoRecord(); break; default: break; } recordSendDataIntervalCounter = 0; state = NVM_SEND_RECORD_STATE_IDLE; } return state; } static BOOL sendDDSystemRecord( void ) { BOOL sysStatus = FALSE; DD_SYSTEM_RECORD_T* systemRecord; sysStatus = getNVMRecord( GET_SYSTEM_RECORD, (U08*)&systemRecord, sizeof( DD_SYSTEM_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_SYSTEM_RECORD_CRC ); sysStatus = sendDDRecord( MSG_ID_DD_NVM_SYSTEM_RECORD_RESPONSE, 0, sizeof(DD_SYSTEM_RECORD_T), (U08*)&systemRecord ); return sysStatus; } static BOOL sendDDServiceRecord( void ) { BOOL serStatus = FALSE; DD_SERVICE_RECORD_T* serviceRecord; serStatus = getNVMRecord( GET_SERVICE_RECORD, (U08*)&serviceRecord, sizeof( DD_SERVICE_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_SYSTEM_RECORD_CRC ); serStatus = sendDDRecord( MSG_ID_DD_NVM_SERVICE_RECORD_RESPONSE, 0, sizeof(DD_SERVICE_RECORD_T), (U08*)&serviceRecord ); return serStatus; } static BOOL sendDDCalibrationRecord( void ) { BOOL calStatus = FALSE; int i; DD_PRES_SENSORS_CAL_RECORD_T* pressure; calStatus = getNVMRecord( GET_CAL_PRESSURE_SENOSRS, (U08*)&pressure, sizeof( DD_PRES_SENSORS_CAL_RECORD_T ), NUM_OF_PRESSURE_SENSORS, ALARM_ID_DD_NVM_INVALID_CAL_PRESSURE_SENSOR ); for ( i = 0; i < NUM_OF_PRESSURE_SENSORS; i++ ) { calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_PRESSURE_SENSOR_RESPONSE, i, sizeof(DD_PRES_SENSORS_CAL_RECORD_T), (U08*)&pressure->pressureSensors[ i ] ); } DD_TEMP_SENSORS_CAL_RECORD_T* temperature; calStatus = getNVMRecord( GET_CAL_TEMP_SENSORS, (U08*)&temperature, sizeof( DD_TEMP_SENSORS_CAL_RECORD_T ), NUM_OF_TEMPERATURE_SENSORS, ALARM_ID_DD_NVM_INVALID_CAL_TEMP_SENSOR ); for ( i = 0; i < NUM_OF_TEMPERATURE_SENSORS; i++ ) { calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_TEMP_SENSOR_RESPONSE, i, sizeof(DD_PRES_SENSORS_CAL_RECORD_T), (U08*)&temperature->tempSensors[ i ] ); } DD_CONC_PUMPS_CAL_RECORD_T* concPump; calStatus = getNVMRecord( GET_CAL_CONCENTRATE_PUMPS_RECORD, (U08*)&concPump, sizeof( DD_CONC_PUMPS_CAL_RECORD_T ), NUM_OF_CONCENTRATE_PUMPS, ALARM_ID_DD_NVM_INVALID_CAL_CONC_PUMP ); for ( i = 0; i < NUM_OF_CONCENTRATE_PUMPS; i++ ) { calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_CONC_PUMP_RESPONSE, i, sizeof(DD_CONC_PUMPS_CAL_RECORD_T), (U08*)&concPump->concentratePumps[ i ] ); } DD_D12_DIALYSATE_PUMP_RECORD_T* d12Pump; calStatus = getNVMRecord( GET_CAL_D12_PUMP_RECORD, (U08*)&d12Pump, sizeof( DD_D12_DIALYSATE_PUMP_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_CAL_D12_PUMP ); calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_D12_PUMP_RESPONSE, 0, sizeof(DD_D12_DIALYSATE_PUMP_RECORD_T), (U08*)&d12Pump ); DD_D48_DIALYSATE_PUMP_RECORD_T* d48Pump; calStatus = getNVMRecord( GET_CAL_D48_PUMP_RECORD, (U08*)&d48Pump, sizeof( DD_D48_DIALYSATE_PUMP_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_CAL_D48_PUMP ); calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_D48_PUMP_RESPONSE, 0, sizeof(DD_D48_DIALYSATE_PUMP_RECORD_T), (U08*)&d48Pump ); DD_ACID_CONCENTRATES_RECORD_T* acidConc; calStatus = getNVMRecord( GET_CAL_ACID_CONCENTREATES, (U08*)&acidConc, sizeof( DD_ACID_CONCENTRATES_RECORD_T ), NUM_OF_CAL_DATA_ACID_CONCENTRATES, ALARM_ID_DD_NVM_INVALID_CAL_ACID_CONCENTRATE ); for ( i = 0; i < NUM_OF_CAL_DATA_ACID_CONCENTRATES; i++ ) { calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_ACID_CONCENTRATE_RESPONSE, i, sizeof(DD_ACID_CONCENTRATES_RECORD_T), (U08*)&acidConc->acidConcentrate[ i ] ); } DD_BICARB_CONCENTRATES_RECORD_T* bicarbConc; calStatus |= getNVMRecord( GET_CAL_BICARB_CONCENTRATES, (U08*)&bicarbConc, sizeof( DD_BICARB_CONCENTRATES_RECORD_T ), NUM_OF_CAL_DATA_BICARB_CONCENTRATES, ALARM_ID_DD_NVM_INVALID_CAL_BICARB_CONCENTRATE ); for ( i = 0; i < NUM_OF_CAL_DATA_BICARB_CONCENTRATES; i++ ) { calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_BICARB_CONCENTRATE_RESPONSE, i, sizeof(DD_BICARB_CONCENTRATES_RECORD_T), (U08*)&bicarbConc->bicarbConcentrate[ i ] ); } DD_ACCEL_SENSOR_CAL_RECORD_T* accelerometer; calStatus = getNVMRecord( GET_CAL_ACCEL_SENSORS, (U08*)&accelerometer, sizeof( DD_ACCEL_SENSOR_CAL_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_CAL_ACCEL_SENSOR ); calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_ACCEL_SENSOR_RESPONSE, 0, sizeof(DD_ACCEL_SENSOR_CAL_RECORD_T), (U08*)&accelerometer ); DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T* bloodLeak; calStatus = getNVMRecord( GET_CAL_BLOOD_LEAK_SENSOR, (U08*)&bloodLeak, sizeof( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_CAL_BLOOD_LEAK_SENSOR ); calStatus = sendDDRecord( MSG_ID_DD_NVM_CAL_BLOOD_LEAK_SENSOR_RESPONSE, 0, sizeof(DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T), (U08*)&bloodLeak ); return calStatus; } static BOOL sendDDInstitutionalRecord( void ) { BOOL institStatus = FALSE; DD_INSTITUTIONAL_RECORD_T* institRecord; institStatus = getNVMRecord( GET_INSTITUTIONAL_RECORD, (U08*)&institRecord, sizeof( DD_INSTITUTIONAL_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_INSTITUTIONAL_RECORD_CRC ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_DIALYSATE_FLOW_MLPM, sizeof(U32), (U08*)&institRecord->minDialysateFlowMLPM ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_DIALYSATE_FLOW_MLPM, sizeof(U32), (U08*)&institRecord->maxDialysateFlowMLPM ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_DIALYSATE_TEMP_C, sizeof(F32), (U08*)&institRecord->minDialysateTempC ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_DIALYSATE_TEMP_C, sizeof(F32), (U08*)&institRecord->maxDialysateTempC ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_ACID_CONCENTRATE, sizeof(U32), (U08*)&institRecord->minAcidConcentrate ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_ACID_CONCENTRATE, sizeof(U32), (U08*)&institRecord->maxAcidConcentrate ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_BICARB_CARTRIDGE_SIZE_G, sizeof(U32), (U08*)&institRecord->minBicarbCartridgeSizeG ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_BICARB_CARTRIDGE_SIZE_G, sizeof(U32), (U08*)&institRecord->maxBicarbCartridgeSizeG ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_SODIUM_MEQL, sizeof(U32), (U08*)&institRecord->minSodiumMEQL ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_SODIUM_MEQL, sizeof(U32), (U08*)&institRecord->maxSodiumMEQL ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_BICARBONATE_MEQL, sizeof(U32), (U08*)&institRecord->minBicarbonateMEQL ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_BICARBONATE_MEQL, sizeof(U32), (U08*)&institRecord->maxBicarbonateMEQL ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_RO_REJECTION_RATIO_PCT, sizeof(U32), (U08*)&institRecord->minRORejectionRatioPCT ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_DISINFECTION_FREQUENCY, sizeof(F32), (U08*)&institRecord->disinfectionFrequency ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_DISINFECTION_CYCLE_TIME, sizeof(F32), (U08*)&institRecord->disinfectionCycleTime ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_INLET_WATER_COND_ALARM_LIMIT_USPCM, sizeof(F32), (U08*)&institRecord->minInletWaterCondAlarmLimitUSPCM ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MAX_INLET_WATER_COND_ALARM_LIMIT_USPCM, sizeof(F32), (U08*)&institRecord->maxInletWaterCondAlarmLimitUSPCM ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_ACID_CONCENTRATE_JUG_SIZE_L, sizeof(F32), (U08*)&institRecord->acidConcentrateJugSizeL ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_ACID_ALARM_LIMIT_PCT, sizeof(F32), (U08*)&institRecord->minAcidAlarmLimitPCT ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_MIN_BICARB_ALARM_LIMIT_PCT, sizeof(F32), (U08*)&institRecord->minBicarbAlarmLimitPCT ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_POST_TREAT_DRAIN_OPTION, sizeof(U32), (U08*)&institRecord->postTreatDrainOption ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_POST_TREAT_DRY_BICARB_OPTION, sizeof(U32), (U08*)&institRecord->postTreatDryBicarbOption ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_CALIBRATION_TIME, sizeof(U32), (U08*)&institRecord->calibrationTime ); institStatus = sendDDRecord( MSG_ID_DD_NVM_INSTITUTIONAL_RECORD_RESPONSE, DD_INSTIT_CRC, sizeof(U16), (U08*)&institRecord->crc ); return institStatus; } static BOOL sendDDUsageInfoRecord( void ) { BOOL usageStatus = FALSE; DD_USAGE_INFO_RECORD_T* usageInfoRecord; usageStatus = getNVMRecord( GET_USAGE_RECORD, (U08*)&usageInfoRecord, sizeof( DD_USAGE_INFO_RECORD_T ), 0, ALARM_ID_DD_NVM_INVALID_USAGE_RECORD_CRC ); usageStatus = sendDDRecord( MSG_ID_DD_NVM_USAGE_INFO_RECORD_RESPONSE, 0, sizeof(DD_USAGE_INFO_RECORD_T), (U08*)&usageInfoRecord ); return usageStatus; } /*********************************************************************//** * @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 idx, U32 length, U08* recordAddress ) { BOOL result = FALSE; DD_NVM_SEND_RECORD_PAYLOAD_T payload; payload.idx = idx; memcpy( payload.data, recordAddress, length ); result = sendMessage( msgId, COMM_BUFFER_OUT_DD_CAN_PC, (U08 *)&payload, sizeof( DD_NVM_SEND_RECORD_PAYLOAD_T ) ); 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, NVM_RECORD_TYPE_T recordType, U16 recordSize ) { BOOL status = FALSE; if (message->hdr.payloadLen == recordSize) { U08 tempBuffer[ recordSize ]; memcpy( tempBuffer, message->payload, recordSize ); // CRC assumed at end of record U16 *recordCRC = (U16 *)( tempBuffer + ( recordSize - sizeof(U16) ) ); U16 calcCRC = crc16( tempBuffer, recordSize - sizeof(U16) ); if ( calcCRC == *recordCRC ) { PROCESS_RECORD_SPECS_T recordSpec = getProcessRecord( recordType ); memcpy( recordSpec.structAddressPtr, tempBuffer, recordSize ); setNVMRecord( recordType, tempBuffer ); status = enqueueEraseAndWriteSector( recordType ); sendNVEvent( recordType, 0, 0 ); } } return status; } static BOOL receiveCalRecord( MESSAGE_T *message, DD_CAL_REC_TYPE calRecordType, U16 recordSize ) { BOOL status = FALSE; U08 idx = 0; MSG_ID_T msgID = (MSG_ID_T)message->hdr.msgID; U08* payloadPtr = message->payload; U08 expectedPayloadLen = ( sizeof(U08) + recordSize ); U08 tempBuffer[ recordSize ]; if ( message->hdr.payloadLen == expectedPayloadLen ) { memcpy(&idx, payloadPtr, sizeof(U32)); payloadPtr += sizeof(U08); memcpy( tempBuffer, payloadPtr, recordSize ); // CRC assumed at end of record U16 *recordCRC = (U16 *)( tempBuffer + ( recordSize - sizeof(U16) ) ); U16 calcCRC = crc16( tempBuffer, recordSize - sizeof(U16) ); if (calcCRC == *recordCRC) { nvmExecreceiveRecordState = NVM_RECEIVE_RECORD_STATE_RECEIVE; status = setNVMCalRecord( calRecordType, &tempBuffer, idx ); // It is possible that we receive multiple packets of cal record // So we write it to flash when we finish receiving all packets or // a timeout occurs. calRecordReceiveStartTime = getMSTimerCount(); } } return status; } static BOOL receiveInstitRecord( MESSAGE_T *message ) { BOOL status = FALSE; U08 idx = 0; U08* payloadPtr = message->payload; U08 expectedPayloadLen = sizeof(U08); if ( message->hdr.payloadLen >= expectedPayloadLen ) { nvmExecreceiveRecordState = NVM_RECEIVE_RECORD_STATE_RECEIVE; memcpy( &idx, payloadPtr, sizeof(U32) ); payloadPtr += sizeof(U08); status = setNVMInstitRecord( (DD_CAL_REC_TYPE)idx, payloadPtr ); // It is possible that we receive multiple packets of instit record // So we write it to flash when we finish receiving all packets or // a timeout occurs. institRecordReceiveStartTime = getMSTimerCount(); } return status; } /*********************************************************************//** * @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, NVM_SYSTEM_RECORD, sizeof( DD_SYSTEM_RECORD_T ) ); } 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, NVM_SERVICE_RECORD, sizeof( DD_SERVICE_RECORD_T ) ); } 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, NVM_USAGE_INFO_RECORD, sizeof( DD_USAGE_INFO_RECORD_T ) ); 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 = receiveInstitRecord( message ); return result; } BOOL testDDSetPressureSensorCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_PRESSURE_SENSOR , sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } return result; } BOOL testDDSetTempSensorCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_TEMPERATURE_SENSOR , sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } return result; } BOOL testDDSetConcPumpCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_CONCENTRATE_PUMP , sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } return result; } BOOL testDDSetD12PumpCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_D12_PUMP , sizeof( DD_D12_DIALYSATE_PUMP_RECORD_T ) ); } return result; } BOOL testDDSetD48CalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_D48_PUMP , sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } return result; } BOOL testDDSetAcidConcCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_ACID_CONCENTRATE , sizeof( DD_ACID_CONCENTRATE_T ) ); } return result; } BOOL testDDSetBicarbConcCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_BICARB_CONCENTRATE , sizeof( DD_BICARB_CONCENTRATE_T ) ); } return result; } BOOL testDDSetAccelSensorCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_ACCELEROMETER_SENSOR , sizeof( DD_ACCEL_SENSOR_CAL_RECORD_T ) ); } return result; } BOOL testDDSetBloodLeakSensorCalRecord( MESSAGE_T *message ) { BOOL result = FALSE; if ( DD_MODE_SERV == getCurrentOperationMode() ) { result = receiveCalRecord( message, DD_CAL_RECORD_BLLOD_LEAK_SENSOR , sizeof( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ) ); } 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; } /**@}*/