Skip to content

Meck-P4 v0.3 -- Audio Player, Active Discovery, Internationalised Keyboard

Pre-release
Pre-release

Choose a tag to compare

@pelgraine pelgraine released this 16 May 03:53
· 97 commits to main since this release

The third Meck-P4 pre-release. Audio playback from SD, active zero-hop neighbour discovery with one-tap contact add, and a substantially upgraded virtual keyboard with light/dark theme, three physical layouts, and long-press accent input for French and Czech. Plus per-message hop and ACK metadata, and a fix for the battery cell capacity (which had been wrong since v0.1).

**⚠️ Still a pre-release.⚠️ ** Direct messaging, roomserver access, repeater admin, trace route, web browser, IRC, and the BLE companion path are still not in this build. See What's Not Yet Implemented for the full pending list.


First-Time Flashing -- Read This First

Meck-P4 ships as a single merged binary (bootloader + partition table + application combined). One file, flash at offset 0x0.

An SD card is recommended. With a FAT32-formatted card inserted, every saved setting and channel message is mirrored automatically, audio files have somewhere to live, and the device recovers gracefully from a wiped NVS. Without an SD card the device still works but loses message history on reboot.

correct port usage for flashing

Ensure you use the right-side USB-C port (the data port), not the high-speed charger port, to flash.

Flashing with the MeshCore Web Flasher (recommended)

  1. Go to https://flasher.meshcore.io/
  2. Scroll to the bottom and select Custom Firmware
  3. Select the meck-p4-0.3-version-merged.bin file you downloaded
  4. Click OK on the merged-binary warning
  5. Click Flash, pick your device in the popup, and click Connect

Flashing with esptool.py

pip install esptool
esptool.py --chip esp32p4 -p PORT write_flash 0x0 meck-p4-0.3-version-merged.bin

(Replace PORT with /dev/cu.usbmodemXXXX on macOS, /dev/ttyACM0 on Linux, or COM3 on Windows.)

If you're upgrading from v0.1 and want to start with clean defaults, run esptool.py --chip esp32p4 -p PORT erase_flash before the write. Your contacts and prefs will be restored from the SD card mirror on first boot.

⚠️ AMOLED variant is untested. The -amoled.bin is built from the same source tree with the AMOLED display option selected in menuconfig, but the project maintainer doesn't have the AMOLED hardware on hand and hasn't been able to flash or run it. Community members are currently testing it. If you have an AMOLED board, please report back via the MeshCore Discord or a GitHub issue with whether it boots, the display works, and touch works. The TFT variant is the tested and known-working build.


What's New Since v0.1

Audio Player

MP3 playback directly from the SD card. Two top-level subtrees give the player different defaults so music and audiobooks behave appropriately:

Subtree Defaults
/sdcard/audio/music/ Standard playback. Resume bookmark off.
/sdcard/audio/audiobooks/ Audiobook mode. Resume bookmark on, sleep timer available, position tracked through the playlist.

