Index: firmware/App/Controllers/ConductivitySensors.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r7cc6fbb41e6b460fedff71581f6205ef36d5deb6 --- firmware/App/Controllers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Controllers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 7cc6fbb41e6b460fedff71581f6205ef36d5deb6) @@ -31,32 +31,61 @@ // ********** private definitions ********** -#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.02 ///< 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 SIEMEN_TO_MICROSIEMEN_CONVERSION 1000000 ///< Siemen to microsiemens conversion factor. -#define COND_SENSOR_CPI_CPO_MAX_VALUE 2000 ///< Maximum inlet water conductivity. -#define COND_SENSOR_CPI_CPO_MIN_VALUE 100 ///< Minimum inlet water conductivity. -#define COND_SENSOR_PERSISTENCE_COUNT (5 * MS_PER_SECOND / TASK_GENERAL_INTERVAL) ///< Number of persistence count for conductivity sensor out of range error. +#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.02 ///< 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_ALLOWED_UNCHANGED_CONDUCTIVITY_READS 100 ///< New reading every 640 ms, expect to get 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 COND_SENSOR_CPI_CPO_MAX_VALUE 2000 ///< Maximum inlet water conductivity. +#define COND_SENSOR_CPI_CPO_MIN_VALUE 100 ///< Minimum inlet water conductivity. +#define COND_SENSOR_PERSISTENCE_PERIOD ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity sensor out of range error. -#define RO_REJECTION_RATIO_OUT_OF_RANGE_VALUE 1.0 ///< Out of range value for RO rejection ratio when CPi conductivity is zero. -#define MAX_RO_REJECTION_RATIO_ALLOW 0.1 ///< Maximum RO rejection ratio. -#define MAX_CPO_CONDUCTIVITY_ALLOW 15.0 ///< Maximum CPo sensor conductivity value. -#define RO_REJECTION_RATIO_PERSISTENCE_COUNT (10 * MS_PER_SECOND / TASK_GENERAL_INTERVAL) ///< Number of persistence count for RO rejection ratio. +#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.0 ///< Out of range value for RO rejection ratio when CPi conductivity is zero. +#define MAX_RO_REJECTION_RATIO_ALLOW 0.1 ///< Maximum RO rejection ratio. +#define MAX_CPO_CONDUCTIVITY_ALLOW 15.0 ///< Maximum CPo sensor conductivity value. +#define RO_REJECTION_RATIO_PERSISTENCE_PERIOD ( 10 * MS_PER_SECOND ) ///< Persistence period for RO rejection ratio. + +#define CONCENTRATE_POST_ACID_MIN_CONDUCTIVITY 11.0 ///< Minimum conductivity allow after adding acid. +#define CONCENTRATE_POST_ACID_MAX_CONDUCTIVITY 12.0 ///< Maximum conductivity allow after adding acid. + +#define CONCENTRATE_POST_BICARB_MIN_CONDUCTIVITY 13.0 ///< Minimum conductivity allow after adding bicarbonate. +#define CONCENTRATE_POST_BICARB_MAX_CONDUCTIVITY 14.0 ///< Maximum conductivity allow after adding bicarbonate. + +#define POST_ACID_CONDUCTIVITY_PERSISTENCE_PERIOD ( 5 * MS_PER_SECOND ) ///< Persistence period for post-acid concentrate conductivity out of range. +#define POST_BICARB_CONDUCTIVITY_PERSISTENCE_PERIOD ( 5 * MS_PER_SECOND ) ///< Persistence period for post-bicarb concentrate conductivity out of range. + +#define EMSTAT_PICO_MEASUREMENT_OFFSET 0x8000000 ///< Measurement offset for emstat pico measurement data. +#define EMSTAT_PICO_GOOD_STATUS 0x10 ///< Measurement good status. + +#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. @@ -68,12 +97,21 @@ COND_SENSOR_REPORT_PERIOD, 0, 0 }; ///< Conductivity sensors publish time interval override. static U32 conductivityDataPublicationTimerCounter = 0; ///< Conductivity sensors data publish timer counter. +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. + // ********** private function prototypes ********** static F32 getConductivityValue( U32 sensorId ); 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 hexStrToDec( U08 const * const valuePtr, U08 size ); +static U32 prefixStrToSIFactor( U08 prefix ); +static void processMeasurementDataPackage( U32 sensorId ); +static void processCD1CD2SensorRead( U08 fpgaReadCount, U08 fpgaErrorCount ); static U32 getConductivityDataPublishInterval( void ); /*********************************************************************//** @@ -103,11 +141,15 @@ initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CONDUCTIVITY_SENSOR_ERROR, MAX_CONDUCTIVITY_SENSOR_FAILURES, MAX_CONDUCTIVITY_SENSOR_FAILURE_WINDOW_MS ); initPersistentAlarm( PERSISTENT_ALARM_INLET_WATER_HIGH_CONDUCTIVITY, ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY, - TRUE, COND_SENSOR_PERSISTENCE_COUNT, COND_SENSOR_PERSISTENCE_COUNT ); + FALSE, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( PERSISTENT_ALARM_INLET_WATER_LOW_CONDUCTIVITY, ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY, - TRUE, COND_SENSOR_PERSISTENCE_COUNT, COND_SENSOR_PERSISTENCE_COUNT ); + FALSE, COND_SENSOR_PERSISTENCE_PERIOD, COND_SENSOR_PERSISTENCE_PERIOD ); initPersistentAlarm( PERSISTENT_ALARM_RO_REJECTION_RATIO_OUT_OF_RANGE, ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE, - TRUE, RO_REJECTION_RATIO_PERSISTENCE_COUNT, RO_REJECTION_RATIO_PERSISTENCE_COUNT ); + FALSE, RO_REJECTION_RATIO_PERSISTENCE_PERIOD, RO_REJECTION_RATIO_PERSISTENCE_PERIOD ); + initPersistentAlarm( PERSISTENT_ALARM_POST_ACID_CONDUCTIVITY_OUT_OF_RANGE, ALARM_ID_POST_ACID_CONDUCTIVITY_OUT_OF_RANGE, + TRUE, POST_ACID_CONDUCTIVITY_PERSISTENCE_PERIOD, POST_ACID_CONDUCTIVITY_PERSISTENCE_PERIOD ); + initPersistentAlarm( PERSISTENT_ALARM_POST_BICARB_CONDUCTIVITY_OUT_OF_RANGE, ALARM_ID_POST_BICARB_CONDUCTIVITY_OUT_OF_RANGE, + TRUE, POST_ACID_CONDUCTIVITY_PERSISTENCE_PERIOD, POST_ACID_CONDUCTIVITY_PERSISTENCE_PERIOD ); } /*********************************************************************//** @@ -122,20 +164,21 @@ { processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPI_SENSOR, getFPGACPi(), getFPGACPiReadCount(), getFPGACPiErrorCount(), getFPGACPiFault() ); processCPiCPoSensorRead( CONDUCTIVITYSENSORS_CPO_SENSOR, getFPGACPo(), getFPGACPoReadCount(), getFPGACPoErrorCount(), getFPGACPoFault() ); + processCD1CD2SensorRead( getFPGAEmstatRxFifoCount(), getFPGAEmstatRxErrCount() ); if ( ++conductivityDataPublicationTimerCounter >= getConductivityDataPublishInterval() ) { conductivityDataPublicationTimerCounter = 0; calcRORejectionRatio(); - broadcastConductivityData( roRejectionRatio, getConductivityValue(CONDUCTIVITYSENSORS_CPI_SENSOR), - getConductivityValue(CONDUCTIVITYSENSORS_CPO_SENSOR) ); + broadcastConductivityData( roRejectionRatio, getConductivityValue(CONDUCTIVITYSENSORS_CPI_SENSOR), getConductivityValue(CONDUCTIVITYSENSORS_CPO_SENSOR), + getConductivityValue(CONDUCTIVITYSENSORS_CD1_SENSOR), getConductivityValue(CONDUCTIVITYSENSORS_CD2_SENSOR) ); } } /*********************************************************************//** * @brief - * The checkInletWaterConductivity checks inlet water conductivity value + * 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 @@ -153,7 +196,7 @@ /*********************************************************************//** * @brief - * The checkRORejectionRatio checks RO rejection ratio and outlet water + * 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 @@ -169,6 +212,27 @@ /*********************************************************************//** * @brief + * The checkConcentrateConductivity function checks concentrate conductivity + * after adding acid and bicarbonate and triggers an alarm when conductivity + * is out of allowed range. + * @details Inputs: CD1 and CD2 sensor conductivity + * @details Outputs: Trigger alarms when conductivity is out of allowed range + * @return none + *************************************************************************/ +void checkConcentrateConductivity( void ) +{ + F32 const postAcidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + F32 const postBicarbonateConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); + BOOL const isPostAcidConductivityOutOfRange = ( postAcidConductivity <= CONCENTRATE_POST_ACID_MIN_CONDUCTIVITY ) || ( postAcidConductivity >= CONCENTRATE_POST_ACID_MAX_CONDUCTIVITY ); + BOOL const isPostBicarbConductivityOutOfRange = ( postBicarbonateConductivity <= CONCENTRATE_POST_BICARB_MIN_CONDUCTIVITY ) || ( postBicarbonateConductivity >= CONCENTRATE_POST_BICARB_MAX_CONDUCTIVITY ); + + checkPersistentAlarm( PERSISTENT_ALARM_POST_ACID_CONDUCTIVITY_OUT_OF_RANGE, isPostAcidConductivityOutOfRange, postAcidConductivity ); + checkPersistentAlarm( PERSISTENT_ALARM_POST_BICARB_CONDUCTIVITY_OUT_OF_RANGE, isPostBicarbConductivityOutOfRange, postBicarbonateConductivity ); +} + + +/*********************************************************************//** + * @brief * The getConductivityValue function gets the compensated conductivity * value for a given conductivity sensor id. * @details Inputs: compensatedConductivityValues[] @@ -284,6 +348,154 @@ /*********************************************************************//** * @brief + * The hexStrToDec function convert hex string to decimal value. + * @details Inputs: none + * @details Outputs: none + * @param valuePtr pointer to hex string to convert + * @param size size of the hex string to convert + * @return converted value of hex string + *************************************************************************/ +static U32 hexStrToDec( U08 const * const valuePtr, U08 size ) +{ + U08 ii; + U08 value; + U32 result = 0; + + for ( ii = 0; ii < size; ++ii ) + { + if ( valuePtr[ii] < 0x40 ) + { + value = ( valuePtr[ii] - 0x30 ); + result = ( result << 4 ) | value; + } + else + { + value = ( valuePtr[ii] - 0x37 ); + result = ( result << 4 ) | value; + } + } + + return result; +} + +/*********************************************************************//** + * @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; + + if ( EMSTAT_PICO_GOOD_STATUS == hexStrToDec( (U08 *)&measurementPtr->status, sizeof( measurementPtr->status ) ) ) + { + internalErrorCount[ sensorId ] = 0; + U32 const prefix = prefixStrToSIFactor( measurementPtr->prefix ); + 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 * SIEMEN_TO_MICROSIEMEN_CONVERSION ); + compensatedConductivityValues[ sensorId ].data = calcCompensatedConductivity( conductivity, temperature ); + } + else + { + ++internalErrorCount[ sensorId ]; + if ( internalErrorCount[ sensorId ] > MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, sensorId ); + } + } +} + +/*********************************************************************//** + * @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 sensorId Conductivity sensor id to process + * @return none + *************************************************************************/ +static void processCD1CD2SensorRead( U08 fpgaReadCount, U08 fpgaErrorCount ) +{ + if ( fpgaErrorCount == 0 ) + { + if ( fpgaReadCount > 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 ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CONDUCTIVITY_SENSOR_FAULT, CONDUCTIVITYSENSORS_CD1_SENSOR ); + } + } +} + +/*********************************************************************//** + * @brief * The getConductivityDataPublishInterval function gets the conductivity * data publication interval. * @details Inputs: conductivityDataPublishInterval @@ -337,7 +549,7 @@ /*********************************************************************//** * @brief - * The testResetConductivityOverride function resets the override of the \n + * The testResetConductivityOverride function resets the override of the * conductivity sensor value. * @details Inputs: compensatedConductivityValues[] * @details Outputs: compensatedConductivityValues[]