qmk_firmware/docs/xap_0.3.0.md
2024-02-29 02:08:30 +00:00

19 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
bool Data type that contains values 0 and 1. Implemented as an alias of u8.
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 - token
u8 - type
u8 - length
ID A single octet / 8-bit byte, representing Subsystem or Route index.
Request Header Packet format for inbound data. Takes the format:
token - token
u8 - length
Response Flags An u8 containing the status of the request.
Response Header Packet format for outbound data. Takes the format:
token - token
response_flags - flags
u8 - length
Token A u16 associated with a specific request as well as its corresponding response. Valid token values are within the range 0x0100-0xFFFF.

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. This allows 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. To ensure host interoperability, valid token values are within the range 0x0100-0xFFFF.

This token is followed by a u8 signifying the length of data in the request.

Two token values are reserved: 0xFFFE and 0xFFFF:

  • 0xFFFE: 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
- - - - - - SECURE_FAILURE SUCCESS
  • 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 Tags Payloads Description
Version Query 0x00 0x00 Response: u32 XAP protocol version query.

* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => 0xXXYYZZZZ
* e.g. 3.2.115 will match 0x03020115, or bytes {0x15,0x01,0x02,0x03}.
Capabilities Query 0x00 0x01 Response: u32 XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Enabled subsystem query 0x00 0x02 Response: u32 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 Response: u8 Query secure route status

* 0 means secure routes are disabled
* 1 means unlock sequence initiated but incomplete
* 2 means secure routes are allowed
* any other value should be interpreted as disabled
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 Tags Payloads Description
Version Query 0x01 0x00 Response: u32 QMK protocol version query.

* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => 0xXXYYZZZZ
* e.g. 3.2.115 will match 0x03020115, or bytes {0x15,0x01,0x02,0x03}.
Capabilities Query 0x01 0x01 Response: u32 QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Board identifiers 0x01 0x02 Response:
    * Vendor ID: u16
    * Product ID: u16
    * Product Version: u16
    * QMK Unique Identifier: u32
Retrieves the set of identifying information for the board.
Board Manufacturer 0x01 0x03 Response: string Retrieves the name of the manufacturer
Product Name 0x01 0x04 Response: string Retrieves the product name
Config Blob Length 0x01 0x05 Response: u16 Retrieves the length of the configuration data bundled within the firmware
Config Blob Chunk 0x01 0x06 Request: u16

Response: u8[32]
Retrieves a chunk of the configuration data bundled within the firmware
Jump to bootloader 0x01 0x07 Secure Response: u8 Jump to bootloader

May not be present - if QMK capabilities query returns “true”, then jump to bootloader is supported

* 0 means secure routes are disabled, and should be considered as a failure
* 1 means successful, board will jump to bootloader
Hardware Identifier 0x01 0x08 Response: u32[4] Retrieves a unique identifier for the board.
Reinitialize EEPROM 0x01 0x09 Secure Response: u8 Reinitializes the keyboard's EEPROM (persistent memory)

May not be present - if QMK capabilities query returns “true”, then reinitialize is supported

* 0 means secure routes are disabled, and should be considered as a failure
* 1 means successful, board will reinitialize and then reboot

Keyboard - 0x02

This subsystem is always present, and reserved for vendor-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.

Keymap - 0x04

This subsystem allows for query of currently configured keycodes.

Name Route Tags Payloads Description
Capabilities Query 0x04 0x01 Response: u32 Keymap subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Layer Count 0x04 0x02 Response: u8 Query maximum number of layers that can be addressed within the keymap.
Get Keycode 0x04 0x03 Request:
    * Layer: u8
    * Row: u8
    * Column: u8

Response: u16
Query the Keycode at the requested location.
Get Encoder Keycode 0x04 0x04 Request:
    * Layer: u8
    * Encoder: u8
    * Clockwise: u8

Response: u16
Query the Keycode at the requested location.

Remapping - 0x05

This subsystem allows for live reassignment of keycodes without rebuilding the firmware.

