kopia lustrzana https://github.com/SP8EBC/ParaTNC
226 wiersze
7.1 KiB
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;
|
|
}
|
|
|
|
|