Skip to content

Add MarkWTech extra buttons and dual-slot HTTP firmware OTA - #3

Merged
keskad merged 38 commits into
mainfrom
feat/markwtech-extra-buttons
Aug 21, 2026
Merged

Add MarkWTech extra buttons and dual-slot HTTP firmware OTA#3
keskad merged 38 commits into
mainfrom
feat/markwtech-extra-buttons

Conversation

@keskad

@keskad keskad commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Why this is one PR

MarkWTech hardware bring-up and dual-slot firmware OTA are the same initiative. Extra GPIO buttons, pin remaps, and the DevKit wiring guide exist so the throttle can be assembled and driven. HTTP OTA is how firmware is iterated while that hardware is being built (no USB cable on every change) and is also the intended production update path once the dual-slot table is on the chip.

Companion: wireless-programmer#2 (update-firmware --mode ap|lan|usb).

MarkWTech extra buttons and wiring

  • Five debounced GPIO tact switches: menu left, Stop, menu right, Back, Menu. Scanner in extra_buttons, mapped through MarkwtechSurface / MarkwtechNav (Back = Cancel; left/right page lists or move the cursor in text entry). Provisioning chord remains * + Stop (8 s).

  • Pins that actually exist on the ESP32-C6-WROOM-1 / DevKitC-1 headers (GPIO 14 is not broken out; GPIO 16 is UART0 TX):

    Button GPIO Header
    Menu left 11 J1-11
    Stop 12 (USB_D−) J3-14
    Menu right 4 J1-3
    Back 5 J1-4
    Menu 15 J3-4
  • Native USB is sacrificed only on D− (Stop). Firmware is flashed on the UART Type-C. GPIO 4/5/15 are strapping pins but idle-high with pull-up does not change boot mode if those buttons are not held at reset.

  • Hardware guide (docs/hardware/markwtech.md): per-component tables, master GPIO map, J1/J3 positions, and the battery hardware the DevKit lacks vs the original LOLIN32 WiTcontroller (TP4056, S7V8F3 3.3 V, 47 kΩ/47 kΩ divider on GPIO 1).

Dual-slot HTTP firmware OTA

First flash of the new table is USB (espflash / wireless-programmer update-firmware --mode usb with ELF + partitions.csv). After that, updates are HTTP:

nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000
phy_init, data, phy, 0xf000, 0x1000
ota_0, app, ota_0, 0x10000, 0x3C0000
ota_1, app, ota_1, 0x3D0000, 0x3C0000

NVS stays at 0x9000. No factory partition. Slot size 0x3C0000; NET_SOCKETS=6 / PROG_NET_SOCKETS=4.

Two HTTP paths, same POST /api/v1/firmware (streamed, magic 0xE9, chip id 0x000D / ESP32-C6). Body is .app.bin (espflash save-image without --merge); merged dumps are rejected.

  1. Soft-AP (8 s chord) — DHCP 192.168.0.50–200, HTTP at 192.168.0.1. After OTA the throttle stays in programming_mode. heiko-wifred: AP chord only (no Extras menu).
  2. STA / layout Wi-Fi — Extras → Firmware update enables HTTP on the layout IP and advertises mDNS _longfred-ota._tcp. Leaving the screen disables it. STA HTTP is firmware + GET settings/page only (no PUT settings, no programming-mode/off). After OTA the throttle reboots onto layout Wi-Fi.

Flash writes take a mutex. CI publishes .app.bin artifacts; size-check covers the new slot.

Test plan

  • make build VARIANT=markwtech
  • make build VARIANT=longfred-standard
  • On hardware: left/right page lists, Back cancels, Menu opens menu, Stop is EStop
  • On hardware: * + Stop for 8 s enters provisioning
  • USB first install: update-firmware --mode usb with ELF + partitions.csv
  • Soft-AP OTA: chord, then update-firmware --mode ap --file *.app.bin
  • LAN OTA: Extras → Firmware update, then scan --mode lan / update-firmware --mode lan --host <ipv4> --file *.app.bin

keskad and others added 6 commits August 13, 2026 08:20
Wire left/Stop/right/Back/Menu on GPIO 11–14 and 16 with a debounced scanner, map them through MarkwtechSurface/NavProfile, and document the pinout so provisioning chord *+Stop works on hardware.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep GPIO 16 free for the serial console; GPIO 15 is strapping but idle-high with pull-up is safe if Menu is not held at reset.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add per-component connection tables, a master GPIO map, and clarify GPIO 15 strapping behavior on stock DevKitC-1 boards.

Co-authored-by: Cursor <cursoragent@cursor.com>
GPIO 14 is not broken out on the ESP32-C6-WROOM-1 module, so the Back
button had no header to connect to. Move it to GPIO 5 and Menu-right
from USB_D+ (13) to GPIO 4, keeping the native USB pair intact apart
from Stop on USB_D-.

Document the ESP32-C6-DevKitC-1 J1/J3 header positions for every wire,
and add the battery hardware the DevKit lacks compared to the LOLIN32
the original WiTcontroller uses: charger, 3.3 V regulator and the
47k/47k divider feeding the ADC on GPIO 1.

Co-authored-by: Cursor <cursoragent@cursor.com>
Serve POST /api/v1/firmware from the pairing AP (with DHCP) and from the
Extras firmware-update screen on STA, writing the inactive OTA slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
Point the first dual-slot install at update-firmware --mode usb as well as
a raw espflash invocation.