Name Route Tags Payloads Description
Capabilities Query 0x05 0x01 Response: u32 Remapping subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Layer Count 0x05 0x02 Response: u8 Query maximum number of layers that can be addressed within the keymap.
Set Keycode 0x05 0x03 Secure Request:
    * Layer: u8
    * Row: u8
    * Column: u8
    * Keycode: u16
Modify the Keycode at the requested location.
Set Encoder Keycode 0x05 0x04 Secure Request:
    * Layer: u8
    * Encoder: u8
    * Clockwise: u8
    * Keycode: u16
Modify the Keycode at the requested location.

Lighting - 0x06

This subsystem allows for control over the lighting subsystem.

Name Route Tags Payloads Description
Capabilities Query 0x06 0x01 Response: u32 Lighting subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.

backlight - 0x06 0x02

This subsystem allows for control over the backlight subsystem.

Name Route Tags Payloads Description
Capabilities Query 0x06 0x02 0x01 Response: u32 backlight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Enabled Effects 0x06 0x02 0x02 Response: u8 Each bit should be considered as a "usable" effect id
Get Config 0x06 0x02 0x03 Response:
    * enable: u8
    * mode: u8
    * val: u8
Query the current config.
Set Config 0x06 0x02 0x04 Request:
    * enable: u8
    * mode: u8
    * val: u8
Set the current config.
Save Config 0x06 0x02 0x05 Save the current config.

rgblight - 0x06 0x03

This subsystem allows for control over the rgblight subsystem.

Name Route Tags Payloads Description
Capabilities Query 0x06 0x03 0x01 Response: u32 rgblight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Enabled Effects 0x06 0x03 0x02 Response: u64 Each bit should be considered as a "usable" effect id
Get Config 0x06 0x03 0x03 Response:
    * enable: u8
    * mode: u8
    * hue: u8
    * sat: u8
    * val: u8
    * speed: u8
Query the current config.
Set Config 0x06 0x03 0x04 Request:
    * enable: u8
    * mode: u8
    * hue: u8
    * sat: u8
    * val: u8
    * speed: u8
Set the current config.
Save Config 0x06 0x03 0x05 Save the current config.

rgbmatrix - 0x06 0x04

This subsystem allows for control over the rgb matrix subsystem.

Name Route Tags Payloads Description
Capabilities Query 0x06 0x04 0x01 Response: u32 rgb matrix subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Enabled Effects 0x06 0x04 0x02 Response: u64 Each bit should be considered as a "usable" effect id
Get Config 0x06 0x04 0x03 Response:
    * enable: u8
    * mode: u8
    * hue: u8
    * sat: u8
    * val: u8
    * speed: u8
    * flags: u8
Query the current config.
Set Config 0x06 0x04 0x04 Request:
    * enable: u8
    * mode: u8
    * hue: u8
    * sat: u8
    * val: u8
    * speed: u8
    * flags: u8
Set the current config.
Save Config 0x06 0x04 0x05 Save the current config.

Audio - 0x07

This subsystem allows for control over the audio subsystem.
Name Route Tags Payloads Description
Capabilities Query 0x07 0x01 Response: u32 Audio subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
Get Config 0x07 0x03 Response:
    * enable: u8
    * clicky_enable: u8
Query the current config.
Set Config 0x07 0x04 Request:
    * enable: u8
    * clicky_enable: u8
Set the current config.
Save Config 0x07 0x05 Save the current config.

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, then the response payload length, and finally the 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 u8[Length] containing the text, where the length of the text is the broadcast_header.length field.

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. Payloads include a u8 matching a 'Secure Status' request.

Example Secure Status Broadcast -- secure "Unlocking"

Byte 0 1 2 3 4
Purpose Token Token Broadcast Type Length Secure Status
Value 0xFF 0xFF 0x01 0x01 0x01

Keyboard - 0x02

Reserved for vendor-specific functionality. No messages are defined by XAP.

User - 0x03

Reserved for user-specific functionality. No messages are defined by XAP.