github cvhviz/CAIRN cvhbuild-v56
Wio L1 Pro build 56 (archive)

pre-release28 days ago

Archived from the old WioL1Pro-CVHBuild repository (first published 2026-08-09). These are the Wio Tracker L1 Pro builds from before Cairn; current builds are in the latest Cairn release.

Changelog

Notable changes in this fork of MeshCore, targeting the
Seeed Wio Tracker L1 Pro (nRF52840, SH1106 128×64 OLED, joystick, buzzer, L76K GNSS).

Based on upstream MeshCore v1.16.0 (companion). Format follows
Keep a Changelog. This fork versions by build number —
CVHBuild N, shown on the splash screen — so a device can be matched to a tag from its own display.

Build environments:

Env Target
WioTrackerL1_companion_radio_ble SH1106 OLED (primary)
WioTrackerL1Eink_companion_radio_ble Waveshare 2.13" B/W e-ink
WioTrackerL1Eink3C_companion_radio_ble Waveshare 2.13" tri-colour e-ink

cvhbuild-v56 — 2026-08-09

Builds 48–56. Only build 48 was flashed and tested on hardware; 49–56 are staged.

Added

Bluetooth

  • The BLE pairing pin can be set on the device. The Settings row was previously hardcoded
    read-only, so the pin could only be changed from the phone app. Six digit cells: Left/Right
    walks them, Up/Down cycles the one under the caret through 0–9. 000000 means auto, where
    the device picks a pin each session.
  • Pin changes apply without a reboot, via a new BaseSerialInterface::setPin() implemented
    for nRF52 and ESP32. Devices already bonded keep their keys and stay paired — the pin gates
    new pairings only.
  • The app's CMD_SET_DEVICE_PIN and the set pin serial command now route through the same
    MyMesh::setBLEPin(), so all three paths validate, persist and apply identically.

Display

  • Brightness setting, 10/25/50/75/100 %, persisted at NodePrefs byte 146. The SH1106 has
    no backlight, so this drives the contrast register (0x81) that sets segment current — a
    real power lever, not just a comfort one. Applied live while stepping; Back restores.
    Percentages are perceived brightness, squared on the way to the register (10 % → 2,
    50 % → 63, 100 % → 255), because eye response to luminance is a power law and a linear map
    leaves every visible step crowded into the bottom fifth of the range.
  • New DisplayDriver::hasBrightness() / setBrightness() virtuals, defaulting to no-ops. The
    row reads n/a on e-ink, which is reflective and has nothing to turn up.

Radio page

  • Third sub-view: fullscreen spectrum. Up/Down now cycles settings+spectrum → traffic →
    fullscreen. 24 px graph with a dotted peak-hold rule, live channel RSSI and noise floor, and
    the peak/low of the window in dBm.
  • Enter sends an advert from any Radio sub-view, using the Recent page's existing zero-hop vs.
    flood chooser. Nothing transmits until the choice is confirmed.

Battery view

  • Discharge graph replacing the fill-bar, with a dotted 20 % reference line and an
    estimated time remaining. The bar only restated a percentage already printed twice on the
    same page; the trend is the part a number cannot give you.
  • The buffer is self-scaling: 63 slots, 126 bytes, allocated once. Sampling starts at 20 s
    spacing and each time the buffer fills it discards every other sample in place and doubles
    the spacing — 21 min of window at first, ~11 h after five compactions, ~90 h after eight. It
    never grows, wraps or resets.

Changed

  • Key lock is two gestures instead of one toggle: hold Back to lock, double-click Back to
    unlock. Double-click no longer locks. UITask::toggleLock() was removed so nothing can
    reintroduce the toggle. Triple-click still unlocks, for a fumbled double.
  • Radio page values are laid out on a real column grid — labels on a left rule, values
    right-aligned onto a common rule, split by a vertical divider — so digits stack vertically.
    Units were dropped from the values, which is what makes the numbers align rather than merely
    the fields. Previously the second column was padded inside a single sprintf(), so
    BW 250.00 versus BW 7.80 shifted CR sideways.
  • Spectrum samples are captured at the fullscreen graph's resolution and divided down for the
    compact band, instead of being captured at the compact 7 px resolution and blown up.
  • setBLEPin() accepts 0–999999 rather than 0 or 100000–999999. A BLE passkey is a
    six-character field, so 012345 is a real pin; both backends already format to six digits.

