Skip to content

Fix MJ-18: NACK unsupported partial-update (0x76) and buzzer (0x77) commands#7

Open
balloob wants to merge 1 commit into
OpenDisplay:mainfrom
balloob:fix/nack-unsupported-commands
Open

Fix MJ-18: NACK unsupported partial-update (0x76) and buzzer (0x77) commands#7
balloob wants to merge 1 commit into
OpenDisplay:mainfrom
balloob:fix/nack-unsupported-commands

Conversation

@balloob

@balloob balloob commented Jul 5, 2026

Copy link
Copy Markdown

The BLE client can send partial-update (0x76) and buzzer (0x77) commands that the Silabs firmware does not implement. Both fell through the dispatch switch default case in opendisplay_pipe.c, which only printed unknown cmd and returned nothing. The client then blocked waiting for an ACK until its timeout expired (finding MJ-18).

Fix

Reply to both opcodes with a NACK frame {0xFF, cmd_low, 0x07, 0x00} so the client fails fast instead of hanging:

  • 0x76 (partial-update start): the frame matches the client's parse_nack() ({0xFF, opcode, err, 0x00}), so it logs the rejection and cleanly falls back to a full upload. Error code 0x07 corresponds to the client's ERR_PARTIAL_UNSUPPORTED.
  • 0x77 (buzzer): the client only calls validate_ack_response(), which rejects 0xFF77 immediately as a non-ACK (InvalidResponseError).

Genuinely unknown opcodes keep the existing default behavior (print + drop). Behavior for internal/no-response opcodes is unchanged. Scope is limited to {0x76, 0x77}.

Verification

  • No embedded toolchain (arm-none-eabi-gcc/slc) was available in the working environment, so the full firmware image was not built. opendisplay_protocol.h was host syntax-checked standalone (self-contained, only depends on stdint.h) and the new switch cases were syntax-checked in an isolated stub with gcc -std=c11 -fsyntax-only -Wall -Wextra — both clean.
  • Client recognition was confirmed against the actual py-opendisplay code: parse_nack(bytes([0xFF,0x76,0x07,0x00])) == (0x76, 0x07) (fallback to full upload) and validate_ack_response(bytes([0xFF,0x77,0x07,0x00]), BUZZER_ACTIVATE) raises InvalidResponseError.

Companion

An nRF firmware PR addresses the same MJ-18 finding on that platform. The separate nonce/replay-protection and config-parser fixes are out of scope here.

🤖 Generated with Claude Code

https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR


Companion PR: OpenDisplay/Firmware_NRF#2 (same MJ-18 fix, nRF side). Note: nRF uses err code 0x01 vs this PR's 0x07 (ERR_PARTIAL_UNSUPPORTED) — both work; 0x07 is the semantically-correct code.

…ommands

The BLE client can send partial-update (0x76) and buzzer (0x77) commands
that the Silabs firmware does not implement. Both fell through the dispatch
switch's default case, which only printed "unknown cmd" and returned nothing.
The client then blocked waiting for an ACK until its timeout expired.

Reply to both opcodes with a NACK frame {0xFF, cmd_low, 0x07, 0x00} so the
client fails fast: for 0x76 this matches parse_nack() and triggers a clean
fallback to a full upload; for 0x77 validate_ack_response() rejects it
immediately as a non-ACK. Genuinely unknown opcodes keep the existing
default (print + drop). Behavior for internal/no-response opcodes is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR
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