feat(ui-core,ui-lvgl): diagnostics rows in the Core, L2 diagnostics, auto-advert setting, compass

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-25 23:01:42 +02:00
co-authored by Claude Opus 5.5
parent 8663d50412
commit 63db1e2e07
15 changed files with 666 additions and 343 deletions
@@ -66,6 +66,14 @@ Confirmed: green dot inside the ring, waypoints much better, download works, set
- [ ] Room server login from the phone app / L1 still works while this exists (only admin logins go to the new session)
- [ ] L1 (ui-new): Tools > Admin works as before (login, saved password, typed values, confirm reboot); it now also skips the login for the node you just used
## New: Diagnostics, auto-advert, compass (2026-09-25)
- [ ] Settings > SYSTEM > Diagnostics: tabs Live / System / Font; Live counters (uptime, rx/tx, heap, noise floor, RSSI/SNR, queue, errors) tick every second
- [ ] Live > Reset → confirm popup → "Counters reset", rx/tx and forwarded go back to 0
- [ ] System shows firmware, build date, board, node name, frequency / SF / BW / CR, TX power; Font shows Polish, Greek and Cyrillic samples without boxes
- [ ] Settings > Trail, live share, alerts > LIVE SHARE > Auto-advert 30 s: another node sees your advert (with position) every ~30 s; Off stops it; survives a reboot
- [ ] L1: Tools › Auto-Advert shows the value set on L2 (same pref), Tools › Diagnostics unchanged
- [ ] Home page 2 > Compass: without a fix "Waiting for a GPS fix" (GPS off: hint to turn it on); standing still "Move to set the heading"; walking: dial turns so your course is under the amber pointer, degrees + cardinal on the right
## New: Node name, reboot, lock screen, favourites dial (2026-09-25)
- [ ] Settings > NODE > Name: popup with the current name, Enter saves; Home and Settings show the new name; another node sees it after your next advert
- [ ] Settings > SYSTEM > Reboot / Power off: confirm popup (red button); reboot comes back normally, messages and settings kept
+1 -1
View File
@@ -110,7 +110,7 @@ call the same ones, so e.g. "marking a channel read" has one implementation.
### 5. Declarative settings schema
`ui-core/SettingsSchema.h` holds three pages -- navigation (trail, live share, arrival alert, units), display & power (brightness, screen off, wake on message, battery shutdown, GPS power saving, time zone) and messages & contacts (DM resends, contact expiry, favourites first). An entry is a one-byte index by default, or a `values` table over a 1/2/4-byte field (seconds, millivolts, an hour offset, `{1, 0}` for a field stored inverted); side effects run through `UiCore` (`applyGpsInterval()`, `host()->applyDisplayPrefs()`). ui-lvgl renders each page; ui-new still uses its own screens. Radio settings are not schema rows (preset list, typed frequency, radio side effects): `ui-core/RadioControl.h` applies them (`applyParams`, `applyTxPower`, `applyApc`, presets = built-ins + user slots) for both ui-new's Settings > Radio and ui-lvgl's Radio screen. Channel management is `ui-core/ChannelControl.h` (`chanctl::`): add Public / Hashtag / Private (passphrase or 32-hex key), rename, delete, notifications / favourite / scope, and `onRemoved()` -- the cleanup of every channel-keyed pref, run by `UiCore::onChannelRemoved` whoever deleted the channel (this device or the app); contacts get the same through `UiCore::cleanupContactPrefs`. Favourites dial slots: `ui-core/Favourites.h` (`pinContact` / `pinChannel` move an entry that is already on another slot; the slot's name is `contactctl::favName`). The schema's display page also carries the lock screen (`auto_lock`) and the 12-hour clock, which ui-lvgl implements (a slide-to-unlock card after the screen turns off). Remote admin is `ui-core/AdminSession.h` (`UiCore::admin`): login with the saved password (forgotten on a wrong password or a silent timeout), CLI round trips with timeouts, the field table (`admin::`), typed values; results come out one at a time through `take()`. `UiCore` offers login answers and CLI replies to it first; only room logins it wasn't waiting for reach the frontend. ui-new's Tools > Admin and ui-lvgl's Admin screen are views over it. The bot's settings are a table too, `ui-core/BotConfig.h` (`botcfg::`: tabs, rows, the NodePrefs flag / text / hour behind each, reply placeholders); ui-new's Tools > Bot and ui-lvgl's Bot screen render it, the bot itself runs in MyMesh. Room servers: `ui-core/RoomSessions.h` (`UiCore::rooms`) keeps who is logged in this session, the one login in flight (with a timeout) and the saved passwords (saved on success, forgotten on failure); `open(contact)` says whether to go straight in, wait for a background login or ask for a password, and outcomes come out through `take()`. Per-contact helpers are `ui-core/ContactControl.h` (`contactctl::`: DM notification / melody overrides, favourite flag, the `@[name] ` reply prefix, splitting a room post into author and text, naming a message's path hops). ui-new's Messages and ui-lvgl's Chats / thread use both.
`ui-core/SettingsSchema.h` holds three pages -- navigation (trail, live share, arrival alert, units), display & power (brightness, screen off, wake on message, battery shutdown, GPS power saving, time zone) and messages & contacts (DM resends, contact expiry, favourites first). An entry is a one-byte index by default, or a `values` table over a 1/2/4-byte field (seconds, millivolts, an hour offset, `{1, 0}` for a field stored inverted); side effects run through `UiCore` (`applyGpsInterval()`, `host()->applyDisplayPrefs()`). ui-lvgl renders each page; ui-new still uses its own screens. Radio settings are not schema rows (preset list, typed frequency, radio side effects): `ui-core/RadioControl.h` applies them (`applyParams`, `applyTxPower`, `applyApc`, presets = built-ins + user slots) for both ui-new's Settings > Radio and ui-lvgl's Radio screen. Channel management is `ui-core/ChannelControl.h` (`chanctl::`): add Public / Hashtag / Private (passphrase or 32-hex key), rename, delete, notifications / favourite / scope, and `onRemoved()` -- the cleanup of every channel-keyed pref, run by `UiCore::onChannelRemoved` whoever deleted the channel (this device or the app); contacts get the same through `UiCore::cleanupContactPrefs`. Favourites dial slots: `ui-core/Favourites.h` (`pinContact` / `pinChannel` move an entry that is already on another slot; the slot's name is `contactctl::favName`). The schema's display page also carries the lock screen (`auto_lock`) and the 12-hour clock, which ui-lvgl implements (a slide-to-unlock card after the screen turns off). Remote admin is `ui-core/AdminSession.h` (`UiCore::admin`): login with the saved password (forgotten on a wrong password or a silent timeout), CLI round trips with timeouts, the field table (`admin::`), typed values; results come out one at a time through `take()`. `UiCore` offers login answers and CLI replies to it first; only room logins it wasn't waiting for reach the frontend. ui-new's Tools > Admin and ui-lvgl's Admin screen are views over it. The bot's settings are a table too, `ui-core/BotConfig.h` (`botcfg::`: tabs, rows, the NodePrefs flag / text / hour behind each, reply placeholders); ui-new's Tools > Bot and ui-lvgl's Bot screen render it, the bot itself runs in MyMesh. Room servers: `ui-core/RoomSessions.h` (`UiCore::rooms`) keeps who is logged in this session, the one login in flight (with a timeout) and the saved passwords (saved on success, forgotten on failure); `open(contact)` says whether to go straight in, wait for a background login or ask for a password, and outcomes come out through `take()`. Per-contact helpers are `ui-core/ContactControl.h` (`contactctl::`: DM notification / melody overrides, favourite flag, the `@[name] ` reply prefix, splitting a room post into author and text, naming a message's path hops). ui-new's Messages and ui-lvgl's Chats / thread use both. Diagnostics rows are `ui-core/Diagnostics.h` (`diag::`: live counters, system card, font card, counter reset), shown by ui-new's Tools > Diagnostics and ui-lvgl's Settings > Diagnostics. Auto-advert is a schema row (`advert_auto_interval_sec`, sent by MyMesh); ui-new keeps its Tools > Auto-Advert screen over the same pref. The compass (ui-lvgl Home > Compass, ui-new Tools > Compass) reads `UiCore::course`.
Replaces the per-item code in `SettingsScreen`:
@@ -0,0 +1,152 @@
#pragma once
// Device diagnostics shared by ui-new's Tools > Diagnostics and ui-lvgl's
// Settings > Diagnostics: the live counters (uptime, packets by category,
// heap / stack, radio, queue, error flags), the static system card (firmware,
// board, radio parameters) and the font test card. Each frontend lays the rows
// out its own way.
//
// Packet counts come from Dispatcher's per-type counters, grouped into a few
// categories rather than all 16 raw PAYLOAD_TYPE_* values, so they stay
// readable on a 128x64 OLED.
#include <helpers/DeviceDiag.h>
#include <stdarg.h>
namespace diag {
struct Row { const char* label; char value[20]; };
static const int MAX_ROWS = 14;
static const int MAX_LINES = 15;
typedef char Line[40];
inline void addRow(Row* rows, int& n, const char* label, const char* fmt, ...) {
if (n >= MAX_ROWS) return;
rows[n].label = label;
va_list ap; va_start(ap, fmt);
vsnprintf(rows[n].value, sizeof(rows[n].value), fmt, ap);
va_end(ap);
n++;
}
inline void addLine(Line* lines, int& n, const char* fmt, ...) {
if (n >= MAX_LINES) return;
va_list ap; va_start(ap, fmt);
vsnprintf(lines[n], sizeof(lines[n]), fmt, ap);
va_end(ap);
n++;
}
inline uint32_t sumByTypes(bool recv, const uint8_t* types, int n) {
uint32_t total = 0;
for (int i = 0; i < n; i++)
total += recv ? the_mesh.getNumRecvByType(types[i]) : the_mesh.getNumSentByType(types[i]);
return total;
}
// Live counters, label / value. Returns the row count.
inline int liveRows(Row* rows) {
int n = 0;
uint32_t up = millis() / 1000;
unsigned long d = up / 86400, h = (up % 86400) / 3600, m = (up % 3600) / 60, s = up % 60;
if (d > 0) addRow(rows, n, "Uptime", "%lud %02lu:%02lu:%02lu", d, h, m, s);
else addRow(rows, n, "Uptime", "%02lu:%02lu:%02lu", h, m, s);
static const uint8_t MSG[] = { PAYLOAD_TYPE_TXT_MSG, PAYLOAD_TYPE_GRP_TXT };
static const uint8_t ADVERT[] = { PAYLOAD_TYPE_ADVERT };
static const uint8_t ROUTE[] = { PAYLOAD_TYPE_ACK, PAYLOAD_TYPE_PATH, PAYLOAD_TYPE_TRACE };
static const uint8_t OTHER[] = { PAYLOAD_TYPE_REQ, PAYLOAD_TYPE_RESPONSE, PAYLOAD_TYPE_ANON_REQ,
PAYLOAD_TYPE_GRP_DATA, PAYLOAD_TYPE_MULTIPART, PAYLOAD_TYPE_CONTROL,
PAYLOAD_TYPE_RAW_CUSTOM };
unsigned long msg_rx = sumByTypes(true, MSG, 2), msg_tx = sumByTypes(false, MSG, 2);
unsigned long adv_rx = sumByTypes(true, ADVERT, 1), adv_tx = sumByTypes(false, ADVERT, 1);
unsigned long rte_rx = sumByTypes(true, ROUTE, 3), rte_tx = sumByTypes(false, ROUTE, 3);
unsigned long oth_rx = sumByTypes(true, OTHER, 7), oth_tx = sumByTypes(false, OTHER, 7);
// "12345/12345" rather than "rx12345 tx12345": 5-digit counts would collide
// with a long label on a 128 px OLED. "Total rx/tx" spells out the order once.
addRow(rows, n, "Total rx/tx", "%lu/%lu", msg_rx + adv_rx + rte_rx + oth_rx, msg_tx + adv_tx + rte_tx + oth_tx);
addRow(rows, n, "Msg", "%lu/%lu", msg_rx, msg_tx);
addRow(rows, n, "Advert", "%lu/%lu", adv_rx, adv_tx);
addRow(rows, n, "Ack/Path", "%lu/%lu", rte_rx, rte_tx);
addRow(rows, n, "Other", "%lu/%lu", oth_rx, oth_tx);
addRow(rows, n, "Forwarded", "%lu", (unsigned long)the_mesh.getNumForwarded());
uint32_t heap_free, heap_total;
DeviceDiag::getHeapStats(heap_free, heap_total);
if (heap_total > 0) addRow(rows, n, "Heap free", "%lu/%luKB", (unsigned long)(heap_free / 1024), (unsigned long)(heap_total / 1024));
else addRow(rows, n, "Heap free", "N/A");
addRow(rows, n, "Stack free", "%luB", (unsigned long)DeviceDiag::getStackFreeBytes());
addRow(rows, n, "Noise floor", "%d dBm", (int)radio_driver.getNoiseFloor());
addRow(rows, n, "RSSI/SNR", "%d/%.1f", (int)radio_driver.getLastRSSI(), radio_driver.getLastSNR());
addRow(rows, n, "Pool free", "%d", the_mesh.getPoolFreeCount());
addRow(rows, n, "Queue", "%d", the_mesh.getOutboundQueueLen());
// Radio error flags since boot / reset (F = queue full, C = CAD timeout,
// R = RX-start timeout), "OK" when none have fired.
uint16_t err = the_mesh.getErrFlags();
if (err == 0) addRow(rows, n, "Errors", "OK");
else addRow(rows, n, "Errors", "%s%s%s", (err & ERR_EVENT_FULL) ? "F " : "",
(err & ERR_EVENT_CAD_TIMEOUT) ? "C " : "", (err & ERR_EVENT_STARTRX_TIMEOUT) ? "R " : "");
if (err) { // drop the trailing space so right-alignment sits flush
char* v = rows[n - 1].value;
size_t len = strlen(v);
if (len && v[len - 1] == ' ') v[len - 1] = '\0';
}
#if FEAT_RX_POWERSAVE
// RX duty-cycle watchdog recoveries since boot / reset (soft re-arm / hard
// chip reset); 0/0 where duty-cycle power-save never arms.
addRow(rows, n, "RXPS wd s/h", "%lu/%lu", (unsigned long)radio_driver.getRxPsWatchdogSoftCount(),
(unsigned long)radio_driver.getRxPsWatchdogHardCount());
#endif
return n;
}
// Zeroes the packet / forward counters, error flags and the radio's own counts.
inline void resetCounters() {
the_mesh.resetStats();
radio_driver.resetStats();
}
// Firmware version minus the commit-hash suffix build.sh appends as the last
// dash-segment (v1.16-solo.0-abcdef -> v1.16-solo.0; the last dash, since a
// tag like v1.21-rc1 has one of its own).
inline void shortVersion(char* out, size_t n) {
const char* ver = FIRMWARE_VERSION;
const char* dash = strrchr(ver, '-');
size_t len = dash ? (size_t)(dash - ver) : strlen(ver);
if (len >= n) len = n - 1;
memcpy(out, ver, len);
out[len] = '\0';
}
// Static system card, one full-width line each. Returns the line count.
inline int systemLines(Line* lines) {
int n = 0;
char sv[24];
shortVersion(sv, sizeof(sv));
addLine(lines, n, "FW %s", sv);
addLine(lines, n, "Built %s", FIRMWARE_BUILD_DATE);
addLine(lines, n, "Dev %s", board.getManufacturerName());
addLine(lines, n, "Node %s", the_mesh.getNodeName());
NodePrefs* p = the_mesh.getNodePrefs();
if (p) {
addLine(lines, n, "Freq %.3f MHz", p->freq);
addLine(lines, n, "SF%u BW%.0f CR%u", (unsigned)p->sf, p->bw, (unsigned)p->cr);
addLine(lines, n, "TX %d dBm", (int)p->tx_power_dbm);
}
return n;
}
// One sample per script the UI font covers, to check coverage by eye. "Acc"
// takes one letter from each of the keyboard's accent-popup groups.
inline int fontLines(Line* lines) {
int n = 0;
addLine(lines, n, "Latin ABCabc xyz");
addLine(lines, n, "Acc áçďéíłñóřśťúýź");
addLine(lines, n, "Grk ΑΒΓ αβγξω");
addLine(lines, n, "Cyr АБВ абвжя");
addLine(lines, n, "Num 0123456789");
addLine(lines, n, "Sym @#&*()[]{}/\\+=");
return n;
}
} // namespace diag
@@ -112,6 +112,9 @@ static const int32_t TZ[] = { -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
static void optTz(uint8_t v, char* b, int n, const NodePrefs&) {
if (TZ[v] == 0) snprintf(b, n, "UTC"); else snprintf(b, n, "UTC%+ld", (long)TZ[v]);
}
// The same steps as ui-new's Tools > Auto-Advert.
static const int32_t AUTO_ADVERT[] = { 0, 30, 60, 120, 300, 600, 1800, 3600 };
static void optAutoAdvert(uint8_t v, char* b, int n, const NodePrefs&) { fmtSecs(b, n, AUTO_ADVERT[v], "Off"); }
static const int32_t INVERTED[] = { 1, 0 }; // switch over a field stored as "off" flag
static void optResend(uint8_t v, char* b, int n, const NodePrefs&) {
if (v == 0) snprintf(b, n, "Off"); else snprintf(b, n, "%u more", (unsigned)v);
@@ -151,6 +154,8 @@ static const Setting ALL[] = {
NodePrefs::LOC_SHARE_INTERVAL_COUNT, optGap, nullptr),
IDX("Heartbeat", "Resend while standing still", SEC_LIVE_SHARE, loc_share_heartbeat_idx,
NodePrefs::LOC_SHARE_HEARTBEAT_COUNT, optHeartbeat, nullptr),
MAP("Auto-advert", "Advert with your position", SEC_LIVE_SHARE, advert_auto_interval_sec, AUTO_ADVERT,
optAutoAdvert, nullptr),
SW("Arrival alert", "When you reach the target", SEC_LOCATOR, locator_enabled, rearmLocator),
IDX("Radius", nullptr, SEC_LOCATOR, locator_radius_idx,
@@ -0,0 +1,142 @@
#pragma once
// Home > Compass -- ui-new's Tools > Compass. The course over ground from GPS
// movement (no magnetometer; the Core's CourseEngine, trail or not) on a dial
// that turns so the heading is up under a fixed pointer, with the degrees and
// cardinal beside it. Standing still, the heading is undefined: the dial greys
// out and a hint says to move.
//
// Single-TU fragment: included by ui-lvgl/UITask.cpp after DiagScreen.h.
namespace compassview {
static lv_obj_t* s_dial = nullptr;
static lv_obj_t* s_deg = nullptr;
static lv_obj_t* s_degsign = nullptr;
static lv_obj_t* s_card = nullptr;
static lv_obj_t* s_hint = nullptr;
static int s_cog = 0;
static bool s_have = false;
static const int DIAL = 176;
} // namespace compassview
static void onOpenCompass(lv_event_t* e) { (void)e; s_ui->showCompass(); }
// The dial, drawn over its round background: ticks every 10 degrees (longer
// every 30, longest at the cardinals), N / E / S / W and the 30-degree
// numbers, all turned by the heading; the fixed pointer at the top.
static void onCompassDraw(lv_event_t* e) {
using namespace compassview;
lv_obj_t* o = (lv_obj_t*)lv_event_get_target(e);
lv_layer_t* layer = lv_event_get_layer(e);
lv_area_t a;
lv_obj_get_coords(o, &a);
float cx = (a.x1 + a.x2) / 2.0f, cy = (a.y1 + a.y2) / 2.0f;
float r = DIAL / 2.0f - 14; // the ring; the pointer sits outside it
uint32_t ink = s_have ? theme::TEXT : theme::TEXT_MUTED;
static const char* LBL[12] = { "N", "30", "60", "E", "120", "150", "S", "210", "240", "W", "300", "330" };
lv_draw_line_dsc_t ld;
lv_draw_line_dsc_init(&ld);
lv_draw_label_dsc_t td;
lv_draw_label_dsc_init(&td);
td.align = LV_TEXT_ALIGN_CENTER;
for (int deg = 0; deg < 360; deg += 10) {
float ang = (deg - s_cog) * (float)M_PI / 180.0f;
float sx = sinf(ang), sy = -cosf(ang);
bool card = deg % 90 == 0, major = deg % 30 == 0;
float len = card ? 12 : major ? 9 : 5;
ld.width = card ? 3 : major ? 2 : 1;
ld.color = lv_color_hex(ink);
ld.p1.x = cx + sx * r; ld.p1.y = cy + sy * r;
ld.p2.x = cx + sx * (r - len); ld.p2.y = cy + sy * (r - len);
lv_draw_line(layer, &ld);
if (!major) continue;
td.text = LBL[deg / 30];
td.font = card ? THEME_FONT_LARGE : THEME_FONT_SMALL;
td.color = lv_color_hex(deg == 0 && s_have ? theme::FAIL : card ? ink : theme::TEXT_MUTED);
float lr = r - (card ? 26 : 22);
int32_t h = lv_font_get_line_height(td.font);
int32_t px = (int32_t)(cx + sx * lr), py = (int32_t)(cy + sy * lr);
lv_area_t la = { px - 20, py - h / 2, px + 20, py + h / 2 };
lv_draw_label(layer, &td, &la);
}
// Fixed pointer: points down at the ring, the heading always under it.
lv_draw_triangle_dsc_t tri;
lv_draw_triangle_dsc_init(&tri);
tri.bg_color = lv_color_hex(theme::ACCENT);
tri.bg_opa = LV_OPA_COVER;
tri.p[0].x = cx - 8; tri.p[0].y = cy - r - 12;
tri.p[1].x = cx + 8; tri.p[1].y = cy - r - 12;
tri.p[2].x = cx; tri.p[2].y = cy - r + 2;
lv_draw_triangle(layer, &tri);
}
void UITask::showCompass() {
_screen = SCR_COMPASS;
buildCompass();
}
void UITask::buildCompass() {
using namespace compassview;
lv_obj_t* body = newScreen("Compass", true);
lv_obj_set_flex_flow(body, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(body, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_remove_flag(body, LV_OBJ_FLAG_SCROLLABLE);
s_dial = lv_obj_create(body);
styleSurface(s_dial, theme::BG);
lv_obj_remove_flag(s_dial, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(s_dial, DIAL, DIAL);
lv_obj_set_style_radius(s_dial, LV_RADIUS_CIRCLE, 0);
lv_obj_add_event_cb(s_dial, onCompassDraw, LV_EVENT_DRAW_MAIN_END, NULL);
lv_obj_t* col = lv_obj_create(body);
lv_obj_remove_style_all(col);
lv_obj_set_size(col, 110, LV_SIZE_CONTENT);
lv_obj_set_flex_flow(col, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(col, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_row(col, 2, 0);
lv_obj_t* num = lv_obj_create(col); // "044" + a raised degree sign (ui_font_40 is digits only)
lv_obj_remove_style_all(num);
lv_obj_set_size(num, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_flex_flow(num, LV_FLEX_FLOW_ROW);
s_deg = label(num, "", THEME_FONT_CLOCK, theme::TEXT);
s_degsign = label(num, "", THEME_FONT_LARGE, theme::TEXT);
s_card = label(col, "", THEME_FONT_LARGE, theme::ACCENT);
s_hint = label(col, "", THEME_FONT_SMALL, theme::TEXT_MUTED);
lv_label_set_long_mode(s_hint, LV_LABEL_LONG_WRAP);
lv_obj_set_width(s_hint, LV_PCT(100));
lv_obj_set_style_text_align(s_hint, LV_TEXT_ALIGN_CENTER, 0);
refreshCompass();
}
// From loop(), once a second.
void UITask::refreshCompass() {
using namespace compassview;
if (_screen != SCR_COMPASS || !s_dial) return;
int32_t lat, lon;
int cog = 0;
const char* hint = nullptr;
if (!_core->course.currentLocation(lat, lon))
hint = _core->gpsAvailable() && !_core->gpsEnabled() ? "GPS is off - turn it on in Settings" : "Waiting for a GPS fix";
else if (!_core->course.currentCourse(cog)) hint = "Move to set the heading";
bool have = hint == nullptr;
if (have != s_have || cog != s_cog) {
s_have = have;
if (have) s_cog = cog;
lv_obj_invalidate(s_dial);
}
if (have) {
lv_label_set_text_fmt(s_deg, "%03d", cog);
lv_label_set_text(s_degsign, "\xC2\xB0");
lv_label_set_text(s_card, geo::bearingCardinal(cog));
lv_label_set_text(s_hint, "Course over ground");
} else {
lv_label_set_text(s_deg, "");
lv_label_set_text(s_degsign, "");
lv_label_set_text(s_card, "--");
lv_label_set_text(s_hint, hint);
}
}
@@ -0,0 +1,112 @@
#pragma once
// Settings > Diagnostics -- ui-new's Tools > Diagnostics. Tabs Live / System /
// Font; the rows come from ui-core/Diagnostics.h. Live refreshes every second
// and its header button resets the counters (after a confirm).
//
// Single-TU fragment: included by ui-lvgl/UITask.cpp after DeviceScreen.h.
namespace diagview {
enum : uint8_t { TAB_LIVE, TAB_SYSTEM, TAB_FONT, TAB_COUNT };
static uint8_t s_tab = TAB_LIVE; // kept across visits
static lv_obj_t* s_list = nullptr;
static lv_obj_t* s_vals[diag::MAX_ROWS];
static int s_rows = 0;
} // namespace diagview
static void onOpenDiag(lv_event_t* e) { (void)e; s_ui->showDiag(); }
static void onDiagTab(lv_event_t* e) {
s_ui->diagTab((int)lv_buttonmatrix_get_selected_button((lv_obj_t*)lv_event_get_target(e)));
}
static void onDiagReset(lv_event_t* e) { (void)e; s_ui->diagResetPopup(); }
static void onDiagResetGo(lv_event_t* e) { (void)e; s_ui->diagReset(); }
void UITask::showDiag() {
_screen = SCR_DIAG;
buildDiag();
}
void UITask::diagTab(int tab) {
if (tab < 0 || tab >= diagview::TAB_COUNT) return;
diagview::s_tab = (uint8_t)tab;
buildDiag();
}
void UITask::buildDiag() {
using namespace diagview;
lv_obj_t* body = newScreen("Diagnostics", true);
lv_obj_set_style_pad_row(body, 4, 0);
if (s_tab == TAB_LIVE && _header) headerButton(_header, LV_SYMBOL_REFRESH " Reset", onDiagReset, 4, NULL);
static const char* TABS[] = { "Live", "System", "Font", "" };
lv_obj_t* tabs = segmented(body, TABS, s_tab, lv_pct(100), 34);
lv_obj_set_style_bg_color(tabs, lv_color_hex(theme::SURFACE), LV_PART_ITEMS);
lv_obj_add_event_cb(tabs, onDiagTab, LV_EVENT_VALUE_CHANGED, NULL);
s_list = lv_obj_create(body);
styleSurface(s_list, theme::SURFACE);
lv_obj_set_style_radius(s_list, theme::RADIUS, 0);
lv_obj_set_style_pad_all(s_list, theme::PAD, 0);
lv_obj_set_style_pad_row(s_list, 3, 0);
lv_obj_set_width(s_list, LV_PCT(100));
lv_obj_set_flex_grow(s_list, 1);
lv_obj_set_flex_flow(s_list, LV_FLEX_FLOW_COLUMN);
lv_obj_set_scrollbar_mode(s_list, LV_SCROLLBAR_MODE_ACTIVE);
s_rows = 0;
if (s_tab == TAB_LIVE) {
diag::Row rows[diag::MAX_ROWS];
s_rows = diag::liveRows(rows);
for (int i = 0; i < s_rows; i++) {
lv_obj_t* r = lv_obj_create(s_list);
lv_obj_remove_style_all(r);
lv_obj_remove_flag(r, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(r, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_align(label(r, rows[i].label, THEME_FONT_BODY, theme::TEXT_MUTED), LV_ALIGN_LEFT_MID, 0, 0);
s_vals[i] = label(r, rows[i].value, THEME_FONT_BODY, theme::TEXT);
lv_obj_align(s_vals[i], LV_ALIGN_RIGHT_MID, 0, 0);
}
return;
}
diag::Line lines[diag::MAX_LINES];
int n = s_tab == TAB_SYSTEM ? diag::systemLines(lines) : diag::fontLines(lines);
for (int i = 0; i < n; i++) {
lv_obj_t* l = label(s_list, lines[i], s_tab == TAB_FONT ? THEME_FONT_TITLE : THEME_FONT_BODY, theme::TEXT);
lv_label_set_long_mode(l, LV_LABEL_LONG_WRAP);
lv_obj_set_width(l, LV_PCT(100));
}
}
// From loop(), once a second: the Live values in place.
void UITask::refreshDiag() {
using namespace diagview;
if (_screen != SCR_DIAG || s_tab != TAB_LIVE || _nav_overlay) return;
diag::Row rows[diag::MAX_ROWS];
int n = diag::liveRows(rows);
if (n != s_rows) { buildDiag(); return; }
for (int i = 0; i < n; i++)
if (strcmp(lv_label_get_text(s_vals[i]), rows[i].value) != 0) lv_label_set_text(s_vals[i], rows[i].value);
}
void UITask::diagResetPopup() {
lv_obj_t* panel = navPopupPanel("Reset counters?", false);
lv_obj_t* t = label(panel, "Zeroes the packet counts, forwarded count and radio errors.", THEME_FONT_SMALL,
theme::TEXT_MUTED);
lv_label_set_long_mode(t, LV_LABEL_LONG_WRAP);
lv_obj_set_width(t, LV_PCT(100));
lv_obj_t* b = lv_button_create(panel);
lv_obj_set_size(b, LV_PCT(100), 40);
lv_obj_set_style_shadow_width(b, 0, 0);
lv_obj_set_style_radius(b, theme::RADIUS, 0);
lv_obj_set_style_bg_color(b, lv_color_hex(theme::FAIL), 0);
lv_obj_add_event_cb(b, onDiagResetGo, LV_EVENT_CLICKED, NULL);
lv_obj_center(label(b, LV_SYMBOL_REFRESH " Reset", THEME_FONT_BODY, theme::TEXT));
}
void UITask::diagReset() {
diag::resetCounters();
navClosePopup();
refreshDiag();
showToast("Counters reset");
}
+1
View File
@@ -39,4 +39,5 @@ namespace theme {
#define UI_SYMBOL_CLOCK "\xEF\x80\x97" // U+F017, Clock tools
#define UI_SYMBOL_STOPWATCH "\xEF\x8B\xB2" // U+F2F2
#define UI_SYMBOL_RADIO "\xEF\x94\x99" // U+F519, broadcast tower
#define UI_SYMBOL_CHART "\xEF\x82\x80" // U+F080, diagnostics
}
+12 -1
View File
@@ -13,6 +13,7 @@
#include "../ui-core/GpsAverager.h"
#include "../ui-core/TrackBack.h"
#include "../ui-core/RadioControl.h"
#include "../ui-core/Diagnostics.h"
#include "../ui-core/ChannelControl.h"
#include "../ui-core/BotConfig.h"
#include "Theme.h"
@@ -189,6 +190,8 @@ void UITask::loop() {
refreshStatusBar();
refreshLock();
if (_screen == SCR_HOME) refreshHome();
refreshDiag();
refreshCompass();
}
if (locked()) lockPoll();
else if (_screen == SCR_HOME) homeSwipePoll();
@@ -492,6 +495,8 @@ void UITask::back() {
case SCR_CHANNEL_EDIT: showChats(); break;
case SCR_BOT: if (_nav_overlay) navClosePopup(); else showHome(); break;
case SCR_FAVS: if (_nav_overlay) navClosePopup(); else showHome(); break;
case SCR_DIAG: if (_nav_overlay) navClosePopup(); else showSettings(); break;
case SCR_COMPASS: showHome(); break;
case SCR_ADMIN: if (_nav_overlay) navClosePopup(); else adminLeave(); break;
case SCR_SETTINGS: if (_nav_overlay) navClosePopup(); else showHome(); break;
case SCR_SETTINGS_NAV: showSettings(); break;
@@ -530,6 +535,8 @@ static void onOpenNav(lv_event_t* e) { (void)e; s_ui->openMap(true); }
static void onOpenClock(lv_event_t* e); // ClockScreen.h
static void onOpenBot(lv_event_t* e); // BotScreen.h
static void onOpenFavourites(lv_event_t* e); // DeviceScreen.h
static void onOpenCompass(lv_event_t* e); // CompassScreen.h
static void onOpenDiag(lv_event_t* e); // DiagScreen.h
static void onNodeName(lv_event_t* e);
static void onPowerRow(lv_event_t* e);
@@ -544,6 +551,7 @@ static const App APPS[] = {
{ LV_SYMBOL_SETTINGS, "Settings", onOpenSettings, false },
// Page 2: tools
{ UI_SYMBOL_STAR, "Favourites", onOpenFavourites, false },
{ UI_SYMBOL_COMPASS, "Compass", onOpenCompass, false },
{ UI_SYMBOL_CLOCK, "Clock", onOpenClock, false },
{ LV_SYMBOL_CHARGE, "Bot", onOpenBot, false },
};
@@ -2007,7 +2015,7 @@ void UITask::buildSettings() {
if (_core->gpsEnabled()) lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, onGpsSwitch, LV_EVENT_VALUE_CHANGED, NULL);
}
listRow(body, UI_SYMBOL_COMPASS " Trail, live share, alerts", "Point spacing, auto-pause, sharing, radius",
listRow(body, UI_SYMBOL_COMPASS " Trail, live share, alerts", "Trail, sharing, auto-advert, radius",
onOpenSchemaPage, (void*)(uintptr_t)settings::PG_NAV);
sectionTitle(body, "DEVICE");
listRow(body, LV_SYMBOL_EYE_OPEN " Display & power", "Brightness, screen off, battery, GPS, time zone",
@@ -2028,6 +2036,7 @@ void UITask::buildSettings() {
label(body, "Hold a letter for accents and other variants.", THEME_FONT_SMALL, theme::TEXT_MUTED);
sectionTitle(body, "SYSTEM");
listRow(body, UI_SYMBOL_CHART " Diagnostics", "Packet counts, memory, radio, firmware", onOpenDiag, NULL);
listRow(body, LV_SYMBOL_REFRESH " Reboot", NULL, onPowerRow, (void*)(uintptr_t)1);
listRow(body, LV_SYMBOL_POWER " Power off", NULL, onPowerRow, (void*)(uintptr_t)0);
@@ -2051,3 +2060,5 @@ void UITask::setKeyboardAlphabets(int main_idx, int alt_sel) {
#include "ConversationScreen.h"
#include "DeviceScreen.h"
#include "DiagScreen.h"
#include "CompassScreen.h"
+10 -1
View File
@@ -153,6 +153,11 @@ public:
void unlockScreen();
bool locked() const;
void showFavourites();
void showDiag();
void diagTab(int tab);
void diagResetPopup();
void diagReset();
void showCompass();
void favTap(int slot);
void favHold(int slot);
void favAction(uint8_t act);
@@ -167,7 +172,7 @@ public:
void openAdminFor(const ContactInfo& ci, bool from_picker) { (void)ci; (void)from_picker; }
private:
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE, SCR_MAP, SCR_WIFI, SCR_SETTINGS_NAV, SCR_CLOCK, SCR_RADIO, SCR_CHANNEL_EDIT, SCR_ADMIN, SCR_BOT, SCR_FAVS };
enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE, SCR_MAP, SCR_WIFI, SCR_SETTINGS_NAV, SCR_CLOCK, SCR_RADIO, SCR_CHANNEL_EDIT, SCR_ADMIN, SCR_BOT, SCR_FAVS, SCR_DIAG, SCR_COMPASS };
void buildStatusBar();
void refreshStatusBar();
@@ -232,6 +237,10 @@ private:
void refreshLock();
void lockPoll();
void buildFavourites();
void buildDiag();
void refreshDiag();
void buildCompass();
void refreshCompass();
void favPickPopup(int slot);
void adminValuePopup();
void adminTextPopup(const char* text, bool digits);
@@ -29,8 +29,8 @@ TEXT="$TEXT,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122"
# plus 61612 = globe (keyboard script key), 61445 = star (favourite),
# 62073 = map, 61632 = users (home tiles), 61774 = compass (Navigate),
# 61476 = flag (waypoint), 62405 = map marker (mark here), 61463 = clock,
# 62194 = stopwatch, 62745 = broadcast tower (radio)
SYMS="62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650"
# 62194 = stopwatch, 62745 = broadcast tower (radio), 61568 = bar chart (diagnostics)
SYMS="61568,62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650"
CONV="npx -y lv_font_conv@1.5.3"
gen() { # size weight ranges name
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 12 px
* Bpp: 4
* Opts: --bpp 4 --size 12 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_12 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_12.c
* Opts: --bpp 4 --size 12 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61568,62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_12 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_12.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -6686,6 +6686,14 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x9d, 0x0, 0x3c, 0xce, 0xf4, 0x58, 0x7, 0xff,
0xc1, 0x0, 0x3f, 0xc8,
/* U+F080 "" */
0xf7, 0x0, 0x88, 0x80, 0x3, 0xf3, 0xf, 0x0,
0xa6, 0x40, 0x7, 0x7, 0x0, 0xe7, 0x72, 0xd8,
0x7, 0x8c, 0x40, 0x1a, 0x80, 0x1e, 0xc6, 0x0,
0xff, 0xe0, 0x3b, 0xbc, 0x1c, 0x1c, 0x2, 0xf7,
0xbb, 0x3f, 0x9f, 0x98, 0x24, 0x47, 0xf3, 0x91,
0xbb, 0xff, 0x40,
/* U+F093 "" */
0x0, 0xe2, 0x20, 0x7, 0xf1, 0xe6, 0xc, 0x3,
0xe3, 0xd1, 0x16, 0x98, 0x7, 0x1e, 0x88, 0x0,
@@ -8046,39 +8054,40 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 32682, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 32716, .adv_w = 240, .box_w = 16, .box_h = 10, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 32776, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 32796, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 32853, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 32917, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 32987, .adv_w = 240, .box_w = 15, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33061, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33122, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33162, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33206, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33238, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33277, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 33323, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33368, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33421, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33477, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 33540, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33612, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33635, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33710, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 32796, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 32839, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 32896, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 32960, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33030, .adv_w = 240, .box_w = 15, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33104, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33165, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33205, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33249, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33281, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33320, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 33366, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33411, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33464, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33520, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 33583, .adv_w = 186, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33655, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33678, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33753, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33802, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33851, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33900, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33942, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 33979, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 34044, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34108, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 33796, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33845, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33894, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33943, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 33985, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 34022, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 34087, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34151, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34212, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 34279, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34331, .adv_w = 240, .box_w = 15, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34413, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 34468, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34497, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
{.bitmap_index = 34194, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34255, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 34322, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34374, .adv_w = 240, .box_w = 15, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34456, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 34511, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 34540, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0}
};
/*---------------------
@@ -8106,11 +8115,12 @@ static const uint16_t unicode_list_12[] = {
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf6a,
0xcf7d, 0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3,
0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045,
0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171,
0xd17d, 0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac,
0xd78c
};
/*Collect the unicode lists and glyph_id offsets*/
@@ -8166,7 +8176,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
},
{
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 73, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -8314,7 +8324,7 @@ static const uint8_t kern_left_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Map glyph_ids to kern right classes*/
@@ -8456,7 +8466,7 @@ static const uint8_t kern_right_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Kern values between classes*/
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 14 px
* Bpp: 4
* Opts: --bpp 4 --size 14 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_14 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_14.c
* Opts: --bpp 4 --size 14 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61568,62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_14 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_14.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -7620,6 +7620,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0xf8, 0x8c, 0xf2, 0x48, 0x7, 0xff, 0xfc, 0x3,
0xf9, 0x40, 0x3f, 0xf8, 0xc,
/* U+F080 "" */
0x86, 0x0, 0xfe, 0x58, 0x7, 0xa0, 0xd, 0x30,
0x1, 0x7b, 0x88, 0x7, 0x9d, 0x40, 0x3f, 0xf8,
0x47, 0xec, 0x1, 0xe1, 0x20, 0x9, 0xc0, 0x40,
0x3d, 0x7a, 0x20, 0x1f, 0xfc, 0xd9, 0x90, 0xdc,
0xac, 0xac, 0xc8, 0x40, 0x23, 0x60, 0x54, 0x16,
0x23, 0x60, 0x1, 0xe6, 0x7f, 0xd6, 0x60, 0x67,
0xff, 0x20,
/* U+F093 "" */
0x0, 0xff, 0xe3, 0x8e, 0xe8, 0x40, 0x3f, 0x87,
0x8, 0x98, 0x20, 0x1f, 0xe, 0x10, 0x0, 0xb0,
@@ -9037,39 +9046,40 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 40136, .adv_w = 196, .box_w = 13, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 40181, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 40252, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 40281, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40353, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 40432, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40525, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40623, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40704, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40752, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40808, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40848, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 40901, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 40957, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41020, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41086, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41159, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 41236, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41325, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41357, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41454, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41506, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41561, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41616, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41671, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41720, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41765, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41845, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41929, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41985, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42050, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 42127, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42200, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42315, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 42393, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42429, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
{.bitmap_index = 40281, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 40331, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40403, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 40482, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40575, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40673, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40754, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 40802, .adv_w = 196, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40858, .adv_w = 196, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 40898, .adv_w = 224, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 40951, .adv_w = 140, .box_w = 10, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 41007, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41070, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41136, .adv_w = 252, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41209, .adv_w = 224, .box_w = 16, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 41286, .adv_w = 217, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41375, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41407, .adv_w = 280, .box_w = 18, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41504, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41556, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41611, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41666, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41721, .adv_w = 280, .box_w = 18, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 41770, .adv_w = 252, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41815, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 41895, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 41979, .adv_w = 196, .box_w = 13, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42035, .adv_w = 196, .box_w = 12, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42100, .adv_w = 224, .box_w = 15, .box_h = 15, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 42177, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42250, .adv_w = 280, .box_w = 18, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42365, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 42443, .adv_w = 168, .box_w = 11, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 42479, .adv_w = 225, .box_w = 15, .box_h = 10, .ofs_x = 0, .ofs_y = 0}
};
/*---------------------
@@ -9097,11 +9107,12 @@ static const uint16_t unicode_list_12[] = {
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf6a,
0xcf7d, 0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3,
0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045,
0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171,
0xd17d, 0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac,
0xd78c
};
/*Collect the unicode lists and glyph_id offsets*/
@@ -9157,7 +9168,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
},
{
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 73, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -9305,7 +9316,7 @@ static const uint8_t kern_left_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Map glyph_ids to kern right classes*/
@@ -9447,7 +9458,7 @@ static const uint8_t kern_right_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Kern values between classes*/
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 16 px
* Bpp: 4
* Opts: --bpp 4 --size 16 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_16 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_16.c
* Opts: --bpp 4 --size 16 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61568,62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_16 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_16.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -8712,6 +8712,13 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0xff, 0xd, 0xc0, 0x3f, 0xff, 0xe0, 0x1f, 0xfd,
0x97, 0x0, 0xff, 0xe1, 0x38,
/* U+F080 "" */
0xee, 0x0, 0x7f, 0xdf, 0xe0, 0x11, 0x0, 0x77,
0xf8, 0x3, 0xff, 0xab, 0xfe, 0x0, 0xff, 0xe6,
0x7f, 0x80, 0x3f, 0xfc, 0x5f, 0xe0, 0xff, 0x7,
0xf8, 0x3f, 0xc0, 0x1f, 0xfc, 0x7f, 0xff, 0xfe,
0xf, 0x18, 0x7, 0xff, 0xc,
/* U+F093 "" */
0x0, 0xfa, 0xec, 0x1, 0xff, 0xc1, 0xb4, 0x45,
0x80, 0x7f, 0xd6, 0x80, 0x4, 0xb0, 0xf, 0xeb,
@@ -10155,39 +10162,40 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 48847, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 48904, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 48992, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 49021, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49089, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 49183, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49291, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49401, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49492, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49539, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49591, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49646, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 49705, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 49773, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49834, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49904, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 49970, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 50059, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50161, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50194, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 50307, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50352, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50396, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50440, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50486, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50526, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50585, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 50686, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 50782, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50837, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50919, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 51013, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 51095, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 51226, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 51315, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 51354, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
{.bitmap_index = 49021, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 49058, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49126, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 49220, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49328, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49438, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49529, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49576, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49628, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 49683, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 49742, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 49810, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49871, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 49941, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 50007, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 50096, .adv_w = 248, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50198, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50231, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 50344, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50389, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50433, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50477, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50523, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 50563, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50622, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 50723, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 50819, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50874, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 50956, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 51050, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 51132, .adv_w = 320, .box_w = 20, .box_h = 17, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 51263, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 51352, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 51391, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1}
};
/*---------------------
@@ -10215,11 +10223,12 @@ static const uint16_t unicode_list_12[] = {
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf6a,
0xcf7d, 0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3,
0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045,
0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171,
0xd17d, 0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac,
0xd78c
};
/*Collect the unicode lists and glyph_id offsets*/
@@ -10275,7 +10284,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
},
{
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 73, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -10423,7 +10432,7 @@ static const uint8_t kern_left_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Map glyph_ids to kern right classes*/
@@ -10565,7 +10574,7 @@ static const uint8_t kern_right_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Kern values between classes*/
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 20 px
* Bpp: 4
* Opts: --bpp 4 --size 20 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_20 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_20.c
* Opts: --bpp 4 --size 20 --force-fast-kern-format --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/NotoSans-Medium.ttf -r 0x20-0x7E,0xA0-0x24F,0x370-0x3FF,0x400-0x52F,0x1E80-0x1E85,0x1E9E,0x1EF2-0x1EF3,0x2010-0x2027,0x2030,0x2039-0x203A,0x20A4-0x20BF,0x2116,0x2122 --font /var/folders/1d/dgkmygls6x5gsb16pbn2mwlr0000gn/T//meshcore-ui-fonts/fa.woff -r 61568,62745,61463,62194,61612,61445,62073,61632,61774,61476,62405,61441,61448,61451,61452,61453,61457,61459,61461,61465,61468,61473,61478,61479,61480,61502,61507,61512,61515,61516,61517,61521,61522,61523,61524,61543,61544,61550,61552,61553,61556,61559,61560,61561,61563,61587,61589,61636,61637,61639,61641,61664,61671,61674,61683,61724,61732,61787,61931,62016,62017,62018,62019,62020,62087,62099,62212,62189,62810,63426,63650 --format lvgl --lv-include lvgl.h --lv-font-name ui_font_20 -o /Users/jakub/Documents/MeshCore/MeshCore/examples/companion_radio/ui-lvgl/fonts/ui_font_20.c
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -10954,6 +10954,18 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x80, 0x7f, 0x84, 0x3, 0xff, 0x8c, 0x36, 0x20,
0x1f, 0xfc, 0x41, 0xb0,
/* U+F080 "" */
0xef, 0x60, 0xf, 0xfe, 0xe, 0xfb, 0x80, 0x87,
0x0, 0x7a, 0xec, 0x60, 0x18, 0xc3, 0x80, 0x3f,
0x85, 0x10, 0xa0, 0x1f, 0xfc, 0x93, 0x20, 0xf,
0xfe, 0x2b, 0xe6, 0x80, 0x7f, 0xf1, 0x7c, 0x3,
0xff, 0x81, 0x58, 0x80, 0x1f, 0xfc, 0x55, 0x3c,
0x0, 0xff, 0xec, 0x88, 0x70, 0x80, 0xf, 0x80,
0x40, 0xc3, 0x80, 0x3d, 0xde, 0xc1, 0xfe, 0x56,
0xfe, 0xd, 0xf7, 0x0, 0xff, 0xe5, 0xa4, 0x47,
0xff, 0x11, 0x80, 0x6, 0xef, 0xff, 0xc4, 0x95,
0x0, 0xff, 0xe3, 0x8,
/* U+F093 "" */
0x0, 0xfe, 0x31, 0x0, 0xff, 0xe2, 0xb6, 0x60,
0x40, 0x3f, 0xf8, 0x6d, 0x20, 0x58, 0x20, 0x1f,
@@ -12543,39 +12555,40 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 66503, .adv_w = 280, .box_w = 18, .box_h = 11, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 66581, .adv_w = 400, .box_w = 26, .box_h = 16, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 66699, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 66743, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 66853, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 66991, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 67150, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67319, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67467, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 67540, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67633, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 67693, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 67783, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 67876, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 67964, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68075, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 68201, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 68322, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68473, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68521, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 68685, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68752, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68820, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68887, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68954, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 69014, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 69101, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 69235, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 69382, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69469, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69598, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 69738, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69851, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 70055, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 70175, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 70234, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
{.bitmap_index = 66743, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 66819, .adv_w = 320, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 66929, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 67067, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 67226, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67395, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67543, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 67616, .adv_w = 280, .box_w = 18, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 67709, .adv_w = 280, .box_w = 18, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 67769, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 67859, .adv_w = 200, .box_w = 14, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 67952, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68040, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68151, .adv_w = 360, .box_w = 23, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 68277, .adv_w = 320, .box_w = 22, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 68398, .adv_w = 310, .box_w = 20, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68549, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 68597, .adv_w = 400, .box_w = 25, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 68761, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68828, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68896, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 68963, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 69030, .adv_w = 400, .box_w = 25, .box_h = 13, .ofs_x = 0, .ofs_y = 1},
{.bitmap_index = 69090, .adv_w = 360, .box_w = 23, .box_h = 19, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 69177, .adv_w = 400, .box_w = 26, .box_h = 17, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 69311, .adv_w = 280, .box_w = 16, .box_h = 21, .ofs_x = 1, .ofs_y = -3},
{.bitmap_index = 69458, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69545, .adv_w = 280, .box_w = 18, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69674, .adv_w = 320, .box_w = 21, .box_h = 21, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 69814, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 69927, .adv_w = 400, .box_w = 25, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 70131, .adv_w = 400, .box_w = 25, .box_h = 15, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 70251, .adv_w = 240, .box_w = 15, .box_h = 21, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 70310, .adv_w = 322, .box_w = 21, .box_h = 13, .ofs_x = 0, .ofs_y = 1}
};
/*---------------------
@@ -12603,11 +12616,12 @@ static const uint16_t unicode_list_12[] = {
0xcefb, 0xcefd, 0xceff, 0xcf01, 0xcf03, 0xcf06, 0xcf0b, 0xcf0e,
0xcf10, 0xcf11, 0xcf12, 0xcf28, 0xcf2d, 0xcf32, 0xcf35, 0xcf36,
0xcf37, 0xcf3b, 0xcf3c, 0xcf3d, 0xcf3e, 0xcf51, 0xcf52, 0xcf58,
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf7d,
0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3, 0xcfca,
0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045, 0xd0d5,
0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171, 0xd17d,
0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac, 0xd78c
0xcf5a, 0xcf5b, 0xcf5e, 0xcf61, 0xcf62, 0xcf63, 0xcf65, 0xcf6a,
0xcf7d, 0xcf7f, 0xcf96, 0xcfaa, 0xcfae, 0xcfaf, 0xcfb1, 0xcfb3,
0xcfca, 0xcfd1, 0xcfd4, 0xcfdd, 0xd006, 0xd00e, 0xd038, 0xd045,
0xd0d5, 0xd12a, 0xd12b, 0xd12c, 0xd12d, 0xd12e, 0xd163, 0xd171,
0xd17d, 0xd1d7, 0xd1dc, 0xd1ee, 0xd2af, 0xd403, 0xd444, 0xd6ac,
0xd78c
};
/*Collect the unicode lists and glyph_id offsets*/
@@ -12663,7 +12677,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
},
{
.range_start = 8470, .range_length = 55181, .glyph_id_start = 1017,
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
.unicode_list = unicode_list_12, .glyph_id_ofs_list = NULL, .list_length = 73, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -12811,7 +12825,7 @@ static const uint8_t kern_left_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Map glyph_ids to kern right classes*/
@@ -12953,7 +12967,7 @@ static const uint8_t kern_right_class_mapping[] =
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
0, 0
};
/*Kern values between classes*/
@@ -1,13 +1,12 @@
#pragma once
#include <helpers/ui/DisplayDriver.h>
#include <helpers/ui/UIScreen.h>
#include <helpers/DeviceDiag.h>
#include <Arduino.h>
#include <stdarg.h>
#include "icons.h"
#include "PopupMenu.h"
#include "TabBar.h"
#include "../MyMesh.h"
#include "../ui-core/Diagnostics.h"
extern MyMesh the_mesh;
@@ -22,10 +21,8 @@ extern MyMesh the_mesh;
// Font — a rendering test card: one sample line per script the UI font
// claims to cover (Latin, diacritics, Greek, Cyrillic, digits,
// symbols), so the on-device font can be eyeballed for coverage.
// The packet counts are built from Dispatcher's per-type counters — grouped
// into a handful of categories rather than all 16 raw PAYLOAD_TYPE_* values,
// so they stay readable on a 128x64 OLED. Every tab falls back to scrolling on
// screens too small to show its rows at once.
// The rows themselves come from the UI Core (ui-core/Diagnostics.h). Every tab
// falls back to scrolling on screens too small to show its rows at once.
class DiagnosticsScreen : public UIScreen {
UITask* _task;
int _scroll = 0;
@@ -35,169 +32,12 @@ class DiagnosticsScreen : public UIScreen {
enum Tab : uint8_t { TAB_LIVE, TAB_SYSTEM, TAB_FONT, TAB_COUNT };
static const char* const TAB_LABELS[TAB_COUNT];
struct Row { const char* label; char value[20]; };
static const int MAX_ROWS = 14;
Row _rows[MAX_ROWS];
// Rows / lines built by the Core (ui-core/Diagnostics.h).
diag::Row _rows[diag::MAX_ROWS];
int _row_count = 0;
// Full-width text lines (System / Font tabs) — long values (device model,
// node name) don't fit the Live tab's narrow right-aligned value column, so
// these tabs draw one ellipsized line each instead of a label/value pair.
static const int MAX_LINES = 15;
char _lines[MAX_LINES][40];
diag::Line _lines[diag::MAX_LINES];
int _line_count = 0;
void addRow(const char* label, const char* value) {
if (_row_count >= MAX_ROWS) return;
_rows[_row_count].label = label;
strncpy(_rows[_row_count].value, value, sizeof(_rows[_row_count].value) - 1);
_rows[_row_count].value[sizeof(_rows[_row_count].value) - 1] = 0;
_row_count++;
}
// "12345/12345" rather than "rx12345 tx12345" — at 5-digit counts (a busy
// repeater after weeks of uptime) the longer form collides with the value
// column on a 128px OLED when paired with a long label like "Ack/Path".
// The "Total rx/tx" label spells out the rx/tx order once for every row below it.
void addRxTxRow(const char* label, uint32_t rx, uint32_t tx) {
char buf[20];
snprintf(buf, sizeof(buf), "%lu/%lu", (unsigned long)rx, (unsigned long)tx);
addRow(label, buf);
}
void addLine(const char* fmt, ...) {
if (_line_count >= MAX_LINES) return;
va_list ap; va_start(ap, fmt);
vsnprintf(_lines[_line_count], sizeof(_lines[_line_count]), fmt, ap);
va_end(ap);
_line_count++;
}
static uint32_t sumByTypes(bool recv, const uint8_t* types, int n) {
uint32_t total = 0;
for (int i = 0; i < n; i++)
total += recv ? the_mesh.getNumRecvByType(types[i]) : the_mesh.getNumSentByType(types[i]);
return total;
}
void buildLiveRows() {
_row_count = 0;
uint32_t up_secs = millis() / 1000;
char buf[20];
uint32_t d = up_secs / 86400, h = (up_secs % 86400) / 3600, m = (up_secs % 3600) / 60, s = up_secs % 60;
if (d > 0) snprintf(buf, sizeof(buf), "%lud %02lu:%02lu:%02lu", (unsigned long)d, (unsigned long)h, (unsigned long)m, (unsigned long)s);
else snprintf(buf, sizeof(buf), "%02lu:%02lu:%02lu", (unsigned long)h, (unsigned long)m, (unsigned long)s);
addRow("Uptime", buf);
static const uint8_t MSG_TYPES[] = { PAYLOAD_TYPE_TXT_MSG, PAYLOAD_TYPE_GRP_TXT };
static const uint8_t ADVERT_TYPES[] = { PAYLOAD_TYPE_ADVERT };
static const uint8_t ROUTE_TYPES[] = { PAYLOAD_TYPE_ACK, PAYLOAD_TYPE_PATH, PAYLOAD_TYPE_TRACE };
static const uint8_t OTHER_TYPES[] = { PAYLOAD_TYPE_REQ, PAYLOAD_TYPE_RESPONSE, PAYLOAD_TYPE_ANON_REQ,
PAYLOAD_TYPE_GRP_DATA, PAYLOAD_TYPE_MULTIPART, PAYLOAD_TYPE_CONTROL,
PAYLOAD_TYPE_RAW_CUSTOM };
uint32_t msg_rx = sumByTypes(true, MSG_TYPES, 2), msg_tx = sumByTypes(false, MSG_TYPES, 2);
uint32_t adv_rx = sumByTypes(true, ADVERT_TYPES, 1), adv_tx = sumByTypes(false, ADVERT_TYPES, 1);
uint32_t rte_rx = sumByTypes(true, ROUTE_TYPES, 3), rte_tx = sumByTypes(false, ROUTE_TYPES, 3);
uint32_t oth_rx = sumByTypes(true, OTHER_TYPES, 7), oth_tx = sumByTypes(false, OTHER_TYPES, 7);
addRxTxRow("Total rx/tx", msg_rx + adv_rx + rte_rx + oth_rx, msg_tx + adv_tx + rte_tx + oth_tx);
addRxTxRow("Msg", msg_rx, msg_tx);
addRxTxRow("Advert", adv_rx, adv_tx);
addRxTxRow("Ack/Path", rte_rx, rte_tx);
addRxTxRow("Other", oth_rx, oth_tx);
snprintf(buf, sizeof(buf), "%lu", (unsigned long)the_mesh.getNumForwarded());
addRow("Forwarded", buf);
uint32_t heap_free, heap_total;
DeviceDiag::getHeapStats(heap_free, heap_total);
if (heap_total > 0) snprintf(buf, sizeof(buf), "%lu/%luKB", (unsigned long)(heap_free / 1024), (unsigned long)(heap_total / 1024));
else strcpy(buf, "N/A");
addRow("Heap free", buf);
uint32_t stack_free = DeviceDiag::getStackFreeBytes();
snprintf(buf, sizeof(buf), "%luB", (unsigned long)stack_free);
addRow("Stack free", buf);
snprintf(buf, sizeof(buf), "%d dBm", (int)radio_driver.getNoiseFloor());
addRow("Noise floor", buf);
snprintf(buf, sizeof(buf), "%d/%.1f", (int)radio_driver.getLastRSSI(), radio_driver.getLastSNR());
addRow("RSSI/SNR", buf);
snprintf(buf, sizeof(buf), "%d", the_mesh.getPoolFreeCount());
addRow("Pool free", buf);
snprintf(buf, sizeof(buf), "%d", the_mesh.getOutboundQueueLen());
addRow("Queue", buf);
// Radio error flags since boot/reset, decoded to short tokens (F=queue full,
// C=CAD timeout, R=RX-start timeout). "OK" when none have fired.
uint16_t err = the_mesh.getErrFlags();
if (err == 0) strcpy(buf, "OK");
else {
buf[0] = '\0';
if (err & ERR_EVENT_FULL) strcat(buf, "F ");
if (err & ERR_EVENT_CAD_TIMEOUT) strcat(buf, "C ");
if (err & ERR_EVENT_STARTRX_TIMEOUT) strcat(buf, "R ");
int len = strlen(buf); // drop the trailing space so right-alignment sits flush
if (len > 0 && buf[len - 1] == ' ') buf[len - 1] = '\0';
}
addRow("Errors", buf);
#if FEAT_RX_POWERSAVE
// RX duty-cycle watchdog recovery counts since boot/reset (soft re-arm /
// hard chip reset). Always 0/0 on radios or profiles that never arm
// duty-cycle power-save (repeaters force it off — see applyPowerSave()).
snprintf(buf, sizeof(buf), "%lu/%lu", (unsigned long)radio_driver.getRxPsWatchdogSoftCount(),
(unsigned long)radio_driver.getRxPsWatchdogHardCount());
addRow("RXPS wd s/h", buf);
#endif
}
void buildSystemLines() {
_line_count = 0;
// Firmware version, minus the commit-hash suffix build.sh appends as the
// LAST dash-segment (v1.16-solo.0-abcdef -> v1.16-solo.0) — same strip the
// boot screen does; the last dash, not the first, since a tag like
// v1.21-rc1 has a dash of its own before the hash.
const char* ver = FIRMWARE_VERSION;
const char* dash = strrchr(ver, '-');
int plen = dash ? (int)(dash - ver) : (int)strlen(ver);
char sv[24];
if (plen >= (int)sizeof(sv)) plen = sizeof(sv) - 1;
memcpy(sv, ver, plen); sv[plen] = '\0';
addLine("FW %s", sv);
addLine("Built %s", FIRMWARE_BUILD_DATE);
addLine("Dev %s", board.getManufacturerName());
addLine("Node %s", the_mesh.getNodeName());
NodePrefs* p = the_mesh.getNodePrefs();
if (p) {
addLine("Freq %.3f MHz", p->freq);
addLine("SF%u BW%.0f CR%u", (unsigned)p->sf, p->bw, (unsigned)p->cr);
addLine("TX %d dBm", (int)p->tx_power_dbm);
}
}
// One sample line per script/keyboard alphabet the UI font claims to cover
// (all inside the U+0020-04FF glyph range the OLED misc-fixed / e-ink Lemon
// fonts carry), so the font's coverage can be checked by eye on real
// hardware. "Acc" samples one variant from each KeyboardWidget.h
// KB_ACCENT_VARIANTS group (the Hold-Enter accent popup that replaced the
// old per-language alt-alphabet pages) so every accented letter actually
// reachable in the UI still gets an eyeball check.
void buildFontLines() {
_line_count = 0;
addLine("Latin ABCabc xyz");
addLine("Acc áçďéíłñóřśťúýź");
addLine("Grk ΑΒΓ αβγξω"); // ΑΒΓ αβγξω
addLine("Cyr АБВ абвжя"); // АБВ абвжя
addLine("Num 0123456789");
addLine("Sym @#&*()[]{}/\\+=");
}
// Shared scrollable renderer for the label/value Live tab. Neither tab has a
// row cursor -- UP/DOWN move _scroll directly -- so this passes _scroll as
// drawList()'s `sel` too: its internal clamp-toward-sel is then a no-op
@@ -210,7 +50,7 @@ class DiagnosticsScreen : public UIScreen {
clampScroll(_row_count, visible);
drawList(display, _row_count, _scroll, _scroll,
[&](int idx, int y, bool, int reserve) {
const Row& r = _rows[idx];
const diag::Row& r = _rows[idx];
display.setCursor(2, y);
display.print(r.label);
display.drawTextRightAlign(display.width() - reserve - 2, y, r.value);
@@ -245,9 +85,9 @@ public:
tabbar::draw(display, TAB_LABELS, TAB_COUNT, _tab);
switch (_tab) {
case TAB_SYSTEM: buildSystemLines(); renderLines(display); break;
case TAB_FONT: buildFontLines(); renderLines(display); break;
default: buildLiveRows(); renderRows(display); break;
case TAB_SYSTEM: _line_count = diag::systemLines(_lines); renderLines(display); break;
case TAB_FONT: _line_count = diag::fontLines(_lines); renderLines(display); break;
default: _row_count = diag::liveRows(_rows); renderRows(display); break;
}
display.setColor(DisplayDriver::LIGHT);
@@ -262,8 +102,7 @@ public:
if (_reset_menu.active) {
auto res = _reset_menu.handleInput(c);
if (res == PopupMenu::SELECTED && _reset_menu.selectedIndex() == 0) {
the_mesh.resetStats(); // zeroes Dispatcher per-type counters + Mesh forward count + err flags
radio_driver.resetStats(); // zeroes the radio's own counters, incl. RXPS watchdog soft/hard counts
diag::resetCounters();
_task->showAlert("Counters reset", 800);
}
return true;