Fixed

  • The GPS was left running through hibernate. nRF52 System OFF retains GPIO levels, so a
    GPS enabled at power-off kept acquiring at tens of milliamps on a device that looked off.
    It is now stopped before powerOff(), without touching prefs, so the chosen mode returns on
    the next boot.
  • start_gps() / stop_gps() are idempotent. Re-selecting the mode already active leaked a
    ref-counted claim on the shared peripheral rail that the matching stop could never undo, and
    re-ran _location->reset(), forcing a cold start on boards with a GPS reset pin.
  • E-ink layout occupied roughly two thirds of the panel. EINK_SCALE_Y was 1.28 for a
    250×122 panel showing a 128×64 canvas, mapping 64 rows onto 82 pixels and leaving the bottom
    third blank, while crushing the 9 px row pitch to 11.5 physical px against a font needing 18.
    Now 1.90625 (122 ÷ 64).
  • E-ink text baselines are derived from each font's ascent (EINK_TEXT_BASELINE_AUTO) instead
    of a hand-tuned EINK_Y_OFFSET that could only line up for one text size. Adafruit_GFX
    places custom fonts on the baseline while every caller passes the top-left corner.
  • New EINK_LOGICAL_W/EINK_LOGICAL_H report the canvas the UI was drawn for, so anything
    sizing itself off height() — the alert popup — is no longer given 128 on a 64-row layout.

cvhbuild-v47 — 2026-08-06

First tagged release. Everything below is relative to upstream v1.16.0.

Added

