diff --git a/data/xap/xap_0.1.0.hjson b/data/xap/xap_0.1.0.hjson index 132fc421bc..e9506b5c7b 100755 --- a/data/xap/xap_0.1.0.hjson +++ b/data/xap/xap_0.1.0.hjson @@ -78,6 +78,28 @@ ''' } + type_definitions: { + broadcast_header: { + name: Broadcast Header + description: Packet format for broadcast messages. + type: struct + struct_members: [ + { + type: token + name: token + }, + { + type: u8 + name: type + }, + { + type: u8 + name: length + } + ] + } + } + broadcast_messages: { define_prefix: XAP_BROADCAST messages: { @@ -97,6 +119,15 @@ | **Value** | `0xFF` | `0xFF` | `0x00` | `0x0A`(10) | `0x48`(H) | `0x65`(e) | `0x6C`(l) | `0x6C`(l) | `0x6F`(o) | `0x20`( ) | `0x51`(Q) | `0x4D`(M) | `0x4B`(K) | `0x21`(!) | ''' } + 0x01: { + name: Secure Status + define: SECURE_STATUS + description: + ''' + Secure status has changed. + ''' + return_type: u8 + } } } diff --git a/lib/python/qmk/cli/xap/xap.py b/lib/python/qmk/cli/xap/xap.py index 5765bfeb8a..e61f7fe48b 100644 --- a/lib/python/qmk/cli/xap/xap.py +++ b/lib/python/qmk/cli/xap/xap.py @@ -48,7 +48,7 @@ def print_dotted_output(kb_info_json, prefix=''): cli.echo(' {fg_blue}%s{fg_reset}: %s', new_prefix, kb_info_json[key]) -def _xap_transaction(device, sub, route, ret_len, *args): +def _xap_transaction(device, sub, route, *args): # gen token tok = random.getrandbits(16) token = tok.to_bytes(2, byteorder='little') @@ -78,16 +78,20 @@ def _xap_transaction(device, sub, route, ret_len, *args): device.write(buffer) # get resp - array_alpha = device.read(4 + ret_len, 100) + array_alpha = device.read(64, 100) # validate tok sent == resp if str(token) != str(array_alpha[:2]): return None - return array_alpha[4:] + if int(array_alpha[2]) != 0x01: + return None + + payload_len = int(array_alpha[3]) + return array_alpha[4:4 + payload_len] def _query_device(device): - ver_data = _xap_transaction(device, 0x00, 0x00, 4) + ver_data = _xap_transaction(device, 0x00, 0x00) if not ver_data: return {'xap': 'UNKNOWN'} @@ -95,14 +99,14 @@ def _query_device(device): a = (ver_data[3] << 24) + (ver_data[2] << 16) + (ver_data[1] << 8) + (ver_data[0]) ver = f'{a>>24}.{a>>16 & 0xFF}.{a & 0xFFFF}' - secure = int.from_bytes(_xap_transaction(device, 0x00, 0x03, 1), 'little') + secure = int.from_bytes(_xap_transaction(device, 0x00, 0x03), 'little') secure = 'unlocked' if secure == 2 else 'LOCKED' return {'xap': ver, 'secure': secure} def _query_device_info_len(device): - len_data = _xap_transaction(device, 0x01, 0x05, 4) + len_data = _xap_transaction(device, 0x01, 0x05) if not len_data: return 0 @@ -111,7 +115,7 @@ def _query_device_info_len(device): def _query_device_info_chunk(device, offset): - return _xap_transaction(device, 0x01, 0x06, 32, offset) + return _xap_transaction(device, 0x01, 0x06, offset) def _query_device_info(device): @@ -143,7 +147,42 @@ def _list_devices(): # TODO: better formatting like "lsusb -v"? data = _query_device_info(device) print_dotted_output(data) - # _xap_transaction(device, 0x01, 0x07, 1) + + +def xap_doit(): + print("xap_doit") + # get layer count + # layers = _xap_transaction(device, 0x04, 0x01) + # layers = int.from_bytes(layers, "little") + # print(f'layers:{layers}') + + # get keycode [layer:0, row:0, col:0] + # keycode = _xap_transaction(device, 0x04, 0x02, b"\x00\x00\x00") + # keycode = int.from_bytes(keycode, "little") + # keycode_map = { + # # TODO: this should be data driven... + # 0x04: 'KC_A', + # 0x05: 'KC_B', + # 0x29: 'KC_ESCAPE' + # } + # print('keycode:' + keycode_map.get(keycode, 'unknown')) + + # Reboot + # _xap_transaction(device, 0x01, 0x07) + + +def xap_broadcast_listen(device): + try: + cli.log.info("Listening for XAP broadcasts...") + while 1: + array_alpha = device.read(64, 100) + if str(b"\xFF\xFF") == str(array_alpha[:2]): + if array_alpha[2] == 1: + cli.log.info(" Broadcast: Secure[%02x]", array_alpha[4]) + else: + cli.log.info(" Broadcast: type[%02x] data:[%02x]", array_alpha[2], array_alpha[4]) + except KeyboardInterrupt: + cli.log.info("Stopping...") @cli.argument('-d', '--device', help='device to select - uses format :.') @@ -161,25 +200,14 @@ def xap(cli): return _list_devices() # Connect to first available device - dev = _search()[0] + devices = _search() + if not devices: + cli.log.error("No devices found!") + return False + + dev = devices[0] device = hid.Device(path=dev['path']) cli.log.info("Connected to:%04x:%04x %s %s", dev['vendor_id'], dev['product_id'], dev['manufacturer_string'], dev['product_string']) - # get layer count - layers = _xap_transaction(device, 0x04, 0x01, 1) - layers = int.from_bytes(layers, "little") - print(f'layers:{layers}') - - # get keycode [layer:0, row:0, col:0] - keycode = _xap_transaction(device, 0x04, 0x02, 2, b"\x00\x00\x00") - keycode = int.from_bytes(keycode, "little") - keycode_map = { - # TODO: this should be data driven... - 0x04: 'KC_A', - 0x05: 'KC_B', - 0x29: 'KC_ESCAPE' - } - print('keycode:' + keycode_map.get(keycode, 'unknown')) - - # Reboot - # _xap_transaction(device, 0x01, 0x07, 1) + # xap_doit(device) + xap_broadcast_listen(device) diff --git a/lib/python/qmk/xap/gen_firmware/header_generator.py b/lib/python/qmk/xap/gen_firmware/header_generator.py index 6b58947471..0af3b6d7c4 100755 --- a/lib/python/qmk/xap/gen_firmware/header_generator.py +++ b/lib/python/qmk/xap/gen_firmware/header_generator.py @@ -177,6 +177,16 @@ def _append_internal_types(lines, container): lines.append(f'#define {prefix}_FAILED 0x00') lines.append('') + broadcast_messages = container.get('broadcast_messages', {}) + broadcast_prefix = broadcast_messages['define_prefix'] + for key, value in broadcast_messages['messages'].items(): + define = value.get('define') + lines.append(f'#define {broadcast_prefix}_{define} {key}') + + # Add special + lines.append(f'#define {broadcast_prefix}_TOKEN 0xFFFF') + lines.append('') + additional_types = {} types = container.get('type_definitions', {}) for key, value in types.items(): diff --git a/lib/python/qmk/xap/gen_firmware/inline_generator.py b/lib/python/qmk/xap/gen_firmware/inline_generator.py index 5b81176202..074a37729d 100755 --- a/lib/python/qmk/xap/gen_firmware/inline_generator.py +++ b/lib/python/qmk/xap/gen_firmware/inline_generator.py @@ -245,6 +245,22 @@ def _append_routing_tables(lines, container, container_id=None, route_stack=None route_stack.pop() +def _append_broadcast_messages(lines, container): + """TODO: + """ + broadcast_messages = container.get('broadcast_messages', {}) + broadcast_prefix = broadcast_messages['define_prefix'] + for key, value in broadcast_messages['messages'].items(): + define = value.get('define') + name = to_snake(f'{broadcast_prefix}_{define}') + + if 'return_type' in value: + ret_type = _get_c_type(value['return_type']) + lines.append(f'void {name}({ret_type} value) {{ xap_broadcast({key}, &value, sizeof(value)); }}') + else: + lines.append(f'void {name}(const void *data, size_t length){{ xap_broadcast({key}, data, length); }}') + + def generate_inline(output_file): """Generates the XAP protocol header file, generated during normal build. """ @@ -254,6 +270,7 @@ def generate_inline(output_file): lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, ''] # Add all the generated code + _append_broadcast_messages(lines, xap_defs) _append_routing_tables(lines, xap_defs) dump_lines(output_file, lines) diff --git a/quantum/xap/xap.h b/quantum/xap/xap.h index 7c43d90e27..76e5095492 100644 --- a/quantum/xap/xap.h +++ b/quantum/xap/xap.h @@ -35,3 +35,4 @@ bool xap_respond_data(xap_token_t token, const void *data, size_t length); bool xap_respond_data_P(xap_token_t token, const void *data, size_t length); void xap_send(xap_token_t token, xap_response_flags_t response_flags, const void *data, size_t length); +void xap_broadcast(uint8_t type, const void *data, size_t length); diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 53116d1562..af4eca4da0 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -1137,7 +1137,7 @@ void xap_send_base(uint8_t *data, uint8_t length) { chnWrite(&drivers.xap_driver.driver, data, length); } -void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_t length) { +void xap_send(xap_token_t token, xap_response_flags_t response_flags, const void *data, size_t length) { uint8_t rdata[XAP_EPSIZE] = {0}; xap_response_header_t *header = (xap_response_header_t *)&rdata[0]; header->token = token; @@ -1154,6 +1154,21 @@ void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_ xap_send_base(rdata, sizeof(rdata)); } +void xap_broadcast(uint8_t type, const void *data, size_t length) { + uint8_t rdata[XAP_EPSIZE] = {0}; + xap_broadcast_header_t *header = (xap_broadcast_header_t *)&rdata[0]; + header->token = XAP_BROADCAST_TOKEN; + header->type = type; + + if (length > (XAP_EPSIZE - sizeof(xap_broadcast_header_t))) return; + + header->length = (uint8_t)length; + if (data != NULL) { + memcpy(&rdata[sizeof(xap_broadcast_header_t)], data, length); + } + xap_send_base(rdata, sizeof(rdata)); +} + void xap_receive_base(const void *data) { const uint8_t * u8data = (const uint8_t *)data; xap_request_header_t *header = (xap_request_header_t *)&u8data[0]; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 969bf1ab21..0353ec7d4d 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -243,7 +243,7 @@ void xap_send_base(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) { +void xap_send(xap_token_t token, xap_response_flags_t response_flags, const void *data, size_t length) { uint8_t rdata[XAP_EPSIZE] = {0}; xap_response_header_t *header = (xap_response_header_t *)&rdata[0]; header->token = token; @@ -260,6 +260,21 @@ void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_ xap_send_base(rdata, sizeof(rdata)); } +void xap_broadcast(uint8_t type, const void *data, size_t length) { + uint8_t rdata[XAP_EPSIZE] = {0}; + xap_broadcast_header_t *header = (xap_broadcast_header_t *)&rdata[0]; + header->token = XAP_BROADCAST_TOKEN; + header->type = type; + + if (length > (XAP_EPSIZE - sizeof(xap_broadcast_header_t))) return; + + header->length = (uint8_t)length; + if (data != NULL) { + memcpy(&rdata[sizeof(xap_broadcast_header_t)], data, length); + } + xap_send_base(rdata, sizeof(rdata)); +} + void xap_receive_base(const void *data) { const uint8_t * u8data = (const uint8_t *)data; xap_request_header_t *header = (xap_request_header_t *)&u8data[0]; diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index 49d59f1574..f8375de369 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -204,7 +204,7 @@ void xap_send_base(uint8_t *data, uint8_t length) { usbSetInterrupt4(0, 0); } -void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_t length) { +void xap_send(xap_token_t token, xap_response_flags_t response_flags, const void *data, size_t length) { uint8_t rdata[XAP_BUFFER_SIZE] = {0}; xap_response_header_t *header = (xap_response_header_t *)&rdata[0]; header->token = token; @@ -221,6 +221,21 @@ void xap_send(xap_token_t token, uint8_t response_flags, const void *data, size_ xap_send_base(rdata, sizeof(rdata)); } +void xap_broadcast(uint8_t type, const void *data, size_t length) { + uint8_t rdata[XAP_BUFFER_SIZE] = {0}; + xap_broadcast_header_t *header = (xap_broadcast_header_t *)&rdata[0]; + header->token = XAP_BROADCAST_TOKEN; + header->type = type; + + if (length > (XAP_BUFFER_SIZE - sizeof(xap_broadcast_header_t))) return; + + header->length = (uint8_t)length; + if (data != NULL) { + memcpy(&rdata[sizeof(xap_broadcast_header_t)], data, length); + } + xap_send_base(rdata, sizeof(rdata)); +} + void xap_receive_base(const void *data) { const uint8_t * u8data = (const uint8_t *)data; xap_request_header_t *header = (xap_request_header_t *)&u8data[0];