Skip to main content
Version: Latest 🚧

RawHID API

Overview​

The HID RawHID interface provides custom communication protocols for applications that need specialized HID functionality beyond standard keyboard, mouse, and gamepad interfaces. This allows for bidirectional communication and application-specific messaging.

The Python HID RawHID API is implemented in Applications/Python/PikaPython/MatrixOS_HID_RawHID.py with type hints in Applications/Python/PikaPython/_MatrixOS_HID_RawHID.pyi.


RawHID Functions​

Get​

def Get(timeout_ms: int = 0) -> bytes

Receives raw HID data from the host.

Parameters:

  • timeout_ms (int, optional): Timeout in milliseconds to wait for data (defaults to 0 for no timeout)

Returns:

  • bytes: Received raw HID data, or empty bytes if no data available

Example:

if MatrixOS.HID.Ready():
# Wait up to 100ms for HID data
data = MatrixOS.HID.RawHID.Get(100)
if data:
print(f"Received {len(data)} bytes: {data.hex()}")

Send​

def Send(report: bytes) -> bool

Sends raw HID data to the host.

Parameters:

  • report (bytes): Raw HID report data to send

Returns:

  • bool: True if sent successfully, False on error

Example:

if MatrixOS.HID.Ready():
# Send custom HID report
report_data = bytes([0x01, 0x02, 0x03, 0x04])
success = MatrixOS.HID.RawHID.Send(report_data)
if success:
print("HID report sent successfully")

RawHID Concepts​

Custom HID Reports​

RawHID allows sending and receiving custom HID reports that don't fit standard HID device classes:

  • Custom Input Reports: Device to host communication
  • Custom Output Reports: Host to device communication
  • Feature Reports: Bidirectional configuration data

Data Protocols​

  • Binary Data: Raw byte transmission
  • Structured Messages: Protocol-specific data formats
  • Command/Response: Request-response communication patterns

Example Implementation​

def rawhid_communication_example():
"""Example RawHID communication interface"""

def send_custom_message(message_type, data):
"""Send a custom message via RawHID"""
# This would depend on actual RawHID implementation
print(f"Sending RawHID message: Type {message_type}, Data: {data}")

def handle_rawhid_input():
"""Handle incoming RawHID data"""
# This would depend on actual RawHID implementation
print("Checking for RawHID input...")

message_types = {
0: "status_request",
1: "led_control",
2: "config_update",
3: "sensor_data"
}

print("RawHID Communication Interface")
print("Press keys to send different message types")

# Display message types
for key_id, msg_type in message_types.items():
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(0, 100, 200), 100)

MatrixOS.LED.Update(255)

while True:
if not MatrixOS.HID.Ready():
print("HID not ready, retrying...")
MatrixOS.SYS.DelayMs(1000)
continue

# Check for incoming data
handle_rawhid_input()

# Handle key input for sending messages
key_event = MatrixOS.KeyPad.Get(100)
if key_event is not None:
key_id = key_event.ID()
key_info = key_event.KeyInfo()

if key_info.Active() and key_id in message_types:
msg_type = message_types[key_id]

# Prepare sample data based on message type
if msg_type == "status_request":
data = {"uptime": MatrixOS.SYS.Millis()}
elif msg_type == "led_control":
data = {"pattern": "rainbow", "brightness": 255}
elif msg_type == "config_update":
data = {"setting": "auto_brightness", "value": True}
elif msg_type == "sensor_data":
data = {"temperature": 25.5, "humidity": 60}

send_custom_message(key_id, data)

# Visual feedback
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(255, 255, 255), 255)
MatrixOS.LED.Update(255)
MatrixOS.SYS.DelayMs(200)
MatrixOS.LED.SetColor(xy, Color(0, 100, 200), 100)
MatrixOS.LED.Update(255)

rawhid_communication_example()

Advanced RawHID Examples​

Data Logger Interface​

def rawhid_data_logger():
"""RawHID-based data logging interface"""

log_buffer = []
max_buffer_size = 100

def add_log_entry(entry_type, data):
"""Add entry to log buffer"""
timestamp = MatrixOS.SYS.Millis()
entry = {
"timestamp": timestamp,
"type": entry_type,
"data": data
}

log_buffer.append(entry)

# Maintain buffer size
if len(log_buffer) > max_buffer_size:
log_buffer.pop(0)

print(f"Log entry added: {entry_type}")

def send_log_data():
"""Send log data via RawHID"""
if log_buffer:
# In actual implementation, this would send via RawHID
print(f"Sending {len(log_buffer)} log entries via RawHID")
# Could implement chunked transmission for large logs
else:
print("No log data to send")

log_types = {
8: "key_press",
9: "system_event",
10: "error_event",
16: "send_logs"
}

print("RawHID Data Logger")
print("Generate log entries and send via RawHID")