How to use the audio player:

  1. Drop your music/ and audiobooks/ folders into /sdcard/audio/ on the SD card (the firmware creates the subtree automatically on first boot if it doesn't exist)
  2. Insert the card and power on
  3. Tap the Audio tile on the home grid to open the browser
  4. Navigate to a track and tap to play
  5. Use the transport row on the Now Playing screen for skip / play-pause / volume

Read the audio player guide before copying files to your SD card. MP3s with large embedded album art can starve the IDLE task on first decode and trigger a watchdog reboot. The guide walks through the tools/mp3_clean.py script that strips oversized art at the source and recovers SD space, plus how to set up cover sidecars for the eventual cover-art display.

Cover art status: the cover-art decoder isn't working yet, so the music-note placeholder is shown for every track. The browser does still look for cover.png / folder.png / front.png / album.png next to your tracks, so any covers you put in place now will display once the decoder is fixed in a future release.

Discover

Active zero-hop neighbour discovery. Tap the Discover tile on the home grid to send a single DISCOVER_REQ control packet on the air; any repeater or room server within radio range responds with its public key, type, and the SNR it measured when receiving your probe. Same mechanism the MeshCore mobile app uses for its scan feature.

How to use Discover:

  1. Tap Discover from the home grid
  2. The scan opens with a 30-second window, pre-seeded with up to 32 recently-heard repeaters and rooms so the screen has content immediately
  3. Live responses arrive within 1 to 3 seconds. Live entries display SNR in dB (colour-graded green / yellow / red); cached entries display a hop count in grey
  4. Tap any row to add that node to your contacts. The [+] marker shows which rows are already in contacts
  5. Tap Rescan to start a fresh scan

Adding nodes you've never heard before: if a DISCOVER_RESP arrives for a node that isn't already in your contacts and isn't in your recent-heard cache, Meck adds it with a placeholder name (e.g. Rptr 19855E54 using the 4-byte pub-key prefix). The full name and any location fields populate automatically next time that node sends a flood advert, or you can prompt one by sending a manual advert yourself.

This makes Discover the practical way to pick up a nearby repeater you've just brought online, without waiting up to 12 hours for it to spontaneously advert.

The probe is repeater-and-room scoped (type_filter = 0x0C), so companion nodes and sensors won't respond to your scan.

Virtual Keyboard Improvements

Four upgrades to the on-screen keyboard.

Dark / Light theme. Two themes are now available. Dark is the default. Switch via Settings → KB Theme. The choice persists via NVS and applies live to every keyboard instance the moment you change it.

Three physical layouts. Switch via Settings → KB Layout which cycles through:

Layout Description
QWERTY (default) Standard English
AZERTY French layout. A and Q swap, W and Z swap, M moves from row 3 (after L) to the right of row 2
QWERTZ German layout. Y and Z swap; same shape as QWERTY everywhere else

Layout switches apply live and persist via NVS.

Long-press accent popover. Touch and hold any vowel or accented base letter to bring up a horizontal strip of accented variants. Tap one to insert it; tap anywhere else to dismiss. Disabled in symbol/number mode (no accents on digits or punctuation).

Variants available, both lower and upper case:

Base Variants
a / A á à â
c / C č ç
e / E é è ê ë ě
i / I í ï
o / O ô
r / R ř
s / S š
u / U ù û ü
y / Y ý
z / Z ž

The set covers French and Czech in full; other languages with overlapping accents (Spanish, Italian, German umlaut variants, Portuguese, Slovak) are partially served.

Symbol row reshuffle. The 1# shift key had a placement bug that conflicted with _, ,, and :. Those three have moved to the symbol row, accessed via the #+= key on the bottom row. Tap abc to switch back to letters.

Per-Message Hop Count and ACK Indicators

Two pieces of metadata are now visible alongside every channel message.

Incoming messages display a small hop-count badge showing how many repeaters the packet passed through to reach you. Direct receptions show 0 hops.

Outgoing messages show an ACK indicator next to each send. The indicator updates from "pending" to "acked" as repeater echoes confirm propagation; subsequent acks bump a delivery counter so you can see how many neighbours heard you. Useful for sanity-checking that your message actually went out, particularly in marginal-signal conditions.

Battery Calibration Fix

The battery cell capacity was wrong in v0.1. The firmware was telling the BQ27220 the cell was 2000 mAh based on an unverified attribution; the actual cell shipped on the T-Display P4 is 1000 mAh per LilyGo wiki FAQ 9.9.

v0.3 sets design_capacity = 1000 and adds a defensive software cap: if the chip still reports a stale Full Charge Capacity (FCC) above 1000 mAh from v0.1, the UI caps the displayed FCC at design and logs a warning at boot prompting recalibration. Percentage readings are recomputed against min(FCC, design) so a stale internal value can't skew the displayed SoC. Voltage and current readings are direct measurements and were always correct.

One-time recalibration on upgrade: to clear the stale FCC and let the gauge re-learn the cell, run one full charge → natural discharge to power-off → recharge cycle as instructed in the LilyGo wiki. After that single cycle the BQ27220 has the right reference value and the displayed percentage tracks reality.

Other Changes

  • Bigger Back button across all screens, more comfortable to hit on the punch-hole TFT
  • Active-discovery state added to MeckMesh.h, including a _recent[] ring pre-seed and a per-scan random tag so late responses to previous scans are ignored
  • MeckAudio backend added (MeckAudio.cpp, MeckAudioUI.cpp, es8311.cpp) wrapping chmorgan/esp-audio-player and routing PCM through LilyGo's existing Cpp_Bus_Driver::Es8311 codec instance, so the I²S and I²C buses stay shared with the rest of the device
  • Build-time epoch baked in via CMake string(TIMESTAMP ... %s UTC) so the soft RTC's pre-sync fallback is a real UTC value rather than the build machine's local time
  • Custom path lock flag (CONTACT_FLAG_CUSTOM_PATH, bit 7 of ContactInfo.flags) reserved for upcoming manual path-editor UI; not user-facing yet
  • Repository docs: new Audio Player guide under information/Meck Docs/, plus expanded README coverage of all the above

Known Limitations

  • Cover art doesn't display in the audio player. The browser finds the cover files and the player has a 280×280 slot ready for them, but LVGL's LODEPNG decoder can't allocate the framebuffer for typical cover sizes. A future build will downscale at decode time. Music-note placeholder shows in the meantime.
  • MP3 files with large embedded album art can starve the IDLE task on the audio core and fire the watchdog. There's a firmware defensive ID3v2-skip patch but the durable fix is tools/mp3_clean.py (see the audio guide).
  • Battery FCC may need one full charge / discharge / charge cycle on first boot after upgrade from v0.1 before the gauge's stored FCC drops back into the right range. The warning at boot tells you when this is needed.
  • Discover depends on the responding node having v1.x firmware with zero-hop neighbour discovery enabled (a checkbox on Meck firmware repeaters, on by default in recent builds). Older repeater firmware won't respond to DISCOVER_REQ and won't show up in Discover unless they happen to flood-advert during the scan window.
  • Default channel boots on Australia Narrow. If your local mesh has moved to a different preset (e.g. Australia Mid in Sydney as of mid-2026), change it in Settings → Radio Preset after first boot. The change persists.

What's Not Yet Implemented

Carried over from v0.1, minus what landed in this release:

  • Direct messaging (DM compose, DM inbox with unread indicators, DM persistence to SD)
  • Roomserver access (login flow, message handling, mark-read on login)
  • Repeater admin (login, clock sync push, send advert, get status, neighbours, version)
  • Trace route (view the relay path of a received packet)
  • Notes app
  • Audio cover-art rendering (pre-flight succeeds but heap allocation for the decoded framebuffer fails for typical cover sizes; needs decode-time downscale or a streaming decoder)
  • Web browser & IRC client
  • ESP32-C6 BLE companion firmware (the C6 is on the board but Meck-P4 doesn't drive it yet)
  • PCF8563 hardware RTC integration (init only, not yet read on boot or written on shutdown)
  • Deep sleep with wake-on-touch (auto-off dims the screen but the SoC doesn't enter deep sleep, so battery life is still short)
  • Map tile rendering
  • OTA firmware updates over WiFi via the C6
  • Region scope (MeshCore v1.15+ compatibility)

PRs welcome. See the full roadmap in the README.


Reporting Issues

The Meck-P4 channel on the MeshCore Discord is the fastest path. GitHub Issues on the Meck-P4 repo also work for anything reproducible. Include the serial log if you can (idf.py monitor or any serial terminal at 115200 baud will show what's happening).


License

MIT for Meck-specific code. The combined firmware binary links libraries with mixed licensing including GPL-3.0 and is effectively GPL-3.0 when distributed.