/* * wx_handler_temperature.c * * Created on: Apr 14, 2021 * Author: mateusz */ #include "wx_handler_temperature.h" #include #include #include #include #include #include #include #include #include #include #define WX_MAX_TEMPERATURE_SLEW_RATE 4.0f inline static int8_t wx_handler_temperature_check_slew(const float last, const float_average_t* average) { // 0 -> OK int8_t result = 0; float avg = 0.0f; // continue only if average circular buffer is completely full if (float_get_nonfull(average) == 0) { // get current average avg = float_get_average(average); // get difference avg = avg - last; // resuse result variable to save stack space result = (int8_t)avg; if (result < DALLAS_TEMPERATURE_NEG_SLEW) { result = 1; } else if (result > DALLAS_TEMPERATURE_POS_SLEW) { result = 1; } else { result = 0; } } return result; } int32_t wx_get_temperature_measurement(const config_data_wx_sources_t * const config_sources, const config_data_mode_t * const config_mode, const config_data_umb_t * const config_umb, const config_data_rtu_t * const config_rtu, float * output) { int32_t measurement_result = -1; // used for return values from various functions int32_t parameter_result = 0; // stores which parameters have been retrieved successfully. this is used for failsafe handling umb_qf_t umb_quality_factor = UMB_QF_UNITIALIZED; // wuality factor for UMB communication int16_t temp = 0; float temperature = 0.0f; float dallas_temperature = 0.0f; // choose main temperature source from the configuration. main sensor is something which is used to send data though aprs switch(config_sources->temperature) { // controller measures two temperatures // internal - provided by pressure/humidity sensor on PCB // external - usually dallas one wire but it might by something different case WX_SOURCE_INTERNAL: case WX_SOURCE_INTERNAL_PT100: { // internal means sensors connected directly to the controller - one-wire and/or I2C on the PCB // it has nothing to do with distinction between external and internal temperature // check which sensor is configured. it doesn't check which one is // in fact installed. if the configuration doesn't mach with hardware // the measuremenet won't be retrieved if (config_mode->wx_ms5611_or_bme == 1) { // this will get all three parameters (humidity, pressure, internal temp) in single call measurement_result = wx_get_temperature_bme280(&rte_wx_temperature_internal); } else { // ms5611 is a bit different as the sensor (internal) temperature is collected separately from pressure measurement_result = wx_get_temperature_ms5611(&rte_wx_temperature_internal); } // check if temperature from pressure sensor has been retrieved w/o errors if (measurement_result == BME280_OK || measurement_result == MS5611_OK) { rte_wx_temperature_internal_valid = rte_wx_temperature_internal; // set the flag for internal temperature parameter_result = parameter_result | WX_HANDLER_PARAMETER_RESULT_TEMP_INTERNAL; } // measure an external temperature using Dallas one wire sensor. // this function has blockin I/O which also adds a delay required by MS5611 // sensor to finish data acquisition after the pressure measurement // is triggered. dallas_temperature = dallas_query(&rte_wx_current_dallas_qf); // check against excessive slew rate const uint8_t dallas_slew_exceeded = wx_handler_temperature_check_slew(dallas_temperature, &rte_wx_dallas_average); if (dallas_slew_exceeded > 0) { rte_wx_current_dallas_qf = DALLAS_QF_NOT_AVALIABLE; } #ifdef STM32L471xx // measure temperature from PT100 sensor if it is selected as main temperature sensor // (main means sensor which is used to send WX packets) if (config_sources->temperature == WX_SOURCE_INTERNAL_PT100 && max31865_get_qf() == MAX_QF_FULL) { temperature = (float)rte_wx_temperature_average_pt / 10.0f; parameter_result = parameter_result | WX_HANDLER_PARAMETER_RESULT_TEMPERATURE; } #endif if (config_sources->temperature == WX_SOURCE_INTERNAL && rte_wx_current_dallas_qf == DALLAS_QF_FULL) { // updating last good measurement time wx_last_good_temperature_time = master_time; // include current temperature into the average float_average(dallas_temperature, &rte_wx_dallas_average); temperature = float_get_average(&rte_wx_dallas_average); #if defined(STM32L471xx) rte_wx_temperature_average_dallas = (int16_t)(temperature * 10.0f); #endif parameter_result = parameter_result | WX_HANDLER_PARAMETER_RESULT_TEMPERATURE; } else if (config_sources->temperature == WX_SOURCE_INTERNAL && rte_wx_current_dallas_qf == DALLAS_QF_DEGRADATED) { // if there were a communication error set the error to unavaliable rte_wx_error_dallas_qf = DALLAS_QF_NOT_AVALIABLE; // increase degraded quality factor counter rte_wx_dallas_degraded_counter++; } else if (config_sources->temperature == WX_SOURCE_INTERNAL && rte_wx_current_dallas_qf == DALLAS_QF_NOT_AVALIABLE) { // if there were a communication error set the error to unavaliable rte_wx_error_dallas_qf = DALLAS_QF_NOT_AVALIABLE; } break; } case WX_SOURCE_UMB: { // get current UMB bus quality factor umb_quality_factor = umb_get_current_qf(&rte_wx_umb_context, master_time); // if there are any data collected from UMB sensors if (umb_quality_factor == UMB_QF_FULL || umb_quality_factor == UMB_QF_DEGRADED) { // get the average temperature directly, there is no need for any further processing temperature = umb_get_temperature(config_umb); // set the flag that external temperature is available parameter_result = parameter_result | WX_HANDLER_PARAMETER_RESULT_TEMPERATURE; } else { // do nothing if no new data was received from UMB sensor in last 10 minutes ; } break; } case WX_SOURCE_RTU: case WX_SOURCE_FULL_RTU: { // get the value read from RTU registers measurement_result = rtu_get_temperature(&temp, config_rtu); temperature = (float)temp / 10.0f; // check if (measurement_result == MODBUS_RET_OK || measurement_result == MODBUS_RET_DEGRADED) { // set the flag that external temperature is available parameter_result |= WX_HANDLER_PARAMETER_RESULT_TEMPERATURE; } break; } case WX_SOURCE_DAVIS_SERIAL: break; } if ((parameter_result & WX_HANDLER_PARAMETER_RESULT_TEMPERATURE) != 0) { *output = temperature; } return parameter_result; } int32_t wx_get_temperature_ms5611(float * const temperature) { int32_t return_value = 0; // quering MS5611 sensor for temperature return_value = ms5611_get_temperature(temperature, &rte_wx_ms5611_qf); return return_value; } int32_t wx_get_temperature_bme280(float * const temperature){ int32_t output = 0; if (rte_wx_bme280_qf == BME280_QF_FULL) { output = bme280_get_temperature(temperature, bme280_get_adc_t(), &rte_wx_bme280_qf); } return output; }