mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
- KeyboardWidget: replace inline placeholder overlay with PopupMenu - UITask QuickMsgScreen: replace inline CONTACT_PICK/CHANNEL_PICK context menus with PopupMenu; notif label stored in _ctx_notif_item at open time - BotScreen: clear placeholder list for trigger field (expansion tokens would never match incoming literal text) - MsgExpand: fix APPEND macro off-by-one (oi+_l < out_len-1 → < out_len) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
133 lines
5.1 KiB
C++
133 lines
5.1 KiB
C++
#pragma once
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
#include <cstdint>
|
|
#include <helpers/SensorManager.h>
|
|
#include <helpers/sensors/LPPDataHelpers.h>
|
|
|
|
// Expands placeholders in tmpl into out (out_len bytes).
|
|
// {loc} — GPS coordinates (lat/lon) or "no GPS"
|
|
// {time} — local time HH:MM from RTC
|
|
// {temp} — temperature in °C (requires sm)
|
|
// {hum} — relative humidity % (requires sm)
|
|
// {pres} — barometric pressure hPa (requires sm)
|
|
// {batt} — battery voltage V (batt_volts >= 0 or LPP_VOLTAGE from sm)
|
|
// {alt} — altitude m (requires sm)
|
|
// {lux} — luminosity lux (requires sm)
|
|
// {dist} — distance m (requires sm)
|
|
// {co2} — CO2 concentration ppm (requires sm)
|
|
inline void expandMsg(const char* tmpl, char* out, int out_len,
|
|
double lat, double lon, bool gps_valid,
|
|
uint32_t utc_ts, int8_t tz_hours,
|
|
SensorManager* sm = nullptr,
|
|
float batt_volts = -1.0f) {
|
|
// sv indices: 0=temp 1=hum 2=pres 3=batt 4=alt 5=lux 6=dist 7=co2
|
|
float sv[8] = {};
|
|
bool sv_ok[8] = {};
|
|
|
|
if (sm) {
|
|
CayenneLPP lpp(100);
|
|
sm->querySensors(0xFF, lpp);
|
|
LPPReader r(lpp.getBuffer(), lpp.getSize());
|
|
uint8_t ch, type;
|
|
while (r.readHeader(ch, type)) {
|
|
float tmp;
|
|
switch (type) {
|
|
case LPP_TEMPERATURE:
|
|
r.readTemperature(tmp);
|
|
if (!sv_ok[0]) { sv[0] = tmp; sv_ok[0] = true; } break;
|
|
case LPP_RELATIVE_HUMIDITY:
|
|
r.readRelativeHumidity(tmp);
|
|
if (!sv_ok[1]) { sv[1] = tmp; sv_ok[1] = true; } break;
|
|
case LPP_BAROMETRIC_PRESSURE:
|
|
r.readPressure(tmp);
|
|
if (!sv_ok[2]) { sv[2] = tmp; sv_ok[2] = true; } break;
|
|
case LPP_VOLTAGE:
|
|
r.readVoltage(tmp);
|
|
if (!sv_ok[3]) { sv[3] = tmp; sv_ok[3] = true; } break;
|
|
case LPP_ALTITUDE:
|
|
r.readAltitude(tmp);
|
|
if (!sv_ok[4]) { sv[4] = tmp; sv_ok[4] = true; } break;
|
|
case LPP_LUMINOSITY:
|
|
r.readLuminosity(tmp);
|
|
if (!sv_ok[5]) { sv[5] = tmp; sv_ok[5] = true; } break;
|
|
case LPP_DISTANCE:
|
|
r.readDistance(tmp);
|
|
if (!sv_ok[6]) { sv[6] = tmp; sv_ok[6] = true; } break;
|
|
case LPP_CONCENTRATION:
|
|
r.readConcentration(tmp);
|
|
if (!sv_ok[7]) { sv[7] = tmp; sv_ok[7] = true; } break;
|
|
default:
|
|
r.skipData(type); break;
|
|
}
|
|
}
|
|
}
|
|
// board battery takes precedence over INA sensor voltage
|
|
if (batt_volts >= 0.0f) { sv[3] = batt_volts; sv_ok[3] = true; }
|
|
|
|
int oi = 0;
|
|
const char* p = tmpl;
|
|
while (*p && oi < out_len - 1) {
|
|
// helper macro: append a buffer whose length is already known
|
|
#define APPEND(s, slen) do { \
|
|
int _l = (slen); \
|
|
if (oi + _l < out_len) { memcpy(out + oi, (s), _l); oi += _l; } \
|
|
} while(0)
|
|
|
|
if (strncmp(p, "{loc}", 5) == 0) {
|
|
char lb[32];
|
|
if (gps_valid) snprintf(lb, sizeof(lb), "%.5f,%.5f", lat, lon);
|
|
else strcpy(lb, "no GPS");
|
|
APPEND(lb, strlen(lb)); p += 5;
|
|
} else if (strncmp(p, "{time}", 6) == 0) {
|
|
if (utc_ts > 1000000000UL) {
|
|
uint32_t local_ts = utc_ts + (int32_t)tz_hours * 3600;
|
|
time_t t = (time_t)local_ts;
|
|
struct tm* ti = gmtime(&t);
|
|
char tb[8];
|
|
snprintf(tb, sizeof(tb), "%02d:%02d", ti->tm_hour, ti->tm_min);
|
|
APPEND(tb, strlen(tb));
|
|
}
|
|
p += 6;
|
|
} else if (strncmp(p, "{temp}", 6) == 0) {
|
|
if (sv_ok[0]) { char b[10]; snprintf(b,sizeof(b),"%.1fC",sv[0]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{temp}", 6); }
|
|
p += 6;
|
|
} else if (strncmp(p, "{hum}", 5) == 0) {
|
|
if (sv_ok[1]) { char b[8]; snprintf(b,sizeof(b),"%.0f%%",sv[1]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{hum}", 5); }
|
|
p += 5;
|
|
} else if (strncmp(p, "{pres}", 6) == 0) {
|
|
if (sv_ok[2]) { char b[12]; snprintf(b,sizeof(b),"%.0fhPa",sv[2]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{pres}", 6); }
|
|
p += 6;
|
|
} else if (strncmp(p, "{batt}", 6) == 0) {
|
|
if (sv_ok[3]) { char b[8]; snprintf(b,sizeof(b),"%.2fV",sv[3]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{batt}", 6); }
|
|
p += 6;
|
|
} else if (strncmp(p, "{alt}", 5) == 0) {
|
|
if (sv_ok[4]) { char b[10]; snprintf(b,sizeof(b),"%.0fm",sv[4]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{alt}", 5); }
|
|
p += 5;
|
|
} else if (strncmp(p, "{lux}", 5) == 0) {
|
|
if (sv_ok[5]) { char b[10]; snprintf(b,sizeof(b),"%.0flux",sv[5]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{lux}", 5); }
|
|
p += 5;
|
|
} else if (strncmp(p, "{dist}", 6) == 0) {
|
|
if (sv_ok[6]) { char b[12]; snprintf(b,sizeof(b),"%.2fm",sv[6]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{dist}", 6); }
|
|
p += 6;
|
|
} else if (strncmp(p, "{co2}", 5) == 0) {
|
|
if (sv_ok[7]) { char b[12]; snprintf(b,sizeof(b),"%.0fppm",sv[7]); APPEND(b,strlen(b)); }
|
|
else { APPEND("{co2}", 5); }
|
|
p += 5;
|
|
} else {
|
|
out[oi++] = *p++;
|
|
}
|
|
|
|
#undef APPEND
|
|
}
|
|
out[oi] = '\0';
|
|
}
|