Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r766708fceb0bdf1af8c7897df29d4f5036bfd3db -r27f3db92495948d4c1192421c1b0c20338c4a034 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 766708fceb0bdf1af8c7897df29d4f5036bfd3db) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 27f3db92495948d4c1192421c1b0c20338c4a034) @@ -15,7 +15,9 @@ * ***************************************************************************/ -#include "DialInFlow.h" +#include "DialInFlow.h" +#include "DGDefs.h" +#include "ModeInitPOST.h" #include "ModeTreatment.h" #include "OperationModes.h" #include "SystemCommMessages.h" @@ -35,8 +37,8 @@ #define RESERVOIR_SETTLE_TIME_MS 5000 ///< Time (in ms) allotted for reservoir to settle (after fill, before drain). #define SIZE_OF_SMALL_LOAD_CELL_AVG 8 ///< Small load cell moving average has 8 samples. -#define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. - +#define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. + /// States of the treatment reservoir management state machine. typedef enum TreatmentReservoirMgmt_States { @@ -47,7 +49,7 @@ TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE, ///< Wait for fill to complete. TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE, ///< Wait a bit for filled reservoir to settle before getting baseline weight (volume). TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE, ///< Wait for active reservoir to be consumed and switch cmd given - then back to flush DG lines state. - TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Wait for inactive reservoir to settle before getting final weight (volume) before starting to drain. + TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Wait for inactive reservoir to settle before getting final weight (volume) before starting to drain. NUM_OF_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of treatment reservoir mgmt. states. } TREATMENT_RESERVOIR_MGMT_STATE_T; @@ -82,14 +84,14 @@ static F32 lgFilteredReservoirWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; // Load cell filtering data -/// Holds load cell samples for small load cell moving average +/// Holds load cell samples for small load cell moving average. static F32 smLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_SMALL_LOAD_CELL_AVG ]; -static U32 smLoadCellReadingsIdx = 0; ///< index for next sample in small load cell rolling average sample array -static F32 smLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< rolling total - used to calc small load cell moving average -/// Holds load cell samples for large load cell moving average +static U32 smLoadCellReadingsIdx = 0; ///< Index for next sample in small load cell rolling average sample array. +static F32 smLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc small load cell moving average. +/// Holds load cell samples for large load cell moving average. static F32 lgLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; -static U32 lgLoadCellReadingsIdx = 0; ///< index for next sample in large load cell rolling average sample array -static F32 lgLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< rolling total - used to calc large load cell moving average +static U32 lgLoadCellReadingsIdx = 0; ///< Index for next sample in large load cell rolling average sample array. +static F32 lgLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. // DG pumps data static F32 dgROPumpFlowRateMlMin = 0.0; ///< Latest RO water flow rate reported by the DG. @@ -105,7 +107,9 @@ static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. static U32 resUseTimer = 0; ///< Used to track time pumping from active reservoir (for volume used calculation). static F32 resUseVolumeMl = 0.0; ///< Accumulated volume used from active reservoir. -static BOOL resHasBeenTared[ NUM_OF_DG_RESERVOIRS ]; ///< Flags indicate whether the reservoir has been tared for this treatment. + +// 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 ********** @@ -152,6 +156,15 @@ lgLoadCellReadings[ i ][ j ] = 0.0; } } + + // initialize DG command response + for ( i = 0; i < NUM_OF_DG_COMMANDS; i++ ) + { + dgCmdResp[ i ].commandID = DG_CMD_NONE; + dgCmdResp[ i ].rejected = TRUE; + dgCmdResp[ i ].rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + } + smLoadCellReadingsIdx = 0; smLoadCellReadingsTotal[ DG_RESERVOIR_1 ] = 0.0; smLoadCellReadingsTotal[ DG_RESERVOIR_2 ] = 0.0; @@ -173,21 +186,6 @@ // TODO - make sure DG sensor/state data is coming in timely manner (e.g. load cells s/b every 100 ms) } -/*********************************************************************//** - * @brief - * The initPreTreatmentReservoirMgmt function initializes the pre-treatment - * reservoir management state machine. - * @details Inputs: none - * @details Outputs: pre-treatment reservoir management state machine initialized. - * @return none - *************************************************************************/ -void initPreTreatmentReservoirMgmt( void ) -{ - // TODO - currentPreTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; - resMgmtTimer = 0; - resHasBeenTared[ DG_RESERVOIR_1 ] = FALSE; - resHasBeenTared[ DG_RESERVOIR_2 ] = FALSE; -} /*********************************************************************//** * @brief @@ -203,6 +201,19 @@ resMgmtTimer = 0; resUseTimer = getMSTimerCount(); resUseVolumeMl = 0.0; +} + +/*********************************************************************//** + * @brief + * The dialysisResumed function initializes the reservoir re-use timer + * when dialysis is started/resumed so that dialysate usage can be tracked. + * @details Inputs: none + * @details Outputs: resUseTimer + * @return none + *************************************************************************/ +void dialysisResumed( void ) +{ + resUseTimer = getMSTimerCount(); } /*********************************************************************//** @@ -219,22 +230,22 @@ U32 dgSubMode = getDGSubMode(); U32 msSinceLastVolumeCalc = calcTimeSince( resUseTimer ); F32 flowRateMlPerMs = (F32)getTargetDialInFlowRate() / (F32)( MS_PER_SECOND * SEC_PER_MIN ); - + // Calculate volume used from active reservoir - do not accumulate if saline bolus in progress if ( SALINE_BOLUS_STATE_IN_PROGRESS != getSalineBolusState() ) { resUseVolumeMl += ( flowRateMlPerMs * msSinceLastVolumeCalc ); // TODO - should this calc be done and kept by Dialysis sub-mode? } - resUseTimer = getMSTimerCount(); - + resUseTimer = getMSTimerCount(); + // Treatment reservoir mgmt. state machine switch ( currentTrtResMgmtState ) { case TREATMENT_RESERVOIR_MGMT_START_STATE: currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; break; - case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: + case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: if ( DG_MODE_CIRC == dgOpMode ) { if ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) @@ -255,7 +266,7 @@ case TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE: if ( DG_MODE_CIRC == dgOpMode ) { - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; + currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; } break; @@ -278,7 +289,7 @@ if ( DG_MODE_FILL == dgOpMode ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; - } + } break; case TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE: @@ -302,11 +313,10 @@ if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) && ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) ) { - DG_RESERVOIR_ID_T activeRes = dgActiveReservoirSet; - DG_RESERVOIR_ID_T inactiveRes = ( activeRes == DG_RESERVOIR_1 ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); + DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); // Signal dialysis sub-mode to capture baseline volume for next reservoir. - setStartReservoirVolume(); + setStartReservoirVolume( inactiveRes ); // Command DG to switch reservoirs cmdSetDGActiveReservoir( inactiveRes ); // Signal dialysis sub-mode to switch reservoirs @@ -326,8 +336,8 @@ // Reset to start state to restart drain, fill, switch process. currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; } - break; - + break; + default: // TODO - s/w fault currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; @@ -463,7 +473,7 @@ * @param loadCellID ID of load cell to get * @return the current load cell weight in grams *************************************************************************/ -F32 getLoadCellWeightInGrams( LOAD_CELL_T loadCellID ) +F32 getLoadCellWeightInGrams( LOAD_CELL_ID_T loadCellID ) { F32 result = 0.0; @@ -489,7 +499,7 @@ /*********************************************************************//** * @brief * The getReservoirWeightSmallFilter function gets the load cell weight - * of the given reservoir after large (8 sample) filter applied. + * of the given reservoir after small (8 sample) filter applied. * @details Inputs: lgFilteredReservoirWeightInGrams[] * @details Outputs: none * @param resID ID of reservoir to get filtered weight for @@ -672,6 +682,8 @@ void setNewLoadCellReadings( F32 res1Primary, F32 res1Backup, F32 res2Primary, F32 res2Backup ) { DG_RESERVOIR_ID_T res; + DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); + BOOL inTreatment = ( MODE_TREA == getCurrentOperationMode() ? TRUE : FALSE ); loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_PRIMARY ].data = res1Primary; loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_BACKUP ].data = res1Backup; @@ -681,8 +693,7 @@ // feed new weight samples into filters and update moving averages for ( res = DG_RESERVOIR_1; res < NUM_OF_DG_RESERVOIRS; res++ ) { - F32 wt = ( res == DG_RESERVOIR_1 ? res1Primary : res2Primary ); - + F32 wt = ( res == DG_RESERVOIR_1 ? res1Primary : res2Primary ); smLoadCellReadingsTotal[ res ] -= smLoadCellReadings[ res ][ smLoadCellReadingsIdx ]; lgLoadCellReadingsTotal[ res ] -= lgLoadCellReadings[ res ][ lgLoadCellReadingsIdx ]; smLoadCellReadings[ res ][ smLoadCellReadingsIdx ] = wt; @@ -710,7 +721,7 @@ { dgPrimaryTempSet = primaryHtrTemp; dgTrimmerTempSet = trimmerHtrTemp; - sendDialysateTempTargetsToDG( primaryHtrTemp, trimmerHtrTemp ); + sendDialysateTempTargetsToDG( dgPrimaryTempSet, dgTrimmerTempSet ); } /*********************************************************************//** @@ -751,8 +762,9 @@ *************************************************************************/ void cmdStartDGTrimmerHeater( void ) { - dgTrimmerHeaterOn = TRUE; - sendDGStartStopTrimmerHeaterCommand( START_DG_CMD ); + dgTrimmerHeaterOn = TRUE; + dgCmdResp[ DG_CMD_START_TRIMMER_HEATER ].commandID = DG_CMD_NONE; + sendDGStartStopTrimmerHeaterCommand( START_DG_CMD, dgTrimmerTempSet ); } /*********************************************************************//** @@ -765,8 +777,9 @@ *************************************************************************/ void cmdStopDGTrimmerHeater( void ) { - dgTrimmerHeaterOn = FALSE; - sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD ); + dgTrimmerHeaterOn = FALSE; + dgCmdResp[ DG_CMD_STOP_TRIMMER_HEATER ].commandID = DG_CMD_NONE; + sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD, 0 ); } /*********************************************************************//** @@ -782,14 +795,37 @@ { if ( resID < NUM_OF_DG_RESERVOIRS ) { - dgActiveReservoirSet = resID; + dgActiveReservoirSet = resID; + dgCmdResp[ DG_CMD_SWITCH_RESERVOIR ].commandID = DG_CMD_NONE; sendDGSwitchReservoirCommand( (U32)resID ); } else { - // TODO - s/w fault + 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 + * message to the DG. + * @details Inputs: none + * @details Outputs: change valve setting command sent to DG. + * @param valveSettingID ID of valve setting to change to + * @return none + *************************************************************************/ +void cmdChangeDGValveSetting( DG_VALVE_SETTING_ID_T valveSettingID ) +{ + if ( valveSettingID < NUM_OF_DG_VALVE_SETTTINGS ) + { + dgCmdResp[ DG_CMD_VALVE_SETTING ].commandID = DG_CMD_NONE; + sendDGChangeValveSettingCommand( (U32)valveSettingID ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_VALVE_SETTING_ID, (U32)valveSettingID ); + } +} /*********************************************************************//** * @brief @@ -800,7 +836,8 @@ * @return none *************************************************************************/ void cmdStartDGFill( U32 fillToVolMl ) -{ +{ + dgCmdResp[ DG_CMD_START_FILL ].commandID = DG_CMD_NONE; dgReservoirFillVolumeTargetSet = fillToVolMl; sendDGFillCommand( fillToVolMl ); } @@ -818,6 +855,7 @@ { DRAIN_RESERVOIR_CMD_PAYLOAD_T payload; + dgCmdResp[ DG_CMD_START_DRAIN ].commandID = DG_CMD_NONE; payload.drainToVolumeML = drainToVolMl; payload.tareLoadCells = tareLoadCell; dgReservoirDrainVolumeTargetSet = drainToVolMl; @@ -837,7 +875,70 @@ sendDGSampleWaterCommand(); } +/*********************************************************************//** + * @brief + * The handleDGCommandResponse function processes the latest DG command response. + * @details Inputs: none + * @details Outputs: process command response from DG + * @param dgCmdRespPtr pointer to DG command response data record + * @return none + *************************************************************************/ +void handleDGCommandResponse( DG_CMD_RESPONSE_T *dgCmdRespPtr ) +{ + if ( dgCmdRespPtr->commandID < NUM_OF_DG_COMMANDS ) + { + if ( DG_CMD_NONE != dgCmdRespPtr->commandID ) + { + memcpy( &dgCmdResp[ dgCmdRespPtr->commandID ], dgCmdRespPtr, sizeof( DG_CMD_RESPONSE_T ) ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_COMMAND_RESPONSE_ID, dgCmdRespPtr->commandID ); + } + if ( TRUE == dgCmdRespPtr->rejected ) + { + switch ( dgCmdRespPtr->rejectCode ) + { + case DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER: + activateAlarmNoData( ALARM_ID_DG_COMMAND_INVALID_PARAMETER_FAULT ); + break; + + case DG_CMD_REQUEST_REJECT_REASON_NONE: + case DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE: + default: + // Our state machines will detect and handle DG mode out of sync + // TODO Consider a generic handler for all state machine + break; + } + } +} + +/*********************************************************************//** + * @brief + * The getDGCommandResponse function gets the latest command response from DG. + * @details Inputs: dgCmdResp + * @details Outputs: none + * @param commandID id of specific interested command response + * @param cmdRespPtr pointer to data record to copy DG command response to + * @return TRUE if a specific command response has been received, otherwise FALSE + *************************************************************************/ +BOOL getDGCommandResponse( U32 commandID, DG_CMD_RESPONSE_T *cmdRespPtr ) +{ + BOOL hasCommandResp = FALSE; + + if ( commandID == dgCmdResp[ commandID ].commandID ) + { + hasCommandResp = TRUE; + memcpy( cmdRespPtr, &dgCmdResp[ commandID ], sizeof( DG_CMD_RESPONSE_T ) ); + dgCmdResp[ commandID ].commandID = DG_CMD_NONE; + } + + return hasCommandResp; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/