Display & text

  • UTF-8 text folding for the CP437 bitmap fonts, replacing the previous
    "every non-ASCII byte becomes a solid block" behaviour. Typographic punctuation folds to
    ASCII (don’t → don't, … → ..., en/em dashes → -), accented Latin folds to base
    letters (café → cafe, straße → strasse), and ~40 emoji map to real font glyphs
    (❤ → ♥, 🙂 → ☺, 🎵 → ♫, 👍 → +1, arrows → ← → ↑ ↓).
  • Cyrillic and Greek romanisation — Привет → Privet, Ретранслятор → Retranslyator,
    Αθήνα → Athina. Covers the main Cyrillic block, the Ukrainian/Serbian/Macedonian
    extensions, and Greek including final sigma and accented vowels. The table is Russian-style,
    so Ukrainian и romanises as i rather than y.
  • Context-dependent handling for emoji with no font glyph: dropped from names (a marker is
    just noise in front of the word), shown as a bullet in message bodies (silently dropping
    what a sender wrote would change the message). Names fall back to blocks only when a name
    would otherwise render empty.

UI pages

  • Clock page with 12h / 24h / analogue styles and a persisted UTC offset, plus a battery
    sub-view (percentage, charge bar, millivolts, power source, uptime, CPU die temperature).
  • Recent page listing heard nodes, with per-node ping, a zero-hop/flood advert chooser, and a
    confirm-guarded clear.
  • Radio page with a live channel-RSSI spectrum anchored to the noise floor, and a traffic
    monitor sub-view tabulating the last frames by type, route, hops, RSSI, SNR and age.
  • GPS page with satellite bar, speed, altitude, and a course-over-ground compass sub-view.
  • Settings page consolidating Bluetooth, GPS, tones, screen, clock, region, TX power, BLE pin,
    auto-lock and hibernate, with in-place editing and confirm-on-commit for destructive changes.
  • Node-to-node ping from the UI, over telemetry request for known chat contacts and trace
    otherwise, reporting round-trip time and SNR.

GPS

  • Eco mode — a third GPS state that duty-cycles the receiver (10 min interval, 90 s fix window,
    15 s settle) instead of running it continuously. No preferences are written per cycle.
  • Cached last-known fix, so the GPS page shows coordinates and the fix time while the receiver
    is powered down between eco cycles, rather than a countdown.
  • Speed and course over ground added to LocationProvider (getSpeedKnotsX1000(),
    getCourseDegX1000()), defaulting to unsupported for providers that cannot supply them.

Messaging

  • Conversation threading, a message read view with scrolling, and quick-reply presets.
  • Wake on msg setting — whether an incoming message may light the screen. Messages never
    take over the display during active use, and a screen switched off deliberately with Back
    stays off.

Power & display

  • Configurable screen timeout, keep-awake-while-USB-powered, and auto-lock on timeout.

E-ink

  • Two e-ink variants (B/W and tri-colour) with activity-aware refresh pacing and periodic
    full refreshes to clear ghosting.

Changed

  • Settings item Screen off is now Screen, a submenu covering timeout, USB behaviour and
    message wake.
  • Altitude in feet, speed in mph, temperature in °F, battery as a percentage.

Fixed

  • Contact names in the compose recipient picker were rendered without UTF-8 filtering, sending
    raw bytes to a CP437 font and producing mojibake. Every other name path was already filtered.

Security

These harden upstream code and are not specific to this board.

  • Decryption wrote past the destination buffer. Utils::decrypt() always writes whole
    16-byte blocks, but neither it nor MACThenDecrypt() knew how large the destination was.
    Both now take a dest_size and refuse to write when the block-rounded length will not fit.
  • Attacker-supplied embedded paths were trusted. A malformed path_len in a received PATH
    packet pushed the read cursor past the decrypted data, underflowing extra_len. The path
    length is now validated and the cursor bounds-checked before use.
  • Unused channel slots matched anything. Empty slots are all zeroes, so they matched hash 0
    with a secret any attacker could guess. Slots with an all-zero secret are now skipped.
  • BLE queue races. recv_queue is produced on the BLE callback task and consumed on the
    loop task; dequeue-and-shift, frame enqueue and buffer clearing were unsynchronised, so a
    preempting callback could splice two frames together or corrupt the queue length. These are
    now critical sections, reads happen outside them, and enqueue is bounded by the queue size.
  • Off-air lengths were used unclamped when building serial frames; they are now clamped to
    what the serial layer accepts.

Build history

Per-build detail, newest first. Builds up to and including 48 were flashed and tested on
hardware; 49–56 are staged but unflashed. All predate the repository's commit history.

Build Change
56 Battery graph made self-scaling; time-remaining gated on elapsed time, not sample count
55 Battery discharge graph replaces the fill-bar
54 Brightness corrected to perceived scale; Radio page column divider
53 Brightness setting; Radio page column grid
52 Fullscreen spectrum sub-view
51 Hold Back to lock, double-click to unlock
50 Enter sends an advert from the Radio page
49 Pin editor: six digit cells, full 0–9, leading zeros allowed
48 BLE pin editable at all; e-ink geometry; GPS powered down on hibernate
47 Emoji marker split by context: dropped in names, bullet in message bodies
46 Cyrillic + Greek romanisation
45 Unmappable emoji dropped rather than blocked; fixed unfiltered compose picker
44 GPS eco sleep shows cached coordinates and fix time instead of a countdown
43 UTF-8 folding: punctuation, accents, emoji-to-glyph mapping
42 Wake on msg simplified to a plain on/off toggle
41 Wake on msg setting added
40 E-ink refresh pacing; tri-colour variant
39 Spectrum framing and scale refinements
33–38 Battery view expansion, advert chooser, GPS compass sub-view, status bar cleanup
28–32 GPS eco mode, message-wake suppression during active use, clock settings moved
23–27 Traffic monitor table, spectrum capture fixes, hybrid ping, Back-to-off
19–22 Satellite bar, speed row, spectrum anchored to noise floor
13–18 UI ping from Recent, live RSSI spectrum, traffic monitor

Don't miss a new CAIRN release

NewReleases is sending notifications on new releases.