# Display log type options
for key_id, log_type in log_types.items():
xy = MatrixOS.KeyPad.ID2XY(key_id)
if log_type == "send_logs":
color = Color(255, 255, 0) # Yellow for send
else:
color = Color(0, 255, 100) # Green for log types
MatrixOS.LED.SetColor(xy, color, 150)

MatrixOS.LED.Update(255)

while True:
if MatrixOS.HID.Ready():
key_event = MatrixOS.KeyPad.Get(100)
if key_event is not None:
key_id = key_event.ID()
key_info = key_event.KeyInfo()

if key_info.Active() and key_id in log_types:
log_type = log_types[key_id]

if log_type == "send_logs":
send_log_data()
else:
# Generate sample log data
sample_data = {
"key_press": {"key_id": key_id, "velocity": key_info.Velocity()},
"system_event": {"event": "mode_change", "new_mode": "logging"},
"error_event": {"error": "test_error", "severity": "low"}
}

add_log_entry(log_type, sample_data.get(log_type, {}))

# Visual feedback
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(255, 255, 255), 255)
MatrixOS.LED.Update(255)
MatrixOS.SYS.DelayMs(150)

# Restore color
if log_type == "send_logs":
color = Color(255, 255, 0)
else:
color = Color(0, 255, 100)
MatrixOS.LED.SetColor(xy, color, 150)
MatrixOS.LED.Update(255)

rawhid_data_logger()

Custom Control Protocol​

def rawhid_control_protocol():
"""Custom control protocol via RawHID"""

device_state = {
"mode": "normal",
"brightness": 128,
"pattern": "solid",
"color": [255, 0, 0]
}

def send_state_update():
"""Send current device state via RawHID"""
# In actual implementation, this would serialize and send state
print("Sending device state update:")
for key, value in device_state.items():
print(f" {key}: {value}")

def process_control_command(command, value):
"""Process incoming control command"""
if command == "set_brightness":
device_state["brightness"] = max(0, min(255, value))
elif command == "set_mode":
device_state["mode"] = value
elif command == "set_pattern":
device_state["pattern"] = value
elif command == "set_color":
device_state["color"] = value

print(f"Command processed: {command} = {value}")
send_state_update()

controls = {
0: ("brightness_up", lambda: device_state["brightness"] + 32),
1: ("brightness_down", lambda: device_state["brightness"] - 32),
2: ("toggle_mode", lambda: "demo" if device_state["mode"] == "normal" else "normal"),
3: ("cycle_pattern", lambda: {"solid": "fade", "fade": "pulse", "pulse": "solid"}[device_state["pattern"]]),
8: ("red_color", lambda: [255, 0, 0]),
9: ("green_color", lambda: [0, 255, 0]),
10: ("blue_color", lambda: [0, 0, 255]),
16: ("send_state", None)
}

print("RawHID Control Protocol")
print("Control device state via custom HID protocol")

# Display controls
for key_id, (name, _) in controls.items():
xy = MatrixOS.KeyPad.ID2XY(key_id)
if "color" in name:
color = Color(255, 100, 0) # Orange for color controls
elif "brightness" in name:
color = Color(255, 255, 0) # Yellow for brightness
else:
color = Color(0, 200, 255) # Cyan for other controls
MatrixOS.LED.SetColor(xy, color, 100)

MatrixOS.LED.Update(255)

while True:
if MatrixOS.HID.Ready():
key_event = MatrixOS.KeyPad.Get(100)
if key_event is not None:
key_id = key_event.ID()
key_info = key_event.KeyInfo()

if key_info.Active() and key_id in controls:
name, value_func = controls[key_id]

if name == "send_state":
send_state_update()
else:
new_value = value_func()
process_control_command(name, new_value)

# Visual feedback
xy = MatrixOS.KeyPad.ID2XY(key_id)
MatrixOS.LED.SetColor(xy, Color(255, 255, 255), 255)
MatrixOS.LED.Update(255)
MatrixOS.SYS.DelayMs(200)

# Restore color
if "color" in name:
color = Color(255, 100, 0)
elif "brightness" in name:
color = Color(255, 255, 0)
else:
color = Color(0, 200, 255)
MatrixOS.LED.SetColor(xy, color, 100)
MatrixOS.LED.Update(255)

rawhid_control_protocol()

Integration Considerations​

Host Application Requirements​

When using RawHID, the host application must:

  • Support custom HID device classes
  • Handle custom HID reports
  • Implement the corresponding protocol on the host side
  • Manage device enumeration and communication

Development Workflow​

  1. Define Protocol: Specify message formats and communication patterns
  2. Implement Device Side: Create MatrixOS RawHID implementation
  3. Implement Host Side: Create corresponding host application
  4. Test Communication: Verify bidirectional communication works correctly
  5. Handle Edge Cases: Implement error recovery and edge case handling

Comments