Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Repository execution rules

- Project/ProtocolContract.json is the opcode owner for native and Pakar
namespaces. Keep published allocations append-only, generate every consumer
view with interfaces/controller-wire, and retain protected-base CI comparisons.
Fixed A5/1 native and A5/0 Pakar admission is mandatory before dispatch, never
a version selector or advisory byte. Unknown operations must not fall through
into another namespace or be assumed acknowledged. Sync consumers with the
guarded Tools/Build/sync-controller-opcodes.mjs helper.

- RF managers share the reception/learning contract in `docs/RF-RECEPTION-AND-LEARNING.md`: show all complete waveform identities, dim unlearned observations, preserve modal-local count baselines across refresh and use cumulative reception metadata through coalescing. Defaults are timed learning off, optional duration 60 seconds and continuous learning off. Learning settings are persistent, not competing timed/indefinite runtime actions. Keep hard-coded guided entry points hidden until pattern profiles exist. Unknown reception never grants output authority or persists a record without explicit Add/Assign.

- On Windows, never run `go test` directly. It executes test programs from
Expand Down
80 changes: 79 additions & 1 deletion Project/ProtocolContract.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,83 @@
{ "cpp": "HardwareUnavailable", "go": "ErrorHardwareUnavailable", "value": 4 },
{ "cpp": "Busy", "go": "ErrorBusy", "value": 5 },
{ "cpp": "Unsafe", "go": "ErrorUnsafe", "value": 6 }
]
],
"pakar": {
"envelope": {"magic":165,"reserved":0,"maximumPayload":48,"rawFrameOverhead":6,"maximumEncodedFrameOverhead":2},
"opcodes": [
{"cpp":"kHello","rust":"HELLO","dart":"hello","value":1,"wireName":"HELLO","go":"PakarHello"},
{"cpp":"kGetStatus","rust":"GET_STATUS","dart":"getStatus","value":2,"wireName":"GET_STATUS","go":"PakarGetStatus"},
{"cpp":"kSetStreamPeriod","rust":"SET_STREAM_PERIOD","dart":"setStreamPeriod","value":3,"wireName":"SET_STREAM_PERIOD","go":"PakarSetStreamPeriod"},
{"cpp":"kBuzzer","rust":"BUZZER","dart":"buzzer","value":16,"wireName":"BUZZER","go":"PakarBuzzer"},
{"cpp":"kAudioCue","rust":"AUDIO_CUE","dart":"audioCue","value":17,"wireName":"AUDIO_CUE","go":"PakarAudioCue"},
{"cpp":"kAudioStream","rust":"AUDIO_STREAM","dart":"audioStream","value":18,"wireName":"AUDIO_STREAM","go":"PakarAudioStream"},
{"cpp":"kDisplayText","rust":"DISPLAY_TEXT","dart":"displayText","value":56,"wireName":"DISPLAY_TEXT","go":"PakarDisplayText"},
{"cpp":"kSetMode","rust":"SET_MODE","dart":"setMode","value":75,"wireName":"SET_MODE","go":"PakarSetMode"},
{"cpp":"kCellAction","rust":"CELL_ACTION","dart":"cellAction","value":76,"wireName":"CELL_ACTION","go":"PakarCellAction"},
{"cpp":"kGameReset","rust":"GAME_RESET","dart":"gameReset","value":77,"wireName":"GAME_RESET","go":"PakarGameReset"},
{"cpp":"kOutputMask","rust":"OUTPUT_MASK","dart":"outputMask","value":78,"wireName":"OUTPUT_MASK","go":"PakarOutputMask"},
{"cpp":"kPing","rust":"PING","dart":"ping","value":79,"wireName":"PING","go":"PakarPing"},
{"cpp":"kProgrammingState","rust":"PROGRAMMING_STATE","dart":"programmingState","value":80,"wireName":"PROGRAMMING_STATE","go":"PakarProgrammingState"},
{"cpp":"kSetBrightness","rust":"SET_BRIGHTNESS","dart":"setBrightness","value":81,"wireName":"SET_BRIGHTNESS","go":"PakarSetBrightness"},
{"cpp":"kSetLedPattern","rust":"SET_LED_PATTERN","dart":"setLedPattern","value":82,"wireName":"SET_LED_PATTERN","go":"PakarSetLedPattern"},
{"cpp":"kNetworkConfig","rust":"NETWORK_CONFIG","dart":"networkConfig","value":83,"wireName":"NETWORK_CONFIG","go":"PakarNetworkConfig"},
{"cpp":"kAccessConfig","rust":"ACCESS_CONFIG","dart":"accessConfig","value":84,"wireName":"ACCESS_CONFIG","go":"PakarAccessConfig"},
{"cpp":"kDeviceName","rust":"DEVICE_NAME","dart":"deviceName","value":85,"wireName":"DEVICE_NAME","go":"PakarDeviceName"},
{"cpp":"kPcContract","rust":"PC_CONTRACT","dart":"pcContract","value":86,"wireName":"PC_CONTRACT","go":"PakarPcContract"},
{"cpp":"kPcContractChunk","rust":"PC_CONTRACT_CHUNK","dart":"pcContractChunk","value":87,"wireName":"PC_CONTRACT_CHUNK","go":"PakarPcContractChunk"},
{"cpp":"kGetTelemetry","rust":"GET_TELEMETRY","dart":"getTelemetry","value":88,"wireName":"GET_TELEMETRY","go":"PakarGetTelemetry"},
{"cpp":"kGetIdentity","rust":"GET_IDENTITY","dart":"getIdentity","value":89,"wireName":"GET_IDENTITY","go":"PakarGetIdentity"},
{"cpp":"kEspPanel","rust":"ESP_PANEL","dart":"espPanel","value":90,"wireName":"ESP_PANEL","go":"PakarEspPanel"},
{"cpp":"kAvrRxDiagnostic","rust":"AVR_RX_DIAGNOSTIC","dart":"avrRxDiagnostic","value":91,"wireName":"AVR_RX_DIAGNOSTIC","go":"PakarAvrRxDiagnostic"},
{"cpp":"kSetLedOutput","rust":"SET_LED_OUTPUT","dart":"setLedOutput","value":92,"wireName":"SET_LED_OUTPUT","go":"PakarSetLedOutput"},
{"cpp":"kGetTableSnapshot","rust":"GET_TABLE_SNAPSHOT","dart":"getTableSnapshot","value":93,"wireName":"GET_TABLE_SNAPSHOT","go":"PakarGetTableSnapshot"},
{"cpp":"kTableCommand","rust":"TABLE_COMMAND","dart":"tableCommand","value":94,"wireName":"TABLE_COMMAND","go":"PakarTableCommand"},
{"cpp":"kCellsAction","rust":"CELLS_ACTION","dart":"cellsAction","value":95,"wireName":"CELLS_ACTION","go":"PakarCellsAction"},
{"cpp":"kShellRequest","rust":"SHELL_REQUEST","dart":"shellRequest","value":96,"wireName":"SHELL_REQUEST","go":"PakarShellRequest"},
{"cpp":"kPeerReport","rust":"PEER_REPORT","dart":"peerReport","value":97,"wireName":"PEER_REPORT","go":"PakarPeerReport"},
{"cpp":"kCellAssignments","rust":"CELL_ASSIGNMENTS","dart":"cellAssignments","value":98,"wireName":"CELL_ASSIGNMENTS","go":"PakarCellAssignments"},
{"cpp":"kCellLock","rust":"CELL_LOCK","dart":"cellLock","value":99,"wireName":"CELL_LOCK","go":"PakarCellLock"},
{"cpp":"kHostDemand","rust":"HOST_DEMAND","dart":"hostDemand","value":100,"wireName":"HOST_DEMAND","go":"PakarHostDemand"},
{"cpp":"kPixelDiagnostic","rust":"PIXEL_DIAGNOSTIC","dart":"pixelDiagnostic","value":101,"wireName":"PIXEL_DIAGNOSTIC","go":"PakarPixelDiagnostic"},
{"cpp":"kKeyMask","rust":"KEY_MASK","dart":"keyMask","value":102,"wireName":"KEY_MASK","go":"PakarKeyMask"},
{"cpp":"kKeySettings","rust":"KEY_SETTINGS","dart":"keySettings","value":103,"wireName":"KEY_SETTINGS","go":"PakarKeySettings"},
{"cpp":"kGamePress","rust":"GAME_PRESS","dart":"gamePress","value":104,"wireName":"GAME_PRESS","go":"PakarGamePress"},
{"cpp":"kKeyPresentation","rust":"KEY_PRESENTATION","dart":"keyPresentation","value":105,"wireName":"KEY_PRESENTATION","go":"PakarKeyPresentation"},
{"cpp":"kUsbApi","rust":"USB_API","dart":"usbApi","value":106,"wireName":"USB_API","go":"PakarUsbApi"},
{"cpp":"kAck","rust":"ACK","dart":"ack","value":128,"wireName":"ACK","go":"PakarAck"},
{"cpp":"kHelloResponse","rust":"HELLO_RESPONSE","dart":"helloResponse","value":129,"wireName":"HELLO_RESPONSE","go":"PakarHelloResponse"},
{"cpp":"kErrorResponse","rust":"ERROR_RESPONSE","dart":"errorResponse","value":130,"wireName":"ERROR_RESPONSE","go":"PakarErrorResponse"},
{"cpp":"kStatusResponse","rust":"STATUS_RESPONSE","dart":"statusResponse","value":144,"wireName":"STATUS_RESPONSE","go":"PakarStatusResponse"},
{"cpp":"kGameState","rust":"GAME_STATE","dart":"gameState","value":163,"wireName":"GAME_STATE","go":"PakarGameState"},
{"cpp":"kInputEvent","rust":"INPUT_EVENT","dart":"inputEvent","value":164,"wireName":"INPUT_EVENT","go":"PakarInputEvent"},
{"cpp":"kCellEvent","rust":"CELL_EVENT","dart":"cellEvent","value":165,"wireName":"CELL_EVENT","go":"PakarCellEvent"},
{"cpp":"kPong","rust":"PONG","dart":"pong","value":166,"wireName":"PONG","go":"PakarPong"},
{"cpp":"kPcContractResponse","rust":"PC_CONTRACT_RESPONSE","dart":"pcContractResponse","value":176,"wireName":"PC_CONTRACT_RESPONSE","go":"PakarPcContractResponse"},
{"cpp":"kTelemetryResponse","rust":"TELEMETRY_RESPONSE","dart":"telemetryResponse","value":177,"wireName":"TELEMETRY_RESPONSE","go":"PakarTelemetryResponse"},
{"cpp":"kIdentityResponse","rust":"IDENTITY_RESPONSE","dart":"identityResponse","value":178,"wireName":"IDENTITY_RESPONSE","go":"PakarIdentityResponse"},
{"cpp":"kEspPanelResponse","rust":"ESP_PANEL_RESPONSE","dart":"espPanelResponse","value":179,"wireName":"ESP_PANEL_RESPONSE","go":"PakarEspPanelResponse"},
{"cpp":"kAvrRxDiagnosticResponse","rust":"AVR_RX_DIAGNOSTIC_RESPONSE","dart":"avrRxDiagnosticResponse","value":180,"wireName":"AVR_RX_DIAGNOSTIC_RESPONSE","go":"PakarAvrRxDiagnosticResponse"},
{"cpp":"kResetTelemetryResponse","rust":"RESET_TELEMETRY_RESPONSE","dart":"resetTelemetryResponse","value":181,"wireName":"RESET_TELEMETRY_RESPONSE","go":"PakarResetTelemetryResponse"},
{"cpp":"kTableSnapshotResponse","rust":"TABLE_SNAPSHOT_RESPONSE","dart":"tableSnapshotResponse","value":182,"wireName":"TABLE_SNAPSHOT_RESPONSE","go":"PakarTableSnapshotResponse"},
{"cpp":"kTableCommandState","rust":"TABLE_COMMAND_STATE","dart":"tableCommandState","value":183,"wireName":"TABLE_COMMAND_STATE","go":"PakarTableCommandState"},
{"cpp":"kPanelEvent","rust":"PANEL_EVENT","dart":"panelEvent","value":184,"wireName":"PANEL_EVENT","go":"PakarPanelEvent"},
{"cpp":"kShellResponse","rust":"SHELL_RESPONSE","dart":"shellResponse","value":185,"wireName":"SHELL_RESPONSE","go":"PakarShellResponse"},
{"cpp":"kHostDemandResponse","rust":"HOST_DEMAND_RESPONSE","dart":"hostDemandResponse","value":186,"wireName":"HOST_DEMAND_RESPONSE","go":"PakarHostDemandResponse"},
{"cpp":"kAudioStreamResponse","rust":"AUDIO_STREAM_RESPONSE","dart":"audioStreamResponse","value":188,"wireName":"AUDIO_STREAM_RESPONSE","go":"PakarAudioStreamResponse"},
{"cpp":"kUsbApiResponse","rust":"USB_API_RESPONSE","dart":"usbApiResponse","value":189,"wireName":"USB_API_RESPONSE","go":"PakarUsbApiResponse"}
],
"reservedOpcodes": [],
"errors": [
{"cpp":"kNoError","rust":"NO_ERROR","dart":"noError","value":0,"wireName":"NO_ERROR","go":"PakarNoError"},
{"cpp":"kBadEnvelope","rust":"BAD_ENVELOPE","dart":"badEnvelope","value":1,"wireName":"BAD_ENVELOPE","go":"PakarBadEnvelope"},
{"cpp":"kUnsupported","rust":"UNSUPPORTED","dart":"unsupported","value":2,"wireName":"UNSUPPORTED","go":"PakarUnsupported"},
{"cpp":"kBadPayload","rust":"BAD_PAYLOAD","dart":"badPayload","value":3,"wireName":"BAD_PAYLOAD","go":"PakarBadPayload"},
{"cpp":"kHardwareUnavailable","rust":"HARDWARE_UNAVAILABLE","dart":"hardwareUnavailable","value":4,"wireName":"HARDWARE_UNAVAILABLE","go":"PakarHardwareUnavailable"},
{"cpp":"kBusy","rust":"BUSY","dart":"busy","value":5,"wireName":"BUSY","go":"PakarBusy"},
{"cpp":"kUnsafe","rust":"UNSAFE","dart":"unsafe","value":6,"wireName":"UNSAFE","go":"PakarUnsafe"},
{"cpp":"kRedCellsLocked","rust":"RED_CELLS_LOCKED","dart":"redCellsLocked","value":7,"wireName":"RED_CELLS_LOCKED","go":"PakarRedCellsLocked"},
{"cpp":"kInvalidCellAssignments","rust":"INVALID_CELL_ASSIGNMENTS","dart":"invalidCellAssignments","value":8,"wireName":"INVALID_CELL_ASSIGNMENTS","go":"PakarInvalidCellAssignments"},
{"cpp":"kUnsupportedBoardRole","rust":"UNSUPPORTED_BOARD_ROLE","dart":"unsupportedBoardRole","value":9,"wireName":"UNSUPPORTED_BOARD_ROLE","go":"PakarUnsupportedBoardRole"}
]
}
}
8 changes: 4 additions & 4 deletions Project/UartProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ void UartProtocol::processEncodedFrame() {
// in RX storage leaves raw_ available for nested ACK/error/response writes.
const uint8_t rawLength = WireCodec::cobsDecode(
receive_, receiveLength_, receive_, sizeof(receive_));
// The reserved byte is advisory: magic, bounded shape, CRC, and each known
// opcode's semantic validation decide whether a frame is understandable.
// This lets reduced/newer feature sets interoperate without build-specific
// branches; unknown operations still receive Unsupported from the handler.
// This fixed envelope discriminator is not a version selector. Pakar uses
// the same framing but a different command namespace (0x11 is audio, not PWM).
// Reject another envelope before semantic dispatch; never guess/fall back.
if (rawLength < RawOverhead || receive_[0] != Magic ||
receive_[1] != ReservedEnvelopeByte ||
receive_[4] > MaximumPayload ||
rawLength != static_cast<uint8_t>(receive_[4] + RawOverhead)) {
if (framingErrors_ != UINT16_MAX) {
Expand Down
Loading
Loading