Skip to content

Commit d83cdc5

Browse files
committed
ui: use LPPDataHelper and conditionals for sensors page
1 parent 2d4b77c commit d83cdc5

File tree

4 files changed

+306
-26
lines changed

4 files changed

+306
-26
lines changed

examples/companion_radio/ui-new/UITask.cpp

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ class HomeScreen : public UIScreen {
7575
RADIO,
7676
BLUETOOTH,
7777
ADVERT,
78+
#if UI_SENSORS_PAGE == 1
7879
SENSORS,
80+
#endif
7981
SHUTDOWN,
8082
Count // keep as last
8183
};
@@ -114,20 +116,25 @@ class HomeScreen : public UIScreen {
114116
display.fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4);
115117
}
116118

117-
DynamicJsonDocument _sensors_doc;
118-
JsonArray _sensors_arr;
119-
bool scroll = false;
120-
int scroll_offset = 0;
119+
CayenneLPP sensors_lpp;
120+
int sensors_nb = 0;
121+
bool sensors_scroll = false;
122+
int sensors_scroll_offset = 0;
121123
int next_sensors_refresh = 0;
122124

123125
void refresh_sensors() {
124-
CayenneLPP lpp(200);
125126
if (millis() > next_sensors_refresh) {
126-
lpp.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
127-
sensors.querySensors(0xFF, lpp);
128-
_sensors_arr.clear();
129-
lpp.decode(lpp.getBuffer(), lpp.getSize(), _sensors_arr);
130-
scroll = _sensors_arr.size() > UI_RECENT_LIST_SIZE; // there is a status line
127+
sensors_lpp.reset();
128+
sensors_nb = 0;
129+
sensors_lpp.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f);
130+
sensors.querySensors(0xFF, sensors_lpp);
131+
LPPReader reader (sensors_lpp.getBuffer(), sensors_lpp.getSize());
132+
uint8_t channel, type;
133+
while(reader.readHeader(channel, type)) {
134+
reader.skipData(type);
135+
sensors_nb ++;
136+
}
137+
sensors_scroll = sensors_nb > UI_RECENT_LIST_SIZE;
131138
#if AUTO_OFF_MILLIS > 0
132139
next_sensors_refresh = millis() + 5000; // refresh sensor values every 5 sec
133140
#else
@@ -139,7 +146,7 @@ class HomeScreen : public UIScreen {
139146
public:
140147
HomeScreen(UITask* task, mesh::RTCClock* rtc, SensorManager* sensors, NodePrefs* node_prefs)
141148
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0),
142-
_shutdown_init(false), _sensors_doc(2048) { _sensors_arr=_sensors_doc.to<JsonArray>(); }
149+
_shutdown_init(false), sensors_lpp(200) { }
143150

144151
void poll() override {
145152
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
@@ -235,34 +242,78 @@ class HomeScreen : public UIScreen {
235242
display.setColor(DisplayDriver::GREEN);
236243
display.drawXbm((display.width() - 32) / 2, 18, advert_icon, 32, 32);
237244
display.drawTextCentered(display.width() / 2, 64 - 11, "advert: " PRESS_LABEL);
245+
#if UI_SENSORS_PAGE == 1
238246
} else if (_page == HomePage::SENSORS) {
239247
int y = 18;
240248
refresh_sensors();
241-
char buf[100];
242-
int s_size = _sensors_arr.size();
243-
for (int i = 0; i < (scroll?UI_RECENT_LIST_SIZE:s_size); i++) {
244-
JsonObject v = _sensors_arr[(i+scroll_offset)%s_size];
249+
char buf[30];
250+
char name[30];
251+
LPPReader r(sensors_lpp.getBuffer(), sensors_lpp.getSize());
252+
253+
for (int i = 0; i < sensors_scroll_offset; i++) {
254+
uint8_t channel, type;
255+
r.readHeader(channel, type);
256+
r.skipData(type);
257+
}
258+
259+
for (int i = 0; i < (sensors_scroll?UI_RECENT_LIST_SIZE:sensors_nb); i++) {
260+
uint8_t channel, type;
261+
if (!r.readHeader(channel, type)) { // reached end, reset
262+
r.reset();
263+
r.readHeader(channel, type);
264+
}
265+
245266
display.setCursor(0, y);
246-
switch (v["type"].as<int>()) {
247-
case 136: // GPS
248-
sprintf(buf, "%.4f %.4f",
249-
v["value"]["latitude"].as<float>(),
250-
v["value"]["longitude"].as<float>());
267+
float v;
268+
switch (type) {
269+
case LPP_GPS: // GPS
270+
float lat, lon, alt;
271+
r.readGPS(lat, lon, alt);
272+
strcpy(name, "gps"); sprintf(buf, "%.4f %.4f", lat, lon);
273+
break;
274+
case LPP_VOLTAGE:
275+
r.readVoltage(v);
276+
strcpy(name, "voltage"); sprintf(buf, "%6.2f", v);
277+
break;
278+
case LPP_CURRENT:
279+
r.readCurrent(v);
280+
strcpy(name, "current"); sprintf(buf, "%.3f", v);
251281
break;
252-
default: // will be a float for now
253-
sprintf(buf, "%.02f",
254-
v["value"].as<float>());
282+
case LPP_TEMPERATURE:
283+
r.readTemperature(v);
284+
strcpy(name, "temperature"); sprintf(buf, "%.2f", v);
285+
break;
286+
case LPP_RELATIVE_HUMIDITY:
287+
r.readRelativeHumidity(v);
288+
strcpy(name, "humidity"); sprintf(buf, "%.2f", v);
289+
break;
290+
case LPP_BAROMETRIC_PRESSURE:
291+
r.readPressure(v);
292+
strcpy(name, "pressure"); sprintf(buf, "%.2f", v);
293+
break;
294+
case LPP_ALTITUDE:
295+
r.readAltitude(v);
296+
strcpy(name, "altitude"); sprintf(buf, "%.0f", v);
297+
break;
298+
case LPP_POWER:
299+
r.readPower(v);
300+
strcpy(name, "power"); sprintf(buf, "%6.2f", v);
301+
break;
302+
default:
303+
r.skipData(type);
304+
strcpy(name, "unk"); sprintf(buf, "");
255305
}
256306
display.setCursor(0, y);
257-
display.print(v["name"].as<JsonString>().c_str());
307+
display.print(name);
258308
display.setCursor(
259309
display.width()-display.getTextWidth(buf)-1, y
260310
);
261311
display.print(buf);
262312
y = y + 12;
263313
}
264-
if (scroll) scroll_offset = (scroll_offset+1)%s_size;
265-
else scroll_offset = 0;
314+
if (sensors_scroll) sensors_scroll_offset = (sensors_scroll_offset+1)%sensors_nb;
315+
else sensors_scroll_offset = 0;
316+
#endif
266317
} else if (_page == HomePage::SHUTDOWN) {
267318
display.setColor(DisplayDriver::GREEN);
268319
display.setTextSize(1);
@@ -307,11 +358,13 @@ class HomeScreen : public UIScreen {
307358
}
308359
return true;
309360
}
361+
#if UI_SENSORS_PAGE == 1
310362
if (c == KEY_ENTER && _page == HomePage::SENSORS) {
311363
_task->toggleGPS();
312364
next_sensors_refresh=0;
313365
return true;
314366
}
367+
#endif
315368
if (c == KEY_ENTER && _page == HomePage::SHUTDOWN) {
316369
_shutdown_init = true; // need to wait for button to be released
317370
return true;

examples/companion_radio/ui-new/UITask.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <helpers/SensorManager.h>
77
#include <helpers/BaseSerialInterface.h>
88
#include <Arduino.h>
9+
#include <helpers/sensors/LPPDataHelpers.h>
910

1011
#ifdef PIN_BUZZER
1112
#include <helpers/ui/buzzer.h>
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
#define LPP_DIGITAL_INPUT 0 // 1 byte
6+
#define LPP_DIGITAL_OUTPUT 1 // 1 byte
7+
#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed
8+
#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed
9+
#define LPP_GENERIC_SENSOR 100 // 4 bytes, unsigned
10+
#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned
11+
#define LPP_PRESENCE 102 // 1 byte, bool
12+
#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed
13+
#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned
14+
#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G
15+
#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1hPa unsigned
16+
#define LPP_VOLTAGE 116 // 2 bytes 0.01V unsigned
17+
#define LPP_CURRENT 117 // 2 bytes 0.001A unsigned
18+
#define LPP_FREQUENCY 118 // 4 bytes 1Hz unsigned
19+
#define LPP_PERCENTAGE 120 // 1 byte 1-100% unsigned
20+
#define LPP_ALTITUDE 121 // 2 byte 1m signed
21+
#define LPP_CONCENTRATION 125 // 2 bytes, 1 ppm unsigned
22+
#define LPP_POWER 128 // 2 byte, 1W, unsigned
23+
#define LPP_DISTANCE 130 // 4 byte, 0.001m, unsigned
24+
#define LPP_ENERGY 131 // 4 byte, 0.001kWh, unsigned
25+
#define LPP_DIRECTION 132 // 2 bytes, 1deg, unsigned
26+
#define LPP_UNIXTIME 133 // 4 bytes, unsigned
27+
#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s
28+
#define LPP_COLOUR 135 // 1 byte per RGB Color
29+
#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
30+
#define LPP_SWITCH 142 // 1 byte, 0/1
31+
#define LPP_POLYLINE 240 // 1 byte size, 1 byte delta factor, 3 byte lon/lat 0.0001° * factor, n (size-8) bytes deltas
32+
33+
// Multipliers
34+
#define LPP_DIGITAL_INPUT_MULT 1
35+
#define LPP_DIGITAL_OUTPUT_MULT 1
36+
#define LPP_ANALOG_INPUT_MULT 100
37+
#define LPP_ANALOG_OUTPUT_MULT 100
38+
#define LPP_GENERIC_SENSOR_MULT 1
39+
#define LPP_LUMINOSITY_MULT 1
40+
#define LPP_PRESENCE_MULT 1
41+
#define LPP_TEMPERATURE_MULT 10
42+
#define LPP_RELATIVE_HUMIDITY_MULT 2
43+
#define LPP_ACCELEROMETER_MULT 1000
44+
#define LPP_BAROMETRIC_PRESSURE_MULT 10
45+
#define LPP_VOLTAGE_MULT 100
46+
#define LPP_CURRENT_MULT 1000
47+
#define LPP_FREQUENCY_MULT 1
48+
#define LPP_PERCENTAGE_MULT 1
49+
#define LPP_ALTITUDE_MULT 1
50+
#define LPP_POWER_MULT 1
51+
#define LPP_DISTANCE_MULT 1000
52+
#define LPP_ENERGY_MULT 1000
53+
#define LPP_DIRECTION_MULT 1
54+
#define LPP_UNIXTIME_MULT 1
55+
#define LPP_GYROMETER_MULT 100
56+
#define LPP_GPS_LAT_LON_MULT 10000
57+
#define LPP_GPS_ALT_MULT 100
58+
#define LPP_SWITCH_MULT 1
59+
#define LPP_CONCENTRATION_MULT 1
60+
#define LPP_COLOUR_MULT 1
61+
62+
#define LPP_ERROR_OK 0
63+
#define LPP_ERROR_OVERFLOW 1
64+
#define LPP_ERROR_UNKOWN_TYPE 2
65+
66+
class LPPReader {
67+
const uint8_t* _buf;
68+
uint8_t _len;
69+
uint8_t _pos;
70+
71+
float getFloat(const uint8_t * buffer, uint8_t size, uint32_t multiplier, bool is_signed) {
72+
uint32_t value = 0;
73+
for (uint8_t i = 0; i < size; i++) {
74+
value = (value << 8) + buffer[i];
75+
}
76+
77+
int sign = 1;
78+
if (is_signed) {
79+
uint32_t bit = 1ul << ((size * 8) - 1);
80+
if ((value & bit) == bit) {
81+
value = (bit << 1) - value;
82+
sign = -1;
83+
}
84+
}
85+
return sign * ((float) value / multiplier);
86+
}
87+
88+
public:
89+
LPPReader(const uint8_t buf[], uint8_t len) : _buf(buf), _len(len), _pos(0) { }
90+
91+
void reset() {
92+
_pos = 0;
93+
}
94+
95+
bool readHeader(uint8_t& channel, uint8_t& type) {
96+
if (_pos + 2 < _len) {
97+
channel = _buf[_pos++];
98+
type = _buf[_pos++];
99+
100+
return channel != 0; // channel 0 is End-of-data
101+
}
102+
return false; // end-of-buffer
103+
}
104+
105+
bool readGPS(float& lat, float& lon, float& alt) {
106+
lat = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
107+
lon = getFloat(&_buf[_pos], 3, 10000, true); _pos += 3;
108+
alt = getFloat(&_buf[_pos], 3, 100, true); _pos += 3;
109+
return _pos <= _len;
110+
}
111+
bool readVoltage(float& voltage) {
112+
voltage = getFloat(&_buf[_pos], 2, 100, false); _pos += 2;
113+
return _pos <= _len;
114+
}
115+
bool readCurrent(float& amps) {
116+
amps = getFloat(&_buf[_pos], 2, 1000, false); _pos += 2;
117+
return _pos <= _len;
118+
}
119+
bool readPower(float& watts) {
120+
watts = getFloat(&_buf[_pos], 2, 1, false); _pos += 2;
121+
return _pos <= _len;
122+
}
123+
bool readTemperature(float& degrees_c) {
124+
degrees_c = getFloat(&_buf[_pos], 2, 10, true); _pos += 2;
125+
return _pos <= _len;
126+
}
127+
bool readPressure(float& pa) {
128+
pa = getFloat(&_buf[_pos], 2, 10, false); _pos += 2;
129+
return _pos <= _len;
130+
}
131+
bool readRelativeHumidity(float& pct) {
132+
pct = getFloat(&_buf[_pos], 1, 2, false); _pos += 1;
133+
return _pos <= _len;
134+
}
135+
bool readAltitude(float& m) {
136+
m = getFloat(&_buf[_pos], 2, 1, true); _pos += 2;
137+
return _pos <= _len;
138+
}
139+
140+
void skipData(uint8_t type) {
141+
switch (type) {
142+
case LPP_GPS:
143+
_pos += 9; break;
144+
case LPP_POLYLINE:
145+
_pos += 8; break; // TODO: this is MINIMIUM
146+
case LPP_GYROMETER:
147+
case LPP_ACCELEROMETER:
148+
_pos += 6; break;
149+
case LPP_GENERIC_SENSOR:
150+
case LPP_FREQUENCY:
151+
case LPP_DISTANCE:
152+
case LPP_ENERGY:
153+
case LPP_UNIXTIME:
154+
_pos += 4; break;
155+
case LPP_COLOUR:
156+
_pos += 3; break;
157+
case LPP_ANALOG_INPUT:
158+
case LPP_ANALOG_OUTPUT:
159+
case LPP_LUMINOSITY:
160+
case LPP_TEMPERATURE:
161+
case LPP_CONCENTRATION:
162+
case LPP_BAROMETRIC_PRESSURE:
163+
case LPP_ALTITUDE:
164+
case LPP_VOLTAGE:
165+
case LPP_CURRENT:
166+
case LPP_DIRECTION:
167+
case LPP_POWER:
168+
_pos += 2; break;
169+
default:
170+
_pos++;
171+
}
172+
}
173+
};
174+
175+
class LPPWriter {
176+
uint8_t* _buf;
177+
uint8_t _max_len;
178+
uint8_t _len;
179+
180+
void write(uint16_t value) {
181+
_buf[_len++] = (value >> 8) & 0xFF; // MSB
182+
_buf[_len++] = value & 0xFF; // LSB
183+
}
184+
185+
public:
186+
LPPWriter(uint8_t buf[], uint8_t max_len): _buf(buf), _max_len(max_len), _len(0) { }
187+
188+
bool writeVoltage(uint8_t channel, float voltage) {
189+
if (_len + 4 <= _max_len) {
190+
_buf[_len++] = channel;
191+
_buf[_len++] = LPP_VOLTAGE;
192+
uint16_t value = voltage * 100;
193+
write(value);
194+
return true;
195+
}
196+
return false;
197+
}
198+
199+
bool writeGPS(uint8_t channel, float lat, float lon, float alt) {
200+
if (_len + 11 <= _max_len) {
201+
_buf[_len++] = channel;
202+
_buf[_len++] = LPP_GPS;
203+
204+
int32_t lati = lat * 10000; // we lose some precision :-(
205+
int32_t loni = lon * 10000;
206+
int32_t alti = alt * 100;
207+
208+
_buf[_len++] = lati >> 16;
209+
_buf[_len++] = lati >> 8;
210+
_buf[_len++] = lati;
211+
_buf[_len++] = loni >> 16;
212+
_buf[_len++] = loni >> 8;
213+
_buf[_len++] = loni;
214+
_buf[_len++] = alti >> 16;
215+
_buf[_len++] = alti >> 8;
216+
_buf[_len++] = alti;
217+
return true;
218+
}
219+
return false;
220+
}
221+
222+
uint8_t length() { return _len; }
223+
};

0 commit comments

Comments
 (0)