SP8EBC-ParaTNC/src/wx_handler_temperature.c

226 wiersze
7.1 KiB
C

/*
* wx_handler_temperature.c
*
* Created on: Apr 14, 2021
* Author: mateusz
*/
#include "wx_handler_temperature.h"
#include <rte_wx.h>
#include <wx_handler.h>
#include <main.h>
#include <drivers/dallas.h>
#include <drivers/ms5611.h>
#include <drivers/bme280.h>
#include <drivers/max31865.h>
#include <modbus_rtu/rtu_getters.h>
#include <modbus_rtu/rtu_return_values.h>
#include <etc/dallas_temperature_limits.h>
#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;
}