/************************************************************************** * * Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file ConductivitySensors.c * * @author (last) Dara Navaei * @date (last) 23-May-2022 * * @author (original) Quang Nguyen * @date (original) 13-Jul-2020 * ***************************************************************************/ #include // Used for calculating the polynomial calibration equation. #include "ConductivitySensors.h" #include "FPGA.h" #include "NVDataMgmt.h" #include "MessageSupport.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "TemperatureSensors.h" #include "Utilities.h" /** * @addtogroup ConductivitySensors * @{ */ // ********** private definitions ********** #define SIEMENS_TO_MICROSIEMENS_CONVERSION 1000000 ///< Siemens to microSiemens conversion factor. #define COND_CPI_SENSOR_PROBE_TYPE 100 ///< 1 K cell constant conductivity probe. #define COND_CPO_SENSOR_PROBE_TYPE 10 ///< 0.1 K cell constant conductivity probe. #define COND_SENSOR_DECIMAL_CONVERSION 100 ///< Conductivity value from FPGA has two decimal place. #define COND_SENSOR_TEMPERATURE_COEF 0.02F ///< Linear temperature coefficient of variation at 25 Celcius for fresh water. #define COND_SENSOR_REFERENCE_TEMPERATURE 25 ///< Reference temperature for conductivity sensor. #define COND_SENSOR_REPORT_PERIOD ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Broadcast conductivity values message every second. #define MAX_COND_SENSOR_CPI_WARNING_HIGH 2000.0F ///< Maximum allowed high conductivity value. #define MIN_COND_SENSOR_CPI_WARNING_HIGH 1990.0F ///< Minimum allowed high conductivity value. #define MAX_COND_SENSOR_CPI_WARNING_LOW 100.0F ///< Maximum allowed low conductivity value. #define MIN_COND_SENSOR_CPI_WARNING_LOW 110.0F ///< Minimum allowed low conductivity value. #define MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< New reading every 800 ms, expect to get valid new reading in 1s. #define MAX_CONDUCTIVITY_SENSOR_FAILURES 5 ///< maximum number of conductivity sensor errors within window period before alarm. #define MAX_CONDUCTIVITY_SENSOR_FAILURE_WINDOW_MS ( 60 * MS_PER_SECOND ) ///< Conductivity sensor error window. #define RO_REJECTION_RATIO_OUT_OF_RANGE_VALUE 1.0F ///< Out of range value for RO rejection ratio when CPi conductivity is zero. #define MAX_RO_REJECTION_RATIO_ALLOW 0.10F ///< Maximum RO rejection ratio. #define MAX_CPO_CONDUCTIVITY_ALLOW 30.0 ///< Maximum CPo sensor conductivity value. #define COND_SENSOR_PERSISTENCE_PERIOD ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity sensor out of range error. #define RO_REJECTION_RATIO_PERSISTENCE_PERIOD ( 10 * MS_PER_SECOND ) ///< Persistence period for RO rejection ratio. #define EMSTAT_PICO_MEASUREMENT_OFFSET 0x8000000 ///< Measurement offset for emstat pico measurement data. #define EMSTAT_PICO_GOOD_STATUS 0x10 ///< Measurement good status. #define EMSTAT_PICO_TIMING_NOT_MET_STATUS 0x11 ///< Measurement takes too long status. #define EMSTAT_PICO_FIFO_EMPTY_MASK 0x8000 ///< Emstat Pico buffer empty indication bit. #define DATA_PUBLISH_COUNTER_START_COUNT 40 ///< Data publish counter start count. #define COND_SENSOR_BAD_STATUS_PERSISTENCE_PERIOD ( 1 * MS_PER_SECOND ) ///< Conductivity sensor bad status persistence period. #pragma pack(push,1) /// Emstat pico measurement data package structure typedef struct { U16 type; ///< Measurement variable type U08 value[7]; ///< Measurement value U08 prefix; ///< Prefix character for SI prefixes U08 reserved1; ///< Comma separator U16 status; ///< Status for measurement data package U08 reserved2[4]; ///< Comma separator and index of current range } EMSTAT_VARIABLE_T; #pragma pack(pop) // ********** private data ********** /// Conductivity sensors' associated temperature sensors static U32 associateTempSensor[ NUM_OF_CONDUCTIVITY_SENSORS ] = { TEMPSENSORS_INLET_PRIMARY_HEATER, ///< Inlet temperature sensor TEMPSENSORS_OUTLET_PRIMARY_HEATER, ///< Outlet temperature sensor TEMPSENSORS_CONDUCTIVITY_SENSOR_1, ///< Post-acid temperature sensor TEMPSENSORS_CONDUCTIVITY_SENSOR_2, ///< Post-bicarbonate temperature sensor }; static U08 readCount[ NUM_OF_CONDUCTIVITY_SENSORS ]; ///< Read count for conductivity readings. static U32 internalErrorCount[ NUM_OF_CONDUCTIVITY_SENSORS ]; ///< Internal error count for conductivity readings. static OVERRIDE_F32_T compensatedConductivityValues[ NUM_OF_CONDUCTIVITY_SENSORS ]; ///< Latest compensated conductivity values. static F32 rawConductivityValues[ NUM_OF_CONDUCTIVITY_SENSORS ]; ///< Latest raw conductivity values. static F32 roRejectionRatio; ///< Latest RO rejection ratio. static U32 sensorStatus[ NUM_OF_CONDUCTIVITY_SENSORS ]; ///< Latest sensor hardware status. static OVERRIDE_U32_T conductivityDataPublishInterval = { COND_SENSOR_REPORT_PERIOD, COND_SENSOR_REPORT_PERIOD, 0, 0 }; ///< Conductivity sensors publish time interval override. static U32 conductivityDataPublicationTimerCounter; ///< Conductivity sensors data publish timer counter. static BOOL packageStarted; ///< Flag to indicate the start of a package measurement data. static U08 packageIndex; ///< 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 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 F32 getCalibrationAppliedConductivityValue( U32 sensorId, F32 compensatedValue ); /*********************************************************************//** * @brief * The initConductivitySensors function initializes the ConductivitySensors module. * @details Inputs: none * @details Outputs: ConductivitySensors module initialized * @return none *************************************************************************/ void initConductivitySensors( void ) { U32 i; roRejectionRatio = 0.0; packageIndex = 0U; packageStarted = FALSE; conductivityDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; for ( i = 0; i < NUM_OF_CONDUCTIVITY_SENSORS; i++ ) { readCount[ i ] = 0; internalErrorCount[ i ] = 0; rawConductivityValues[ i ] = 0.0; compensatedConductivityValues[ i ].data = 0.0; compensatedConductivityValues[ i ].ovData = 0.0; compensatedConductivityValues[ i ].ovInitData = 0.0; compensatedConductivityValues[ i ].override = OVERRIDE_RESET; benignPolynomialCalRecord( &condSensorsCalRecord.condSensors[ i ] ); } setFPGACPiProbeType( COND_CPI_SENSOR_PROBE_TYPE ); setFPGACPoProbeType( COND_CPO_SENSOR_PROBE_TYPE ); initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CONDUCTIVITY_SENSOR_ERROR, MAX_CONDUCTIVITY_SENSOR_FAILURES, MAX_CONDUCTIVITY_SENSOR_FAILURE_WINDOW_MS ); initPersistentAlarm( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_LOW_RANGE, 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 ); initPersistentAlarm( ALARM_ID_DG_CONDUCTIVITY_SENSOR_BAD_STATUS, COND_SENSOR_BAD_STATUS_PERSISTENCE_PERIOD, COND_SENSOR_BAD_STATUS_PERSISTENCE_PERIOD ); initPersistentAlarm( ALARM_ID_DG_OUTLET_PRIMARY_CONDUCTIVITY_OUT_OF_RANGE, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); } /*********************************************************************//** * @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. * @return none *************************************************************************/ void execConductivitySensors( void ) { // Check if a new calibration is available if ( TRUE == isNewCalibrationRecordAvailable() ) { getNVRecord2Driver( GET_CAL_CONDUCTIVITY_SENSORS, (U08*)&condSensorsCalRecord, sizeof( condSensorsCalRecord ), NUM_OF_CAL_DATA_COND_SENSORS, ALARM_ID_DG_COND_SENSORS_INVALID_CAL_RECORD ); } processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPI_SENSOR, getFPGACPi(), getFPGACPiReadCount(), getFPGACPiErrorCount(), getFPGACPiFault() ); processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPO_SENSOR, getFPGACPo(), getFPGACPoReadCount(), getFPGACPoErrorCount(), getFPGACPoFault() ); processCD1CD2SensorRead( getFPGAEmstatRxFifoCount(), getFPGAEmstatRxErrCount() ); if ( ++conductivityDataPublicationTimerCounter >= getU32OverrideValue( &conductivityDataPublishInterval ) ) { CONDUCTIVITY_DATA_T data; calcRORejectionRatio(); conductivityDataPublicationTimerCounter = 0; data.roRejectionRatio = roRejectionRatio; data.cpi = getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ); data.cpo = getConductivityValue( CONDUCTIVITYSENSORS_CPO_SENSOR ); data.cd1 = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); data.cd2 = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); data.cpiRaw = rawConductivityValues[ CONDUCTIVITYSENSORS_CPI_SENSOR ]; data.cpoRaw = rawConductivityValues[ CONDUCTIVITYSENSORS_CPO_SENSOR ]; data.cd1Raw = rawConductivityValues[ CONDUCTIVITYSENSORS_CD1_SENSOR ]; data.cd2Raw = rawConductivityValues[ CONDUCTIVITYSENSORS_CD2_SENSOR ]; data.cpiSensorStatus = sensorStatus[ CONDUCTIVITYSENSORS_CPI_SENSOR ]; data.cpoSensorStatus = sensorStatus[ CONDUCTIVITYSENSORS_CPO_SENSOR ]; data.cd1SensorStatus = sensorStatus[ CONDUCTIVITYSENSORS_CD1_SENSOR ]; data.cd2SensorStatus = sensorStatus[ CONDUCTIVITYSENSORS_CD2_SENSOR ]; broadcastData( MSG_ID_DG_CONDUCTIVITY_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( CONDUCTIVITY_DATA_T ) ); } } /*********************************************************************//** * @brief * The execConductivitySensorsSelfTest function executes the conductivity * sensors' self-test. * @details Inputs: none * @details Outputs: none * @return PressuresSelfTestResult (SELF_TEST_STATUS_T) *************************************************************************/ SELF_TEST_STATUS_T execConductivitySensorsSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; BOOL calStatus = getNVRecord2Driver( GET_CAL_CONDUCTIVITY_SENSORS, (U08*)&condSensorsCalRecord, sizeof( condSensorsCalRecord ), NUM_OF_CAL_DATA_COND_SENSORS, ALARM_ID_DG_COND_SENSORS_INVALID_CAL_RECORD ); if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; } return result; } /*********************************************************************//** * @brief * The checkInletWaterConductivity function checks inlet water conductivity value * and triggers an alarm when conductivity value is out of allowed range. * @details Inputs: CPi sensor conductivity * @details Outputs: Trigger alarms when conductivity is out of allowed range * @return none *************************************************************************/ void checkInletWaterConductivity( void ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_WATER_QUALITY_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { F32 conductivity = getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ); BOOL isConductTooLow = ( conductivity < MAX_COND_SENSOR_CPI_WARNING_LOW ? TRUE : FALSE ); BOOL isConductInWarningRange = ( conductivity > MAX_COND_SENSOR_CPI_WARNING_HIGH ? TRUE : FALSE ); // Warning per PRS 403 if ( TRUE == isConductTooLow ) { checkPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_LOW_RANGE, isConductTooLow, conductivity, MAX_COND_SENSOR_CPI_WARNING_LOW ); } else if ( conductivity >= MIN_COND_SENSOR_CPI_WARNING_LOW ) { checkPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_LOW_RANGE, FALSE, conductivity, MAX_COND_SENSOR_CPI_WARNING_LOW ); } // Warning per PRS 404 if ( TRUE == isConductInWarningRange ) { checkPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE, isConductInWarningRange, conductivity, MAX_COND_SENSOR_CPI_WARNING_HIGH ); } else if ( conductivity <= MIN_COND_SENSOR_CPI_WARNING_HIGH ) { checkPersistentAlarm( ALARM_ID_INLET_WATER_CONDUCTIVITY_IN_HIGH_RANGE, FALSE, conductivity, MAX_COND_SENSOR_CPI_WARNING_HIGH ); } } } /*********************************************************************//** * @brief * The checkRORejectionRatio function checks RO rejection ratio and outlet water * conductivity. The function triggers an alarm when RO rejection ratio or * outlet water conductivity is out of allowed range for period of time. * @details Inputs: roRejectionRatio, CPo sensor conductivity * @details Outputs: Triggered alarm * @return none *************************************************************************/ void checkRORejectionRatio( void ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RO_RATIO_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { F32 cpo = getConductivityValue( CONDUCTIVITYSENSORS_CPO_SENSOR ); BOOL isRORectionOutOfRange = ( roRejectionRatio > MAX_RO_REJECTION_RATIO_ALLOW ? TRUE : FALSE ); BOOL isCPoOutOfRange = ( cpo >= MAX_CPO_CONDUCTIVITY_ALLOW ? TRUE : FALSE ); // Fault alarm per PRS 483 checkPersistentAlarm( ALARM_ID_DG_OUTLET_PRIMARY_CONDUCTIVITY_OUT_OF_RANGE, isCPoOutOfRange, cpo, MAX_CPO_CONDUCTIVITY_ALLOW ); // Fault alarm per PRS 483 checkPersistentAlarm( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE, isRORectionOutOfRange, roRejectionRatio, MAX_RO_REJECTION_RATIO_ALLOW ); } } /*********************************************************************//** * @brief * The getConductivityValue function gets the compensated conductivity * value for a given conductivity sensor id. * @details Inputs: compensatedConductivityValues[] * @details Outputs: none * @param sensorId conductivity sensor id * @return compensated conductivity *************************************************************************/ F32 getConductivityValue( U32 sensorId ) { F32 result = 0.0; if ( sensorId < NUM_OF_CONDUCTIVITY_SENSORS ) { result = getF32OverrideValue( &compensatedConductivityValues[ sensorId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_CONDUCTIVITY_SENSOR_ID, sensorId ); } return result; } /*********************************************************************//** * @brief * The calcCompensatedConductivity function calculates the compensated * conductivity based on given temperature and conductivity taken at * reference temperature of 25 degree Celsius. * @details Inputs: conductivity, temperature * @details Outputs: none * @param conductivity conductivity value * @param temperature temperature to compensate conductivity with * @return compensated conductivity based on temperature *************************************************************************/ static F32 calcCompensatedConductivity( F32 conductivity, F32 temperature ) { // EC = EC_25 * (1 + temp_coef * ( temperature - 25 )) F32 const compensatedCoef = ( 1.0 + ( COND_SENSOR_TEMPERATURE_COEF * ( temperature - COND_SENSOR_REFERENCE_TEMPERATURE ) ) ); return conductivity / compensatedCoef; } /*********************************************************************//** * @brief * The calcRORejectionRatio function calculates the RO rejection ratio using * the CPi sensor conductivity value and CPo sensor conductivity value. * @details Inputs: CPi sensor conductivity, CPo sensor conductivity * @details Outputs: RO rejection ratio * @return none *************************************************************************/ static void calcRORejectionRatio( void ) { F32 const cpi = getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ); F32 const cpo = getConductivityValue( CONDUCTIVITYSENSORS_CPO_SENSOR ); roRejectionRatio = RO_REJECTION_RATIO_OUT_OF_RANGE_VALUE; if ( fabs(cpi) >= NEARLY_ZERO ) { roRejectionRatio = cpo / cpi; } } /*********************************************************************//** * @brief * The processCPiCPoSensorRead function checks if there is an error in FPGA * and FPGA read count. If there is any error in the FPGA error, it raises an * alarm. If the read count has changed, the new reading will be processed. * @details Inputs: none * @details Outputs: none * @param sensorId Conductivity sensor id to process * @param fgpaRead FPGA conductivity reading value * @param fpgaReadCount FPGA read count * @param fpgaErrorCount FPGA error count * @param fpgaSensorFault FPGA sensor fault * @return none *************************************************************************/ static void processCPiCPoSensorRead( U32 sensorId, U32 fgpaRead, U08 fpgaReadCount, U08 fpgaErrorCount, U08 fpgaSensorFault ) { if ( ( 0 == fpgaErrorCount ) && ( 0 == fpgaSensorFault ) ) { if ( ( readCount[ sensorId ] != fpgaReadCount ) ) { F32 temperature = getTemperatureValue( associateTempSensor[ sensorId ] ); F32 conductivity = ( (F32)( fgpaRead ) / COND_SENSOR_DECIMAL_CONVERSION ); F32 compensatedCond = calcCompensatedConductivity( conductivity, temperature ); readCount[ sensorId ] = fpgaReadCount; internalErrorCount[ sensorId ] = 0; compensatedConductivityValues[ sensorId ].data = getCalibrationAppliedConductivityValue( sensorId, compensatedCond ); rawConductivityValues[ sensorId ] = conductivity; // store raw conductivity data from CPi and CPo } else { ++internalErrorCount[ sensorId ]; if ( internalErrorCount[ sensorId ] > MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_COND_SENSOR_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, sensorId ); } } } } else { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CONDUCTIVITY_SENSOR_ERROR ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_COND_SENSOR_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, sensorId ); } } } } /*********************************************************************//** * @brief * The prefixStrToSIFactor function returns SI factor based on a given ascii prefix. * @details Inputs: none * @details Outputs: none * @param prefix ascii value of the prefix * @return SI factor of the given ascii prefix *************************************************************************/ static U32 prefixStrToSIFactor( U08 prefix ) { U32 result; switch ( prefix ) { case 'm': result = 1000; break; case 'u': result = 1000000; break; default: result = 1; break; } return result; } /*********************************************************************//** * @brief * The processMeasurementDataPackage function processes incoming measurement data * package variables from Emstat Pico and convert it to conductivity. The conductivity * value is then compensated based on associating temperature sensor's value. * @details Inputs: none * @details Outputs: none * @param sensorId Conductivity sensor id to process * @return none *************************************************************************/ static void processMeasurementDataPackage( U32 sensorId ) { EMSTAT_VARIABLE_T const * const measurementPtr = (EMSTAT_VARIABLE_T *)&package; U32 status = hexStrToDec( (U08 *)&measurementPtr->status, sizeof( measurementPtr->status ) ); sensorStatus[ sensorId ] = status; if ( EMSTAT_PICO_GOOD_STATUS == status ) { U32 prefix = prefixStrToSIFactor( measurementPtr->prefix ); F32 resistance = ( ( F32 )( hexStrToDec( measurementPtr->value, sizeof( measurementPtr->value ) ) - EMSTAT_PICO_MEASUREMENT_OFFSET ) / prefix ); F32 temperature = getTemperatureValue( associateTempSensor[ sensorId ] ); F32 conductivity = ( 1.0 / resistance * SIEMENS_TO_MICROSIEMENS_CONVERSION ); F32 compensatedCond = calcCompensatedConductivity( conductivity, temperature ); internalErrorCount[ sensorId ] = 0; compensatedConductivityValues[ sensorId ].data = getCalibrationAppliedConductivityValue( sensorId, compensatedCond ); rawConductivityValues[ sensorId ] = conductivity; // store raw conductivity data from CD1 and CD2 // Clear the alarm checkPersistentAlarm( ALARM_ID_DG_CONDUCTIVITY_SENSOR_BAD_STATUS, FALSE, status, EMSTAT_PICO_GOOD_STATUS ); } else { #ifndef DISABLE_COND_STATUS_CHECK checkPersistentAlarm( ALARM_ID_DG_CONDUCTIVITY_SENSOR_BAD_STATUS, TRUE, status, EMSTAT_PICO_GOOD_STATUS ); #endif } if ( EMSTAT_PICO_TIMING_NOT_MET_STATUS == status ) { if ( ++internalErrorCount[ sensorId ] > MAX_CONDUCTIVITY_SENSOR_FAILURES ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, sensorId ); } } else { internalErrorCount[ sensorId ] = 0; } } /*********************************************************************//** * @brief * The processCD1CD2SensorRead function checks if there is an error with Emstat * conductivity sensors. If there is any error with the Emstat conductivity sensors, * it raises an alarm. If the read count has changed, the new reading will be processed. * @details Inputs: none * @details Outputs: none * @param fpgaReadCount FPGA read count for rx fifo * @param fpgaErrorCount FPGA error count * @return none *************************************************************************/ static void processCD1CD2SensorRead( U16 fpgaReadCount, U08 fpgaErrorCount ) { if ( fpgaErrorCount == 0 ) { if ( ( fpgaReadCount > 0 ) && ( ( fpgaReadCount & EMSTAT_PICO_FIFO_EMPTY_MASK ) == 0 ) ) { U08 const emstatByte = getFPGAEmstatOutByte(); switch ( emstatByte ) { case 'P': packageStarted = TRUE; packageIndex = 0; break; case ';': if ( packageStarted ) { processMeasurementDataPackage( CONDUCTIVITYSENSORS_CD1_SENSOR ); packageIndex = 0; } break; case '\n': if ( packageStarted ) { processMeasurementDataPackage( CONDUCTIVITYSENSORS_CD2_SENSOR ); packageStarted = FALSE; } break; default: if ( packageStarted ) { package[ packageIndex++ ] = emstatByte; } break; } } } else { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CONDUCTIVITY_SENSOR_ERROR ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_COND_SENSOR_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, CONDUCTIVITYSENSORS_CD1_SENSOR, CONDUCTIVITYSENSORS_CD2_SENSOR ); } } } } /*********************************************************************//** * @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 *************************************************************************/ /*********************************************************************//** * @brief * The testSetConductivityOverride function overrides the compensated * conductivity value of given sensor id. * @details Inputs: compensatedConductivityValues[] * @details Outputs: compensatedConductivityValues[] * @param sensorId conductivity sensor id * @param value override compensated conductivity value * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetConductivityOverride( U32 sensorId, F32 value ) { BOOL result = FALSE; if ( sensorId < NUM_OF_CONDUCTIVITY_SENSORS ) { if ( isTestingActivated() ) { result = TRUE; compensatedConductivityValues[ sensorId ].ovData = value; compensatedConductivityValues[ sensorId ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetConductivityOverride function resets the override of the * conductivity sensor value. * @details Inputs: compensatedConductivityValues[] * @details Outputs: compensatedConductivityValues[] * @param sensorId conductivity sensor id * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetConductivityOverride( U32 sensorId ) { BOOL result = FALSE; if ( sensorId < NUM_OF_CONDUCTIVITY_SENSORS ) { if ( isTestingActivated() ) { result = TRUE; compensatedConductivityValues[ sensorId ].ovData = compensatedConductivityValues[ sensorId ].ovInitData; compensatedConductivityValues[ sensorId ].override = OVERRIDE_RESET; } } return result; } /*********************************************************************//** * @brief * The testSetConductivityDataPublishIntervalOverride function overrides * the conductivity data publish interval. * @details Inputs: conductivityDataPublishInterval * @details Outputs: conductivityDataPublishInterval * @param value override conductivity data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetConductivityDataPublishIntervalOverride( U32 interval_ms ) { BOOL result = FALSE; if ( isTestingActivated() ) { result = TRUE; conductivityDataPublishInterval.ovData = interval_ms / TASK_PRIORITY_INTERVAL; conductivityDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetConductivityDataPublishIntervalOverride function resets * the override of the conductivity data publish interval. * @details Inputs: conductivityDataPublishInterval * @details Outputs: conductivityDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetConductivityDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( isTestingActivated() ) { result = TRUE; conductivityDataPublishInterval.ovData = conductivityDataPublishInterval.ovInitData; conductivityDataPublishInterval.override = OVERRIDE_RESET; } return result; } /**@}*/