Index: firmware/App/Controllers/ConductivitySensors.c =================================================================== diff -u -r6085153faf2a176c51a34653bdd3a36a4699e528 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Controllers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 6085153faf2a176c51a34653bdd3a36a4699e528) +++ firmware/App/Controllers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -14,6 +14,7 @@ * @date (original) 13-Jul-2020 * ***************************************************************************/ +#include #include "ConductivitySensors.h" #include "FPGA.h" @@ -106,17 +107,20 @@ static BOOL packageStarted = FALSE; ///< Flag to indicate the start of a package measurement data. static U08 packageIndex = 0U; ///< Current package measurement data bytes index. static U08 package[ 50 ]; ///< Storage of package bytes until ready to process. +static DG_COND_SENSORS_CAL_RECORD_T condSensorsCalRecord; ///< Conductivity sensors' calibration record. // ********** private function prototypes ********** -static F32 calcCompensatedConductivity( F32 conductivity, F32 temperature); +static F32 calcCompensatedConductivity( F32 conductivity, F32 temperature ); static void calcRORejectionRatio( void ); static void processCPiCPoSensorRead( U32 sensorId, U32 fgpaRead, U08 fpgaReadCount, U08 fpgaErrorCount, U08 fpgaSensorFault ); static U32 prefixStrToSIFactor( U08 prefix ); static void processMeasurementDataPackage( U32 sensorId ); static void processCD1CD2SensorRead( U16 fpgaReadCount, U08 fpgaErrorCount ); static U32 getConductivityDataPublishInterval( void ); +static BOOL processCalibrationData( void ); +static F32 getCalibrationAppliedConductivityValue( U32 sensorId, F32 compensatedValue ); /*********************************************************************//** * @brief @@ -148,18 +152,37 @@ initPersistentAlarm( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE, RO_REJECTION_RATIO_PERSISTENCE_PERIOD, RO_REJECTION_RATIO_PERSISTENCE_PERIOD ); + + // TODO remove, temporary code + for ( i = 0; i < NUM_OF_CAL_DATA_COND_SENSORS; i++ ) + { + condSensorsCalRecord.condSensors[ i ].fourthOrderCoeff = 0.0; + condSensorsCalRecord.condSensors[ i ].thirdOrderCoeff = 0.0; + condSensorsCalRecord.condSensors[ i ].secondOrderCoeff = 0.0; + condSensorsCalRecord.condSensors[ i ].gain = 1.0; + condSensorsCalRecord.condSensors[ i ].offset = 0.0; + } + // TODO remove, temporary code } /*********************************************************************//** * @brief * The execConductivitySensors function gets conductivity sensors' latest * readings from FPGA and advertises them over CAN. * @details Inputs: none - * @details Outputs: Conductivity sensors' latest reading is updated and advertised. + * @details Outputs: Conductivity sensors' latest reading is updated and + * advertised. * @return none *************************************************************************/ void execConductivitySensors( void ) { + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPI_SENSOR, getFPGACPi(), getFPGACPiReadCount(), getFPGACPiErrorCount(), getFPGACPiFault() ); processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPO_SENSOR, getFPGACPo(), getFPGACPoReadCount(), getFPGACPoErrorCount(), getFPGACPoFault() ); processCD1CD2SensorRead( getFPGAEmstatRxFifoCount(), getFPGAEmstatRxErrCount() ); @@ -179,7 +202,6 @@ broadcastConductivityData( &data ); } - } /*********************************************************************//** @@ -264,7 +286,8 @@ BOOL isDialysateConductivityInRange( void ) { F32 const bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - BOOL const isConductivityInRange = isAcidConductivityInRange() && ( MIN_DIALYSATE_CONDUCTIVITY <= bicarbConductivity ) && ( bicarbConductivity <= MAX_DIALYSATE_CONDUCTIVITY ); + BOOL const isConductivityInRange = isAcidConductivityInRange() && ( MIN_DIALYSATE_CONDUCTIVITY <= bicarbConductivity ) && + ( bicarbConductivity <= MAX_DIALYSATE_CONDUCTIVITY ); return isConductivityInRange; } @@ -357,15 +380,17 @@ *************************************************************************/ static void processCPiCPoSensorRead( U32 sensorId, U32 fgpaRead, U08 fpgaReadCount, U08 fpgaErrorCount, U08 fpgaSensorFault ) { - if ( ( fpgaErrorCount == 0 ) && ( fpgaSensorFault == 0 ) ) + if ( ( 0 == fpgaErrorCount ) && ( 0 == fpgaSensorFault ) ) { if ( ( readCount[ sensorId ] != fpgaReadCount ) ) { F32 const temperature = getTemperatureValue( associateTempSensor[ sensorId ] ); F32 const conductivity = ( (F32)( fgpaRead ) / COND_SENSOR_DECIMAL_CONVERSION ); + F32 const compensatedCond = calcCompensatedConductivity( conductivity, temperature ); + readCount[ sensorId ] = fpgaReadCount; internalErrorCount[ sensorId ] = 0; - compensatedConductivityValues[ sensorId ].data = calcCompensatedConductivity( conductivity, temperature ); + compensatedConductivityValues[ sensorId ].data = getCalibrationAppliedConductivityValue( sensorId, compensatedCond ); } else { @@ -439,9 +464,10 @@ F32 const resistance = ( ( F32 )( hexStrToDec( measurementPtr->value, sizeof( measurementPtr->value ) ) - EMSTAT_PICO_MEASUREMENT_OFFSET ) / prefix ); F32 const temperature = getTemperatureValue( associateTempSensor[ sensorId ] ); F32 const conductivity = ( 1 / resistance * SIEMENS_TO_MICROSIEMENS_CONVERSION ); + F32 const compensatedCond = calcCompensatedConductivity( conductivity, temperature ); internalErrorCount[ sensorId ] = 0; - compensatedConductivityValues[ sensorId ].data = calcCompensatedConductivity( conductivity, temperature ); + compensatedConductivityValues[ sensorId ].data = getCalibrationAppliedConductivityValue( sensorId, compensatedCond ); } else { @@ -537,7 +563,71 @@ return result; } +/*********************************************************************//** + * @brief + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: condSensorsCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static BOOL processCalibrationData( void ) +{ + BOOL status = TRUE; + U32 sensor; + // Get the calibration record from NVDataMgmt + DG_COND_SENSORS_CAL_RECORD_T calData = getDGConducitivitySensorsCalibrationRecord(); + + for ( sensor = 0; sensor < NUM_OF_CAL_DATA_LOAD_CELLS; sensor++ ) + { + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.condSensors[ sensor ].calibrationTime ) + { +#ifndef DISABLE_CAL_CHECK + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_COND_SENSORS_INVALID_CALIBRATION, (U32)sensor ); +#endif + status = FALSE; + } + else + { + // The calibration data was valid, update the local copy + condSensorsCalRecord.condSensors[ sensor ].fourthOrderCoeff = calData.condSensors[ sensor ].fourthOrderCoeff; + condSensorsCalRecord.condSensors[ sensor ].thirdOrderCoeff = calData.condSensors[ sensor ].thirdOrderCoeff; + condSensorsCalRecord.condSensors[ sensor ].secondOrderCoeff = calData.condSensors[ sensor ].secondOrderCoeff; + condSensorsCalRecord.condSensors[ sensor ].gain = calData.condSensors[ sensor ].gain; + condSensorsCalRecord.condSensors[ sensor ].offset = calData.condSensors[ sensor ].offset; + } + } + + return status; +} + +/*********************************************************************//** + * @brief + * The getCalibrationAppliedConductivityValue function gets the temperature + * compensated conductivity value and applies calibration to it. + * @details Inputs: condSensorsCalRecord + * @details Outputs: none + * @param sensorId which is the conductivity sensor ID + * @param compensatedValue which is the temperature compensated conductivity + * value of the conductivity sensor + * @return the calibration applied conductivity value + *************************************************************************/ +static F32 getCalibrationAppliedConductivityValue( U32 sensorId, F32 compensatedValue ) +{ + F32 conductivity = pow(compensatedValue, 4) * condSensorsCalRecord.condSensors[ (CAL_DATA_DG_COND_SENSORS_T)sensorId ].fourthOrderCoeff + + pow(compensatedValue, 3) * condSensorsCalRecord.condSensors[ (CAL_DATA_DG_COND_SENSORS_T)sensorId ].thirdOrderCoeff + + pow(compensatedValue, 2) * condSensorsCalRecord.condSensors[ (CAL_DATA_DG_COND_SENSORS_T)sensorId ].secondOrderCoeff + + compensatedValue * condSensorsCalRecord.condSensors[ (CAL_DATA_DG_COND_SENSORS_T)sensorId ].gain + + condSensorsCalRecord.condSensors[ (CAL_DATA_DG_COND_SENSORS_T)sensorId ].offset; + return conductivity; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Controllers/DrainPump.c =================================================================== diff -u -ra2c32d4d221603054ca9ad7a097112caebf08c4e -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision a2c32d4d221603054ca9ad7a097112caebf08c4e) +++ firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -297,7 +297,8 @@ targetDrainPumpRPM = 0; drainPumpState = DRAIN_PUMP_OFF_STATE; hasClosedLoopBeenRequested = FALSE; - drainPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; // Set the control mode to none + drainPumpControlMode = PUMP_CONTROL_MODE_NONE; + drainPumpControlModeSet = drainPumpControlMode; drainControlTimerCounter = 0; } @@ -328,12 +329,13 @@ // The RPM is only checked in open loop state that the pump is run at a fixed RPM. // The persistent alarm waits for a couple of seconds before raising an alarm, this is supposed to cover // when the pump is turned on and it takes a while to ramp up to target RPM. - if( PUMP_CONTROL_MODE_OPEN_LOOP == drainPumpControlModeSet ) + if ( PUMP_CONTROL_MODE_OPEN_LOOP == drainPumpControlModeSet ) { - U32 targetRPM = getTargetDrainPumpRPM(); + // Using abs since the read RPM can be above or below the target + U32 rpmDiff = abs( getTargetDrainPumpRPM() - currentDrainPumpRPM ); - // Check if RPM is out of range. Using fabs since the read RPM can be above or below the target. - BOOL isRPMOutOfRange = fabs( targetRPM - currentDrainPumpRPM ) > MAX_ALLOWED_OPEN_LOOP_RPM_OUT_OF_RANGE; + // Check if RPM is out of range + BOOL isRPMOutOfRange = ( rpmDiff > MAX_ALLOWED_OPEN_LOOP_RPM_OUT_OF_RANGE ? TRUE : FALSE ); checkPersistentAlarm( ALARM_ID_DRAIN_PUMP_RPM_OUT_OF_RANGE, isRPMOutOfRange, currentDrainPumpRPM, MAX_ALLOWED_OPEN_LOOP_RPM_OUT_OF_RANGE ); } Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -rcea079b61dbd17b2ddaec99b1124248147d14e72 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision cea079b61dbd17b2ddaec99b1124248147d14e72) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -66,14 +66,14 @@ // ********** private data ********** static OVERRIDE_U32_T loadCellDataPublishInterval = { LOAD_CELL_REPORT_PERIOD, - LOAD_CELL_REPORT_PERIOD, 0, 0 }; ///< Broadcast load cell data publish interval. -static LOADCELL_T loadcells[ NUM_OF_LOAD_CELLS ]; ///< Load cell data structures. -static U32 loadCellFilterTimerCount = 0; ///< Load cell filtering timer count. -static U32 loadCellDataPublicationTimerCounter = 0; ///< Load cell data publication timer counter to CAN bus. + LOAD_CELL_REPORT_PERIOD, 0, 0 }; ///< Broadcast load cell data publish interval. +static LOADCELL_T loadcells[ NUM_OF_LOAD_CELLS ]; ///< Load cell data structures. +static U32 loadCellFilterTimerCount = 0; ///< Load cell filtering timer count. +static U32 loadCellDataPublicationTimerCounter = 0; ///< Load cell data publication timer counter to CAN bus. -static U32 smallReadingsIdx; ///< Index for next sample in load cell small rolling average sample array. -static U32 largeReadingsIdx; ///< Index for next sample in load cell large rolling average sample array. -static DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< Load cells calibration record. +static U32 smallReadingsIdx; ///< Index for next sample in load cell small rolling average sample array. +static U32 largeReadingsIdx; ///< Index for next sample in load cell large rolling average sample array. +static DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< Load cells calibration record. // ********** private function prototypes ********** @@ -174,7 +174,7 @@ } // Check if a new calibration is available - if ( isNewCalibrationRecordAvailable() == TRUE ) + if ( TRUE == isNewCalibrationRecordAvailable() ) { // Get the new calibration data and check its validity processCalibrationData(); @@ -190,13 +190,7 @@ for ( ii = 0; ii < NUM_OF_LOAD_CELLS; ++ii ) { loadcells[ ii ].weight.data = (F32)loadcells[ ii ].rawReading * ADC2GRAM; - // Apply the calibration factors to the data. - // load_cell_weight = fourth_order_coeff * (load_cell^4) + third_order_coeff * (load_cell^3) + second_order_coeff * (load_cell^2) + gain * load_cell + offset - loadcells[ ii ].weight.data = pow(loadcells[ ii ].weight.data, 4) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].fourthOrderCoeff + - pow(loadcells[ ii ].weight.data, 3) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].thirdOrderCoeff + - pow(loadcells[ ii ].weight.data, 2) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].secondOrderCoeff + - loadcells[ ii ].weight.data * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].gain + - loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].offset; + loadcells[ ii ].weight.data = loadcells[ ii ].weight.data - loadcells[ ii ].autoCalOffset; loadcells[ ii ].loadCellVelocity_g_min = ( getLoadCellWeight( (LOAD_CELL_ID_T)ii ) - loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ] ) * (F32)SEC_PER_MIN; @@ -205,7 +199,16 @@ loadcells[ ii ].smallFilterTotal -= loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ]; loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ] = getLoadCellWeight( (LOAD_CELL_ID_T)ii ); loadcells[ ii ].smallFilterTotal += getLoadCellWeight( (LOAD_CELL_ID_T)ii ); - loadcells[ ii ].smallFilteredWeight = (F32)( loadcells[ ii ].smallFilterTotal / (F64)SIZE_OF_SMALL_LOAD_CELL_AVG ); + + // Calculate the load cell value before appyling calibration to it + F32 loadCell = (F32)( loadcells[ ii ].smallFilterTotal / (F64)SIZE_OF_SMALL_LOAD_CELL_AVG ); + // Apply the calibration factors to the data. + // load_cell_weight = fourth_order_coeff * (load_cell^4) + third_order_coeff * (load_cell^3) + second_order_coeff * (load_cell^2) + gain * load_cell + offset + loadcells[ ii ].smallFilteredWeight = pow(loadCell, 4) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].fourthOrderCoeff + + pow(loadCell, 3) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].thirdOrderCoeff + + pow(loadCell, 2) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].secondOrderCoeff + + loadCell * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].gain + + loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].offset; } smallReadingsIdx = INC_WRAP( smallReadingsIdx, 0, SIZE_OF_SMALL_LOAD_CELL_AVG - 1 ); @@ -448,7 +451,7 @@ * The processCalibrationData function gets the calibration data and makes * sure it is valid by checking the calibration date. The calibration date * should not be 0. - * @details Inputs: loadCellsCalRecord + * @details Inputs: none * @details Outputs: loadCellsCalRecord * @return TRUE if the calibration record is valid, otherwise FALSE *************************************************************************/ @@ -465,7 +468,7 @@ // Check if the calibration data that was received from NVDataMgmt is legitimate // The calibration date item should not be zero. If the calibration date is 0, // then the load cells data is not stored in the NV memory or it was corrupted. - if ( calData.loadCells[ cell ].calibrationTime == 0 ) + if ( 0 == calData.loadCells[ cell ].calibrationTime ) { #ifndef DISABLE_CAL_CHECK SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_LOAD_CELLS_INVALID_CALIBRATION, (U32)cell ); Index: firmware/App/Controllers/Pressures.c =================================================================== diff -u -r847478dd75aac2edfe27df454ac5a644b6f30040 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Controllers/Pressures.c (.../Pressures.c) (revision 847478dd75aac2edfe27df454ac5a644b6f30040) +++ firmware/App/Controllers/Pressures.c (.../Pressures.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -14,10 +14,12 @@ * @date (original) 04-Apr-2020 * ***************************************************************************/ +#include #include "AlarmMgmt.h" #include "FPGA.h" -#include "InternalADC.h" +#include "InternalADC.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "Pressures.h" @@ -74,14 +76,16 @@ static U32 pressureFilterCounter = 0; ///< Used to schedule pressure sensor filtering. static PRESSURE_SELF_TEST_STATE_T pressuresSelfTestState; ///< Current pressure self-test state. -static SELF_TEST_STATUS_T pressuresSelfTestResult; ///< Self-test result of the Pressures module. +static SELF_TEST_STATUS_T pressuresSelfTestResult; ///< Self-test result of the Pressures module. +static DG_PRES_SENSORS_CAL_RECORD_T pressuresCalRecord; ///< Pressures calibration record. // ********** private function prototypes ********** static PRESSURE_STATE_T handlePressuresInitState( void ); static PRESSURE_STATE_T handlePressuresContReadState( void ); static void publishPressuresData( void ); -static U32 getPublishPressuresDataInterval( void ); +static U32 getPublishPressuresDataInterval( void ); +static BOOL processCalibrationData( void ); static SELF_TEST_STATUS_T handleSelfTestADCCheck( void ); @@ -94,7 +98,7 @@ *************************************************************************/ void initPressures( void ) { - U32 i; + U32 i; for ( i = 0; i < NUM_OF_PRESSURE_SENSORS; i++ ) { @@ -111,8 +115,84 @@ pressuresDataPublicationTimerCounter = 0; initPersistentAlarm( ALARM_ID_INLET_WATER_LOW_PRESSURE, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD ); - initPersistentAlarm( ALARM_ID_INLET_WATER_PRESSURE_FAULT, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD ); + initPersistentAlarm( ALARM_ID_INLET_WATER_PRESSURE_FAULT, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD, INLET_WATER_PRESSURE_PERSISTENCE_PERIOD ); + + // TODO remove, temporary code + for ( i = 0; i < NUM_OF_CAL_DATA_PRES_SENSORS; i++ ) + { + pressuresCalRecord.pressureSensors[ i ].fourthOrderCoeff = 0.0; + pressuresCalRecord.pressureSensors[ i ].thirdOrderCoeff = 0.0; + pressuresCalRecord.pressureSensors[ i ].secondOrderCoeff = 0.0; + pressuresCalRecord.pressureSensors[ i ].gain = 1.0; + pressuresCalRecord.pressureSensors[ i ].offset = 0.0; + } + // TODO remove, temporary code } + +/*********************************************************************//** + * @brief + * The checkInletPressure function checks inlet water pressure value + * and triggers an alarm when pressure value is out of allowed range. + * @details Inputs: RO pump inlet pressure sensor value + * @details Outputs: Triggers low pressure persistent alarm + * @return none + *************************************************************************/ +void checkInletPressure( void ) +{ +#ifndef DISABLE_WATER_QUALITY_CHECK + F32 const pressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); + BOOL const isPressureTooLow = ( pressure < MIN_INLET_WATER_PRESSURE ); + + checkPersistentAlarm( ALARM_ID_INLET_WATER_LOW_PRESSURE, isPressureTooLow, pressure, MIN_INLET_WATER_PRESSURE ); +#endif +} + +/*********************************************************************//** + * @brief + * The checkInletPressureFault function checks inlet water pressure value + * and triggers a machine fault when pressure value is out of allowed range. + * @details Inputs: RO pump inlet pressure sensor value + * @details Outputs: Triggers pressure fault persistent alarm + * @return none + *************************************************************************/ +void checkInletPressureFault( void ) +{ + F32 const pressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); + BOOL const isPressureTooLow = ( pressure < MIN_INLET_WATER_PRESSURE ); + + checkPersistentAlarm( ALARM_ID_INLET_WATER_PRESSURE_FAULT, isPressureTooLow, pressure, MIN_INLET_WATER_PRESSURE ); +} + +/*********************************************************************//** + * @brief + * The getMeasuredArterialPressure function gets the current arterial pressure. + * @details Inputs: arterialPressure + * @details Outputs: none + * @param pressureID pressure sensor ID + * @return the current arterial pressure (in mmHg). + *************************************************************************/ +F32 getMeasuredDGPressure( U32 pressureID ) +{ + F32 result = 0.0; + + if ( pressureID < NUM_OF_PRESSURE_SENSORS ) + { + if ( OVERRIDE_KEY == pressures[ pressureID ].override ) + { + result = pressures[ pressureID ].ovData; + } + else + { + result = pressures[ pressureID ].data; + } + } + else + { + activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); + } + + return result; +} /*********************************************************************//** * @brief @@ -143,6 +223,39 @@ // publish pressure/occlusion data on interval publishPressuresData(); +} + +/*********************************************************************//** + * @brief + * The execPressureSelfTest function executes the pressures self-test's state machine. + * @details Inputs: pressuresSelfTestState + * @details Outputs: pressuresSelfTestState + * @return PressuresSelfTestResult (SELF_TEST_STATUS_T) + *************************************************************************/ +SELF_TEST_STATUS_T execPressureSelfTest( void ) +{ + switch ( pressuresSelfTestState ) + { + case PRESSURE_SELF_TEST_STATE_START: + pressuresSelfTestState = PRESSURE_TEST_STATE_IN_PROGRESS; + pressuresSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; + break; + + case PRESSURE_TEST_STATE_IN_PROGRESS: + pressuresSelfTestResult = handleSelfTestADCCheck(); + pressuresSelfTestState = PRESSURE_TEST_STATE_COMPLETE; + break; + + case PRESSURE_TEST_STATE_COMPLETE: + // Done with self-test + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_TEMPERATURE_SENSORS_INVALID_SELF_TEST_STATE, pressuresSelfTestState ); + break; + } + + return pressuresSelfTestResult; } /*********************************************************************//** @@ -182,40 +295,62 @@ measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_INLET ] += measuredPressureReadingsRaw[ PRESSURE_SENSOR_RO_PUMP_INLET ]; measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_OUTLET ] += measuredPressureReadingsRaw[ PRESSURE_SENSOR_RO_PUMP_OUTLET ]; measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ] += measuredPressureReadingsRaw[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ]; - measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] += measuredPressureReadingsRaw[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ]; + measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] += measuredPressureReadingsRaw[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ]; + + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } // filter every 200ms if ( ++pressureFilterCounter >= PRESSURE_SAMPLES_TO_AVERAGE ) - { // calculate average pressures + { + U32 sensor; + F32 pressuresBeforeCal[ NUM_OF_PRESSURE_SENSORS ]; + + // Calculate average pressures F32 avgRoIn = (F32)measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_INLET ] * PRESSURE_AVERAGE_MULTIPLIER; F32 avgRoOut = (F32)measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_OUTLET ] * PRESSURE_AVERAGE_MULTIPLIER; F32 avgDrnIn = (F32)measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ] * PRESSURE_AVERAGE_MULTIPLIER; - F32 avgDrnOut = (F32)measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] * PRESSURE_AVERAGE_MULTIPLIER; + F32 avgDrnOut = (F32)measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] * PRESSURE_AVERAGE_MULTIPLIER; + + // Convert average pressure readings to PSI + pressuresBeforeCal[ PRESSURE_SENSOR_RO_PUMP_INLET ] = avgRoIn * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; + pressuresBeforeCal[ PRESSURE_SENSOR_RO_PUMP_OUTLET ] = avgRoOut * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; + pressuresBeforeCal[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ] = avgDrnIn * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; + pressuresBeforeCal[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] = avgDrnOut * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; - // reset average counter - pressureFilterCounter = 0; + // Reset average counter + pressureFilterCounter = 0; + + // Apply calibration to the pressure values prior to storing them + for ( sensor = 0; sensor < NUM_OF_PRESSURE_SENSORS; sensor++ ) + { + pressures[ sensor ].data = pow(pressuresBeforeCal[ sensor ], 4) * pressuresCalRecord.pressureSensors[ sensor ].fourthOrderCoeff + + pow(pressuresBeforeCal[ sensor ], 3) * pressuresCalRecord.pressureSensors[ sensor ].thirdOrderCoeff + + pow(pressuresBeforeCal[ sensor ], 2) * pressuresCalRecord.pressureSensors[ sensor ].secondOrderCoeff + + pressuresBeforeCal[ sensor ] * pressuresCalRecord.pressureSensors[ sensor ].gain + + pressuresCalRecord.pressureSensors[ sensor ].offset; + } - // convert average pressure readings to PSI - pressures[ PRESSURE_SENSOR_RO_PUMP_INLET ].data = avgRoIn * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; - pressures[ PRESSURE_SENSOR_RO_PUMP_OUTLET ].data = avgRoOut * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; - pressures[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ].data = avgDrnIn * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; - pressures[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ].data = avgDrnOut * PUMP_PRESSURE_PSIA_PER_COUNT - PUMP_PRESSURE_PSIA_TO_PSI_OFFSET; - // reset sums for next averaging measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_INLET ] = 0; measuredPressureReadingsSum[ PRESSURE_SENSOR_RO_PUMP_OUTLET ] = 0; measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_INLET ] = 0; measuredPressureReadingsSum[ PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] = 0; - } - + } + // TODO - any other checks return result; } /*********************************************************************//** * @brief - * The getPublishPressuresDataInterval function gets the pressure data publish internval. + * The getPublishPressuresDataInterval function gets the pressure data + * publish interval. * @details Inputs: pressuresDataPublishInterval * @details Outputs: none * @return the current pressures data publication interval (in task intervals). @@ -230,71 +365,49 @@ } return result; -} +} /*********************************************************************//** * @brief - * The checkInletPressure function checks inlet water pressure value - * and triggers an alarm when pressure value is out of allowed range. - * @details Inputs: RO pump inlet pressure sensor value - * @details Outputs: Triggers low pressure persistent alarm - * @return none + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: loadCellsCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE *************************************************************************/ -void checkInletPressure( void ) +static BOOL processCalibrationData( void ) { -#ifndef DISABLE_WATER_QUALITY_CHECK - F32 const pressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); - BOOL const isPressureTooLow = ( pressure < MIN_INLET_WATER_PRESSURE ); + BOOL status = TRUE; + U32 sensor; - checkPersistentAlarm( ALARM_ID_INLET_WATER_LOW_PRESSURE, isPressureTooLow, pressure, MIN_INLET_WATER_PRESSURE ); + // Get the calibration record from NVDataMgmt + DG_PRES_SENSORS_CAL_RECORD_T calData = getDGPressureSensorsCalibrationRecord(); + + for ( sensor = 0; sensor < NUM_OF_CAL_DATA_PRES_SENSORS; sensor++ ) + { + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.pressureSensors[ sensor ].calibrationTime ) + { +#ifndef DISABLE_CAL_CHECK + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRESSURE_SENSORS_INVALID_CALIBRATION, (U32)sensor ); #endif -} + status = FALSE; + } + else + { + // The calibration data was valid, update the local copy + pressuresCalRecord.pressureSensors[ sensor ].fourthOrderCoeff = calData.pressureSensors[ sensor ].fourthOrderCoeff; + pressuresCalRecord.pressureSensors[ sensor ].thirdOrderCoeff = calData.pressureSensors[ sensor ].thirdOrderCoeff; + pressuresCalRecord.pressureSensors[ sensor ].secondOrderCoeff = calData.pressureSensors[ sensor ].secondOrderCoeff; + pressuresCalRecord.pressureSensors[ sensor ].gain = calData.pressureSensors[ sensor ].gain; + pressuresCalRecord.pressureSensors[ sensor ].offset = calData.pressureSensors[ sensor ].offset; + } + } -/*********************************************************************//** - * @brief - * The checkInletPressureFault function checks inlet water pressure value - * and triggers a machine fault when pressure value is out of allowed range. - * @details Inputs: RO pump inlet pressure sensor value - * @details Outputs: Triggers pressure fault persistent alarm - * @return none - *************************************************************************/ -void checkInletPressureFault( void ) -{ - F32 const pressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); - BOOL const isPressureTooLow = ( pressure < MIN_INLET_WATER_PRESSURE ); - - checkPersistentAlarm( ALARM_ID_INLET_WATER_PRESSURE_FAULT, isPressureTooLow, pressure, MIN_INLET_WATER_PRESSURE ); -} - -/*********************************************************************//** - * @brief - * The getMeasuredArterialPressure function gets the current arterial pressure. - * @details Inputs: arterialPressure - * @details Outputs: none - * @param pressureID pressure sensor ID - * @return the current arterial pressure (in mmHg). - *************************************************************************/ -F32 getMeasuredDGPressure( U32 pressureID ) -{ - F32 result = 0.0; - - if ( pressureID < NUM_OF_PRESSURE_SENSORS ) - { - if ( OVERRIDE_KEY == pressures[ pressureID ].override ) - { - result = pressures[ pressureID ].ovData; - } - else - { - result = pressures[ pressureID ].data; - } - } - else - { - activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); - } - - return result; + return status; } /*********************************************************************//** @@ -319,39 +432,6 @@ } } -/*********************************************************************//** - * @brief - * The execPressureSelfTest function executes the pressures self-test's state machine. - * @details Inputs: pressuresSelfTestState - * @details Outputs: pressuresSelfTestState - * @return PressuresSelfTestResult (SELF_TEST_STATUS_T) - *************************************************************************/ -SELF_TEST_STATUS_T execPressureSelfTest( void ) -{ - switch ( pressuresSelfTestState ) - { - case PRESSURE_SELF_TEST_STATE_START: - pressuresSelfTestState = PRESSURE_TEST_STATE_IN_PROGRESS; - pressuresSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; - break; - - case PRESSURE_TEST_STATE_IN_PROGRESS: - pressuresSelfTestResult = handleSelfTestADCCheck(); - pressuresSelfTestState = PRESSURE_TEST_STATE_COMPLETE; - break; - - case PRESSURE_TEST_STATE_COMPLETE: - // Done with self-test - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_TEMPERATURE_SENSORS_INVALID_SELF_TEST_STATE, pressuresSelfTestState ); - break; - } - - return pressuresSelfTestResult; -} - /*********************************************************************//** * @brief * The handleSelfTestADCCheck function checks whether the ADC reads and @@ -366,7 +446,7 @@ SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; U16 const inletPressureADCReading = getIntADCReading( INT_ADC_RO_PUMP_INLET_PRESSURE ); - if ( ( inletPressureADCReading == 0 ) || ( inletPressureADCReading >= INT_ADC_FULL_SCALE_BITS ) ) + if ( ( 0 == inletPressureADCReading ) || ( inletPressureADCReading >= INT_ADC_FULL_SCALE_BITS ) ) { result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_PRESSURE_SENSOR_FAULT, inletPressureADCReading ); Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r81cd7f8794002173ba1b8bb886d33a03ce3c6f83 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 81cd7f8794002173ba1b8bb886d33a03ce3c6f83) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -21,9 +21,10 @@ #include "mibspi.h" #include "FPGA.h" +#include "NVDataMgmt.h" #include "OperationModes.h" -#include "PIControllers.h" #include "PersistentAlarm.h" +#include "PIControllers.h" #include "Pressures.h" #include "ROPump.h" #include "SafetyShutdown.h" @@ -132,6 +133,7 @@ static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. static U32 flowFilterCounter = 0; ///< Flow filtering counter. +static DG_FLOW_SENSORS_CAL_RECORD_T flowSensorsCalRecord; ///< Flow sensors calibration record. // ********** private function prototypes ********** @@ -146,6 +148,7 @@ static void stopROPump( void ); static void publishROPumpData( void ); static U32 getPublishROPumpDataInterval( void ); +static BOOL processCalibrationData( void ); /*********************************************************************//** * @brief @@ -191,6 +194,15 @@ roPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; roPumpControlModeSet = roPumpControlMode; isROPumpOn = FALSE; + + // TODO temporary initialization + // Reset the calibration variables + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].fourthOrderCoeff = 0.0; + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].thirdOrderCoeff = 0.0; + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].secondOrderCoeff = 0.0; + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].gain = 1.0; + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].offset = 0.0; + // TODO temporary initialization, remove } /*********************************************************************//** @@ -334,20 +346,38 @@ BOOL isPressureMax = actualPressure >= MAX_ALLOWED_MEASURED_PRESSURE_PSI; checkPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure, MAX_ALLOWED_MEASURED_PRESSURE_PSI ); + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + // Read flow at the control set if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) { - F32 avgROFlow = (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER; + U32 sensor; + F32 flow = RO_FLOW_ADC_TO_LPM_FACTOR / ( (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER ); + // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that // the flow is 0. Otherwise, convert the count to flow rate in mL/min - if ( ( roFlowReading == FLOW_SENSOR_ZERO_READING ) || ( roFlowReading == 0 ) ) + if ( ( FLOW_SENSOR_ZERO_READING == roFlowReading ) || ( 0 == roFlowReading ) ) { measuredROFlowRateLPM.data = 0.0; } else { - measuredROFlowRateLPM.data = RO_FLOW_ADC_TO_LPM_FACTOR / avgROFlow; + // Right now there is only one flow sensor but a for loop is used here to be able to automatically accommodate + // the future flow sensors + for( sensor = 0; sensor < NUM_OF_CAL_DATA_FLOW_SENSORS; sensor++ ) + { + measuredROFlowRateLPM.data = pow(flow, 4) * flowSensorsCalRecord.flowSensors[ sensor ].fourthOrderCoeff + + pow(flow, 3) * flowSensorsCalRecord.flowSensors[ sensor ].thirdOrderCoeff + + pow(flow, 2) * flowSensorsCalRecord.flowSensors[ sensor ].secondOrderCoeff + + flow * flowSensorsCalRecord.flowSensors[ sensor ].gain + + flowSensorsCalRecord.flowSensors[ sensor ].offset; + } } measuredFlowReadingsSum = 0; @@ -465,6 +495,51 @@ /*********************************************************************//** * @brief + * The getTargetROPumpFlowRate function gets the current target RO pump + * flow rate. + * @details Inputs: targetROPumpFlowRate + * @details Outputs: targetROPumpFlowRate + * @return the current target RO flow rate (in L/min). + *************************************************************************/ +F32 getTargetROPumpFlowRate( void ) +{ + return targetROPumpFlowRate; +} + +/*********************************************************************//** + * @brief + * The getMeasuredROFlowRate function gets the measured RO pump flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @return the current RO pump flow rate (in L/min). + *************************************************************************/ +F32 getMeasuredROFlowRate( void ) +{ + F32 result = measuredROFlowRateLPM.data; + + if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) + { + result = measuredROFlowRateLPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTargetROPumpPressure function gets the current target RO pump + * pressure. + * @details Inputs: targetROPumpPressure + * @details Outputs: targetROPumpPressure + * @return the current target RO targetROPumpPressure in psi. + *************************************************************************/ +F32 getTargetROPumpPressure( void ) +{ + return targetROPumpMaxPressure; +} + +/*********************************************************************//** + * @brief * The handleROPumpOffState function handles the RO pump off state of the * controller state machine. * @details Inputs: roPumpControlMode, roPumpPWMDutyCyclePctSet, @@ -723,51 +798,49 @@ /*********************************************************************//** * @brief - * The getTargetROPumpFlowRate function gets the current target RO pump - * flow rate. - * @details Inputs: targetROPumpFlowRate - * @details Outputs: targetROPumpFlowRate - * @return the current target RO flow rate (in L/min). + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: flowSensorsCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE *************************************************************************/ -F32 getTargetROPumpFlowRate( void ) +static BOOL processCalibrationData( void ) { - return targetROPumpFlowRate; -} + BOOL status = TRUE; + U32 sensor; -/*********************************************************************//** - * @brief - * The getMeasuredROFlowRate function gets the measured RO pump flow rate. - * @details Inputs: measuredROFlowRateLPM - * @details Outputs: measuredROFlowRateLPM - * @return the current RO pump flow rate (in L/min). - *************************************************************************/ -F32 getMeasuredROFlowRate( void ) -{ - F32 result = measuredROFlowRateLPM.data; + // Get the calibration record from NVDataMgmt + DG_FLOW_SENSORS_CAL_RECORD_T calData = getDGFlowSensorsCalibrationRecord(); - if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) + for ( sensor = 0; sensor < NUM_OF_CAL_DATA_FLOW_SENSORS; sensor++ ) { - result = measuredROFlowRateLPM.ovData; + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the flow sensors data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.flowSensors[ sensor ].calibrationTime ) + { +#ifndef DISABLE_CAL_CHECK + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_FLOW_SENSORS_INVALID_CALIBRATION, (U32)sensor ); +#endif + status = FALSE; + } + else + { + // The calibration data was valid, update the local copy + flowSensorsCalRecord.flowSensors[ sensor ].fourthOrderCoeff = calData.flowSensors[ sensor ].fourthOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].thirdOrderCoeff = calData.flowSensors[ sensor ].thirdOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].secondOrderCoeff = calData.flowSensors[ sensor ].secondOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].gain = calData.flowSensors[ sensor ].gain; + flowSensorsCalRecord.flowSensors[ sensor ].offset = calData.flowSensors[ sensor ].offset; + } } - return result; + return status; } /*********************************************************************//** * @brief - * The getTargetROPumpPressure function gets the current target RO pump - * pressure. - * @details Inputs: targetROPumpPressure - * @details Outputs: targetROPumpPressure - * @return the current target RO targetROPumpPressure in psi. - *************************************************************************/ -F32 getTargetROPumpPressure( void ) -{ - return targetROPumpMaxPressure; -} - -/*********************************************************************//** - * @brief * The publishROPumpData function publishes RO pump data at the set interval. * @details Inputs: roPumpDataPublicationTimerCounter * @details Outputs: roPumpDataPublicationTimerCounter @@ -791,6 +864,7 @@ } } + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/DGCommon.h =================================================================== diff -u -r81cd7f8794002173ba1b8bb886d33a03ce3c6f83 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 81cd7f8794002173ba1b8bb886d33a03ce3c6f83) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -55,7 +55,6 @@ #define DISABLE_WATER_QUALITY_CHECK 1 #define DISABLE_RTC_CONFIG 1 //#define V_2_SYSTEM 1 - //#define SKIP_RECIRC 1 #define THD_USING_TRO_CONNECTOR 1 #define IGNORE_CONC_PUMP_IN_HEAT_DISINFECT 1 #include Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -rba0335ef18c7859109251f130178acc785c1d39e -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision ba0335ef18c7859109251f130178acc785c1d39e) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -2012,16 +2012,16 @@ if ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) { - uiData.chemDisinfectTargetTime = CHEM_DISINFECT_TIME_MS; - uiData.chemDisinfectElapsedTime = calcTimeSince( chemDisinfectTimer ); - data.R1FillLevel = R1ChemDisinfectVol; - data.R2FillLevel = R2ChemDisinfectVol; + uiData.chemDisinfectTargetTime = CHEM_DISINFECT_TIME_MS; + uiData.chemDisinfectCountdownTime = CHEM_DISINFECT_TIME_MS - calcTimeSince( chemDisinfectTimer ); + data.R1FillLevel = R1ChemDisinfectVol; + data.R2FillLevel = R2ChemDisinfectVol; } else { - uiData.chemDisinfectElapsedTime = 0.0; - data.R1FillLevel = 0.0; - data.R2FillLevel = 0.0; + uiData.chemDisinfectCountdownTime = 0.0; + data.R1FillLevel = 0.0; + data.R2FillLevel = 0.0; } data.postDisinfectTargetRinseCount = NUM_OF_POST_DISINFECT_RINSES; Index: firmware/App/Modes/ModeChemicalDisinfect.h =================================================================== diff -u -r3f7d30b23906496854054949d4491f3bae6ef3c4 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeChemicalDisinfect.h (.../ModeChemicalDisinfect.h) (revision 3f7d30b23906496854054949d4491f3bae6ef3c4) +++ firmware/App/Modes/ModeChemicalDisinfect.h (.../ModeChemicalDisinfect.h) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -31,26 +31,11 @@ // ********** public definitions ********** -/// Chemical disinfect data -typedef struct -{ - U32 chemDisinfectState; ///< Chemical disinfect state. - U32 overallElapsedTime; ///< Overall elapsed time in chemical disinfect mode. - U32 stateElapsedTime; ///< Current chemical disinfect elapsed time. - U32 cancellationMode; ///< Chemical disinfect cancellation mode. - F32 R1FillLevel; ///< Reservoir 1 level upon starting the chemical disinfect. - F32 R2FillLevel; ///< Reservoir 2 level upon starting the chemical disinfect. - U32 postDisinfectTargetRinseCount; ///< Target post disinfect rinse count. - U32 postDisinfectCurrentRinseCount; ///< Current post disinfect rinse count. - U32 chemDisinfectUIState; ///< Chemical disinfect UI state. -} MODE_CHEMICAL_DISINFECT_DATA_T; - /// Chemical disinfect UI data typedef struct { U32 chemDisinfectTargetTime; ///< Target time during chemical disinfect. - U32 chemDisinfectElapsedTime; ///< Elapsed time during chemical disinfect. - + U32 chemDisinfectCountdownTime; ///< Chemical disinfect count down time. } MODE_CHEMICAL_DISINFECT_UI_DATA_T; // ********** public function prototypes ********** Index: firmware/App/Modes/ModeFlush.c =================================================================== diff -u -r654c5598765bb862c00a0175bdac95604c6c9b24 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 654c5598765bb862c00a0175bdac95604c6c9b24) +++ firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -15,6 +15,7 @@ * ***************************************************************************/ +#include "ConcentratePumps.h" #include "DrainPump.h" #include "Heaters.h" #include "LoadCell.h" @@ -39,33 +40,36 @@ // General defines #define FLUSH_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode flush data publish interval in counts. -#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. TODO original flow was 0.8 -#define RO_PUMP_MAX_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. -#define DRAIN_PUMP_TARGET_RPM 2200 ///< Drain pump target RPM during drain. +#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. +#define RO_PUMP_MAX_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define DRAIN_PUMP_TARGET_RPM 2200 ///< Drain pump target RPM during drain. // Drain R1 & R2 states defines -#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // Flush drain path state defines -#define FLUSH_DRAIN_WAIT_TIME_MS ( 1 * 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time is 2 minutes +#define FLUSH_DRAIN_WAIT_TIME_MS ( 2 * 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. // Flush dialysate state defines #define FLUSH_DIALYSATE_WAIT_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush dialysate wait time in milliseconds. // Flush concentrate straws state defines -#define FLUSH_CONCENTRATE_STRAWS_TIME_MS ( 0.5 * 60 * MS_PER_SECOND ) ///< Flush concentrate straws wait time in milliseconds. TODO original time is 3 minutes +#define FLUSH_CONCENTRATE_STRAWS_TIME_MS ( 3 * 60 * MS_PER_SECOND ) ///< Flush concentrate straws wait time in milliseconds. +#define ACID_PUMP_SPEED_ML_PER_MIN -30.0 ///< Acid pump speed in mL/min. +// The bicarb pump is 2% faster than the acid pump to create a flow from acid to bicarb line during flush +#define BICARB_PUMP_SPEED_ML_PER_MIN 30.6 ///< Bicarb pump speed in mL/min. // Flush and drain R1 and R2 state defines -#define RSRVRS_FULL_VOL_ML 1650.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 -#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. +#define RSRVRS_FULL_VOL_ML 1800.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. #define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. -#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. TODO original value was 5 minutes +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. #define RSRVRS_PARTIAL_FILL_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. -#define RSRVRS_DRAIN_TIMEOUT_MS ( 3 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. TODO original value was 2 minutes -#define FINAL_DRAIN_RO_PUMP_FLOW_LPM 0.6 ///< Final drain RO pump flow rate in L/min. This is used to flush the drain line during drain. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 3 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define FINAL_DRAIN_RO_PUMP_FLOW_LPM 0.6 ///< Final drain RO pump flow rate in L/min. This is used to flush the drain line during drain. // Flush drain line state defines -#define FLUSH_DRAIN_LINE_VOLUME_L 0.1 ///< Water volume to flush in liters. +#define FLUSH_DRAIN_LINE_VOLUME_L 0.1 ///< Water volume to flush in liters. #define FLUSH_DRAIN_LINE_TIMEOUT_MS ( 1 * 60 * MS_PER_SECOND ) ///< Flush drain lines timeout in milliseconds. // Flush circulation state defines @@ -78,6 +82,7 @@ static DG_FLUSH_STATE_T flushState = DG_FLUSH_STATE_START; ///< Current active flush state. static DG_FLUSH_STATE_T prevFlushState = DG_FLUSH_STATE_START; ///< Previous flush state. +static DG_FLUSH_UI_STATE_T flushUIState = FLUSH_UI_STATE_NOT_RUNNING; ///< Current UI flush state. static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. static U32 overallFlushElapsedTimeStart = 0; ///< Overall flush mode elapsed time start. static U32 stateTimerStart = 0; ///< State timer start. @@ -126,6 +131,7 @@ // Initialize the variables flushState = DG_FLUSH_STATE_START; prevFlushState = DG_FLUSH_STATE_START; + flushUIState = FLUSH_UI_STATE_NOT_RUNNING; rsrvrFillStableTimeCounter = 0; overallFlushElapsedTimeStart = 0; isThisInitialDrain = TRUE; @@ -308,6 +314,7 @@ setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + flushUIState = FLUSH_UI_STATE_DRAIN_DEVICE; stateTimerStart = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; state = DG_FLUSH_STATE_DRAIN_R1; @@ -409,10 +416,12 @@ #else setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); #endif + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setROPumpTargetFlowRate( FINAL_DRAIN_RO_PUMP_FLOW_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + flushUIState = FLUSH_UI_STATE_FLUSH_RECIRCULATION_PATH; state = DG_FLUSH_STATE_FLUSH_CIRCULATION_DRAIN_LINE; } @@ -474,7 +483,14 @@ if ( TRUE == didTimeout( stateTimerStart, FLUSH_DIALYSATE_WAIT_TIME_MS ) ) { - // TODO turn on the concentrate pumps + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + + // Turn on the concentrate pumps + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); + stateTimerStart = getMSTimerCount(); state = DG_FLUSH_STATE_FLUSH_CONCENTRATE_STRAWS; @@ -498,14 +514,18 @@ if ( TRUE == didTimeout( stateTimerStart, FLUSH_CONCENTRATE_STRAWS_TIME_MS ) ) { - // TODO turn off the concentrate pumps + // Done with flushing the concentrate pumps line + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); stateTimerStart = getMSTimerCount(); rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + flushUIState = FLUSH_UI_STATE_FLUSH_RESERVOIRS; state = DG_FLUSH_STATE_FLUSH_R1_TO_R2; } @@ -660,6 +680,7 @@ stateTimerStart = getMSTimerCount(); isThisInitialDrain = FALSE; rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + flushUIState = FLUSH_UI_STATE_DRAIN_RESERVOIRS; state = DG_FLUSH_STATE_DRAIN_R1; } // Check if reservoir 1 fill timed out @@ -710,7 +731,6 @@ #endif setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); stateTimerStart = getMSTimerCount(); @@ -774,7 +794,7 @@ if ( TRUE == didTimeout( stateTimerStart, FLUSH_WITH_FRESH_WATER_WAIT_TIME_MS ) ) { deenergizeActuators(); - + flushUIState = FLUSH_UI_STATE_COMPLETE; state = DG_FLUSH_STATE_COMPLETE; } @@ -798,6 +818,8 @@ // deenergize all the actuators failFlushMode(); + flushUIState = FLUSH_UI_STATE_CANCEL_FLUSH; + return state; } @@ -841,6 +863,8 @@ // Start the drain pump setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + flushUIState = FLUSH_UI_STATE_CANCEL_FLUSH; + // Start the timer for drain timeout stateTimerStart = getMSTimerCount(); } @@ -1026,6 +1050,7 @@ data.overallElapsedTime = calcTimeSince( overallFlushElapsedTimeStart ); data.stateElapsedTime = calcTimeSince( stateTimerStart ); data.drainLineVolume = flushLinesVolumeL; + data.flushUIState = (U32)flushUIState; broadcastFlushData( &data ); Index: firmware/App/Modes/ModeFlush.h =================================================================== diff -u -rd7926685f2fe3086bab183166119f0965a192a69 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeFlush.h (.../ModeFlush.h) (revision d7926685f2fe3086bab183166119f0965a192a69) +++ firmware/App/Modes/ModeFlush.h (.../ModeFlush.h) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -29,17 +29,6 @@ * @{ */ -// ********** public definitions ********** - -/// Flush mode data publish struct -typedef struct -{ - U32 flushState; ///< Flush state. - U32 overallElapsedTime; ///< Overall elapsed time in flush mode. - U32 stateElapsedTime; ///< Current flush elapsed time. - F32 drainLineVolume; ///< Drain line volume. -} MODE_FLUSH_DATA_T; - // ********** public function prototypes ********** void initFlushMode( void ); // initialize this module Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r4557f3d5ac6bdbd766153c7c1aabd94db3eee16a -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 4557f3d5ac6bdbd766153c7c1aabd94db3eee16a) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -64,7 +64,7 @@ #define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds #define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 50.0 ///< Maximum flush circulation temperature difference tolerance in C. TODO original difference was 3.0 degrees #define NUM_OF_TEMP_SENSORS_TO_AVG 4.0 ///< Number of temperature sensors to average to check the difference. -#define CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN -30.0 ///< Concentrate pumps reverse speed in mL/min. +#define ACID_PUMP_SPEED_ML_PER_MIN -30.0 ///< Concentrate pumps reverse speed in mL/min. // Flush and drain R1 and R2 #define RSRVRS_FULL_VOL_ML 1750.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 @@ -81,7 +81,7 @@ // R1 to R2 & R2 to R1 heat disinfect circulation #define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.3 ///< Heat disinfect target RO flow rate in L/min. #define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. -#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Heat disinfect target drain outlet pressure in psi. +#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 10.0 ///< Heat disinfect target drain outlet pressure in psi. #define HEAT_DISINFECT_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. #define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. #define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disinfect. TODO change this to 5 seconds @@ -153,6 +153,7 @@ static U32 ROFCirculationTimer = 0; ///< RO filter circulation timer. static U32 ROFCoolingTimer = 0; ///< RO filter cooling timer. static BOOL hasROFCirculationBeenStarted = FALSE; ///< Flag to indicate the water in RO filter has been recirculated. +static U32 targetDisinfectTime = 0; ///< Target disinfect time. // ********** private function prototypes ********** @@ -196,8 +197,8 @@ * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, - * hasROFCirculationBeenStarted, ROFCirculationTimer, - * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer + * hasROFCirculationBeenStarted, ROFCirculationTimer, targetDisinfectTime + * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer, * @return none *************************************************************************/ void initHeatDisinfectMode( void ) @@ -222,6 +223,7 @@ ROFCoolingTimer = 0; hasROFCirculationBeenStarted = FALSE; concentratePumpsPrimeTimer = 0; + targetDisinfectTime = 0; } /*********************************************************************//** @@ -700,8 +702,8 @@ areTempSensorsInRange = TRUE; #ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, ACID_PUMP_SPEED_ML_PER_MIN ); // Turn on the concentrate pumps requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); @@ -719,7 +721,7 @@ rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; - // Done with priming the concentrate pumps line + // Done with flushing the concentrate pumps line requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); @@ -1628,8 +1630,8 @@ setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); #ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, ACID_PUMP_SPEED_ML_PER_MIN ); // Turn on the concentrate pumps requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); @@ -1984,7 +1986,7 @@ // If the volume is out of range and it has timed out, exit else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) { - areRsrvrsLeaking = FALSE; + areRsrvrsLeaking = FALSE; alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; } @@ -2003,6 +2005,7 @@ heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; + targetDisinfectTime = 0; if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) { @@ -2016,15 +2019,16 @@ // The temperature of the coldest spot is in range to start the disinfect timer heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = TRUE; + targetDisinfectTime = HEAT_DISINFECT_TIME_MS; // Set the heat disinfect UI state if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) { heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1; #ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT // Turn the pumps on in reverse - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, ACID_PUMP_SPEED_ML_PER_MIN ); // During R1 to R2 disinfect, the concentrate pumps turn on requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); @@ -2041,7 +2045,11 @@ if ( ( TRUE == isPartialDisinfectInProgress ) && ( TRUE == didTimeout( heatDisinfectTimer, HEAT_DISINFECT_TIME_MS ) ) ) { // Done with this stage of heat disnfect. Reset the variables - status = HEAT_DISINFECT_COMPLETE; + // Target disinfect time is the time that is published to the UI and when there is + // no disinfect count down, this variable is set to 0. When the target time is 0, the UI + // hides the timer on the UI disinfect screen + targetDisinfectTime = 0; + status = HEAT_DISINFECT_COMPLETE; isPartialDisinfectInProgress = FALSE; } @@ -2073,8 +2081,12 @@ if ( ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) || ( DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) ) { - uiData.heatDisinfectTargetTime = HEAT_DISINFECT_TIME_MS; - uiData.heatDisinfectCountdownTime = HEAT_DISINFECT_TIME_MS - calcTimeSince( heatDisinfectTimer ); + // If the disinfect target time is 0, meaning the actual disinfect has not started, set the count down to 0, otherwise, publish + // the actual value + U32 countDown = ( HEAT_DISINFECT_TIME_MS == targetDisinfectTime ? ( targetDisinfectTime - calcTimeSince( heatDisinfectTimer) ) : 0 ); + + uiData.heatDisinfectTargetTime = targetDisinfectTime; + uiData.heatDisinfectCountdownTime = countDown; data.R1FillLevel = R1HeatDisinfectVol; data.R2FillLevel = R2HeatDisinfectVol; } Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -ra2c32d4d221603054ca9ad7a097112caebf08c4e -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision a2c32d4d221603054ca9ad7a097112caebf08c4e) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -24,6 +24,7 @@ #include "FPGA.h" #include "Heaters.h" #include "ModeRecirculate.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "Pressures.h" #include "ROPump.h" @@ -44,19 +45,22 @@ #define TARGET_RO_FLOW_RATE_L 0.3 ///< Target flow rate for RO pump. #define TARGET_FLUSH_LINES_RO_FLOW_RATE_L 0.6 ///< Target flow rate for RO pump. -#define FLUSH_LINES_VOLUME_L 0.01 ///< Water volume (in Liters) to flush when starting re-circulate mode. +#define FLUSH_LINES_VOLUME_L 0.01 ///< Water volume (in Liters) to flush when starting re-circulate mode. // ********** private data ********** -static DG_RECIRCULATE_MODE_STATE_T recircState; ///< Currently active re-circulation state. -static F32 flushLinesVolumeL = 0.0; ///< Volume of water pumped by RO pump during flush lines state. +static DG_RECIRCULATE_MODE_STATE_T recircState; ///< Currently active re-circulation state. +static F32 flushLinesVolumeL = 0.0; ///< Volume of water pumped by RO pump during flush lines state. +static F32 flushLinesTargetVolumeL = FLUSH_LINES_VOLUME_L; ///< Flush lines target volume in liters. // ********** private function prototypes ********** static DG_RECIRCULATE_MODE_STATE_T handleFlushLinesState( void ); static DG_RECIRCULATE_MODE_STATE_T handleRecircWaterState( void ); static DG_RECIRCULATE_MODE_STATE_T handleRecircPauseState( void ); +static BOOL processCalibrationData( void ); + /*********************************************************************//** * @brief * The initRecirculateMode function initializes the re-circulate mode module. @@ -66,8 +70,12 @@ *************************************************************************/ void initRecirculateMode( void ) { - recircState = DG_RECIRCULATE_MODE_STATE_START; - flushLinesVolumeL = 0.0; + recircState = DG_RECIRCULATE_MODE_STATE_START; + flushLinesVolumeL = 0.0; + + // TODO temporary code remove + flushLinesTargetVolumeL = FLUSH_LINES_VOLUME_L; + // TODO temporary code remove } /*********************************************************************//** @@ -124,6 +132,13 @@ *************************************************************************/ U32 execRecirculateMode( void ) { + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + // check inlet water conductivity, temperature, pressure, and RO rejection ratio checkInletWaterConductivity(); checkInletWaterTemperature(); @@ -160,6 +175,35 @@ /*********************************************************************//** * @brief + * The requestDGStop function handles an HD request to stop (return to standby mode). + * @details Inputs: none + * @details Outputs: DG standby mode requested + * @return TRUE if request accepted, FALSE if not. + *************************************************************************/ +BOOL requestDGStop( void ) +{ + BOOL result = TRUE; + + requestNewOperationMode( DG_MODE_STAN ); + + return result; +} + +/*********************************************************************//** + * @brief + * The getCurrentRecirculateState function returns the current state of the + * re-circulate mode. + * @details Inputs: recircState + * @details Outputs: none + * @return the current state of re-circulate mode + *************************************************************************/ +DG_RECIRCULATE_MODE_STATE_T getCurrentRecirculateState( void ) +{ + return recircState; +} + +/*********************************************************************//** + * @brief * The handleFlushLinesState function executes the flush lines state of the * re-circulate mode state machine. * @details Inputs: none @@ -176,11 +220,9 @@ flushLinesVolumeL += waterVolume; // when enough water volume has flowed to flush the lines, transition to re-circ state - if ( flushLinesVolumeL >= FLUSH_LINES_VOLUME_L ) + if ( flushLinesVolumeL >= flushLinesTargetVolumeL ) { -#ifndef SKIP_RECIRC setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); -#endif setROPumpTargetFlowRate( TARGET_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); result = DG_RECIRCULATE_MODE_STATE_RECIRC_WATER; } @@ -220,31 +262,39 @@ /*********************************************************************//** * @brief - * The requestDGStop function handles an HD request to stop (return to standby mode). + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. * @details Inputs: none - * @details Outputs: DG standby mode requested - * @return TRUE if request accepted, FALSE if not. + * @details Outputs: flushLinesVolumeL + * @return TRUE if the calibration record is valid, otherwise FALSE *************************************************************************/ -BOOL requestDGStop( void ) +static BOOL processCalibrationData( void ) { - BOOL result = TRUE; + BOOL status = TRUE; - requestNewOperationMode( DG_MODE_STAN ); + // Get the calibration record from NVDataMgmt + DG_DRAIN_LINE_VOLUME_T calData = getDGDrainLineVolumeRecord(); - return result; -} + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.calibrationTime ) + { +#ifndef DISABLE_CAL_CHECK + activateAlarmNoData( ALARM_ID_DG_DRAIN_LINE_VOLUME_INVALID_CALIBRATION ); +#endif + // In case calibration time was 0 set the flush target volume to default + flushLinesTargetVolumeL = FLUSH_LINES_VOLUME_L; + status = FALSE; + } + else + { + // The calibration data was valid, update the local copy + flushLinesVolumeL = calData.volume; + } -/*********************************************************************//** - * @brief - * The getCurrentRecirculateState function returns the current state of the - * re-circulate mode. - * @details Inputs: recircState - * @details Outputs: none - * @return the current state of re-circulate mode - *************************************************************************/ -DG_RECIRCULATE_MODE_STATE_T getCurrentRecirculateState( void ) -{ - return recircState; + return status; } /**@}*/ Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r3d131237935eb36e56e0d057a713430e31dc6405 -r6f1f269cd7d91f41c51797d17a85a7ea249e21f3 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 3d131237935eb36e56e0d057a713430e31dc6405) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 6f1f269cd7d91f41c51797d17a85a7ea249e21f3) @@ -19,6 +19,7 @@ #include "LoadCell.h" #include "ModeRecirculate.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "Reservoirs.h" #include "SystemCommMessages.h" @@ -63,13 +64,15 @@ static F32 reservoirLowestWeight[ NUM_OF_DG_RESERVOIRS ] = { MAX_RESERVOIR_WEIGHT, MAX_RESERVOIR_WEIGHT }; static U32 reservoirWeightUnchangeStartTime[ NUM_OF_DG_RESERVOIRS ] = { 0, 0 }; ///< The reservoirs' weight start time when weight stop decreasing. static BOOL tareLoadCellRequest; ///< Flag indicates if load cell tare has been requested by HD. +static DG_RESERVOIR_VOLUME_RECORD_T reservoirsNVRecord; ///< DG reservoirs non-volatile record. // ********** private function prototypes ********** static DG_RESERVOIR_ID_T getActiveReservoir( void ); static U32 getReservoirFillVolumeTargetMl( void ); -static U32 getReservoirDrainVolumeTargetMl( void ); +static U32 getReservoirDrainVolumeTargetMl( void ); +static BOOL processCalibrationData( void ); /*********************************************************************//** * @brief @@ -93,7 +96,14 @@ * @return none *************************************************************************/ void execReservoirs( void ) -{ +{ + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + // publish active reservoir, fill/drain volume targets at 1 Hz. if ( ++reservoirDataPublicationTimerCounter >= RESERVOIR_DATA_PUB_INTERVAL ) { @@ -131,9 +141,7 @@ activeReservoir.data = (U32)resID; cmdResponse.rejected = FALSE; setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); -#ifndef V_2_SYSTEM - setValveState( VRD1, VALVE_STATE_OPEN ); -#else +#ifdef V_2_SYSTEM setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); #endif setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); @@ -143,10 +151,8 @@ case DG_RESERVOIR_2: activeReservoir.data = (U32)resID; cmdResponse.rejected = FALSE; - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); -#ifndef V_2_SYSTEM - setValveState( VRD2, VALVE_STATE_OPEN ); -#else + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); +#ifdef V_2_SYSTEM setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); #endif setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); @@ -566,7 +572,49 @@ return result; } +/*********************************************************************//** + * @brief + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: reservoirsNVRecord + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static BOOL processCalibrationData( void ) +{ + BOOL status = TRUE; + U32 reservoir; + // Get the calibration record from NVDataMgmt + DG_RESERVOIR_VOLUME_RECORD_T calData = getDGReservoirsVolumeRecord(); + + for ( reservoir = 0; reservoir < NUM_OF_CAL_DATA_RSRVRS; reservoir++ ) + { + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the flow sensors data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.reservoir[ reservoir ].calibrationTime ) + { +#ifndef DISABLE_CAL_CHECK + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_RESERVOIRS_INVALID_NV_RECORD, (U32)reservoir ); +#endif + status = FALSE; + } + else + { + // The calibration data was valid, update the local copy + reservoirsNVRecord.reservoir[ reservoir ].maxResidualFluid = calData.reservoir[ reservoir ].maxResidualFluid; + reservoirsNVRecord.reservoir[ reservoir ].normalFillVolume = calData.reservoir[ reservoir ].normalFillVolume; + reservoirsNVRecord.reservoir[ reservoir ].rsrvrUnfilledWeight = calData.reservoir[ reservoir ].rsrvrUnfilledWeight; + reservoirsNVRecord.reservoir[ reservoir ].rsrvrVolume = calData.reservoir[ reservoir ].rsrvrVolume; + } + } + + return status; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/