Merge branch 'master' into change-to-sending-expresslrs_RFrates_e-in-sync-packet
[ExpressLRS.git] / src / lib / Baro / devBaro.cpp
blob5d180e80b96ed588ac41cad5a76f351af591ff7e
2 #include "devBaro.h"
4 #if defined(HAS_BARO)
6 #include "CRSF.h"
7 #include "logging.h"
8 #include "telemetry.h"
9 #include "baro_spl06.h"
10 #include "baro_bmp280.h"
11 //#include "baro_bmp085.h"
13 #define BARO_STARTUP_INTERVAL 100
15 /* Shameful externs */
16 extern Telemetry telemetry;
18 /* Local statics */
19 static BaroBase *baro;
20 static eBaroReadState BaroReadState;
22 extern bool i2c_enabled;
24 static bool Baro_Detect()
26 // I2C Baros
27 if (i2c_enabled)
29 if (SPL06::detect())
31 DBGLN("Detected baro: SPL06");
32 baro = new SPL06();
33 return true;
35 if (BMP280::detect())
37 DBGLN("Detected baro: BMP280");
38 baro = new BMP280();
39 return true;
41 // Untested
42 // if (BMP085::detect())
43 // {
44 // DBGLN("Detected baro: BMP085");
45 // baro = new BMP085();
46 // return true;
47 // }
48 // DBGLN("No baro detected");
49 } // I2C
50 return false;
53 static int Baro_Init()
55 baro->initialize();
56 if (baro->isInitialized())
58 // Slow down Vbat updates to save bandwidth
59 Vbat_enableSlowUpdate(true);
60 BaroReadState = brsReadTemp;
61 return DURATION_IMMEDIATELY;
64 // Did not init, try again later
65 return BARO_STARTUP_INTERVAL;
68 static void Baro_PublishPressure(uint32_t pressuredPa)
70 static int32_t last_altitude_cm;
71 static int16_t verticalspd_smoothed;
72 int32_t altitude_cm = baro->pressureToAltitude(pressuredPa);
73 int32_t altitude_diff_cm = altitude_cm - last_altitude_cm;
74 last_altitude_cm = altitude_cm;
76 static uint32_t last_publish_ms;
77 uint32_t now = millis();
78 uint32_t dT_ms = now - last_publish_ms;
79 last_publish_ms = now;
81 //DBGLN("%udPa %dcm", pressuredPa, altitude_cm);
83 if (baro->getAltitudeHome() == BaroBase::ALTITUDE_INVALID)
85 baro->setAltitudeHome(altitude_cm);
86 // skip sending the first reading because the VSpd will be bonkers
87 return;
90 CRSF_MK_FRAME_T(crsf_sensor_baro_vario_t) crsfBaro = {0};
92 // Item: Alt
93 int32_t relative_altitude_dm = (altitude_cm - baro->getAltitudeHome()) / 10;
94 if (relative_altitude_dm > (0x7FFF - 10000))
96 // If the altitude would be 0x8000 or higher, send it in meters with the high bit set
97 crsfBaro.p.altitude = 0x8000 | (uint16_t)(relative_altitude_dm / 10);
99 else
101 // Else it is in decimeters + 10000 (-1000m max negative alt)
102 crsfBaro.p.altitude = relative_altitude_dm + 10000;
104 crsfBaro.p.altitude = htobe16(crsfBaro.p.altitude);
106 // Item: VSpd
107 int16_t vspd = altitude_diff_cm * 1000 / (int32_t)dT_ms;
108 verticalspd_smoothed = (verticalspd_smoothed * 3 + vspd) / 4; // Simple smoothing
109 crsfBaro.p.verticalspd = htobe16(verticalspd_smoothed);
110 //DBGLN("diff=%d smooth=%d dT=%u", altitude_diff_cm, verticalspd_smoothed, dT_ms);
112 // if no external vario is connected output internal Vspd on CRSF_FRAMETYPE_BARO_ALTITUDE packet
113 if (!telemetry.GetCrsfBaroSensorDetected())
115 CRSF::SetHeaderAndCrc((uint8_t *)&crsfBaro, CRSF_FRAMETYPE_BARO_ALTITUDE, CRSF_FRAME_SIZE(sizeof(crsf_sensor_baro_vario_t)), CRSF_ADDRESS_CRSF_TRANSMITTER);
116 telemetry.AppendTelemetryPackage((uint8_t *)&crsfBaro);
120 static int start()
122 if (Baro_Detect())
124 BaroReadState = brsUninitialized;
125 return BARO_STARTUP_INTERVAL;
128 BaroReadState = brsNoBaro;
129 return DURATION_NEVER;
132 static int timeout()
134 if (connectionState >= MODE_STATES)
135 return DURATION_NEVER;
137 switch (BaroReadState)
139 default: // fallthrough
140 case brsNoBaro:
141 return DURATION_NEVER;
143 case brsUninitialized:
144 return Baro_Init();
146 case brsWaitingTemp:
148 int32_t temp = baro->getTemperature();
149 if (temp == BaroBase::TEMPERATURE_INVALID)
150 return DURATION_IMMEDIATELY;
152 // fallthrough
154 case brsReadPres:
156 uint8_t pressDuration = baro->getPressureDuration();
157 BaroReadState = brsWaitingPress;
158 if (pressDuration != 0)
160 baro->startPressure();
161 return pressDuration;
164 // fallthrough
166 case brsWaitingPress:
168 uint32_t press = baro->getPressure();
169 if (press == BaroBase::PRESSURE_INVALID)
170 return DURATION_IMMEDIATELY;
171 Baro_PublishPressure(press);
173 // fallthrough
175 case brsReadTemp:
177 uint8_t tempDuration = baro->getTemperatureDuration();
178 if (tempDuration == 0)
180 BaroReadState = brsReadPres;
181 return DURATION_IMMEDIATELY;
183 BaroReadState = brsWaitingTemp;
184 baro->startTemperature();
185 return tempDuration;
190 device_t Baro_device = {
191 .initialize = nullptr,
192 .start = start,
193 .event = nullptr,
194 .timeout = timeout,
197 #endif