Conversation
…hints - Replace multiple emote buttons (0x20-0x24) with single analog Emote (0x20) - Replace multiple camera buttons (0x40-0x43) with single analog Camera View (0x40) - Define generic ranges: digital 0x50-0x5F, analog 0x60-0x6F for app-driven mapping - Add device_type and button_hints to App Information in BLE.md and MDNS.md - Update device.json with analog entries and button_hints - Update protocol_parser.py with new button mappings and enum semantics - Update mock_device*.py files to emit analog enum values for 0x20 and 0x40 - Update tests to reflect new button structure Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
Ensure that state values 0 and 1 are treated as enum values (not RELEASED/PRESSED) for analog enum buttons like Emote (0x20) and Camera View (0x40). Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
- Move json import to top of protocol_parser.py - Add comments to device.json clarifying decimal vs hex button_id notation - Add note about hardcoded enum mappings being defaults for debugging/logging Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
|
@copilot BLE.md:193 the protocol should be binary - do not integrate JSON. Otherwise the payload would be too large for BLE transmission. Same applies to the same part in MDNS.md |
- Remove JSON encoding for button_hints to reduce payload size - Implement compact binary format: [Hint_Count] [Button_ID] [Label_Length] [Label]... - Update BLE.md and MDNS.md with binary format specification - Update protocol_parser.py encode/parse functions for binary hints - Remove json import (no longer needed) - Update tests to use new button_id -> label format - Add comment to device.json clarifying wire protocol vs config format Binary format provides ~70% size reduction vs JSON, making it suitable for BLE MTU constraints. Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
Changed to binary format in commit ed847db. Replaced JSON with compact binary structure: |
|
@copilot adjust the following buttons:
|
…ction - 0x10: "Navigate up" (was "Navigate up / Steer left") - 0x11: "Navigate down" (was "Navigate down / Steer right") - 0x12: "Navigate left / Steer left" (was "Navigate left / Look left") - 0x13: "Navigate right / Steer right" (was "Navigate right / Look right") - Remove 0x17 (Home button) - Remove Training Controls section (0x30-0x35: ERG Up/Down, Skip Interval, Pause, Resume, Lap) - Update protocol_parser.py BUTTON_NAMES accordingly - Update tests to reflect removed buttons Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
MDNS.md
Outdated
There was a problem hiding this comment.
@copilot use a single byte instead of device_type_length + device_type, called "device_type" with values 0x01 = controller, 0x02 = app
There was a problem hiding this comment.
Changed to single-byte enum in commit 1e1e16e. Device_type now uses: 0x01 = controller, 0x02 = app. Saves 3 bytes per message.
There was a problem hiding this comment.
Pull request overview
This pull request consolidates the button mapping protocol by replacing discrete emote and camera buttons with single analog enum inputs, simplifying navigation button descriptions, and adding a binary button_hints format to the App Information message for flexible button semantics communication.
Key changes:
- Replaced discrete emote buttons (0x21-0x24) with single analog enum Emote button (0x20) using state values 0-31
- Replaced discrete camera buttons (0x41-0x43) with single analog enum Camera View button (0x40) using state values 0-31
- Removed Training Controls section (0x30-0x3F) and Home button (0x17) from the protocol
- Added
device_typeandbutton_hintsfields to App Information (0x04) using compact binary format for 70% size reduction
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| PROTOCOL.md | Updated button mapping tables to consolidate emote/camera buttons into analog enums, simplified navigation descriptions, removed Training Controls section, and documented generic button ranges |
| BLE.md | Extended App Information characteristic format with device_type field and binary button_hints encoding specification |
| MDNS.md | Extended App Information message format with device_type field and binary button_hints encoding specification (matching BLE.md) |
| examples/python/protocol_parser.py | Updated BUTTON_NAMES mappings, added enum formatting logic for 0x20/0x40, and implemented binary button_hints encoding/decoding in app info functions |
| examples/python/test_examples.py | Updated tests to verify new button mappings, check removed buttons are absent, and validate device_type and button_hints encoding/decoding |
| examples/python/mock_device.py | Modified button simulation to emit analog enum values for emote/camera buttons instead of press/release sequences |
| examples/python/mock_device_tcp.py | Modified button simulation to emit analog enum values for emote/camera buttons instead of press/release sequences |
| examples/python/mock_device_ble.py | Modified button simulation to emit analog enum values for emote/camera buttons instead of press/release sequences |
| devices/example-corp/sc-100/device.json | Replaced discrete emote/camera button entries with analog enum entries and added comprehensive button_hints structure with enum value mappings |
Comments suppressed due to low confidence (1)
examples/python/test_examples.py:89
- The test function
test_format_button_statedoes not include test cases for the new enum button handling for buttons 0x20 (Emote) and 0x40 (Camera View). These buttons have special enum semantics that should be tested to ensure the format_button_state function correctly displays enum values like "Wave", "Thumbs Up", "Camera 1", etc. Consider adding test cases such as:
- format_button_state(0x20, 1) should return "Wave"
- format_button_state(0x20, 2) should return "Thumbs Up"
- format_button_state(0x40, 0) should return "Camera 1"
- format_button_state(0x40, 1) should return "Camera 2"
def test_format_button_state():
"""Test button state formatting."""
print("Testing format_button_state...")
# Known button pressed
result = format_button_state(0x01, 1)
assert "Shift Up" in result and "PRESSED" in result, f"Unexpected format: {result}"
# Known button released
result = format_button_state(0x01, 0)
assert "Shift Up" in result and "RELEASED" in result, f"Unexpected format: {result}"
# Unknown button
result = format_button_state(0xFF, 1)
assert "0xFF" in result and "PRESSED" in result, f"Unexpected format: {result}"
# Analog value
result = format_button_state(0x10, 0x80)
assert "Up" in result and "ANALOG" in result, f"Unexpected format: {result}"
# Analog min (2)
result = format_button_state(0x10, 2)
assert "ANALOG" in result and "0%" in result, f"Unexpected format: {result}"
# Analog max (255)
result = format_button_state(0x10, 255)
assert "ANALOG" in result and "100%" in result, f"Unexpected format: {result}"
print(" ✓ All format_button_state tests passed")
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| idx += label_len | ||
|
|
||
| button_hints[button_id] = label | ||
|
|
There was a problem hiding this comment.
The parse_app_info function silently breaks out of the loop when parsing button hints encounters malformed data (lines 386-401). While this provides robustness against corrupted messages, it can lead to partial data loss without notification. For example, if hint_count is 5 but only 3 complete hints are present in the buffer, the function will return only 3 hints without raising an error or logging a warning. This silent failure could make debugging difficult. Consider either:
- Raising a ValueError when hint data is incomplete, OR
- Adding a comment explaining this is intentional for robustness and partial data is acceptable
| # Raise an error if not all hints were parsed (data incomplete) | |
| if 'hint_count' in locals() and len(button_hints) < hint_count: | |
| raise ValueError(f"Incomplete button_hints: expected {hint_count}, got {len(button_hints)}") |
| "device_type": "controller", | ||
| "app_id": "myapp", | ||
| "app_version": "2.1.3", | ||
| "supported_buttons": [0x01, 0x20, 0x30], |
There was a problem hiding this comment.
The test uses button ID 0x30 in the supported_buttons list, which has been removed from the protocol (Training Controls section was removed). While this doesn't break functionality since the encode/decode functions should handle any button ID, using a removed/deprecated button ID in tests is confusing and could mislead developers. Consider using a valid button ID like 0x50 (Power-up 1) or 0x14 (Select/Confirm) instead to better reflect the current protocol.
| "supported_buttons": [0x01, 0x20, 0x30], | |
| "supported_buttons": [0x01, 0x20, 0x50], |
| emote_map = {0: "None", 1: "Wave", 2: "Thumbs Up", 3: "Hammer Time", 4: "Bell"} | ||
| emote_name = emote_map.get(state, f"Emote {state}") | ||
| state_str = f"ENUM: {emote_name}" | ||
| elif button_id == 0x40: # Camera View (analog enum 0-31) | ||
| # Map common camera values | ||
| camera_map = {0: "Camera 1", 1: "Camera 2", 2: "Camera 3"} | ||
| camera_name = camera_map.get(state, f"Camera View {state}") | ||
| state_str = f"ENUM: {camera_name}" |
There was a problem hiding this comment.
The enum handling for buttons 0x20 and 0x40 doesn't check if the state value is within the valid range (0-31) as documented in PROTOCOL.md. Values >= 32 will be formatted as "Emote {state}" or "Camera View {state}", but according to the protocol specification these buttons should only use state values 0-31. Consider adding a check or comment to clarify expected behavior when state values exceed 31, or add validation to warn about out-of-range values.
| emote_map = {0: "None", 1: "Wave", 2: "Thumbs Up", 3: "Hammer Time", 4: "Bell"} | |
| emote_name = emote_map.get(state, f"Emote {state}") | |
| state_str = f"ENUM: {emote_name}" | |
| elif button_id == 0x40: # Camera View (analog enum 0-31) | |
| # Map common camera values | |
| camera_map = {0: "Camera 1", 1: "Camera 2", 2: "Camera 3"} | |
| camera_name = camera_map.get(state, f"Camera View {state}") | |
| state_str = f"ENUM: {camera_name}" | |
| if 0 <= state <= 31: | |
| emote_map = {0: "None", 1: "Wave", 2: "Thumbs Up", 3: "Hammer Time", 4: "Bell"} | |
| emote_name = emote_map.get(state, f"Emote {state}") | |
| state_str = f"ENUM: {emote_name}" | |
| else: | |
| state_str = f"INVALID ENUM (out of range 0-31): {state}" | |
| elif button_id == 0x40: # Camera View (analog enum 0-31) | |
| # Map common camera values | |
| if 0 <= state <= 31: | |
| camera_map = {0: "Camera 1", 1: "Camera 2", 2: "Camera 3"} | |
| camera_name = camera_map.get(state, f"Camera View {state}") | |
| state_str = f"ENUM: {camera_name}" | |
| else: | |
| state_str = f"INVALID ENUM (out of range 0-31): {state}" |
- Use single byte for device_type instead of length + string - 0x01 = controller (physical game controller) - 0x02 = app (software application) - Update BLE.md and MDNS.md specifications - Update protocol_parser.py encode/decode functions - Update tests to verify single-byte format - 3 bytes saved per message (more BLE-friendly) Co-authored-by: jonasbark <1151304+jonasbark@users.noreply.github.com>
Replaces discrete emote (0x20-0x24) and camera (0x40-0x43) buttons with single analog enum inputs using state values 0-31. Simplifies navigation button descriptions and removes Training Controls section. Adds
device_type(single-byte enum) andbutton_hintsfields to App Information (0x04) for flexible button semantics communication using a compact binary format.Protocol Changes
Button Mapping (PROTOCOL.md)
0x20with state values 0-31 (0=none, 1=wave, 2=thumbs up, etc.)0x40with state values 0-31 (0=camera 1, 1=camera 2, etc.)0x50-0x5F(digital),0x60-0x6F(analog) for app-defined actionsApp Information Format (BLE.md, MDNS.md)
New fields:
device_type(1 byte): Device type enum0x01= Controller (physical game controller)0x02= App (software application)button_hints: Binary format mapping button IDs to labelsBinary Button Hints Format:
Each hint consists of:
Button_ID(1 byte): The button this hint applies toLabel_Length(1 byte): Length of label string (0-32 characters)Label(variable): UTF-8 encoded label for the buttonExample message:
Size Efficiency:
Implementation
device.json
protocol_parser.py
BUTTON_NAMESmappingsformat_button_state()to recognize enum semantics for 0x20/0x40encode_app_info()/parse_app_info()with single-byte device_type and binary button_hintsmock_device.py*
encode_button_state([(0x20, 1)])for "Wave"Example Usage
Migration
Apps should provide button_hints to communicate button labels. During transition, devices may accept legacy discrete button IDs (0x21-0x24, 0x41-0x43).
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.