Initial implementation of XAP protocol.
This commit is contained in:
parent
f4c447f2df
commit
eba91c6e28
34 changed files with 1934 additions and 4 deletions
178
data/xap/xap_0.0.1.hjson
Executable file
178
data/xap/xap_0.0.1.hjson
Executable file
|
|
@ -0,0 +1,178 @@
|
|||
{
|
||||
version: 0.0.1
|
||||
|
||||
// Needed for table generation
|
||||
define: XAP_ROUTE
|
||||
|
||||
// Documentation section is used purely for `qmk xap-generate-docs`.
|
||||
documentation: {
|
||||
order: [
|
||||
page_header
|
||||
type_docs
|
||||
!type_docs!
|
||||
term_definitions
|
||||
!term_definitions!
|
||||
request_response
|
||||
reserved_tokens
|
||||
response_flags
|
||||
!response_flags!
|
||||
example_conversation
|
||||
]
|
||||
|
||||
page_header:
|
||||
'''
|
||||
# QMK Firmware XAP Specs
|
||||
|
||||
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
|
||||
'''
|
||||
|
||||
type_docs:
|
||||
'''
|
||||
## Types
|
||||
|
||||
**All integral types are little-endian.**
|
||||
'''
|
||||
|
||||
term_definitions:
|
||||
'''
|
||||
## Definitions
|
||||
|
||||
This list defines the terms used across the entire set of XAP protocol documentation.
|
||||
'''
|
||||
|
||||
request_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 repsonse 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.
|
||||
'''
|
||||
|
||||
// This documentation section reserved for next version
|
||||
reserved_tokens: ''
|
||||
|
||||
response_flags:
|
||||
'''
|
||||
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
|
||||
'''
|
||||
|
||||
example_conversation:
|
||||
'''
|
||||
### 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` |
|
||||
'''
|
||||
}
|
||||
|
||||
type_docs: {
|
||||
u8:
|
||||
'''
|
||||
An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_.
|
||||
'''
|
||||
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_.
|
||||
'''
|
||||
"type[n]":
|
||||
'''
|
||||
An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets.
|
||||
'''
|
||||
}
|
||||
|
||||
term_definitions: {
|
||||
Subsystem:
|
||||
'''
|
||||
A high-level area of functionality within XAP.
|
||||
'''
|
||||
ID:
|
||||
'''
|
||||
A single octet / 8-bit byte.
|
||||
'''
|
||||
Route:
|
||||
'''
|
||||
A sequence of _IDs_ describing the route to invoke a _handler_.
|
||||
'''
|
||||
Handler:
|
||||
'''
|
||||
A piece of code that is executed when a specific _route_ is received.
|
||||
'''
|
||||
Token:
|
||||
'''
|
||||
A `u16` associated with a specific request as well as its corresponding response.
|
||||
'''
|
||||
Response:
|
||||
'''
|
||||
The data sent back to the host during execution of a _handler_.
|
||||
'''
|
||||
"Response Flags":
|
||||
'''
|
||||
An `u8` containing the status of the request.
|
||||
'''
|
||||
Payload:
|
||||
'''
|
||||
Any received data appended to the _route_, which gets delivered to the _handler_ when received.
|
||||
'''
|
||||
}
|
||||
|
||||
response_flags: {
|
||||
define_prefix: XAP_RESP
|
||||
bits: {
|
||||
0: {
|
||||
name: Success
|
||||
define: SUCCESS
|
||||
description:
|
||||
'''
|
||||
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).
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routes: {
|
||||
0x00: {
|
||||
type: router
|
||||
name: XAP
|
||||
define: XAP
|
||||
description:
|
||||
'''
|
||||
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
|
||||
'''
|
||||
routes: {
|
||||
0x00: {
|
||||
type: command
|
||||
name: Version Query
|
||||
define: VERSION_QUERY
|
||||
description:
|
||||
'''
|
||||
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}.
|
||||
* Response:
|
||||
* `u32` value.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: bcd-version
|
||||
return_constant: XAP_BCD_VERSION
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
248
data/xap/xap_0.1.0.hjson
Executable file
248
data/xap/xap_0.1.0.hjson
Executable file
|
|
@ -0,0 +1,248 @@
|
|||
{
|
||||
version: 0.1.0
|
||||
|
||||
documentation: {
|
||||
order: [
|
||||
broadcast_messages
|
||||
]
|
||||
|
||||
reserved_tokens:
|
||||
'''
|
||||
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.
|
||||
'''
|
||||
|
||||
broadcast_messages:
|
||||
'''
|
||||
## 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_.
|
||||
'''
|
||||
}
|
||||
|
||||
response_flags: {
|
||||
bits: {
|
||||
1: {
|
||||
name: Secure Failure
|
||||
define: SECURE_FAILURE
|
||||
description:
|
||||
'''
|
||||
When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed.
|
||||
'''
|
||||
}
|
||||
6: {
|
||||
name: Unlocking
|
||||
define: UNLOCK_IN_PROGRESS
|
||||
description:
|
||||
'''
|
||||
When this bit is set, an _unlock sequence_ is in progress.
|
||||
'''
|
||||
}
|
||||
7: {
|
||||
name: Unlocked
|
||||
define: UNLOCKED
|
||||
description:
|
||||
'''
|
||||
When this bit is set, an _unlock sequence_ has completed, and _secure routes_ may be invoked.
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_docs: {
|
||||
u64:
|
||||
'''
|
||||
An unsigned 64-bit integral, commonly seen as `uint64_t` from _stdint.h_.
|
||||
'''
|
||||
"struct{}":
|
||||
'''
|
||||
A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a C-style `struct`. The order in which they're defined matches the order of the data in the response packet.
|
||||
'''
|
||||
}
|
||||
|
||||
term_definitions: {
|
||||
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_.
|
||||
'''
|
||||
"Secure Route":
|
||||
'''
|
||||
A _route_ which has potentially destructive consequences, necessitating prior approval by the user before executing.
|
||||
'''
|
||||
"Unlock sequence":
|
||||
'''
|
||||
A physical sequence initiated by the user to enable execution of _secure routes_.
|
||||
'''
|
||||
}
|
||||
|
||||
broadcast_messages: {
|
||||
define_prefix: XAP_BROADCAST
|
||||
messages: {
|
||||
0x00: {
|
||||
name: Log message
|
||||
define: LOG_MESSAGE
|
||||
description:
|
||||
'''
|
||||
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`(!) |
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routes: {
|
||||
0x00: {
|
||||
routes: {
|
||||
0x01: {
|
||||
type: command
|
||||
name: Capabilities Query
|
||||
define: CAPABILITIES_QUERY
|
||||
description:
|
||||
'''
|
||||
XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_XAP_CAPABILITIES
|
||||
}
|
||||
0x02: {
|
||||
type: command
|
||||
name: Enabled subsystem query
|
||||
define: SUBSYSTEM_QUERY
|
||||
description:
|
||||
'''
|
||||
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.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_CAPABILITIES
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
0x01: {
|
||||
type: router
|
||||
name: QMK
|
||||
define: QMK
|
||||
description:
|
||||
'''
|
||||
This subsystem is always present, and provides the ability to address QMK-specific functionality.
|
||||
'''
|
||||
routes: {
|
||||
0x00: {
|
||||
type: command
|
||||
name: Version Query
|
||||
define: VERSION_QUERY
|
||||
description:
|
||||
'''
|
||||
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}.
|
||||
* Response:
|
||||
* `u32` value.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: bcd-version
|
||||
return_constant: QMK_BCD_VERSION
|
||||
}
|
||||
0x01: {
|
||||
type: command
|
||||
name: Capabilities Query
|
||||
define: CAPABILITIES_QUERY
|
||||
description:
|
||||
'''
|
||||
QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_QMK_CAPABILITIES
|
||||
}
|
||||
0x02: {
|
||||
type: command
|
||||
name: Board identifiers
|
||||
define: BOARD_IDENTIFIERS
|
||||
description:
|
||||
'''
|
||||
Retrieves the set of identifying information for the board.
|
||||
'''
|
||||
return_type: struct
|
||||
return_struct_members: [
|
||||
{
|
||||
type: u16
|
||||
name: Vendor ID
|
||||
},
|
||||
{
|
||||
type: u16
|
||||
name: Product ID
|
||||
},
|
||||
{
|
||||
type: u16
|
||||
name: Product Version
|
||||
},
|
||||
{
|
||||
type: u32
|
||||
name: QMK Unique Identifier
|
||||
}
|
||||
]
|
||||
return_constant: [
|
||||
VENDOR_ID
|
||||
PRODUCT_ID
|
||||
DEVICE_VER
|
||||
XAP_KEYBOARD_IDENTIFIER
|
||||
]
|
||||
}
|
||||
0x03: {
|
||||
type: command
|
||||
name: Board Manufacturer
|
||||
define: BOARD_MANUFACTURER
|
||||
description: Retrieves the name of the manufacturer
|
||||
return_type: string
|
||||
return_constant: QSTR(MANUFACTURER)
|
||||
}
|
||||
0x04: {
|
||||
type: command
|
||||
name: Product Name
|
||||
define: PRODUCT_NAME
|
||||
description: Retrieves the product name
|
||||
return_type: string
|
||||
return_constant: QSTR(PRODUCT)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
0x02: {
|
||||
type: router
|
||||
name: Keyboard
|
||||
define: KB
|
||||
description:
|
||||
'''
|
||||
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
|
||||
'''
|
||||
routes: {
|
||||
}
|
||||
},
|
||||
|
||||
0x03: {
|
||||
type: router
|
||||
name: User
|
||||
define: USER
|
||||
description:
|
||||
'''
|
||||
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
|
||||
'''
|
||||
routes: {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
data/xap/xap_0.2.0.hjson
Executable file
80
data/xap/xap_0.2.0.hjson
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
version: 0.2.0
|
||||
|
||||
routes: {
|
||||
0x04: {
|
||||
type: router
|
||||
name: Dynamic Keymap
|
||||
define: DYNAMIC_KEYMAP
|
||||
description:
|
||||
'''
|
||||
This subsystem allows for live modifications of the keymap, allowing keys to be reassigned without rebuilding the firmware.
|
||||
'''
|
||||
enable_if_preprocessor: defined(DYNAMIC_KEYMAP_ENABLE)
|
||||
routes: {
|
||||
0x00: {
|
||||
type: command
|
||||
name: Capabilities Query
|
||||
define: CAPABILITIES_QUERY
|
||||
description:
|
||||
'''
|
||||
Dynamic Keymap subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_DYNAMIC_KEYMAP_CAPABILITIES
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0x05: {
|
||||
type: router
|
||||
name: Dynamic Encoders
|
||||
define: DYNAMIC_ENCODER
|
||||
description:
|
||||
'''
|
||||
This subsystem allows for live modifications of the keymap, allowing encoder functionality to be reassigned without rebuilding the firmware.
|
||||
'''
|
||||
enable_if_preprocessor: defined(DYNAMIC_KEYMAP_ENABLE) && defined(ENCODER_MAP_ENABLE)
|
||||
routes: {
|
||||
0x00: {
|
||||
type: command
|
||||
name: Capabilities Query
|
||||
define: CAPABILITIES_QUERY
|
||||
description:
|
||||
'''
|
||||
Dynamic Encoders subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_DYNAMIC_ENCODER_CAPABILITIES
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0x06: {
|
||||
type: router
|
||||
name: Lighting
|
||||
define: LIGHTING
|
||||
description:
|
||||
'''
|
||||
This subsystem allows for control over the lighting subsystem.
|
||||
'''
|
||||
enable_if_preprocessor: defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
|
||||
routes: {
|
||||
0x00: {
|
||||
type: command
|
||||
name: Capabilities Query
|
||||
define: CAPABILITIES_QUERY
|
||||
description:
|
||||
'''
|
||||
Lighting subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
|
||||
'''
|
||||
return_type: u32
|
||||
return_purpose: capabilities
|
||||
return_constant: XAP_ROUTE_LIGHTING_CAPABILITIES
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue