Index: firmware/App/Controllers/BloodLeak.c =================================================================== diff -u -r46b163d19c65e8c21db7b0247bbb1af0dba1ece5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision 46b163d19c65e8c21db7b0247bbb1af0dba1ece5) +++ firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -26,6 +26,7 @@ #include "SystemCommMessages.h" #include "TaskPriority.h" #include "Timers.h" +#include "Utilities.h" /** * @addtogroup BloodLeak @@ -79,7 +80,9 @@ #define BLOOD_LEAK_EMB_MODE_STOP_WRITE_INDEX 3 ///< Blood leak embedded mode stop write to FIFO index. #define BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX 4 ///< Blood leak embedded mode active high command index. #define BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX 0 ///< Blood leak embedded mode request Rx to read index. -#define BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE 10 ///< Blood leak embedded mode command queue maximum size. +#define BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE 12 ///< Blood leak embedded mode command queue maximum size. +#define BLOOD_LEAK_EMB_MODE_ZERO_CMD_RQRD_Q 5 ///< Blood leak embedded mode zero command required queue count. +#define BLOOD_LEAK_EMB_MODE_NUM_OF_RETRIES 3 ///< Blood leak embedded mode number of retries to enqueue. /// Defined states for the blood leak detector state machine. typedef enum BloodLeakStates @@ -163,6 +166,7 @@ static U08 bloodLeakEmbModeCmdQFrontIndex; ///< Blood leak embedded mode command queue front index. static U08 bloodLeakEmbModeCmdQCount; ///< Blood leak embedded mode command queue count. static BOOL bloodLeakEmbModeHasZeroBeenRqustd; ///< Blood leak embedded mode flag to indicate zero has been requested. +static U32 bloodLeakEmbModeCmdEnqueueCount; ///< Blood leak embedded mode command enqueue count. // ********** private function prototypes ********** @@ -184,6 +188,7 @@ static void enqueueEmbModeCmd( U08 cmd ); static U08 dequeueEmbModeCmd( void ); static BOOL isEmbModeCmdQueueEmpty( void ); +static U32 getAvailableEmbModeQueueCount( void ); /*********************************************************************//** * @brief @@ -192,7 +197,7 @@ * @details Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence * bloodLeakDataPublicationTimerCounter, bloodLeakEmbModeHasZeroBeenRqustd - * bloodLeakEmbModeSubstate + * bloodLeakEmbModeSubstate, bloodLeakEmbModeCmdEnqueueCount * bloodLeakPersistenceCtr, bloodLeakSignalEmbModeReq, * bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeOpsStartTime, bloodLeakEmbModeRespBuffer, * bloodLeakEmbModeRespIndex, bloodLeakExitNormalRequested, @@ -226,6 +231,7 @@ bloodLeakEmbModeCmdQRearIndex = 0; bloodLeakEmbModeCmdQCount = 0; bloodLeakEmbModeHasZeroBeenRqustd = FALSE; + bloodLeakEmbModeCmdEnqueueCount = 0; // Set the blood leak embedded mode command queue to zero memset( bloodLeakEmbModeCmdQ, 0x0, BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE ); @@ -322,20 +328,33 @@ * @brief * The zeroBloodLeak function requests that the Blood Leak Detector be * zeroed. - * @details Inputs: none - * @details Outputs: bloodLeakCmd.cmdZeroRequested, bloodLeakUARTCmdIndex - * @return none + * @details Inputs: bloodLeakEmbModeCmdEnqueueCount + * @details Outputs: bloodLeakCmd.cmdZeroRequested, bloodLeakUARTCmdIndex, + * bloodLeakEmbModeCmdEnqueueCount + * @return TRUE if the zero commands were successfully queued otherwise, FALSE *************************************************************************/ -void zeroBloodLeak( void ) +BOOL zeroBloodLeak( void ) { - bloodLeakEmbModeHasZeroBeenRqustd = TRUE; + BOOL status = TRUE; - // Enqueue the zero and self test sequence (Z->G->Z->Q->T) - enqueueEmbModeCmd( Z_EMB_MODE_CMD ); - enqueueEmbModeCmd( G_EMB_MODE_CMD ); - enqueueEmbModeCmd( Z_EMB_MODE_CMD ); - enqueueEmbModeCmd( Q_EMB_MODE_CMD ); - enqueueEmbModeCmd( T_EMB_MODE_CMD ); + if ( getAvailableEmbModeQueueCount() >= BLOOD_LEAK_EMB_MODE_ZERO_CMD_RQRD_Q ) + { + status = TRUE; + bloodLeakEmbModeHasZeroBeenRqustd = TRUE; + + // Enqueue the zero and self test sequence (Z->G->Z->Q->T) + enqueueEmbModeCmd( Z_EMB_MODE_CMD ); + enqueueEmbModeCmd( G_EMB_MODE_CMD ); + enqueueEmbModeCmd( Z_EMB_MODE_CMD ); + enqueueEmbModeCmd( Q_EMB_MODE_CMD ); + enqueueEmbModeCmd( T_EMB_MODE_CMD ); + } + else if ( ++bloodLeakEmbModeCmdEnqueueCount > BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_ENQUEUE_FAILURE ) + } + + return status; } /*********************************************************************//** @@ -401,15 +420,13 @@ } else if ( ( TRUE == bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].isCmdRespRdy ) && ( BLOOD_LEAK_EMB_MODE_FAIL_ASCII == cmdResp ) ) { - if ( bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandRetryCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) + if ( ++bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandRetryCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { // Enqueue the commands to set the embedded mode and request the set point of the blood leak sensor // Since set point was requested in the init function as well, both are requested here because we have to be // in the embedded mode first enqueueEmbModeCmd( CS_EMB_MODE_CMD ); enqueueEmbModeCmd( D_EMB_MODE_CMD ); - - bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandRetryCount++; } else { @@ -424,7 +441,8 @@ if ( ( getCurrentOperationMode() != MODE_INIT ) && ( TRUE == isEmbModeReady ) ) { - state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandRetryCount = 0; + state = BLOOD_LEAK_CHECK_SET_POINT_STATE; } return state; @@ -446,11 +464,9 @@ if ( ( bloodLeakSetPoint != bloodLeakCalRecord.setPoint ) && ( TRUE == isCommandRespReady ) ) { - if ( bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRetryCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) + if ( ++bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRetryCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { enqueueEmbModeCmd( D_EMB_MODE_CMD ); - - bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRetryCount++; } else { @@ -464,7 +480,8 @@ } else if ( TRUE == isCommandRespReady ) { - state = BLOOD_LEAK_INIT_STATE; + bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRetryCount = 0; + state = BLOOD_LEAK_INIT_STATE; } return state; @@ -551,19 +568,30 @@ if ( FALSE == hasCmdSqncFailed ) { - state = BLOOD_LEAK_NORMAL_STATE; + // Done with zero sequence, transition to other states + bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].commandRetryCount = 0; + bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; + state = BLOOD_LEAK_NORMAL_STATE; } else if ( bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].commandRetryCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { - // Zero sequence failed, try again - zeroBloodLeak(); + if ( TRUE == zeroBloodLeak() ) + { + // Check if the zero sequence has been successfully enqueued + // If the command retry of one of the commands in the zero sequence failed, it means all of them have failed + // So in this condition only the Z command is checked + bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].commandRetryCount++; + } } else { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { + bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; + state = BLOOD_LEAK_INIT_STATE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BLOOD_LEAK_SENSOR_ZERO_SEQUENCE_FAILED, failedCmd ); } } @@ -748,6 +776,10 @@ // Clear the response buffer to able to receive fresh data memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_INVALID_EMB_MODE_CMD_SELECTED, bloodLeakEmbModeRqstedCmd ) + break; } } @@ -807,6 +839,10 @@ } bloodLeakUARTCmdIndex++; break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_INVALID_EMB_MODE_CMD_SELECTED, bloodLeakEmbModeRqstedCmd ) + break; } if ( ( bloodLeakEmbModeRqstedCmd != CS_EMB_MODE_CMD ) && ( bloodLeakUARTCmdIndex - 1 > BLOOD_LEAK_EMB_MODE_RESET_INDEX ) && @@ -1163,19 +1199,23 @@ { BLOOD_LEAK_DATA_T data; - data.bloodLeakStatus = (U32)getBloodLeakStatus(); - data.bloodLeakState = (U32)bloodLeakState; - data.bloodLeakZeroStatusCounter = (U32)getFPGABloodLeakZeroStatusCounter(); - data.bloodLeakCounter = (U32)getFPGABloodLeakCounter(); - data.bloodLeakZeroedStatus = (U32)getFPGABloodLeakZeroedStatus(); - data.bloodLeakDetectSetPoint = (U32)getFPGABloodLeakDetectSetPoint(); - data.bloodLeakDetectLevel = (U32)getFPGABloodLeakDetectLevel(); - data.bloodLeakStCount = (U32)getFPGABloodLeakStCount(); - data.bloodLeakLEDIntesity = (U32)getFPGABloodLeakLEDIntensity(); - data.bloodLeakRegisterCounter = (U32)getFPGABloodLeakRegisterCounter(); + data.bloodLeakStatus = (U32)getBloodLeakStatus(); + data.bloodLeakState = (U32)bloodLeakState; + data.bloodLeakDetectSetPoint = bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandResp; + data.bloodLeakDetectLevel = bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].commandResp; + data.bloodLeakLEDIntesity = bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].commandResp; broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); bloodLeakDataPublicationTimerCounter = 0; + + if ( ( bloodLeakState >= BLOOD_LEAK_INIT_STATE ) && ( FALSE == bloodLeakEmbModeHasZeroBeenRqustd ) ) + { + // Once the previous data was broadcast, and the system is not in init and blood leak zero request has not been set, enqueue the data + // to be queried and read again. The data is queried here to make sure there is a second of time in between the queries for I, V, and D + enqueueEmbModeCmd( I_EMB_MODE_CMD ); + enqueueEmbModeCmd( V_EMB_MODE_CMD ); + enqueueEmbModeCmd( D_EMB_MODE_CMD ); + } } } @@ -1353,7 +1393,20 @@ return isEmpty; } +/*********************************************************************//** + * @brief + * The getAvailableEmbModeQueueCount function returns the available embedded + * mode queue count. + * @details Inputs: bloodLeakEmbModeCmdQCount + * @details Outputs: none + * @return Current available embedded mode queue count + *************************************************************************/ +static U32 getAvailableEmbModeQueueCount( void ) +{ + return BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE - bloodLeakEmbModeCmdQCount; +} + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Controllers/BloodLeak.h =================================================================== diff -u -r46b163d19c65e8c21db7b0247bbb1af0dba1ece5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Controllers/BloodLeak.h (.../BloodLeak.h) (revision 46b163d19c65e8c21db7b0247bbb1af0dba1ece5) +++ firmware/App/Controllers/BloodLeak.h (.../BloodLeak.h) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -46,22 +46,17 @@ { U32 bloodLeakStatus; ///< Blood leak detector status U32 bloodLeakState; ///< Blood leak detector state - U32 bloodLeakZeroStatusCounter; ///< Blood leak zero status counter - U32 bloodLeakCounter; ///< Blood leak counter - U32 bloodLeakZeroedStatus; ///< Blood leak zeroed status U32 bloodLeakDetectSetPoint; ///< Blood leak detect set point U32 bloodLeakDetectLevel; ///< Blood leak detect level - U32 bloodLeakStCount; ///< Blood leak st count U32 bloodLeakLEDIntesity; ///< Blood leak LED intensity - U32 bloodLeakRegisterCounter; ///< Blood leak register counter } BLOOD_LEAK_DATA_T; // ********** public function prototypes ********** void initBloodLeak( void ); void execBloodLeak( void ); void execBloodLeakEmbModeCommand( void ); -void zeroBloodLeak( void ); +BOOL zeroBloodLeak( void ); void exitBloodLeakNormalState( void ); Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -rd089b3bd30b565fb264817b6df70e083d8a9ec46 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision d089b3bd30b565fb264817b6df70e083d8a9ec46) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,38 +7,39 @@ * * @file DGInterface.c * -* @author (last) Dara Navaei -* @date (last) 15-Jul-2022 +* @author (last) Dong Nguyen +* @date (last) 27-Sep-2022 * * @author (original) Sean * @date (original) 08-Apr-2020 * ***************************************************************************/ #include // To check for NaN - + #include "DialInFlow.h" #include "Dialysis.h" -#include "DGDefs.h" +#include "DGDefs.h" #include "DGInterface.h" #include "ModeInitPOST.h" #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.h" -#include "SystemCommMessages.h" -#include "Timers.h" - -/** - * @addtogroup DGInterface - * @{ - */ - -// ********** private definitions ********** - -#define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. -#define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. +#include "SystemComm.h" +#include "SystemCommMessages.h" +#include "Timers.h" +/** + * @addtogroup DGInterface + * @{ + */ + +// ********** private definitions ********** + +#define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. +#define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. + #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. #define DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C 2.0F ///< Dialysate temperature out of target tolerance C. @@ -47,32 +48,40 @@ #define DIALYSATE_TEMP_HIGH_SAFETY_TIMEOUT_MS ( 1 * MS_PER_SECOND ) ///< Dialysate temperature high safety timeout in milliseconds. #define DIALYSATE_TEMP_LOW_SAFETY_LIMIT_C 42.0F ///< Dialysate low safety temperature limit in C. #define DIALYSATE_TEMP_LOW_SAFETY_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Dialysate temperature low safety timeout in milliseconds. +#define DG_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< DG data freshness timeout (in ms). // ********** private data ********** +static const U32 DIP_LOAD_CELL_DATA_MESSAGE_ALARM_THRESHOLD = ((2 * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); +static const U32 DIP_TEMPERATURE_DATA_MESSAGE_ALARM_THRESHOLD = ((2 * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); +static const U32 DIP_RESERVOIRS_DATA_MESSAGE_ALARM_THRESHOLD = ((2 * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); +static const U32 DIP_DG_OP_MODE_DATA_MESSAGE_ALARM_THRESHOLD = ((2 * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); + +// ********** private data ********** + // DG status static DG_OP_MODE_T dgCurrentOpMode; ///< Current DG operation mode. static U32 dgSubMode; ///< Current state (sub-mode) of current DG operation mode. static BOOL dgStartCommandSent; ///< Flag indicates command to start DG has been sent. static BOOL dgStarted; ///< Flag indicates whether we have commanded the DG to start or stop. static BOOL dgTrimmerHeaterOn; ///< Flag indicates whether we have commanded the DG to start or stop the trimmer heater. - + // State machine states -static U32 timeStartMS = 0; // TODO is this needed? - -// DG sensor data -static F32 dgDialysateTemp; ///< Dialysate temperature reported by the DG. -static F32 dgRedundantDialysateTemp = 0.0; ///< Redundant dialysate temperature reported by the DG. -static F32 dgPrimaryTemp = 0.0; ///< Latest RO water temperature reported by the DG. -static F32 dgTrimmerTempSet; ///< Trimmer heater target temperature commanded. -static F32 dgTrimmerTemp = 0.0; ///< Latest dialysate temperature reported by the DG. - +static U32 timeStartMS = 0; // TODO is this needed? + +// DG sensor data +static F32 dgDialysateTemp = 0.0; ///< Dialysate temperature reported by the DG. +static F32 dgRedundantDialysateTemp = 0.0; ///< Redundant dialysate temperature reported by the DG. +static F32 dgPrimaryTemp = 0.0; ///< Latest RO water temperature reported by the DG. +static F32 dgTrimmerTempSet = 0.0; ///< Trimmer heater target temperature commanded. +static F32 dgTrimmerTemp = 0.0; ///< Latest dialysate temperature reported by the DG. + /// Measured weight from load cells. static OVERRIDE_F32_T loadCellWeightInGrams[ NUM_OF_LOAD_CELLS ]; /// Filtered (32 sample) weight of reservoirs. static F32 lgFilteredReservoirWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; static F32 lgFilteredReservoirBackupWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; - + // Load cell filtering data static F32 lgLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Holds load cell samples for large load cell moving average. static U32 lgLoadCellReadingsIdx = 0; ///< Index for next sample in large load cell rolling average sample array. @@ -81,18 +90,22 @@ static F32 lgLoadCellBackupReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. // DG Dialysate flow rate -static F32 dgDialysateFlowRateMlMin; ///< Latest dialysate flow rate reported by the DG. -static BOOL dgDialysateFlowDataFreshFlag; ///< Flag to signal the execDialInFlowMonitor() to process fresh flow rate data +static F32 dgDialysateFlowRateMlMin = 0.0; ///< Latest dialysate flow rate reported by the DG. +static BOOL dgDialysateFlowDataFreshFlag = FALSE; ///< Flag to signal the execDialInFlowMonitor() to process fresh flow rate data +static BOOL dgLoadCellDataFreshFlag = FALSE; ///< Flag to signal the handleLoadCellReadingsFromDG() to process fresh load cell data +static BOOL dgDialysateTemperatureDataFreshFlag = FALSE; ///< Flag to signal the handleTemperatureReadingsFromDG() to process fresh temperature data +static BOOL dgReservoirsDataFreshFlag = FALSE; ///< Flag to signal the handleDGReservoirData() to process fresh reservoirs data +static BOOL dgOpModeDataFreshFlag = FALSE; ///< Flag to signal the handleDGOpMode() to process fresh dg op mode data -// Reservoir data -static DG_RESERVOIR_ID_T dgActiveReservoir; ///< Latest active reservoir reported by the DG. -static DG_RESERVOIR_ID_T dgActiveReservoirSet; ///< Active reservoir commanded. +// Reservoir data +static DG_RESERVOIR_ID_T dgActiveReservoir = DG_RESERVOIR_2; ///< Latest active reservoir reported by the DG. +static DG_RESERVOIR_ID_T dgActiveReservoirSet = DG_RESERVOIR_2; ///< Active reservoir commanded. // TODO remove below variables -static U32 dgReservoirFillVolumeTarget = 0; ///< Latest fill-to volume reported by the DG. -static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. -static U32 dgReservoirDrainVolumeTarget = 0; ///< Latest drain-to volume reported by the DG. -static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. +static U32 dgReservoirFillVolumeTarget = 0; ///< Latest fill-to volume reported by the DG. +static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. +static U32 dgReservoirDrainVolumeTarget = 0; ///< Latest drain-to volume reported by the DG. +static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. static DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. static DG_MIXING_RATIOS_T dgMixingRatios; ///< DG mixing ratios. @@ -101,21 +114,21 @@ // DG command response static DG_CMD_RESPONSE_T dgCmdResp[ NUM_OF_DG_COMMANDS ]; ///< Keep the latest DG command response for each command. - -// ********** private function prototypes ********** +// ********** private function prototypes ********** + static void checkDGRestart( void ); static void checkDGTrimmerHeaterStatus( void ); -/*********************************************************************//** - * @brief - * The initDGInterface function initializes the DGInterface module. - * @details Inputs: none - * @details Outputs: DGInterface module initialized. - * @return none - *************************************************************************/ -void initDGInterface( void ) -{ +/*********************************************************************//** + * @brief + * The initDGInterface function initializes the DGInterface module. + * @details Inputs: none + * @details Outputs: DGInterface module initialized. + * @return none + *************************************************************************/ +void initDGInterface( void ) +{ U32 i, j; dgStarted = FALSE; @@ -171,20 +184,67 @@ initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ); + + initPersistentAlarm( ALARM_ID_HD_NEW_LOAD_CELL_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_HD_NEW_DIALYSATE_TEMPERATURE_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_HD_NEW_RESERVOIRS_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_HD_NEW_DG_OPERATION_MODE_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); } - + +/**********************************************************************//** + * @brief + * The checkDGDataFreshness function checks the condition + * for triggering an alarm if the DG fresh data is not received for 2 seconds. + * @details Inputs: none + * @details Outputs: an alarm is triggered or an alarm condition is cleared + * @param alarm ID of alarm to check + * @param flag to signal the fresh data processing + * @return None + *************************************************************************/ +void checkDGDataFreshness( ALARM_ID_T alarmID, BOOL *dgFreshDataFlag ) +{ + if ( TRUE == *dgFreshDataFlag ) + { + *dgFreshDataFlag = FALSE; + checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); + } + else + { // Alarm if not receiving DG fresh data message in timely manner + if ( TRUE == isDGCommunicating() ) + { + checkPersistentAlarm( alarmID, TRUE, 0.0, 0.0 ); + } + else + { + checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); + } + } +} + /*********************************************************************//** * @brief * The execDGInterfaceMonitor function executes the DG Interface monitoring * function. Ensures DG is sending fresh data in a timely manner. - * @details Inputs: TBD - * @details Outputs: TBD + * @details Inputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, + * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag + * @details Outputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, + * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag * @return none *************************************************************************/ void execDGInterfaceMonitor( void ) { - // TODO - make sure DG sensor/state data is coming in timely manner (e.g. load cells s/b every 100 ms) + // Trigger alarm if not receiving new load cell data message in timely manner + checkDGDataFreshness( ALARM_ID_HD_NEW_LOAD_CELL_DATA_MESSAGE_NOT_RECEIVE, &dgLoadCellDataFreshFlag ); + // Trigger alarm if not receiving new dialysate temperature data message in timely manner + checkDGDataFreshness( ALARM_ID_HD_NEW_DIALYSATE_TEMPERATURE_DATA_MESSAGE_NOT_RECEIVE, &dgDialysateTemperatureDataFreshFlag ); + + // Trigger alarm if not receiving new reservoirs data message in timely manner + checkDGDataFreshness( ALARM_ID_HD_NEW_RESERVOIRS_DATA_MESSAGE_NOT_RECEIVE, &dgReservoirsDataFreshFlag ); + + // Trigger alarm if not receiving new DG op mode message in timely manner + checkDGDataFreshness( ALARM_ID_HD_NEW_DG_OPERATION_MODE_MESSAGE_NOT_RECEIVE, &dgOpModeDataFreshFlag ); + // Check to see if DG has restarted checkDGRestart(); @@ -203,46 +263,46 @@ void dialysisResumed( void ) { timeStartMS = getMSTimerCount(); -} - -/*********************************************************************//** - * @brief - * The getDGOpMode function gets the current DG operating mode. - * @details Inputs: dgCurrentOpMode - * @details Outputs: none - * @return Current DG operating mode. - *************************************************************************/ -DG_OP_MODE_T getDGOpMode( void ) -{ - return dgCurrentOpMode; -} - -/*********************************************************************//** - * @brief - * The getDGSubMode function gets the current DG operating sub-mode. - * @details Inputs: dgSubMode - * @details Outputs: none - * @return Current DG operating sub-mode. - *************************************************************************/ -U32 getDGSubMode( void ) -{ - return dgSubMode; -} - -/*********************************************************************//** - * @brief - * The getDGActiveReservoir function gets the current active reservoir. - * @details Inputs: dgActiveReservoirSet - * @details Outputs: none - * @return Currently commanded active reservoir. - *************************************************************************/ -DG_RESERVOIR_ID_T getDGActiveReservoir( void ) -{ - return dgActiveReservoirSet; } /*********************************************************************//** * @brief + * The getDGOpMode function gets the current DG operating mode. + * @details Inputs: dgCurrentOpMode + * @details Outputs: none + * @return Current DG operating mode. + *************************************************************************/ +DG_OP_MODE_T getDGOpMode( void ) +{ + return dgCurrentOpMode; +} + +/*********************************************************************//** + * @brief + * The getDGSubMode function gets the current DG operating sub-mode. + * @details Inputs: dgSubMode + * @details Outputs: none + * @return Current DG operating sub-mode. + *************************************************************************/ +U32 getDGSubMode( void ) +{ + return dgSubMode; +} + +/*********************************************************************//** + * @brief + * The getDGActiveReservoir function gets the current active reservoir. + * @details Inputs: dgActiveReservoirSet + * @details Outputs: none + * @return Currently commanded active reservoir. + *************************************************************************/ +DG_RESERVOIR_ID_T getDGActiveReservoir( void ) +{ + return dgActiveReservoirSet; +} + +/*********************************************************************//** + * @brief * The getDGInactiveReservoir function gets the currently inactive reservoir. * @details Inputs: dgActiveReservoirSet * @details Outputs: none @@ -253,7 +313,7 @@ DG_RESERVOIR_ID_T inactiveRes = ( DG_RESERVOIR_2 == dgActiveReservoirSet ? DG_RESERVOIR_1 : DG_RESERVOIR_2 ); return inactiveRes; -} +} /*********************************************************************//** * @brief @@ -267,7 +327,7 @@ { return ( dgActiveReservoir == dgActiveReservoirSet ); } - + /*********************************************************************//** * @brief * The getDGDialysateFlowRateLMin function gets the latest dialysate flow @@ -281,7 +341,7 @@ F32 result = dgDialysateFlowRateMlMin; return result; -} +} /*********************************************************************//** * @brief @@ -299,7 +359,7 @@ return result; } - + /*********************************************************************//** * @brief * The getLoadCellWeight function gets the current load cell weight. @@ -441,72 +501,78 @@ memcpy( data, &dgServiceAndUsageData, sizeof( DG_SERVICE_AND_USAGE_DATA_T ) ); } -/*********************************************************************//** - * @brief - * The setDGOpMode function sets the latest DG operating mode reported by - * the DG. - * @details Inputs: none - * @details Outputs: dgCurrentOpMode, dgSubMode - * @param opMode operating mode reported by DG - * @param subMode sub-mode (current state) of operating mode reported by DG - * @return none - *************************************************************************/ -void setDGOpMode( U32 opMode, U32 subMode ) -{ - if ( opMode < NUM_OF_DG_MODES ) - { - dgCurrentOpMode = (DG_OP_MODE_T)opMode; - dgSubMode = subMode; - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_OPERATING_MODE, opMode ); - } -} - -/*********************************************************************//** - * @brief - * The setDialysateTemperatureReadings function sets the latest dialysate - * temperatures reported by the DG. - * @details Inputs: none - * @details Outputs: dgDialysateTemp, dgRedundantDialysateTemp - * @param temp1 dialysate temperature reported by DG - * @param temp2 redundant dialysate temperature reported by DG - * @return none - *************************************************************************/ -void setDialysateTemperatureReadings( F32 temp1, F32 temp2 ) -{ - dgDialysateTemp = temp1; - dgRedundantDialysateTemp = temp2; -} - -/*********************************************************************//** - * @brief - * The setDGReservoirsData function sets the latest reservoir data - * reported by the DG. - * @details Inputs: none - * @details Outputs: dgActiveReservoir, dgReservoirFillVolumeTarget, dgReservoirDrainVolumeTarget - * @param resID ID of active reservoir - * @param fillVol Reservoir fill to volume reported by DG - * @param drainVol Reservoir drain to volume reported by DG - * @return none - *************************************************************************/ -void setDGReservoirsData( DG_RESERVOIR_ID_T resID, U32 fillVol, U32 drainVol ) -{ - if ( resID < NUM_OF_DG_RESERVOIRS ) - { - dgActiveReservoir = resID; - dgReservoirFillVolumeTarget = fillVol; - dgReservoirDrainVolumeTarget = drainVol; - } - else +/*********************************************************************//** + * @brief + * The setDGOpMode function sets the latest DG operating mode reported by + * the DG. + * @details Inputs: none + * @details Outputs: dgCurrentOpMode, dgSubMode + * @param opMode operating mode reported by DG + * @param subMode sub-mode (current state) of operating mode reported by DG + * @return none + *************************************************************************/ +void setDGOpMode( U32 opMode, U32 subMode ) +{ + if ( opMode < NUM_OF_DG_MODES ) { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, resID ); - } -} + dgCurrentOpMode = (DG_OP_MODE_T)opMode; + dgSubMode = subMode; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_OPERATING_MODE, opMode ); + } + dgOpModeDataFreshFlag = TRUE; +} + /*********************************************************************//** * @brief + * The setDialysateTemperatureReadings function sets the latest dialysate + * temperatures reported by the DG. + * @details Inputs: none + * @details Outputs: dgDialysateTemp, dgRedundantDialysateTemp + * @param temp1 dialysate temperature reported by DG + * @param temp2 redundant dialysate temperature reported by DG + * @return none + *************************************************************************/ +void setDialysateTemperatureReadings( F32 temp1, F32 temp2 ) +{ + dgDialysateTemp = temp1; + dgRedundantDialysateTemp = temp2; + + dgDialysateTemperatureDataFreshFlag = TRUE; +} + +/*********************************************************************//** + * @brief + * The setDGReservoirsData function sets the latest reservoir data + * reported by the DG. + * @details Inputs: none + * @details Outputs: dgActiveReservoir, dgReservoirFillVolumeTarget, dgReservoirDrainVolumeTarget + * @param resID ID of active reservoir + * @param fillVol Reservoir fill to volume reported by DG + * @param drainVol Reservoir drain to volume reported by DG + * @return none + *************************************************************************/ +void setDGReservoirsData( DG_RESERVOIR_ID_T resID, U32 fillVol, U32 drainVol ) +{ + if ( resID < NUM_OF_DG_RESERVOIRS ) + { + dgActiveReservoir = resID; + dgReservoirFillVolumeTarget = fillVol; + dgReservoirDrainVolumeTarget = drainVol; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, resID ); + } + + dgReservoirsDataFreshFlag = TRUE; +} + +/*********************************************************************//** + * @brief * The setDialysateFlowData function sets the latest dialysate flow rate * and its freshness status. The dialysate flow data is reported by the DG. * @details Inputs: none @@ -570,6 +636,8 @@ // Update Dialysis sub-mode with new reservoir volumes updateReservoirVolumes( res1Primary, res2Primary ); + + dgLoadCellDataFreshFlag = TRUE; } /*********************************************************************//** @@ -645,108 +713,108 @@ memcpy( &dgServiceAndUsageData.dgUsageInfo, data, sizeof( HD_VERSION_DG_USAGE_INFO_T ) ); } -/*********************************************************************//** - * @brief +/*********************************************************************//** + * @brief * The cmdSetDGDialysateHeatingParams function sends the dialysate heating - * parameters to DG. - * @details Inputs: none - * @details Outputs: dgTrimmerTempSet + * parameters to DG. + * @details Inputs: none + * @details Outputs: dgTrimmerTempSet * @param heatingParams Dialysate heating parameters to be sent to DG - * @return none - *************************************************************************/ -void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ) -{ + * @return none + *************************************************************************/ +void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ) +{ dgTrimmerTempSet = heatingParams.trimmerTargetTemperature; - // TODO what should we do with the BOOL return of this function? - sendDialysateHeatingParamsToDG( &heatingParams ); -} - -/*********************************************************************//** - * @brief - * The cmdStartDG function sends a start command to the DG. DG will transition - * from standby to recirculate mode and start producing warm, pure water. - * @details Inputs: none - * @details Outputs: start DG command sent - * @return none - *************************************************************************/ -void cmdStartDG( void ) -{ + // TODO what should we do with the BOOL return of this function? + sendDialysateHeatingParamsToDG( &heatingParams ); +} + +/*********************************************************************//** + * @brief + * The cmdStartDG function sends a start command to the DG. DG will transition + * from standby to recirculate mode and start producing warm, pure water. + * @details Inputs: none + * @details Outputs: start DG command sent + * @return none + *************************************************************************/ +void cmdStartDG( void ) +{ dgStartCommandSent = TRUE; - - sendDGStartStopCommand( (BOOL)START_DG_CMD ); -} - -/*********************************************************************//** - * @brief - * The cmdStopDG function sends a stop command to the DG. DG will transition - * from recirculate mode to standby mode. Pumps and heater go off. - * @details Inputs: none - * @details Outputs: stop DG command sent - * @return none - *************************************************************************/ -void cmdStopDG( void ) -{ + + sendDGStartStopCommand( (BOOL)START_DG_CMD ); +} + +/*********************************************************************//** + * @brief + * The cmdStopDG function sends a stop command to the DG. DG will transition + * from recirculate mode to standby mode. Pumps and heater go off. + * @details Inputs: none + * @details Outputs: stop DG command sent + * @return none + *************************************************************************/ +void cmdStopDG( void ) +{ dgStarted = FALSE; - - sendDGStartStopCommand( (BOOL)STOP_DG_CMD ); -} - -/*********************************************************************//** - * @brief - * The cmdStartDGTrimmerHeater function sends a start trimmer heater command - * to the DG. - * @details Inputs: none - * @details Outputs: start DG trimmer heater command sent - * @return none - *************************************************************************/ -void cmdStartDGTrimmerHeater( void ) -{ + + sendDGStartStopCommand( (BOOL)STOP_DG_CMD ); +} + +/*********************************************************************//** + * @brief + * The cmdStartDGTrimmerHeater function sends a start trimmer heater command + * to the DG. + * @details Inputs: none + * @details Outputs: start DG trimmer heater command sent + * @return none + *************************************************************************/ +void cmdStartDGTrimmerHeater( void ) +{ dgTrimmerHeaterOn = TRUE; dgCmdResp[ DG_CMD_START_TRIMMER_HEATER ].commandID = DG_CMD_NONE; - - sendDGStartStopTrimmerHeaterCommand( START_DG_CMD ); -} - -/*********************************************************************//** - * @brief - * The cmdStopDGTrimmerHeater function sends a stop trimmer heater command - * to the DG. - * @details Inputs: none - * @details Outputs: stop DG trimmer heater command sent - * @return none - *************************************************************************/ -void cmdStopDGTrimmerHeater( void ) -{ + + sendDGStartStopTrimmerHeaterCommand( START_DG_CMD ); +} + +/*********************************************************************//** + * @brief + * The cmdStopDGTrimmerHeater function sends a stop trimmer heater command + * to the DG. + * @details Inputs: none + * @details Outputs: stop DG trimmer heater command sent + * @return none + *************************************************************************/ +void cmdStopDGTrimmerHeater( void ) +{ dgTrimmerHeaterOn = FALSE; dgCmdResp[ DG_CMD_STOP_TRIMMER_HEATER ].commandID = DG_CMD_NONE; - sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD ); -} - -/*********************************************************************//** - * @brief - * The cmdSetDGActiveReservoir function sends a set active reservoir command - * message to the DG. - * @details Inputs: none - * @details Outputs: set active reservoir command sent to DG. - * @param resID ID of reservoir to set as active (reservoir for HD to draw from) - * @return none - *************************************************************************/ -void cmdSetDGActiveReservoir( DG_RESERVOIR_ID_T resID ) -{ - if ( resID < NUM_OF_DG_RESERVOIRS ) - { + sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD ); +} + +/*********************************************************************//** + * @brief + * The cmdSetDGActiveReservoir function sends a set active reservoir command + * message to the DG. + * @details Inputs: none + * @details Outputs: set active reservoir command sent to DG. + * @param resID ID of reservoir to set as active (reservoir for HD to draw from) + * @return none + *************************************************************************/ +void cmdSetDGActiveReservoir( DG_RESERVOIR_ID_T resID ) +{ + if ( resID < NUM_OF_DG_RESERVOIRS ) + { dgActiveReservoirSet = resID; dgCmdResp[ DG_CMD_SWITCH_RESERVOIR ].commandID = DG_CMD_NONE; - - sendDGSwitchReservoirCommand( (U32)resID ); - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, (U32)resID ); - } -} + sendDGSwitchReservoirCommand( (U32)resID ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, (U32)resID ); + } +} + /*********************************************************************//** * @brief * The cmdChangeDGValveSetting function sends a change valve setting command @@ -769,24 +837,24 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_VALVE_SETTING_ID, (U32)valveSettingID ); } } - -/*********************************************************************//** - * @brief - * The cmdStartDGFill function sends a fill command message to the DG. - * @details Inputs: none - * @details Outputs: fill command sent to DG. + +/*********************************************************************//** + * @brief + * The cmdStartDGFill function sends a fill command message to the DG. + * @details Inputs: none + * @details Outputs: fill command sent to DG. * @param fillToVolMl volume (in mL) to fill inactive reservoir to - * @param targetFlowLPM target flow rate in L/min - * @return none - *************************************************************************/ -void cmdStartDGFill( U32 fillToVolMl, F32 targetFlowLPM ) + * @param targetFlowLPM target flow rate in L/min + * @return none + *************************************************************************/ +void cmdStartDGFill( U32 fillToVolMl, F32 targetFlowLPM ) { - dgCmdResp[ DG_CMD_START_FILL ].commandID = DG_CMD_NONE; + dgCmdResp[ DG_CMD_START_FILL ].commandID = DG_CMD_NONE; dgReservoirFillVolumeTargetSet = fillToVolMl; - - sendDGFillCommand( DG_CMD_START, fillToVolMl, targetFlowLPM ); -} + sendDGFillCommand( DG_CMD_START, fillToVolMl, targetFlowLPM ); +} + /*********************************************************************//** * @brief * The cmdStopDGFill function sends a fill command with stop parameter message to the DG. @@ -801,45 +869,45 @@ sendDGFillCommand( DG_CMD_STOP, 0, 0 ); } - -/*********************************************************************//** - * @brief - * The cmdStartDGDrain function sends a drain command message to the DG. - * @details Inputs: none + +/*********************************************************************//** + * @brief + * The cmdStartDGDrain function sends a drain command message to the DG. + * @details Inputs: none * @details Outputs: drain command sent to DG. * @param drainToVolMl volume (in mL) to drain inactive reservoir to * @param tareLoadCell flag to tell DG tare load cell or not - * @param start flag to tell DG to start or stop the drain mode - * @return none - *************************************************************************/ -void cmdStartDGDrain( U32 drainToVolMl, BOOL tareLoadCell, BOOL rinse, BOOL start ) + * @param start flag to tell DG to start or stop the drain mode + * @return none + *************************************************************************/ +void cmdStartDGDrain( U32 drainToVolMl, BOOL tareLoadCell, BOOL rinse, BOOL start ) { DRAIN_RESERVOIR_CMD_PAYLOAD_T payload; dgCmdResp[ DG_CMD_START_DRAIN ].commandID = DG_CMD_NONE; payload.drainToVolumeML = drainToVolMl; payload.tareLoadCells = tareLoadCell; payload.rinseConcentrateLines = rinse; - payload.cmd = start; + payload.cmd = start; dgReservoirDrainVolumeTargetSet = drainToVolMl; - - sendDGDrainCommand( &payload ); -} - -/*********************************************************************//** - * @brief - * The cmdDGSampleWater function sends a sample water command message to the DG. - * @details Inputs: none - * @details Outputs: sample water command sent to DG. - * @return none - *************************************************************************/ -void cmdDGSampleWater( SAMPLE_WATER_CMD_T cmd ) -{ - sendDGSampleWaterCommand( cmd ); + + sendDGDrainCommand( &payload ); } /*********************************************************************//** * @brief + * The cmdDGSampleWater function sends a sample water command message to the DG. + * @details Inputs: none + * @details Outputs: sample water command sent to DG. + * @return none + *************************************************************************/ +void cmdDGSampleWater( SAMPLE_WATER_CMD_T cmd ) +{ + sendDGSampleWaterCommand( cmd ); +} + +/*********************************************************************//** + * @brief * The cmdStartDGFlush function sends a start flush command message to * the DG. * @details Inputs: none @@ -916,7 +984,7 @@ dgCmdResp[ DG_CMD_START_CHEM_DISINFECT ].commandID = DG_CMD_NONE; sendDGStartChemicalDisinfectModeCommand( start ); -} +} /*********************************************************************//** * @brief @@ -949,6 +1017,19 @@ /*********************************************************************//** * @brief + * The cmdSetDGToServiceMode function sends a request to DG to transition + * to service mode. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +void cmdSetDGToServiceMode( void ) +{ + sendDGServiceModeRequest(); +} + +/*********************************************************************//** + * @brief * The handleDGCommandResponse function processes the latest DG command response. * @details Inputs: none * @details Outputs: process command response from DG @@ -1149,4 +1230,4 @@ return result; } -/**@}*/ +/**@}*/ Index: firmware/App/Controllers/DGInterface.h =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file DGInterface.h * -* @author (last) Dara Navaei -* @date (last) 15-Jul-2022 +* @author (last) Dong Nguyen +* @date (last) 27-Sep-2022 * * @author (original) Sean * @date (original) 08-Apr-2020 @@ -177,6 +177,7 @@ void cmdStartDGChemicalDisinfect( void ); void cmdStopDGChemicalDisinfect( void ); void cmdRequestDGMixingRatios( void ); +void cmdSetDGToServiceMode( void ); void handleDGCommandResponse( DG_CMD_RESPONSE_T *dgCmdRespPtr ); BOOL getDGCommandResponse( U32 commandID, DG_CMD_RESPONSE_T *cmdRespPtr ); Index: firmware/App/HDCommon.h =================================================================== diff -u -r611ac03266421f8c4b7a03b4c1576838216aedb5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/HDCommon.h (.../HDCommon.h) (revision 611ac03266421f8c4b7a03b4c1576838216aedb5) +++ firmware/App/HDCommon.h (.../HDCommon.h) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -8,7 +8,7 @@ * @file HDCommon.h * * @author (last) Dara Navaei -* @date (last) 23-May-2022 +* @date (last) 22-Sep-2022 * * @author (original) Sean * @date (original) 27-Feb-2020 @@ -25,7 +25,7 @@ #define HD_VERSION_MAJOR 0 #define HD_VERSION_MINOR 6 #define HD_VERSION_MICRO 0 -#define HD_VERSION_BUILD 50 +#define HD_VERSION_BUILD 54 // ********** development build switches ********** Index: firmware/App/Modes/BloodPrime.c =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file BloodPrime.c * -* @author (last) Sean Nash -* @date (last) 13-Jul-2022 +* @author (last) Dara Navaei +* @date (last) 01-Sep-2022 * * @author (original) Sean Nash * @date (original) 06-Feb-2021 Index: firmware/App/Modes/ModeFault.c =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file ModeFault.c * -* @author (last) Sean Nash -* @date (last) 13-Jul-2022 +* @author (last) Dara Navaei +* @date (last) 01-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r66dda999c5736ecec046197ff1c843c01f6aecc5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 66dda999c5736ecec046197ff1c843c01f6aecc5) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -8,7 +8,7 @@ * @file ModeStandby.c * * @author (last) Dara Navaei -* @date (last) 15-Jul-2022 +* @date (last) 22-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -117,6 +117,8 @@ *************************************************************************/ U32 transitionToStandbyMode( void ) { + HD_OP_MODE_T previousOpMode = getPreviousOperationMode(); + // Re-initialize when transitioning to standby mode initStandbyMode(); initDGInterface(); @@ -143,6 +145,11 @@ setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); + // If we just exited Post Treatment Mode, goto disinfect sub state. + if ( MODE_POST == previousOpMode ) + { + currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; + } // Request DG service record and usage information from DG sendDGServiceRequestToDG(); sendDGUsageInfoRequestToDG(); @@ -433,28 +440,49 @@ * initiation of setting the disinfects submode. * @details Inputs: currentStandbyState * @details Outputs: currentStandbyState + * @param cmd initiate (1) or cancel (0) * @return TRUE if signal accepted, FALSE if not *************************************************************************/ -BOOL signalInitiateStandbyDisinfectSubmode( void ) +BOOL signalInitiateStandbyDisinfectSubmode( U32 cmd ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; - if ( ( MODE_STAN == getCurrentOperationMode() ) && ( STANDBY_WAIT_FOR_TREATMENT_STATE == currentStandbyState ) ) + if ( cmd == 0 ) { - if ( TRUE == isDGCommunicating() ) + // Cancel Disinfect command + if ( STANDBY_WAIT_FOR_DISINFECT_STATE == currentStandbyState ) { - currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; + currentStandbyState = STANDBY_WAIT_FOR_TREATMENT_STATE; result = TRUE; rejReason = REQUEST_REJECT_REASON_NONE; } else { - rejReason = REQUEST_REJECT_REASON_DG_COMM_LOST; + result = FALSE; + rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } } + else + { + // Initiate Disinfect command + if ( ( MODE_STAN == getCurrentOperationMode() ) && ( STANDBY_WAIT_FOR_TREATMENT_STATE == currentStandbyState ) ) + { + if ( TRUE == isDGCommunicating() ) + { + currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; + result = TRUE; + rejReason = REQUEST_REJECT_REASON_NONE; + } + else + { + result = FALSE; + rejReason = REQUEST_REJECT_REASON_DG_COMM_LOST; + } + } + } - sendDisinfectConfirmResponse( result, rejReason ); + handleSetHDStandbyDisinfectSubmodeResponse( result, rejReason ); return result; } @@ -641,6 +669,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_DG_FLUSH_IN_PROGRESS_STATE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DISINFECT_FLUSH, 0 ); } return state; @@ -662,6 +691,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_WAIT_FOR_TREATMENT_STATE; + clearAlarm( ALARM_ID_HD_DISINFECT_FLUSH ); } publishDisinfectData(); @@ -717,6 +747,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_DG_HEAT_DISINFECT_IN_PROGRESS_STATE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DISINFECT_HEAT, 0 ); } return state; @@ -738,6 +769,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_WAIT_FOR_TREATMENT_STATE; + clearAlarm( ALARM_ID_HD_DISINFECT_HEAT ); } publishDisinfectData(); @@ -794,6 +826,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_DG_CHEM_DISINFECT_IN_PROGRESS_STATE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DISINFECT_CHEM, 0 ); } return state; @@ -815,6 +848,7 @@ { dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; state = STANDBY_WAIT_FOR_TREATMENT_STATE; + clearAlarm( ALARM_ID_HD_DISINFECT_CHEM ); } publishDisinfectData(); Index: firmware/App/Modes/OperationModes.c =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -8,7 +8,7 @@ * @file OperationModes.c * * @author (last) Dara Navaei -* @date (last) 03-Aug-2022 +* @date (last) 22-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -r66dda999c5736ecec046197ff1c843c01f6aecc5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision 66dda999c5736ecec046197ff1c843c01f6aecc5) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file SelfTests.c * -* @author (last) Bill Bracken -* @date (last) 22-Aug-2022 +* @author (last) Dara Navaei +* @date (last) 22-Sep-2022 * * @author (original) Quang Nguyen * @date (original) 28-Jan-2021 @@ -45,10 +45,14 @@ #define BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ( 5 * MS_PER_SECOND ) ///< Pressure self-test time to run blood pump in ms. #define NORMALIZED_PRESSURE_SELF_TEST_TIME ( 4 * MS_PER_SECOND ) ///< Time to wait for pressure to normalize in ms. +#define STABILTY_PRESSURE_SELF_TEST_TIME ( 4 * MS_PER_SECOND ) ///< Time to wait for pressure to stabilize in ms. +#define DECAY_PRESSURE_SELF_TEST_TIME ( 2 * MS_PER_SECOND ) ///< time to wait for pressure to decay in ms. #define ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG -50.0F ///< Arterial pressure low limit after running blood pump. #define VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG 400 ///< Venous pressure high limit after running blood pump. +#define DECAY_PRESSURE_DIFF_TOLERANCE_MMHG 5.0F ///< Difference in pressure readings after the pump stops (in mmHg). +#define STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG 2.0F ///< Difference in pressure readings while in a stable pressured state (in mmHg). #define NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG 10.0F ///< Difference in pressure readings after return to normal state tolerance (in mmHg). #define DIP_FLOW_RATE_SETUP_ML_MIN 150 ///< Dialysate inlet pump flow rate during the setup for wet self-test. @@ -70,6 +74,8 @@ #define SELF_TEST_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND ) ///< Interval (ms/task time) at which self-test time data is published on the CAN bus. +#define PRESSURE_CHECK_START_PRESSURE_TOLERANCE_MMHG 10.0F ///< Prior to dry pressure leak test, arterial and venous pressure sensors should read zero +/- this tolerance. + /// Multiplier to conver flow (mL/min) into volume (mL) for period of general task interval. static const F32 SELF_TEST_FLOW_INTEGRATOR = ( ( 1.0F * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); @@ -82,8 +88,14 @@ static DRY_SELF_TESTS_STATE_T currentDrySelfTestsState; ///< Current state of the dry self-tests state machine. static U32 pressureSelfTestBloodPumpRunStartTime; ///< Pressure dry self-test blood pump runs start time. static U32 pressureSelfTestNormalizedStartTime; ///< Normalized pressure dry self-test start time. +static U32 pressureSelfTestDecayStartTime; ///< Decay pressure dry self-test start time. +static U32 pressureSelfTestStabilityStartTime; ///< Stability pressure dry self-test start time. static F32 previousNormalArterialPressure; ///< Holds the previous normal arterial pressure reading. static F32 previousNormalVenousPressure; ///< Holds the previous normal venous pressure reading. +static F32 peakArterialPressure; ///< Holds the peak arterial pressure reading. +static F32 peakVenousPressure; ///< Holds the peak normal venous pressure reading. +static F32 decayedArterialPressure; ///< Holds the decayed arterial pressure reading after blood pump is stopped. +static F32 decayedVenousPressure; ///< Holds the decayed venous pressure reading after blood pump is stopped. static BOOL wetSelfTestsResult; ///< Result of wet self-tests. static WET_SELF_TESTS_STATE_T currentWetSelfTestsState; ///< Current state of the wet self-tests state machine. @@ -118,6 +130,8 @@ static DRY_SELF_TESTS_STATE_T handleDrySelfTestUsedCartridgeCheckState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsSetupState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsState( void ); +static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsDecayState( void ); +static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsStabilityState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsNormalState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpPrimeState( void ); static DRY_SELF_TESTS_STATE_T handleDrySelfTestSyringePumpOcclusionDetectionState( void ); @@ -438,6 +452,14 @@ currentDrySelfTestsState = handleDrySelfTestPressureSensorsState(); break; + case DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE: + currentDrySelfTestsState = handleDrySelfTestPressureSensorsDecayState(); + break; + + case DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE: + currentDrySelfTestsState = handleDrySelfTestPressureSensorsStabilityState(); + break; + case DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsNormalState(); break; @@ -650,15 +672,13 @@ { NO_CART_SELF_TESTS_STATE_T state = NO_CART_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; OPN_CLS_STATE_T frontDoor = getSwitchStatus( FRONT_DOOR ); - OPN_CLS_STATE_T pumpTrack = getSwitchStatus( PUMP_TRACK_SWITCH ); signalBloodPumpHardStop(); signalDialInPumpHardStop(); signalDialOutPumpHardStop(); selfTestStartTime = getMSTimerCount(); - // TODO: Use appropriate sensor driver - if ( ( STATE_CLOSED == frontDoor ) && ( STATE_CLOSED == pumpTrack ) ) + if ( STATE_CLOSED == frontDoor ) { state = NO_CART_SELF_TESTS_PRESSURE_CHECKS_STATE; } @@ -878,6 +898,9 @@ DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); + + SEND_EVENT_WITH_2_U32_DATA(HD_EVENT_DRY_SELF_TEST_CARTRIDGE_RESULT,(U32)ADVBubbleStatus,(U32)BUBBLE_DETECTED) + if ( ( BUBBLE_DETECTED == ADVBubbleStatus ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) @@ -920,6 +943,12 @@ previousNormalArterialPressure = getFilteredArterialPressure(); previousNormalVenousPressure = getFilteredVenousPressure(); + // Check to see if sensor is within normal ranges before we execute pressure sensor tests + if ( ( fabs( previousNormalArterialPressure ) > PRESSURE_CHECK_START_PRESSURE_TOLERANCE_MMHG ) || ( fabs( previousNormalVenousPressure ) > PRESSURE_CHECK_START_PRESSURE_TOLERANCE_MMHG ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, previousNormalArterialPressure, previousNormalVenousPressure ); + } + setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); setValvePosition( VBA, VALVE_POSITION_B_OPEN ); @@ -936,8 +965,10 @@ * @brief * The handleDrySelfTestPressureSensorsState function tests the readings of * pressure sensors and verify they are in correct range. - * @details Inputs: none - * @details Outputs: none + * @details Inputs: peakArterialPressure, peakVenousPressure, + * pressureSelfTestDecayStartTime + * @details Outputs: peakArterialPressure, peakVenousPressure, + * pressureSelfTestDecayStartTime * @return the next state of dry self-tests state machine *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsState( void ) @@ -947,21 +978,112 @@ F32 const venousPressure = getFilteredVenousPressure(); // End the test when reaching target pressure or time out - if ( ( TRUE == didTimeout( pressureSelfTestBloodPumpRunStartTime, BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ) ) || - ( ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG >= arterialPressure ) || ( VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG <= venousPressure ) ) + if ( TRUE == didTimeout( pressureSelfTestBloodPumpRunStartTime, BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ) ) { + peakArterialPressure = arterialPressure; + peakVenousPressure = venousPressure; + signalBloodPumpHardStop(); // Test pass when reading positive arterial pressure and negative venous pressure - if ( ( arterialPressure < 0) && ( venousPressure > 0 ) ) + if ( ( ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG >= arterialPressure ) && ( VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG <= venousPressure ) ) { + pressureSelfTestDecayStartTime = getMSTimerCount(); + state = DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE; + } + else + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialPressure, venousPressure ); + } + } + + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + state = DRY_SELF_TESTS_STOPPED_STATE; + setupForSelfTestsStop(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleDrySelfTestPressureSensorsDecayState function verifies + * the readings of pressure sensors after we have verified the sensors + * are in the correct range by observing the loss in pressure once + * the pump has stopped. + * @details Inputs: decayedArterialPressure, decayedVenousPressure, + * pressureSelfTestStabilityStartTime, peakArterialPressure, + * peakVenousPressure + * @details Outputs: decayedArterialPressure, decayedVenousPressure + * pressureSelfTestStabilityStartTime + * @return the next state of dry self-tests state machine + *************************************************************************/ +static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsDecayState( void ) +{ + DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_DECAY_STATE; + F32 const arterialPressure = getFilteredArterialPressure(); + F32 const venousPressure = getFilteredVenousPressure(); + F32 arterialDecayDiff = 0; + F32 venousDecayDiff = 0; + + if ( ( TRUE == didTimeout( pressureSelfTestDecayStartTime, DECAY_PRESSURE_SELF_TEST_TIME ) ) ) + { + arterialDecayDiff = fabs( arterialPressure - peakArterialPressure ); + venousDecayDiff = fabs( venousPressure - peakVenousPressure ); + + if (arterialDecayDiff < DECAY_PRESSURE_DIFF_TOLERANCE_MMHG && venousDecayDiff < DECAY_PRESSURE_DIFF_TOLERANCE_MMHG) + { + decayedArterialPressure = arterialPressure; + decayedVenousPressure = venousPressure; + pressureSelfTestStabilityStartTime = getMSTimerCount(); + state = DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE; + } + else + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialDecayDiff, venousDecayDiff ); + } + } + + + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + state = DRY_SELF_TESTS_STOPPED_STATE; + setupForSelfTestsStop(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleDrySelfTestPressureSensorsStabilityState function verifies the readings of + * pressure sensors in a stable, pressurized state after decay has been observed. + * @details Inputs: pressureSelfTestNormalizedStartTime, decayedArterialPressure + * decayedVenousPressure + * @details Outputs: pressureSelfTestNormalizedStartTime + * @return the next state of dry self-tests state machine + *************************************************************************/ +static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsStabilityState( void ) +{ + DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STABILITY_STATE; + F32 arterialStabilityDiff = 0; + F32 venousStabilityDiff = 0; + + if ( ( TRUE == didTimeout( pressureSelfTestStabilityStartTime, STABILTY_PRESSURE_SELF_TEST_TIME ) ) ) + { + arterialStabilityDiff = fabs( getFilteredArterialPressure() - decayedArterialPressure ); + venousStabilityDiff = fabs( getFilteredVenousPressure() - decayedVenousPressure ); + + if (arterialStabilityDiff < STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG && venousStabilityDiff < STABILITY_PRESSURE_DIFF_TOLERANCE_MMHG) + { + pressureSelfTestNormalizedStartTime = getMSTimerCount(); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); setValveAirTrap( STATE_OPEN ); - pressureSelfTestNormalizedStartTime = getMSTimerCount(); state = DRY_SELF_TESTS_PRESSURE_SENSORS_NORMAL_STATE; } else { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialPressure, venousPressure ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_PRE_TREATMENT_DRY_PRESSURE_TEST_FAILURE, arterialStabilityDiff, venousStabilityDiff ); } } @@ -1424,6 +1546,9 @@ } #endif + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ) + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, integratedVolumeDiff, WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE ) + if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement ) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( ( integratedVolumeDiff <= integrateVolumeToleranceG ) || ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_PCT_TOLERANCE ) ) ) @@ -1559,6 +1684,10 @@ integrateVolumeToleranceG = 50.0F; } #endif + + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, resOneDiffAfterDisplacement, resTwoDiffAfterDisplacement ) + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT, integratedVolumeToTargetPercent, WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE ) + if ( ( fabs( resOneDiffAfterDisplacement - resTwoDiffAfterDisplacement ) <= WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G ) && ( ( integratedVolumeDiff <= integrateVolumeToleranceG ) || ( integratedVolumeToTargetPercent <= WET_SELF_TEST_INTEGRATED_VOLUME_PCT_TOLERANCE ) ) ) Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r46b163d19c65e8c21db7b0247bbb1af0dba1ece5 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 46b163d19c65e8c21db7b0247bbb1af0dba1ece5) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -170,6 +170,10 @@ SW_FAULT_ID_DG_INVALID_FILL_COMMAND_REJECTED, SW_FAULT_ID_SEMAPHORE_IN_USE_TIMEOUT, // 140 SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, + SW_FAULT_ID_WRITE_USAGE_INFO_TO_NV_FAILURE, + SW_FAULT_ID_INVALID_NV_RECORD_SELECTED, + SW_FAULT_ID_BLOOD_LEAK_ENQUEUE_FAILURE, + SW_FAULT_ID_BLOOD_LEAK_INVALID_EMB_MODE_CMD_SELECTED, // 145 SW_FAULT_ID_INVALID_FPGA_ERROR_GROUP_SELECTED, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/FPGA.c =================================================================== diff -u -r242ad36c7a1ec4ee5012c9f009899f9e0bd87628 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 242ad36c7a1ec4ee5012c9f009899f9e0bd87628) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file FPGA.c * -* @author (last) Dara Navaei -* @date (last) 20-Jun-2022 +* @author (last) Dong Nguyen +* @date (last) 27-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -245,8 +245,10 @@ U16 bloodLeakRxFIFOCount; ///< Reg 448. Blood leak receive FIFO count. U08 bloodLeakRxFIFODataOut; ///< Reg 450. Blood leak receive FIFO data out. U08 dummyByte; ///< Reg 451. Dummy byte to meet the even of the data. + U16 fpgaCompatibilityRev; ///< Reg 452. Compatibility revisions U08 bloodLeakSelfTestErrorCounter; ///< Reg 452. Blood leak self test error counter. U08 bloodLeakZeroErrorCounter; ///< Reg 453. Blood leak zero error counter. + } FPGA_SENSORS_T; /// Record structure for FPGA continuous priority writes. @@ -931,25 +933,18 @@ { SELF_TEST_STATUS_T result; - // Check FPGA reported correct ID + // check FPGA reported correct ID if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) { // Check FPGA compatibility w/ firmware - if ( fpgaHeader.fpgaRevMajor > MIN_HD_FPGA_MAJOR ) + if ( HD_FPGA_COMPATIBILITY_REV == fpgaSensorReadings.fpgaCompatibilityRev ) { result = SELF_TEST_STATUS_PASSED; } else { - if ( fpgaHeader.fpgaRev >= MIN_HD_FPGA_MINOR ) - { - result = SELF_TEST_STATUS_PASSED; - } - else - { - result = SELF_TEST_STATUS_FAILED; - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaRevMajor, (U32)fpgaHeader.fpgaRev ) - } + result = SELF_TEST_STATUS_FAILED; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_POST_TEST_FAILED, (U32)HD_FPGA_COMPATIBILITY_REV, (U32)fpgaSensorReadings.fpgaCompatibilityRev ) } } else @@ -977,11 +972,14 @@ U32 const diffFPGATimerCount = (U32)u16DiffWithWrap( currentFPGATimerCount_ms, newFPGATimerCount_ms ); U32 const diffTimerCount = u32DiffWithWrap( currentTimerCount_ms, newTimerCount_ms ); - if ( getCurrentOperationMode() > MODE_INIT ) + if ( getCurrentOperationMode() != MODE_INIT ) { if ( abs( diffFPGATimerCount - diffTimerCount ) > PROCESSOR_FPGA_CLOCK_DIFF_TOLERANCE ) { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_CLOCK_SPEED_CHECK_FAILURE, diffFPGATimerCount, diffTimerCount ); + if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_CLOCK_SPEED_CHECK_FAILURE, diffFPGATimerCount, diffTimerCount ); + } } } Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file SystemComm.c * -* @author (last) Dara Navaei -* @date (last) 03-Aug-2022 +* @author (last) Dong Nguyen +* @date (last) 27-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -55,7 +55,10 @@ #define MSG_NOT_ACKED_MAX_RETRIES 20 ///< Maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm #define PENDING_ACK_LIST_SIZE 25 ///< Maximum number of Denali messages that can be pending ACK at any given time - + +#define MAX_FPGA_CLOCK_SPEED_ERRORS 3 ///< maximum number of FPGA clock speed errors within window period before alarm +#define MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< FPGA clock speed error window + #pragma pack(push, 1) /// Record for transmitted message that is pending acknowledgment from receiver. @@ -142,6 +145,9 @@ // Initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); + + // Initialize FPGA clock speed error time windowed count + initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CLOCK_SPEED_ERROR, MAX_FPGA_CLOCK_SPEED_ERRORS, MAX_FPGA_CLOCK_SPEED_ERROR_WINDOW_MS); // Initialize pending ACK list for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) @@ -256,7 +262,7 @@ * @return none *************************************************************************/ void execSystemCommRx( void ) -{ +{ // Parse messages from comm buffers and queue them processIncomingData(); @@ -698,7 +704,7 @@ { BOOL isThereMsgRcvd = TRUE; // Assume TRUE at first to get into while loop MESSAGE_WRAPPER_T message; - + while ( TRUE == isThereMsgRcvd ) { // See if any messages received @@ -1622,10 +1628,6 @@ handleTestSyringePumpHeprinBolusTargetRateOverrideRequest( message ); break; - case MSG_ID_HD_REQ_CURRENT_TREATMENT_PARAMETERS: - handleTestCurrentTreamtmentParametersRequest( message ); - break; - case MSG_ID_HD_FANS_DUTY_CYCLE_OVERRIDE: handleSetFansDutyCycleOverrideRequest( message ); break; @@ -1662,6 +1664,10 @@ handleResendAllAlarmsCommand( message ); break; + case MSG_ID_HD_REQ_CURRENT_TREATMENT_PARAMETERS: + handleTestCurrentTreamtmentParametersRequest( message ); + break; + // The default cannot be reached in VectorCAST since the cases are run in a for loop default: // Unrecognized message ID received - ignore Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -7,8 +7,8 @@ * * @file SystemCommMessages.c * -* @author (last) Bill Bracken -* @date (last) 22-Aug-2022 +* @author (last) Dong Nguyen +* @date (last) 27-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -43,6 +43,7 @@ #include "Valves.h" #include "WatchdogMgmt.h" #include "HDDefs.h" +#include "TaskPriority.h" /** * @addtogroup SystemCommMessages @@ -62,9 +63,9 @@ #pragma pack(pop) // ********** private data ********** - static BOOL testerLoggedIn = FALSE; ///< Flag indicates whether an external tester (connected PC) has sent a valid login message. static volatile U16 nextSeqNo = 1; ///< Value of sequence number to use for next transmitted message. + /// List of message IDs that are requested not to be transmitted. static BLOCKED_MSGS_DATA_T blockedMessagesForXmit = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -889,24 +890,26 @@ /*********************************************************************//** * @brief - * The handleSetHDStandbyDisinfectSubmode function handles setting the + * The handleSetHDStandbyDisinfectSubmodeRequest function handles setting the * standby submode to wait for disisnfect state. - * @details Inputs: none + * @details Inputs: 1=initiate, 0=cancel * @details Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ void handleSetHDStandbyDisinfectSubmodeRequest( MESSAGE_T *message ) { - BOOL result = FALSE; + U32 cmd; - // The payload should be 0 in this case because there is mode in this command - if ( 0 == message->hdr.payloadLen ) + if ( sizeof( U32 ) == message->hdr.payloadLen ) { - signalInitiateStandbyDisinfectSubmode(); + memcpy( &cmd, &message->payload[0], sizeof( U32 ) ); + signalInitiateStandbyDisinfectSubmode( cmd ); } - - sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_UI, result ); + else + { + handleSetHDStandbyDisinfectSubmodeResponse( FALSE, REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT ); + } } /*********************************************************************//** @@ -2352,8 +2355,6 @@ memcpy( &payload, message->payload, sizeof( TEMPERATURE_SENSORS_DATA_T ) ); setDialysateTemperatureReadings( payload.inletDialysate, payload.outletRedundant ); } - // TODO - what to do if invalid payload length? - // TODO - how to know if DG stops sending these? } /*********************************************************************//** @@ -7023,15 +7024,26 @@ { BOOL status = FALSE; HD_OP_MODE_T currentMode = getCurrentOperationMode(); + DG_OP_MODE_T currentDGMode = getDGOpMode(); REQUEST_REJECT_REASON_CODE_T reject; if ( 0 == message->hdr.payloadLen ) { if ( ( MODE_STAN == currentMode ) || ( MODE_FAUL == currentMode ) ) { - status = TRUE; + requestNewOperationMode( MODE_SERV ); - reject = REQUEST_REJECT_REASON_NONE; + + if ( (DG_MODE_STAN == currentDGMode) || (DG_MODE_FAUL == currentDGMode) ) + { + status = TRUE; + cmdSetDGToServiceMode(); + reject = REQUEST_REJECT_REASON_NONE; + } + else + { + reject = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; + } } else { @@ -7399,4 +7411,28 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } +/*********************************************************************//** + * @brief + * The sendDGServiceModeRequest function constructs a service mode request msg + * to the DG and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG Service mode request msg constructed and queued. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendDGServiceModeRequest() +{ + BOOL result; + MESSAGE_T msg; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_REQUEST_DG_SERVICE_MODE; + msg.hdr.payloadLen = 0; + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_DG, ACK_REQUIRED ); + + return result; +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 -r402885eda2ed755a079c854d1228ac5f76cbec7c --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 402885eda2ed755a079c854d1228ac5f76cbec7c) @@ -8,7 +8,7 @@ * @file SystemCommMessages.h * * @author (last) Dara Navaei -* @date (last) 03-Aug-2022 +* @date (last) 22-Sep-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -398,6 +398,15 @@ // MSG_ID_DG_START_STOP_CHEM_DISINFECT BOOL sendDGStartChemicalDisinfectModeCommand( BOOL start ); +// MSG_ID_HD_RESPONSE_SERVICE_MODE_REQUEST +void sendUIServiceModeResponse( BOOL accepted, U32 rejCode ); + +// MSG_ID_HD_REQUEST_DG_SERVICE_MODE +BOOL sendDGServiceModeRequest( void ); + +// MSG_ID_UI_REQUEST_SERVICE_MODE +void handleUIServiceModeRequest( MESSAGE_T *message ); + // MSG_ID_ALARM_STATUS BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); @@ -425,9 +434,6 @@ // MSG_ID_HD_SET_SW_CONFIG_RECORD void handleSetHDSoftwareConfigRecord( MESSAGE_T *message ); -// MSG_ID_UI_REQUEST_SERVICE_MODE -void handleUIServiceModeRequest( MESSAGE_T *message ); -void sendUIServiceModeResponse( BOOL accepted, U32 rejCode ); // MSG_ID_HD_REQUEST_DG_ALARMS BOOL sendRequestForDGResendAlarms( void );