Skip to content

Commit

Permalink
XAP payload length.
Browse files Browse the repository at this point in the history
  • Loading branch information
tzarc committed Jul 30, 2021
1 parent bdc9740 commit 770a833
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 61 deletions.
22 changes: 12 additions & 10 deletions data/xap/xap_0.0.1.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,33 @@
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_:
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 |
| --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x00` | `0x00` |
| 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 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x92` | `0x01` | `0x17` | `0x03` |
| 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` |
'''
}

Expand Down Expand Up @@ -164,4 +166,4 @@
}
}
}
}
}
20 changes: 11 additions & 9 deletions docs/xap_0.0.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ 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.


Response messages will always be prefixed by the originating request _token_, directly followed by that request's _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:

| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|--|--|--|--|--|--|--|--|
Expand All @@ -47,14 +49,14 @@ Response messages will always be prefixed by the originating request _token_, di
### Example "conversation":

**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 |
| --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x00` | `0x00` |
| 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 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x92` | `0x01` | `0x17` | `0x03` |
| 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` |

20 changes: 11 additions & 9 deletions docs/xap_0.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ 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.

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_:
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 |
|--|--|--|--|--|--|--|--|
Expand All @@ -59,16 +61,16 @@ Response messages will always be prefixed by the originating request _token_, di
### Example "conversation":

**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 |
| --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x00` | `0x00` |
| 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 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x92` | `0x01` | `0x17` | `0x03` |
| 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` |

## Broadcast messages

Expand Down
49 changes: 19 additions & 30 deletions quantum/xap/xap.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#include <xap.h>
#include <usb_descriptor.h>

typedef uint8_t xap_identifier_t;
typedef uint16_t xap_token_t;

typedef enum xap_route_type_t {
XAP_UNKNOWN = 0,
XAP_ROUTE,
Expand All @@ -34,7 +31,7 @@ typedef struct xap_route_flags_t {

_Static_assert(sizeof(xap_route_flags_t) == 1, "xap_route_flags_t is not length of 1");

extern void xap_send(uint8_t *data, uint8_t length);
extern void xap_send_base(uint8_t *data, uint8_t length);

#define XAP_SUBSYSTEM_XAP 0x00
#define XAP_SUBSYSTEM_XAP_ROUTE_VERSION 0x00
Expand All @@ -60,28 +57,27 @@ struct xap_route_t {
};

#ifdef CONSOLE_ENABLE
# define DUMP_XAP_DATA(name, token, data, len) \
do { \
dprintf("%s(%04X, ..., %d):", (#name), (int)(token), (int)(len)); \
for (int i = 0; i < (len); ++i) { \
dprintf(" %02X", (int)((data)[i])); \
} \
dprint("\n"); \
# define DUMP_XAP_DATA(name, token, data, len) \
do { \
dprintf("%s(%04X, ..., %d)%s", (#name), (int)(token), (int)(len), (len > 0) ? ":" : ""); \
for (int i = 0; i < (len); ++i) { \
dprintf(" %02X", (int)((data)[i])); \
} \
dprint("\n"); \
} while (0)
#else
# define DUMP_XAP_DATA(name, token, data, len) \
do { \
} while (0)
#endif

void xap_respond_failure(xap_token_t token) { xap_send(token, 0, NULL, 0); }

void xap_route_version(xap_token_t token, const uint8_t *data, size_t data_len) {}
void qmk_route_version(xap_token_t token, const uint8_t *data, size_t data_len) {
// DUMP_XAP_DATA(qmk_route_version, token, data, data_len);
uint8_t rdata[XAP_EPSIZE] = {0};
*(uint16_t *)rdata = token;
rdata[2] = 0x01;
*(uint32_t *)&rdata[3] = 0x12345678;
xap_send(rdata, sizeof(rdata));
DUMP_XAP_DATA(qmk_route_version, token, data, data_len);
uint32_t version = 0x12345678;
xap_send(token, XAP_RESPONSE_FLAG_SUCCESS, &version, sizeof(version));
}
void qmk_caps_query(xap_token_t token, const uint8_t *data, size_t data_len) {}

Expand All @@ -99,15 +95,10 @@ static const xap_route_t root_routes[] = {
[XAP_SUBSYSTEM_QMK] = {.flags = {.type = XAP_ROUTE, .is_secure = 0}, .child_routes = qmk_routes, .child_routes_len = sizeof(qmk_routes) / sizeof(qmk_routes[0])},
};

void xap_respond_failure(xap_token_t token) {
uint8_t data[XAP_EPSIZE] = {0};
*(uint16_t *)data = token;
data[2] = 0;
xap_send(data, sizeof(data));
}

void xap_execute_route(xap_token_t token, const xap_route_t *routes, size_t max_routes, const uint8_t *data, size_t data_len) {
// DUMP_XAP_DATA(xap_execute_route, token, data, data_len);
if (data_len == 0) return;

DUMP_XAP_DATA(xap_execute_route, token, data, data_len);
xap_identifier_t id = data[0];
if (id < max_routes) {
const xap_route_t *route = &routes[id];
Expand All @@ -129,9 +120,7 @@ void xap_execute_route(xap_token_t token, const xap_route_t *routes, size_t max_
}
}

void xap_receive(const void *data, size_t length) {
const uint8_t *u8data = (const uint8_t *)data;
xap_token_t token = *(const xap_token_t *)data;
// DUMP_XAP_DATA(xap_receive, token, u8data, length);
xap_execute_route(token, root_routes, sizeof(root_routes) / sizeof(root_routes[0]), &u8data[2], length - 2);
void xap_receive(xap_token_t token, const uint8_t *data, size_t length) {
DUMP_XAP_DATA(xap_receive, token, data, length);
xap_execute_route(token, root_routes, sizeof(root_routes) / sizeof(root_routes[0]), data, length);
}
10 changes: 9 additions & 1 deletion quantum/xap/xap.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@

#pragma once

void xap_receive(const void* data, size_t length);
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t xap_identifier_t;
typedef uint16_t xap_token_t;

#define XAP_RESPONSE_FLAG_SUCCESS (1 << 0)

void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_t length);
29 changes: 27 additions & 2 deletions tmk_core/protocol/lufa/lufa.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ static void raw_hid_task(void) {
#endif

#ifdef XAP_ENABLE
void xap_send(uint8_t *data, uint8_t length) {
extern void xap_receive(xap_token_t token, const uint8_t *data, size_t length);

void xap_send_base(uint8_t *data, uint8_t length) {
// TODO: implement variable size packet
if (length != XAP_EPSIZE) {
return;
Expand All @@ -281,6 +283,29 @@ void xap_send(uint8_t *data, uint8_t length) {
Endpoint_SelectEndpoint(ep);
}

void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_t length) {
uint8_t rdata[XAP_EPSIZE] = {0};
rdata[0] = (token >> 8);
rdata[1] = (token & 0xFF);
rdata[2] = response_flags;
if (response_flags & XAP_RESPONSE_FLAG_SUCCESS && length <= (XAP_EPSIZE - 4)) {
rdata[3] = (uint8_t)length;
if (data != NULL) {
memcpy(&rdata[4], data, length);
}
}
xap_send_base(rdata, sizeof(rdata));
}

void xap_receive_base(const void *data) {
const uint8_t *u8data = (const uint8_t *)data;
xap_token_t token = ((xap_token_t)u8data[0]) << 8 | u8data[1];
uint8_t length = u8data[2];
if (length <= (XAP_EPSIZE - 3)) {
xap_receive(token, &u8data[3], length);
}
}

static void xap_task(void) {
// Create a temporary buffer to hold the read in data from the host
uint8_t data[XAP_EPSIZE];
Expand All @@ -304,7 +329,7 @@ static void xap_task(void) {
Endpoint_ClearOUT();

if (data_read) {
xap_receive(data, sizeof(data));
xap_receive_base(data);
}
}
}
Expand Down

0 comments on commit 770a833

Please sign in to comment.