/************************************************************************** * * Copyright (c) 2024-2024 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 Temperature.c * * @author (last) Vinayakam Mani * @date (last) 23-Sep-2024 * * @author (original) Vinayakam Mani * @date (original) 23-Sep-2024 * ***************************************************************************/ #include "ConductivitySensors.h" #include "Messaging.h" #include "MessageSupport.h" #include "OperationModes.h" #include "Temperature.h" #include "Timers.h" #include "TaskPriority.h" #include "Utilities.h" /** * @addtogroup Temperature * @{ */ // ********** private definitions ********** #define ADC_FPGA_READ_DELAY 30U ///< Delay in ms before reading the ADC values from FPGA. #define TEMP_SENSORS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Temperature sensors publish data time interval. #define TEMP_SENSORS_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Temperature sensors FPGA error timeout in milliseconds. #define D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES ( 2 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< D4 temperature sensor moving average number of samples ( 2sec filter ). #define D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES 25 ///< D50 temperature sensor moving average number of samples ( 250ms filter ). #define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. /// Temperature sensor exec states. typedef enum tempSensors_Exec_States { TEMPSENSORS_EXEC_STATE_START = 0, ///< Temperature sensors exec start TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES, ///< Temperature sensors exec get ADC values NUM_OF_TEMPSENSORS_EXEC_STATES, ///< Total number of exec states } TEMPSENSORS_EXEC_STATES_T; // ********** private data ********** static TEMPSENSORS_EXEC_STATES_T tempSensorsExecState; ///< TemperatureSensor exec state. static U32 startTime; ///< start time to read FPGA values. static F32 d4TempAvgC; ///< D4 temperature average in C. static F32 d4TempRunningSumC; ///< D4 temperature running sum in C. static F32 d4TempSamplesC[ D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES ]; ///< D4 temperature samples array in C. static U32 d4TempSamplesNextIndex; ///< D4 temperature sample next index number. static U32 d4TempCount; ///< D4 Number of samples in average buffer. static F32 d50TempAvgC; ///< D50 temperature average in C. static F32 d50TempRunningSumC; ///< D50 temperature running sum in C. static F32 d50TempSamplesC[ D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES ]; ///< D50 temperature samples array in C. static U32 d50TempSamplesNextIndex; ///< D50 temperature sample next index number. static U32 d50TempCount; ///< D50 Number of samples in average buffer. static U32 dataPublicationTimerCounter; ///< Temperature sensors data publish timer counter. static OVERRIDE_U32_T tempSensorsPublishInterval = { TEMP_SENSORS_DATA_PUBLISH_INTERVAL, TEMP_SENSORS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Temperature sensors publish time interval override. // ********** private function prototypes ********** static TEMPSENSORS_EXEC_STATES_T handleExecStart( void ); static TEMPSENSORS_EXEC_STATES_T handleExecGetADCValues( void ); static void filterTemperatureReadings( void ); static void publishTemperatureSensorsData( void ); /*********************************************************************//** * @brief * The initTemperature function initializes the temperature unit. * @details \b Inputs: none * @details \b Outputs: temperature unit variables initialized. * @return none *************************************************************************/ void initTemperature( void ) { startTime = 0; tempSensorsExecState = TEMPSENSORS_EXEC_STATE_START; dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; d4TempRunningSumC = 0.0F; d4TempAvgC = 0.0F; d4TempSamplesNextIndex = 0; d4TempCount = 0; d50TempRunningSumC = 0.0F; d50TempAvgC = 0.0F; d50TempSamplesNextIndex = 0; d50TempCount = 0; // Initialize the temperature sensors initTemperatureSensors(); } /*********************************************************************//** * @brief * The execTemperatureSensorsSelfTest function runs the TemperatureSensors * POST during the self-test. * @details \b Inputs: none * @details \b Outputs: none * @return tempSensorsSelfTestState which is the status of the self test *************************************************************************/ SELF_TEST_STATUS_T execTemperatureSensorsSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; //BOOL calStatus = getNVRecord2Driver( GET_CAL_TEMP_SENSORS, (U08*)&tempSensorCalRecord, sizeof( DD_TEMP_SENSORS_CAL_RECORD_T ), // NUM_OF_CAL_DATA_TEMP_SENSORS, ALARM_ID_DD_TEMPERATURE_SENSORS_INVALID_CAL_RECORD ); BOOL calStatus = TRUE; if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; } return result; } /*********************************************************************//** * @brief * The execTemperatureSensors function executes the temperature sensors' * state machine. * @details \b Inputs: tempSensorsExecState * @details \b Outputs: tempSensorsExecState * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid temperature * sensor state is seen. * @return none *************************************************************************/ void execTemperatureSensors( void ) { // Check if a new calibration is available // if ( TRUE == isNewCalibrationRecordAvailable() ) // { // getNVRecord2Driver( GET_CAL_TEMP_SENSORS, (U08*)&tempSensorCalRecord, sizeof( DD_TEMP_SENSORS_CAL_RECORD_T ), // NUM_OF_CAL_DATA_TEMP_SENSORS, ALARM_ID_DD_TEMPERATURE_SENSORS_INVALID_CAL_RECORD ); // } // Read the sensors all the time switch ( tempSensorsExecState ) { case TEMPSENSORS_EXEC_STATE_START: tempSensorsExecState = handleExecStart(); break; case TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES: tempSensorsExecState = handleExecGetADCValues(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_TEMPERATURE_SENSORS_EXEC_INVALID_STATE, tempSensorsExecState ); tempSensorsExecState = TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; break; } // Monitor the temperature values monitorTemperatureSenors(); // Filter D4/D50 temperature readings filterTemperatureReadings(); // Publish the data publishTemperatureSensorsData(); } /*********************************************************************//** * @brief * The handleExecStart function waits for a period of time and switches to * the state that reads the ADC values from FPGA. * @details \b Inputs: startTime * @details \b Outputs: startTime, baroCoeffsWaitToRcvStartTime * @return the next state of the state machine *************************************************************************/ static TEMPSENSORS_EXEC_STATES_T handleExecStart( void ) { TEMPSENSORS_EXEC_STATES_T state = TEMPSENSORS_EXEC_STATE_START; if ( 0 == startTime ) { startTime = getMSTimerCount(); } // A delay to let FPGA to boot up else if ( TRUE == didTimeout( startTime, ADC_FPGA_READ_DELAY ) ) { startTime = 0; setBaroSensorCoefficientReadStartTime(); state = TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; } return state; } /*********************************************************************//** * @brief * The handleExecGetADCValues function reads the ADC values from FPGA and * at the specified time intervals and calls required functions to calculate * the actual tempetature from the raw ADC values. * @details \b Inputs: FPGA * @details \b Outputs: temperature value. * @return the next state of the state machine *************************************************************************/ static TEMPSENSORS_EXEC_STATES_T handleExecGetADCValues( void ) { // Read temperature sensors readTemperatureSensors(); return TEMPSENSORS_EXEC_STATE_GET_ADC_VALUES; } /*********************************************************************//** * @brief * The filterTemperatureReadings function adds a new temperature sensor * sample to the filters. * @details \b Inputs: D4 and D50 Temperature * @details \b Outputs: d4TempSamplesC[], d4TempSamplesNextIndex, d4TempRunningSumC, * d4TempCount, d4TempAvgC, d50TempSamplesC, d50TempRunningSumC, d50TempSamplesNextIndex, * d50TempCount, d50TempAvgC * @return none *************************************************************************/ static void filterTemperatureReadings( void ) { // Filter D4 Temperature ( 1sec filter) if ( d4TempCount >= D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES ) { d4TempRunningSumC -= d4TempSamplesC[ d4TempSamplesNextIndex ]; } F32 d4Temp = getTemperatureValue( D4_TEMP ); d4TempSamplesC[ d4TempSamplesNextIndex ] = d4Temp; d4TempRunningSumC += d4Temp; d4TempSamplesNextIndex = INC_WRAP( d4TempSamplesNextIndex, 0, D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); d4TempCount = INC_CAP( d4TempCount, D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES ); d4TempAvgC = d4TempRunningSumC / (F32)d4TempCount; // Filter D50 Temperature ( 250 ms filter ) if ( d50TempCount >= D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES ) { d50TempRunningSumC -= d50TempSamplesC[ d50TempSamplesNextIndex ]; } F32 d50Temp = getTemperatureValue( D50_TEMP ); d50TempSamplesC[ d50TempSamplesNextIndex ] = d50Temp; d50TempRunningSumC += d50Temp; d50TempSamplesNextIndex = INC_WRAP( d50TempSamplesNextIndex, 0, D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); d50TempCount = INC_CAP( d50TempCount, D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES ); d50TempAvgC = d50TempRunningSumC / (F32)d50TempCount; } /*********************************************************************//** * @brief * The getD4AverageTemperature function returns the average temperature * for D4 temp sensor. * @details \b Inputs: none * @details \b Outputs: none * @return the D4 average temperature *************************************************************************/ F32 getD4AverageTemperature( void ) { return d4TempAvgC; } /*********************************************************************//** * @brief * The getD50AverageTemperature function returns the average temperature * for D50 temp sensor. * @details \b Inputs: none * @details \b Outputs: none * @return the D50 average temperature *************************************************************************/ F32 getD50AverageTemperature( void ) { return d50TempAvgC; } /*********************************************************************//** * @brief * The publishTemperatureSensorsData function broadcasts the temperature * sensors data at the publication interval. * @details \b Inputs: dataPublicationTimerCounter and publish interval time. * @details \b Outputs: dataPublicationTimerCounter * @details \b Message \b Sent: MSG_ID_DD_TEMPERATURE_DATA publishes the temperature * data in a periodic interval. * @return none *************************************************************************/ static void publishTemperatureSensorsData( void ) { if ( ++dataPublicationTimerCounter >= getU32OverrideValue( &tempSensorsPublishInterval ) ) { TEMPERATURE_SENSORS_DATA_T data; data.d1Temp = getTemperatureValue( D1_TEMP ); data.x6Temp = getTemperatureValue( X6_TEMP ); data.d4Temp = getTemperatureValue( D4_TEMP ); data.d50Temp = getTemperatureValue( D50_TEMP ); data.boardTemp = getTemperatureValue( BRD_TEMP ); data.baroTemp = getTemperatureValue( BARO_TEMP ); data.d16CondTemp = getConductivityTemperatureValue( D17_COND ); data.d28CondTemp = getConductivityTemperatureValue( D27_COND ); data.d30CondTemp = getConductivityTemperatureValue( D29_COND ); data.d44CondTemp = getConductivityTemperatureValue( D43_COND ); data.d75CondTemp = getConductivityTemperatureValue( D74_COND ); data.d4AvgTemp = getD4AverageTemperature(); data.d50AvgTemp = getD50AverageTemperature(); broadcastData( MSG_ID_DD_TEMPERATURE_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( TEMPERATURE_SENSORS_DATA_T ) ); dataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testTemperatureSensorsDataPublishIntervalOverride function overrides the * temperature sensor data publish interval. * @details \b Inputs: none * @details \b Outputs: tempSensorsPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the temperature sensor data broadcast interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testTemperatureSensorsDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &tempSensorsPublishInterval, TASK_PRIORITY_INTERVAL ); return result; } /**@}*/