Index: firmware/App/Controllers/Pressures.c =================================================================== diff -u -rebbb1f85550a1f9b8f946655f7b2b63f76fbf67d -r67021fbc633259e8e1bce76749dbef7d0cb51998 --- firmware/App/Controllers/Pressures.c (.../Pressures.c) (revision ebbb1f85550a1f9b8f946655f7b2b63f76fbf67d) +++ firmware/App/Controllers/Pressures.c (.../Pressures.c) (revision 67021fbc633259e8e1bce76749dbef7d0cb51998) @@ -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" @@ -35,7 +37,7 @@ #define PUMP_PRESSURE_ZERO 777 ///< ADC counts equivalent to 0 PSI for pump in/out pressure sensors. #define PUMP_PRESSURE_PSIA_PER_COUNT 0.06434 ///< PSIA per ADC count conversion factor for pump in/out pressure sensors. -#define PUMP_PRESSURE_PSIA_TO_PSI_OFFSET 14.7 ///< Subtract this offset to convert PSIA to PSI. +#define PUMP_PRESSURE_PSIA_TO_PSI_OFFSET 14.7 ///< Subtract this offset to convert PSIA to PSI. TODO - use barometric sensor when available. #define PRESSURE_SAMPLES_TO_AVERAGE ( 200 / TASK_PRIORITY_INTERVAL ) ///< Averaging pressure data over the reporting interval. #define PRESSURE_AVERAGE_MULTIPLIER ( 1.0 / (F32)PRESSURE_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. @@ -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,73 @@ 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 ); } + +/*********************************************************************//** + * @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 +212,41 @@ // 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: + processCalibrationData(); + 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_DG_PRESSURES_INVALID_SELF_TEST_STATE, pressuresSelfTestState ); + break; + } + + return pressuresSelfTestResult; } /*********************************************************************//** @@ -182,40 +286,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,75 +356,52 @@ } 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: pressuresCalRecord + * @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++ ) + { +#ifndef SKIP_CAL_CHECK + // 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 ) + { + + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRESSURE_SENSORS_INVALID_CAL_RECORD, (U32)sensor ); + status = FALSE; + } #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 ); + // 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; + } - checkPersistentAlarm( ALARM_ID_INLET_WATER_PRESSURE_FAULT, isPressureTooLow, pressure, MIN_INLET_WATER_PRESSURE ); + return status; } /*********************************************************************//** * @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 * The publishPressuresData function publishes DG pressures data at a set interval. * @details Inputs: pressuresDataPublicationTimerCounter * @details Outputs: Pressures data are published to CAN bus @@ -319,39 +422,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 +436,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 );