8.6 KiB
QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
Types
All integral types are little-endian.
Name | Definition |
---|---|
struct{} | A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a packed C-style struct . The order in which they're defined matches the order of the data in the response packet. |
type[n] | An array of type , with array extent of N -- e.g. u8[2] signifies two consecutive octets. |
u16 | An unsigned 16-bit integral, commonly seen as uint16_t from stdint.h. |
u32 | An unsigned 32-bit integral, commonly seen as uint32_t from stdint.h. |
u64 | An unsigned 64-bit integral, commonly seen as uint64_t from stdint.h. |
u8 | An unsigned 8-bit integral (octet, or byte), commonly seen as uint8_t from stdint.h. |
Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
Name | Definition |
---|---|
Capability | A way to determine if certain functionality is enabled in the firmware. Any subsystem that provides build-time restriction of functionality must provide a route for a capabilities query. |
Handler | A piece of code that is executed when a specific route is received. |
Payload | Any received data appended to the route, which gets delivered to the handler when received. |
Response | The data sent back to the host during execution of a handler. |
Route | A sequence of IDs describing the route to invoke a handler. |
Secure Route | A route which has potentially destructive consequences, necessitating prior approval by the user before executing. |
Subsystem | A high-level area of functionality within XAP. |
Unlock sequence | A physical sequence initiated by the user to enable execution of secure routes. |
Broadcast Header | Packet format for broadcast messages. Takes the format:token - tokenu8 - typeu8 - length |
ID | A single octet / 8-bit byte, representing Subsystem or Route index. |
Request Header | Packet format for inbound data. Takes the format:token - tokenu8 - length |
Response Flags | An u8 containing the status of the request. |
Response Header | Packet format for outbound data. Takes the format:token - tokenresponse_flags - flagsu8 - length |
Token | A u16 associated with a specific request as well as its corresponding response. |
Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a token -- this u16
value prefixes each outbound request from the host application and its corresponding response, allowing response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously. Host applications should randomly generate a token ID for every outbound request, unless using a reserved token defined below.
This token is followed by a u8
signifying the length of data in the request.
Two token values are reserved: 0x0000
and 0xFFFF
:
0x0000
: A message sent by a host application may use this token if no response is to be sent -- a "fire and forget" message.0xFFFF
: Signifies a "broadcast" message sent by the firmware without prompting from the host application. Broadcast messages are defined later in this document.
Any request will generate at least one corresponding response, with the exception of messages using reserved tokens. Maximum total message length is 128 bytes due to RAM constraints.
Response messages will always be prefixed by the originating request token, directly followed by that request's response flags, then the response payload length:
Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|---|---|
UNLOCKED |
UNLOCK_IN_PROGRESS |
- |
- |
- |
- |
SECURE_FAILURE |
SUCCESS |
- Bit 7 (
UNLOCKED
): When this bit is set, an unlock sequence has completed, and secure routes may be invoked. - Bit 6 (
UNLOCK_IN_PROGRESS
): When this bit is set, an unlock sequence is in progress. - Bit 1 (
SECURE_FAILURE
): When this bit is set, the requested route was marked secure but an unlock sequence has not completed. - Bit 0 (
SUCCESS
): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
Example "conversation":
Request -- version query:
Byte | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Purpose | Token | Token | Payload Length | Route | Route |
Value | 0x43 |
0x2B |
0x02 |
0x00 |
0x00 |
Response -- matching token, successful flag, payload of 0x03170192
= 3.17.192:
Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
Purpose | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
Value | 0x43 |
0x2B |
0x01 |
0x04 |
0x92 |
0x01 |
0x17 |
0x03 |
Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01). This is the primary method for determining if a subsystem has been enabled in the running firmware.
XAP - 0x00
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
Name | Route | Definition |
---|---|---|
Version Query | 0x00 0x00 |
XAP protocol version query. |
Capabilities Query | 0x00 0x01 |
XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem. |
Enabled subsystem query | 0x00 0x02 |
XAP protocol subsystem query. Each bit should be considered as a "usable" subsystem. For example, checking (value & (1 << XAP_ROUTE_QMK) != 0) means the QMK subsystem is enabled and available for querying. |
Secure Status | 0x00 0x03 |
Query secure route status |
Secure Unlock | 0x00 0x04 |
Initiate secure route unlock sequence |
Secure Lock | 0x00 0x05 |
Disable secure routes |
QMK - 0x01
This subsystem is always present, and provides the ability to address QMK-specific functionality.
Name | Route | Definition |
---|---|---|
Version Query | 0x01 0x00 |
QMK protocol version query. |
Capabilities Query | 0x01 0x01 |
QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem. |
Board identifiers | 0x01 0x02 |
Retrieves the set of identifying information for the board. |
Board Manufacturer | 0x01 0x03 |
Retrieves the name of the manufacturer |
Product Name | 0x01 0x04 |
Retrieves the product name |
info.json length | 0x01 0x05 |
Retrieves the length of info.json |
info.json | 0x01 0x06 |
Retrieves a chunk of info.json |
Jump to bootloader | 0x01 0x07 |
Jump to bootloader |
info.json | 0x01 0x08 |
Retrieves a unique identifier for the board. |
Keyboard - 0x02
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
User - 0x03
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
Broadcast messages
Broadcast messages may be sent by the firmware to the host, without a corresponding inbound request. Each broadcast message uses the token 0xFFFF
, and does not expect a response from the host. Tokens are followed by an ID signifying the type of broadcast, with corresponding payload.
Log message - 0x00
Replicates and replaces the same functionality as if using the standard QMK CONSOLE_ENABLE = yes
in rules.mk
. Normal prints within the firmware will manifest as log messages broadcast to the host. hid_listen
will not be functional with XAP enabled.
Log message payloads include a u8
signifying the length of the text, followed by the u8[Length]
containing the text itself.
Example Log Broadcast -- log message "Hello QMK!"
Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Purpose | Token | Token | Broadcast Type | Length | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload |
Value | 0xFF |
0xFF |
0x00 |
0x0A (10) |
0x48 (H) |
0x65 (e) |
0x6C (l) |
0x6C (l) |
0x6F (o) |
0x20 ( ) |
0x51 (Q) |
0x4D (M) |
0x4B (K) |
0x21 (!) |
Secure Status - 0x01
Secure status has changed.