mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-15 20:49:53 +00:00
- gps: servers honour gps_enabled at boot (was lost on reboot; zc.gps_set upgrades older prefs to on once); sleep lock only while acquiring; gps off works on boards without a power line (UART sleep); UI toggles and fixes handled on the main thread; configure only after a good init; observer parks its GPS; one interval clamp (clampGpsInterval); one nav-mode knob (room servers on Air530Z now stationary); GNSS UARTE from DT - gps: split into ZephyrGPSManager / gps_power / gps_module_cfg (+gps_internal.h); dead driver branches, gps_get_diag, sats_* removed - clock: ZephyrRTCClock writes the hardware RTC itself (clkreboot now resets it); MESH_EVENT_RTC_SAVE gone - power: one power-off path (zephcore_power_off, ZephyrBoard::powerOff), poweroff/shutdown CLI, get pwrmgt.*, crash record kept across reboot, battery reading cached 10 s, fuel gauge on the current API - telemetry: upstream SensorManager + CayenneLPP (rounded to nearest), one builder for all roles; per-sensor channels, MCU temp always, guest gating and inverse mask on servers; sensor list/get/set work; BME280/BMP280 also probed at 0x77 - CLI: gps in upstream's form, get gps detail, gps sync
174 lines
5.7 KiB
C++
174 lines
5.7 KiB
C++
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* CayenneLPP - the subset of the electroniccats/CayenneLPP 1.6.1 encoder
|
|
* (upstream MeshCore's dependency) that MeshCore's telemetry uses, with the
|
|
* same API and wire format: [channel][type][value, big-endian], the add*
|
|
* functions returning the new size, or 0 when the field does not fit.
|
|
*
|
|
* One deliberate difference: values are rounded to the nearest step after
|
|
* scaling, where the library truncates toward zero. The library turns a
|
|
* 3850 mV battery into 3.84 V (3.85f * 100 = 384.99997); this sends 3.85.
|
|
* Same bytes on the wire for any decoder, closer to the reading.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
/* Type codes and multipliers, as the library's CayenneLPP.h */
|
|
#define LPP_ANALOG_INPUT 2 /* 2 bytes, 0.01 signed */
|
|
#define LPP_GENERIC_SENSOR 100 /* 4 bytes, unsigned */
|
|
#define LPP_LUMINOSITY 101 /* 2 bytes, 1 lux unsigned */
|
|
#define LPP_TEMPERATURE 103 /* 2 bytes, 0.1°C signed */
|
|
#define LPP_RELATIVE_HUMIDITY 104 /* 1 byte, 0.5% unsigned */
|
|
#define LPP_BAROMETRIC_PRESSURE 115 /* 2 bytes 0.1hPa unsigned */
|
|
#define LPP_VOLTAGE 116 /* 2 bytes 0.01V */
|
|
#define LPP_CURRENT 117 /* 2 bytes 0.001A */
|
|
#define LPP_ALTITUDE 121 /* 2 bytes 1m signed */
|
|
#define LPP_POWER 128 /* 2 bytes, 1W unsigned */
|
|
#define LPP_DISTANCE 130 /* 4 bytes, 0.001m unsigned */
|
|
#define LPP_GPS 136 /* 3 bytes lat/lon 0.0001°, 3 bytes alt 0.01m */
|
|
|
|
#define LPP_ANALOG_INPUT_MULT 100
|
|
#define LPP_TEMPERATURE_MULT 10
|
|
#define LPP_RELATIVE_HUMIDITY_MULT 2
|
|
#define LPP_BAROMETRIC_PRESSURE_MULT 10
|
|
#define LPP_VOLTAGE_MULT 100
|
|
#define LPP_CURRENT_MULT 1000
|
|
#define LPP_DISTANCE_MULT 1000
|
|
#define LPP_GPS_LAT_LON_MULT 10000
|
|
#define LPP_GPS_ALT_MULT 100
|
|
|
|
/* Upstream sizes its telemetry buffer from MAX_PACKET_PAYLOAD; this holds it. */
|
|
#define CAYENNE_LPP_MAX_SIZE 192
|
|
|
|
class CayenneLPP {
|
|
public:
|
|
explicit CayenneLPP(uint8_t size)
|
|
: _maxsize(size > CAYENNE_LPP_MAX_SIZE ? CAYENNE_LPP_MAX_SIZE : size), _cursor(0) {}
|
|
|
|
void reset(void) { _cursor = 0; }
|
|
uint8_t getSize(void) { return _cursor; }
|
|
uint8_t *getBuffer(void) { return _buffer; }
|
|
|
|
uint8_t addTemperature(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_TEMPERATURE, channel, value, 2, LPP_TEMPERATURE_MULT, true);
|
|
}
|
|
uint8_t addRelativeHumidity(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_RELATIVE_HUMIDITY, channel, value, 1,
|
|
LPP_RELATIVE_HUMIDITY_MULT, false);
|
|
}
|
|
/* The library takes an integer: a relative-scale light sensor (the T1000-E
|
|
* photocell's 0-100) goes through unchanged, as upstream reports it. */
|
|
uint8_t addLuminosity(uint8_t channel, uint32_t value)
|
|
{
|
|
return addField(LPP_LUMINOSITY, channel, (float)value, 2, 1, false);
|
|
}
|
|
uint8_t addBarometricPressure(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_BAROMETRIC_PRESSURE, channel, value, 2,
|
|
LPP_BAROMETRIC_PRESSURE_MULT, false);
|
|
}
|
|
uint8_t addVoltage(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_VOLTAGE, channel, value, 2, LPP_VOLTAGE_MULT, true);
|
|
}
|
|
/* Signed, so a bidirectional monitor (INA219) reports discharge as negative. */
|
|
uint8_t addCurrent(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_CURRENT, channel, value, 2, LPP_CURRENT_MULT, true);
|
|
}
|
|
uint8_t addPower(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_POWER, channel, value, 2, 1, false);
|
|
}
|
|
uint8_t addAltitude(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_ALTITUDE, channel, value, 2, 1, true);
|
|
}
|
|
uint8_t addDistance(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_DISTANCE, channel, value, 4, LPP_DISTANCE_MULT, false);
|
|
}
|
|
uint8_t addAnalogInput(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_ANALOG_INPUT, channel, value, 2, LPP_ANALOG_INPUT_MULT, true);
|
|
}
|
|
uint8_t addGenericSensor(uint8_t channel, float value)
|
|
{
|
|
return addField(LPP_GENERIC_SENSOR, channel, value, 4, 1, false);
|
|
}
|
|
|
|
uint8_t addGPS(uint8_t channel, float latitude, float longitude, float altitude)
|
|
{
|
|
if (_cursor + 9 + 2 > _maxsize) {
|
|
return 0;
|
|
}
|
|
int32_t lat = scaled(latitude, LPP_GPS_LAT_LON_MULT);
|
|
int32_t lon = scaled(longitude, LPP_GPS_LAT_LON_MULT);
|
|
int32_t alt = scaled(altitude, LPP_GPS_ALT_MULT);
|
|
|
|
_buffer[_cursor++] = channel;
|
|
_buffer[_cursor++] = LPP_GPS;
|
|
_buffer[_cursor++] = lat >> 16;
|
|
_buffer[_cursor++] = lat >> 8;
|
|
_buffer[_cursor++] = lat;
|
|
_buffer[_cursor++] = lon >> 16;
|
|
_buffer[_cursor++] = lon >> 8;
|
|
_buffer[_cursor++] = lon;
|
|
_buffer[_cursor++] = alt >> 16;
|
|
_buffer[_cursor++] = alt >> 8;
|
|
_buffer[_cursor++] = alt;
|
|
return _cursor;
|
|
}
|
|
|
|
private:
|
|
uint8_t _buffer[CAYENNE_LPP_MAX_SIZE];
|
|
uint8_t _maxsize;
|
|
uint8_t _cursor;
|
|
|
|
/* value * multiplier, rounded to nearest (half away from zero). */
|
|
static int32_t scaled(float value, uint32_t multiplier)
|
|
{
|
|
float x = value * (float)multiplier;
|
|
|
|
return (int32_t)(x < 0 ? x - 0.5f : x + 0.5f);
|
|
}
|
|
|
|
/* The library's addField(): the magnitude scaled (rounded here, see the
|
|
* top of the file), then the sign applied as two's complement within the
|
|
* field. */
|
|
uint8_t addField(uint8_t type, uint8_t channel, float value, uint8_t size,
|
|
uint32_t multiplier, bool is_signed)
|
|
{
|
|
if (_cursor + size + 2 > _maxsize) {
|
|
return 0;
|
|
}
|
|
bool sign = value < 0;
|
|
|
|
if (sign) {
|
|
value = -value;
|
|
}
|
|
uint32_t v = (uint32_t)(value * (float)multiplier + 0.5f);
|
|
|
|
if (is_signed && sign) {
|
|
uint32_t mask = (size >= 4) ? 0xFFFFFFFFu : ((1u << (size * 8)) - 1);
|
|
|
|
v = v & mask;
|
|
v = mask - v + 1;
|
|
}
|
|
_buffer[_cursor++] = channel;
|
|
_buffer[_cursor++] = type;
|
|
for (uint8_t i = 1; i <= size; i++) {
|
|
_buffer[_cursor + size - i] = v & 0xFF;
|
|
v >>= 8;
|
|
}
|
|
_cursor += size;
|
|
return _cursor;
|
|
}
|
|
};
|