Co-authored-by: Cursor <cursoragent@cursor.com>
@keskad keskad changed the title Add MarkWTech extra GPIO tact buttons Add MarkWTech extra buttons and dual-slot HTTP firmware OTA Aug 15, 2026
keskad and others added 23 commits August 15, 2026 11:21
Add an English step-by-step build plus a Polish translation, log a
suggested ADC factor for first-power calibration, and enable 4-minute
inactivity sleep with a 5% low-battery cutoff.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tor.

Adds paged lists, splash, T9 keyboard, diagnostics, ICMP ping, and
expanded NVS persist. Documents MarkWTech assembly and adds a dedicated
flash target.

Co-authored-by: Cursor <cursoragent@cursor.com>
…outer.

Replace the firmware FSM menus with one screen type per file, Intent-based
side effects, and borrowed drive/network snapshots so the UI no longer
depends on DomainState.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the text caret on ASCII, parse prefix digits without wrapping, honor
EStop during HTTP OTA, bound nav hops, and serve static i18n tables.

Co-authored-by: Cursor <cursoragent@cursor.com>
NetField, menu/extras/direct/device rows, and language entries encode
legal choices in the type system. Drop dead Intent/menu/boot APIs and
route analog pot and loco-slot switches into domain actions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Numbered layout lives on the list widget so screens stop passing a redundant flag and rebuilding labels on digit-select; firmware builds context through UiWorld instead of copying screen_ctx at every event.

Co-authored-by: Cursor <cursoragent@cursor.com>
Firmware reuses longfred-ui GridView instead of memcpy, invert is a bitmask, text insert no longer clones the buffer, and nav mapping takes InputMode rather than a pair of booleans.

Co-authored-by: Cursor <cursoragent@cursor.com>
Screens stay stateless across navigation, compiled SSID lists have an explicit cap, and host tests cover stack overflow plus keyboard/list edges; make test also runs the release-assertions profile.

Co-authored-by: Cursor <cursoragent@cursor.com>
…red-ui.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ocs allow.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce ProtocolCaps, a BigFred protocol variant, and LocoCatalog so the roster picker no longer guesses from an empty live list.

Co-authored-by: Cursor <cursoragent@cursor.com>
Honour Auto/Static/AddressOnly at connect with a one-step fallback to address-only, without writing NVS, and expose the setting in Extras, Soft-AP, and diagnostics.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep five numbered shortcuts: AddressOnly opens AddrEdit, roster sources still open the list, and acquire reuses the existing address path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Release the current slot and acquire the neighbour into the same throttle; AddressOnly leaves the keys unused.

Co-authored-by: Cursor <cursoragent@cursor.com>
Compose WiThrottle in a BigFredAdapter that owns the timed function-digit FSM, and route sentinel, success, and timeout events through dedicated pairing screens.

Co-authored-by: Cursor <cursoragent@cursor.com>
Extend TAG_BIGFRED compatibly to version 5, expose pairingCode in Soft-AP, and clear stale codes after success or timeout.

Co-authored-by: Cursor <cursoragent@cursor.com>
Recognize the stable product marker in a bounded HTTP response and gracefully retain WiThrottle when the probe fails or does not match.

Co-authored-by: Cursor <cursoragent@cursor.com>
POST the bounded login/PIN/deviceId DTO after protocol detection, persist a valid 201 response, and feed its code into the existing pairing FSM.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the collection's contains helper so the full make lint gate remains warning-free.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the WiThrottle session responsive while fetching a code, bound retries to one per pairing cycle, and reject stale responses after reconnect.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep public types one level deep via mod.rs re-exports so firmware and UI import withrottle, z21, bigfred, and network rather than scattered leaf files.

Co-authored-by: Cursor <cursoragent@cursor.com>
keskad and others added 9 commits August 17, 2026 10:38
ProtocolSpec lives next to the adapters; Protocol is only the NVS/wire identity with one info() match, so UI and firmware ask for caps, probe, glyph, and transport instead of matching variants.

Co-authored-by: Cursor <cursoragent@cursor.com>
Archive the loco-source and pairing design as a completed plan and gate pairing HTTP on protocol capabilities instead of BigFred identity.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the cramped "manetka" labels with "kontroler jazdy" so extras and the direct menu match the longer OLED line budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reuse a live BigFred session instead of pairing again, overlay station
messages, probe mDNS hosts as BigFred, and keep locomotive lists in
DCC address order.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reserve the last visible content row for hints when lists use a footer,
so the fifth main-menu item stays on screen on 128×64 and mini paginates
correctly. Align grid Y positions with FONT_6X10 bounds on 64 and 32 px
panels. Map extras digit keys to label numbers via select_label_digit, and
rename heartbeat toggle state to dead-man switch in UI and proto.

Co-authored-by: Cursor <cursoragent@cursor.com>
Show roster position, line-drawn direction, server link status, and
battery percent on the drive screen. Release the current slot before every
roster or address acquire so functions and speed never hit two locos at
once; document the single-loco policy in ARCHITECTURE.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add star-prefix row selection on MarkWTech lists and Shift+F shortcuts on LongFred, gate background ICMP ping to the diagnostics screen, merge RF and ping on one diagnostics page, and add server menu flows with reconnect/disconnect plus session restart when the station changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the one-loco toggle and drop-before-acquire path, raise MAX_THROTTLES to 9, and add a numeric Slot count screen with SetMaxThrottles and a confirmation overlay.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace edge-triggered A/B sampling with a polled quadrature state machine so mechanical bounce no longer flips rotation direction.

Co-authored-by: Cursor <cursoragent@cursor.com>
@keskad
keskad merged commit 5f0ff09 into main Aug 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant