Skip to content

Peripheral status relay - #5

Merged
reversebias merged 5 commits into
masterfrom
peripheral-status-relay
Aug 9, 2026
Merged

Peripheral status relay#5
reversebias merged 5 commits into
masterfrom
peripheral-status-relay

Conversation

@reversebias

Copy link
Copy Markdown
Owner

No description provided.

reversebias and others added 5 commits August 9, 2026 22:01
The right half cannot see layer or BLE-profile state (endpoints.c/ble.c/
keymap.c are central-only at v0.3.0 and the split GATT service has no
such characteristic - see zmk-next-steps.md §3). Instead of new GATT,
the central pushes a snapshot over the stock RUN_BEHAVIOR channel by
invoking a carrier behavior on the peripheral, the same mechanism
&bootloader locality uses.

- stat_rly behavior (anaphase,behavior-status-relay): node name kept to
  8 chars to fit the 9-byte behavior_dev split payload field (cf.
  upstream's 'bootload'/'sysreset' naming). Never bound in a keymap.
- status_relay.c: central listens to layer_state_changed +
  ble_active_profile_changed and sends (layer id, profile index); a 15s
  refresh timer heals stale displays after split reconnects. Peripheral
  side stores the snapshot and raises a local event.
- layer_status widget: peripheral branch renders the relayed layer id
  using a name table generated from this half's own keymap devicetree
  (present even though keymap.c isn't compiled). '----' until first
  relay. Studio runtime renames won't propagate (DT names only).
- output_status widget: peripheral name row now shows the central's
  active profile nickname (name_array moved to shared scope);
  'ANAPHASE' fallback until the relay lands. Split-link PAIRED/WAITING
  unchanged.
- Gated behind CONFIG_ANAPHASE_STATUS_RELAY (default y) - one line to
  disable if the relay ever misbehaves.

Known risk (accepted): zmk_split_central_invoke_behavior is exported
but undocumented; the v0.4 split-transport rework will likely force a
re-port. Cost: +320B flash central, +740B peripheral.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The left screen wakes on any keypress because the central sees both
halves' key events; the peripheral has no reverse traffic, so its OLED
only woke on its own keys. Fix: the relay payload gains a
central-activity flag (param2 bit 8). The central's activity state
already represents the whole keyboard, so mirroring its ACTIVE/IDLE
transitions onto the peripheral as synthetic zmk_activity_state_changed
events gives the right OLED identical semantics to the left - wake ~20ms
after the first keypress on either half, blank 60s after the last one.

ZMK's stock blank-on-idle machinery does all the work; no per-keystroke
traffic (transitions + the existing 15s refresh only), no custom blank
manager. Deep sleep deliberately stays local to each half - the mirror
never raises SLEEP.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hardware test caught the hole: the wake worked, but the right half's own
activity.c only watches local keys, so 60s after the last RIGHT keypress
it raised IDLE and blanked - while the mirror's change-detector stayed
silent (the central's state hadn't changed).

Fix on the peripheral, two parts:
- Local IDLE arriving while the mirrored central state is active AND
  fresh (relay heard <35s = two refresh periods + slack) is countered by
  re-asserting ACTIVE from a deferred work item (50ms; worst case a
  brief blink once per local-idle expiry).
- The override is edge-triggered but staleness is a state: a watchdog
  re-checks at the freshness deadline, so a central that dies AFTER an
  override kept the screen on gets its claim dropped and the display
  blanked. A dead left half costs at most ~35s of extra screen-on time
  in every ordering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All three test cases pass: sustained left-only typing keeps the right
OLED lit (one blink at local-idle expiry), both screens blank together
on whole-keyboard idle, and the watchdog blanks the right screen ~50s
after the left half powers off mid-override.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@reversebias
reversebias merged commit 7a150ff into master Aug 9, 2026
8 checks passed
@reversebias
reversebias deleted the peripheral-status-relay branch August 9, 2026 12:47
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