mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
modtrezormsg: WIP python USB API
This commit is contained in:
parent
03aac60681
commit
46f748205d
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) Pavol Rusnak, SatoshiLabs
|
||||
* Copyright (c) Pavol Rusnak, Jan Pochyla, SatoshiLabs
|
||||
*
|
||||
* Licensed under TREZOR License
|
||||
* see LICENSE file for details
|
||||
@ -17,18 +17,259 @@
|
||||
|
||||
#if defined TREZOR_STM32
|
||||
#include "modtrezormsg-stm32.h"
|
||||
#include "pendsv.h"
|
||||
#elif defined TREZOR_UNIX
|
||||
#include "modtrezormsg-unix.h"
|
||||
#else
|
||||
#error Unsupported TREZOR port. Only STM32 and UNIX ports are supported.
|
||||
#endif
|
||||
|
||||
#define MAX_INTERFACES 8
|
||||
typedef struct _mp_obj_USB_t {
|
||||
mp_obj_base_t base;
|
||||
usb_dev_info_t info;
|
||||
} mp_obj_USB_t;
|
||||
|
||||
static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) {
|
||||
size_t len;
|
||||
const char *s = mp_obj_str_get_data(o, &len);
|
||||
if ((s != NULL) && (len >= min_len) && (len <= max_len)) {
|
||||
return s;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_TrezorMsg_USB_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_vendor_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_product_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_release_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_manufacturer_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_product_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_serial_number_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_configuration_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_interface_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
|
||||
|
||||
const mp_int_t vendor_id = vals[0].u_int;
|
||||
const mp_int_t product_id = vals[1].u_int;
|
||||
const mp_int_t release_num = vals[2].u_int;
|
||||
const char *manufacturer_str = get_0str(vals[3].u_obj, 1, 32);
|
||||
const char *product_str = get_0str(vals[4].u_obj, 1, 32);
|
||||
const char *serial_number_str = get_0str(vals[5].u_obj, 1, 32);
|
||||
const char *configuration_str = get_0str(vals[6].u_obj, 1, 32);
|
||||
const char *interface_str = get_0str(vals[7].u_obj, 1, 32);
|
||||
|
||||
if (vendor_id < 0 || vendor_id > 65535) {
|
||||
mp_raise_ValueError("vendor_id is invalid");
|
||||
}
|
||||
if (product_id < 0 || product_id > 65535) {
|
||||
mp_raise_ValueError("product_id is invalid");
|
||||
}
|
||||
if (manufacturer_str == NULL) {
|
||||
mp_raise_ValueError("manufacturer_str is invalid");
|
||||
}
|
||||
if (product_str == NULL) {
|
||||
mp_raise_ValueError("product_str is invalid");
|
||||
}
|
||||
if (serial_number_str == NULL) {
|
||||
mp_raise_ValueError("serial_number_str is invalid");
|
||||
}
|
||||
if (configuration_str == NULL) {
|
||||
mp_raise_ValueError("configuration_str is invalid");
|
||||
}
|
||||
if (interface_str == NULL) {
|
||||
mp_raise_ValueError("interface_str is invalid");
|
||||
}
|
||||
|
||||
mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t);
|
||||
o->base.type = type;
|
||||
|
||||
o->info.vendor_id = (uint16_t)(vendor_id);
|
||||
o->info.product_id = (uint16_t)(product_id);
|
||||
o->info.release_num = (uint16_t)(release_num);
|
||||
o->info.manufacturer_str = (const uint8_t *)(manufacturer_str);
|
||||
o->info.product_str = (const uint8_t *)(product_str);
|
||||
o->info.serial_number_str = (const uint8_t *)(serial_number_str);
|
||||
o->info.configuration_str = (const uint8_t *)(configuration_str);
|
||||
o->info.interface_str = (const uint8_t *)(interface_str);
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t mod_TrezorMsg_USB_locals_dict_table[] = {};
|
||||
STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_USB_locals_dict, mod_TrezorMsg_USB_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t mod_TrezorMsg_USB_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_USB,
|
||||
.make_new = mod_TrezorMsg_USB_make_new,
|
||||
.locals_dict = (void*)&mod_TrezorMsg_USB_locals_dict,
|
||||
};
|
||||
|
||||
typedef struct _mp_obj_HID_t {
|
||||
mp_obj_base_t base;
|
||||
usb_hid_info_t info;
|
||||
} mp_obj_HID_t;
|
||||
|
||||
STATIC mp_obj_t mod_TrezorMsg_HID_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
|
||||
{ MP_QSTR_report_desc, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
|
||||
|
||||
const mp_int_t iface_num = vals[0].u_int;
|
||||
const mp_int_t ep_in = vals[1].u_int;
|
||||
const mp_int_t ep_out = vals[2].u_int;
|
||||
const mp_int_t subclass = vals[3].u_int;
|
||||
const mp_int_t protocol = vals[4].u_int;
|
||||
const mp_int_t polling_interval = vals[5].u_int;
|
||||
const mp_int_t max_packet_len = vals[6].u_int;
|
||||
mp_buffer_info_t report_desc;
|
||||
mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ);
|
||||
|
||||
if (report_desc.buf == NULL || report_desc.len == 0 || report_desc.len > 255) {
|
||||
mp_raise_ValueError("report_desc is invalid");
|
||||
}
|
||||
if (iface_num < 0 || iface_num > 32) {
|
||||
mp_raise_ValueError("iface_num is invalid");
|
||||
}
|
||||
if (ep_in < 0 || ep_in > 255) {
|
||||
mp_raise_ValueError("ep_in is invalid");
|
||||
}
|
||||
if (ep_out < 0 || ep_out > 255) {
|
||||
mp_raise_ValueError("ep_out is invalid");
|
||||
}
|
||||
if (subclass < 0 || subclass > 255) {
|
||||
mp_raise_ValueError("subclass is invalid");
|
||||
}
|
||||
if (protocol < 0 || protocol > 255) {
|
||||
mp_raise_ValueError("protocol is invalid");
|
||||
}
|
||||
if (polling_interval < 1 || polling_interval > 255) {
|
||||
mp_raise_ValueError("polling_interval is invalid");
|
||||
}
|
||||
if (max_packet_len != 64) {
|
||||
mp_raise_ValueError("max_packet_len is invalid");
|
||||
}
|
||||
|
||||
mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t);
|
||||
o->base.type = type;
|
||||
|
||||
o->info.rx_buffer = m_new(uint8_t, max_packet_len);
|
||||
o->info.report_desc = report_desc.buf;
|
||||
o->info.iface_num = (uint8_t)(iface_num);
|
||||
o->info.ep_in = (uint8_t)(ep_in);
|
||||
o->info.ep_out = (uint8_t)(ep_out);
|
||||
o->info.subclass = (uint8_t)(subclass);
|
||||
o->info.protocol = (uint8_t)(protocol);
|
||||
o->info.polling_interval = (uint8_t)(polling_interval);
|
||||
o->info.max_packet_len = (uint8_t)(max_packet_len);
|
||||
o->info.report_desc_len = (uint8_t)(report_desc.len);
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t mod_TrezorMsg_HID_locals_dict_table[] = {};
|
||||
STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_HID_locals_dict, mod_TrezorMsg_HID_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t mod_TrezorMsg_HID_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HID,
|
||||
.make_new = mod_TrezorMsg_HID_make_new,
|
||||
.locals_dict = (void*)&mod_TrezorMsg_HID_locals_dict,
|
||||
};
|
||||
|
||||
typedef struct _mp_obj_VCP_t {
|
||||
mp_obj_base_t base;
|
||||
usb_vcp_info_t info;
|
||||
} mp_obj_VCP_t;
|
||||
|
||||
STATIC mp_obj_t mod_TrezorMsg_VCP_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_data_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_ep_cmd, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
|
||||
|
||||
const mp_int_t iface_num = vals[0].u_int;
|
||||
const mp_int_t data_iface_num = vals[1].u_int;
|
||||
const mp_int_t ep_in = vals[2].u_int;
|
||||
const mp_int_t ep_out = vals[3].u_int;
|
||||
const mp_int_t ep_cmd = vals[4].u_int;
|
||||
|
||||
if (iface_num < 0 || iface_num > 32) {
|
||||
mp_raise_ValueError("iface_num is invalid");
|
||||
}
|
||||
if (data_iface_num < 0 || data_iface_num > 32) {
|
||||
mp_raise_ValueError("iface_num is invalid");
|
||||
}
|
||||
if (ep_in < 0 || ep_in > 255) {
|
||||
mp_raise_ValueError("ep_in is invalid");
|
||||
}
|
||||
if (ep_out < 0 || ep_out > 255) {
|
||||
mp_raise_ValueError("ep_out is invalid");
|
||||
}
|
||||
if (ep_cmd < 0 || ep_cmd > 255) {
|
||||
mp_raise_ValueError("ep_cmd is invalid");
|
||||
}
|
||||
|
||||
const size_t vcp_buffer_len = 1024;
|
||||
const size_t vcp_packet_len = 64;
|
||||
|
||||
mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t);
|
||||
o->base.type = type;
|
||||
|
||||
o->info.tx_packet = m_new(uint8_t, vcp_packet_len);
|
||||
o->info.tx_buffer = m_new(uint8_t, vcp_buffer_len);
|
||||
o->info.rx_packet = m_new(uint8_t, vcp_packet_len);
|
||||
o->info.rx_buffer = m_new(uint8_t, vcp_buffer_len);
|
||||
o->info.tx_buffer_len = vcp_buffer_len;
|
||||
o->info.rx_buffer_len = vcp_buffer_len;
|
||||
o->info.rx_intr_fn = pendsv_kbd_intr;
|
||||
o->info.rx_intr_byte = 3; // Ctrl-C
|
||||
o->info.iface_num = (uint8_t)(iface_num);
|
||||
o->info.data_iface_num = (uint8_t)(data_iface_num);
|
||||
o->info.ep_cmd = (uint8_t)(ep_cmd);
|
||||
o->info.ep_in = (uint8_t)(ep_in);
|
||||
o->info.ep_out = (uint8_t)(ep_out);
|
||||
o->info.polling_interval = 10;
|
||||
o->info.max_packet_len = (uint8_t)(vcp_packet_len);
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t mod_TrezorMsg_VCP_locals_dict_table[] = {};
|
||||
STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_VCP_locals_dict, mod_TrezorMsg_VCP_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t mod_TrezorMsg_VCP_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_VCP,
|
||||
.make_new = mod_TrezorMsg_VCP_make_new,
|
||||
.locals_dict = (void*)&mod_TrezorMsg_VCP_locals_dict,
|
||||
};
|
||||
|
||||
typedef struct _mp_obj_Msg_t {
|
||||
mp_obj_base_t base;
|
||||
uint16_t usage_pages[MAX_INTERFACES];
|
||||
mp_uint_t interface_count;
|
||||
mp_obj_t usb_info;
|
||||
mp_obj_t usb_ifaces;
|
||||
} mp_obj_Msg_t;
|
||||
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
@ -36,64 +277,74 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_make_new(const mp_obj_type_t *type, size_t n_a
|
||||
msg_init();
|
||||
mp_obj_Msg_t *o = m_new_obj(mp_obj_Msg_t);
|
||||
o->base.type = type;
|
||||
o->interface_count = 0;
|
||||
o->usb_info = mp_const_none;
|
||||
o->usb_ifaces = mp_const_none;
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
/// def trezor.msg.set_interfaces(ifaces: list/tuple) -> None:
|
||||
/// def trezor.msg.init_usb(usb_info, usb_ifaces) -> None:
|
||||
/// '''
|
||||
/// Configures USB interfaces with a list/tuple of (usage_page, ...)
|
||||
/// Registers passed interfaces and initializes the USB stack
|
||||
/// '''
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_set_interfaces(mp_obj_t self, mp_obj_t ifaces) {
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_init_usb(mp_obj_t self, mp_obj_t usb_info, mp_obj_t usb_ifaces) {
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(usb_info, &mod_TrezorMsg_USB_type)) {
|
||||
mp_raise_TypeError("Expected USB type");
|
||||
}
|
||||
mp_obj_USB_t *usb = MP_OBJ_TO_PTR(self);
|
||||
if (0 != usb_init(&usb->info)) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Failed to initialize USB layer");
|
||||
}
|
||||
|
||||
size_t iface_cnt;
|
||||
mp_obj_t *usage_pages;
|
||||
mp_obj_get_array(ifaces, &iface_cnt, &usage_pages);
|
||||
if (iface_cnt > MAX_INTERFACES) {
|
||||
mp_raise_ValueError("Maximum number of interfaces exceeded");
|
||||
}
|
||||
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
mp_obj_t *iface_objs;
|
||||
mp_obj_get_array(usb_ifaces, &iface_cnt, &iface_objs);
|
||||
|
||||
for (size_t i = 0; i < iface_cnt; i++) {
|
||||
uint16_t usage_page = mp_obj_get_int(usage_pages[i]);
|
||||
o->usage_pages[i] = usage_page;
|
||||
mp_obj_t iface = iface_objs[i];
|
||||
|
||||
if (MP_OBJ_IS_TYPE(iface, &mod_TrezorMsg_HID_type)) {
|
||||
mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface);
|
||||
if (0 != usb_hid_add(&hid->info)) {
|
||||
usb_deinit();
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Failed to add HID interface");
|
||||
}
|
||||
} else if (MP_OBJ_IS_TYPE(iface, &mod_TrezorMsg_VCP_type)) {
|
||||
mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface);
|
||||
if (0 != usb_vcp_add(&vcp->info)) {
|
||||
usb_deinit();
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Failed to add VCP interface");
|
||||
}
|
||||
} else {
|
||||
usb_deinit();
|
||||
mp_raise_TypeError("Unknown interface type");
|
||||
}
|
||||
}
|
||||
o->interface_count = iface_cnt;
|
||||
|
||||
if (0 != usb_start()) {
|
||||
usb_deinit();
|
||||
mp_raise_msg(&mp_type_RuntimeError, "Failed to start USB layer");
|
||||
}
|
||||
|
||||
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
o->usb_info = usb_info;
|
||||
o->usb_ifaces = usb_ifaces;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorMsg_Msg_set_interfaces_obj, mod_TrezorMsg_Msg_set_interfaces);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_init_usb_obj, mod_TrezorMsg_Msg_init_usb);
|
||||
|
||||
/// def trezor.msg.get_interfaces() -> tuple:
|
||||
/// '''
|
||||
/// Reads a tuple (of usage pages) of configured USB interfaces
|
||||
/// '''
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_get_interfaces(mp_obj_t self) {
|
||||
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->interface_count, NULL));
|
||||
for (mp_uint_t i = 0; i < o->interface_count; i++) {
|
||||
tuple->items[i] = MP_OBJ_NEW_SMALL_INT(o->usage_pages[i]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorMsg_Msg_get_interfaces_obj, mod_TrezorMsg_Msg_get_interfaces);
|
||||
|
||||
/// def trezor.msg.send(usage_page: int, message: bytes) -> int:
|
||||
/// def trezor.msg.send(iface: int, message: bytes) -> int:
|
||||
/// '''
|
||||
/// Sends message using USB HID (device) or UDP (emulator).
|
||||
/// '''
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_send(mp_obj_t self, mp_obj_t usage_page, mp_obj_t message) {
|
||||
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
if (o->interface_count == 0) {
|
||||
mp_raise_TypeError("No interfaces registered");
|
||||
}
|
||||
uint16_t up = mp_obj_get_int(usage_page);
|
||||
for (uint8_t i = 0; i < o->interface_count; i++) {
|
||||
if (o->usage_pages[i] == up) {
|
||||
mp_buffer_info_t msg;
|
||||
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
|
||||
ssize_t r = msg_send(i, msg.buf, msg.len);
|
||||
return MP_OBJ_NEW_SMALL_INT(r);
|
||||
}
|
||||
}
|
||||
mp_raise_TypeError("Interface not found");
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_send(mp_obj_t self, mp_obj_t iface, mp_obj_t message) {
|
||||
// mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
uint8_t i = mp_obj_get_int(iface);
|
||||
mp_buffer_info_t msg;
|
||||
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ);
|
||||
ssize_t r = msg_send(i, msg.buf, msg.len);
|
||||
return MP_OBJ_NEW_SMALL_INT(r);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_send_obj, mod_TrezorMsg_Msg_send);
|
||||
|
||||
@ -107,12 +358,12 @@ extern uint32_t touch_read(void); // defined in HAL
|
||||
/// Function returns None if timeout specified in microseconds is reached.
|
||||
/// '''
|
||||
STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) {
|
||||
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
// mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
||||
int timeout = mp_obj_get_int(timeout_us);
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
uint32_t e = touch_read();
|
||||
if (e) {
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
|
||||
@ -122,23 +373,19 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) {
|
||||
tuple->items[3] = MP_OBJ_NEW_SMALL_INT((e & 0xFF)); // y position
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
// check for interfaces only when some have been registered
|
||||
if (o->interface_count > 0) {
|
||||
uint8_t iface;
|
||||
uint8_t recvbuf[64];
|
||||
ssize_t l = msg_recv(&iface, recvbuf, 64);
|
||||
if (l > 0 && iface < o->interface_count) {
|
||||
if (l == 8 && memcmp("PINGPING", recvbuf, 8) == 0) {
|
||||
msg_send(iface, (const uint8_t *)"PONGPONG", 8);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
uint16_t iface_usage_page = o->usage_pages[iface];
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(iface_usage_page);
|
||||
tuple->items[1] = mp_obj_new_str_of_type(&mp_type_bytes, recvbuf, l);
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
}
|
||||
uint8_t iface;
|
||||
uint8_t recvbuf[64];
|
||||
ssize_t l = msg_recv(&iface, recvbuf, 64);
|
||||
if (l > 0) {
|
||||
if (l == 8 && memcmp("PINGPING", recvbuf, 8) == 0) {
|
||||
msg_send(iface, (const uint8_t *)"PONGPONG", 8);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(iface);
|
||||
tuple->items[1] = mp_obj_new_str_of_type(&mp_type_bytes, recvbuf, l);
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
}
|
||||
if (timeout <= 0) {
|
||||
break;
|
||||
@ -151,10 +398,10 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorMsg_Msg_select_obj, mod_TrezorMsg_Msg_select);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mod_TrezorMsg_Msg_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mod_TrezorMsg_Msg_select_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_init_usb_obj) },
|
||||
// { MP_ROM_QSTR(MP_QSTR_deinit_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_deinit_usb_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&mod_TrezorMsg_Msg_send_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_interfaces), MP_ROM_PTR(&mod_TrezorMsg_Msg_set_interfaces_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_interfaces), MP_ROM_PTR(&mod_TrezorMsg_Msg_get_interfaces_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mod_TrezorMsg_Msg_select_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_Msg_locals_dict, mod_TrezorMsg_Msg_locals_dict_table);
|
||||
|
||||
@ -167,9 +414,11 @@ STATIC const mp_obj_type_t mod_TrezorMsg_Msg_type = {
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_TrezorMsg_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_TrezorMsg) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_TrezorMsg_USB_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_TrezorMsg_HID_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_VCP), MP_ROM_PTR(&mod_TrezorMsg_VCP_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Msg), MP_ROM_PTR(&mod_TrezorMsg_Msg_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_TrezorMsg_globals, mp_module_TrezorMsg_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_TrezorMsg = {
|
||||
|
@ -131,9 +131,9 @@ int main(void) {
|
||||
__fatal_error("touch_init failed");
|
||||
}
|
||||
|
||||
if (0 != usb_init_all()) {
|
||||
__fatal_error("usb_init_all failed");
|
||||
}
|
||||
// if (0 != usb_init_all()) {
|
||||
// __fatal_error("usb_init_all failed");
|
||||
// }
|
||||
|
||||
for (;;) {
|
||||
// Stack limit should be less than real stack size, so we have a chance
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#define VCP_IFACE 0x01
|
||||
#define VCP_READ_TIMEOUT 25
|
||||
#define VCP_WRITE_TIMEOUT 5
|
||||
#define VCP_WRITE_TIMEOUT 0
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
uint8_t c = 0;
|
||||
|
@ -83,12 +83,9 @@ int usb_init(const usb_dev_info_t *dev_info) {
|
||||
usb_config_desc->bmAttributes = 0x80; // 0x80 = bus powered; 0xc0 = self powered
|
||||
usb_config_desc->bMaxPower = 0xfa; // Maximum Power Consumption in 2mA units
|
||||
|
||||
// Reset pointer to interface descriptor data
|
||||
// Pointer to interface descriptor data
|
||||
usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength);
|
||||
|
||||
// Reset the iface state map
|
||||
memset(&usb_ifaces, 0, sizeof(usb_ifaces));
|
||||
|
||||
if (0 != USBD_Init(&usb_dev_handle, (USBD_DescriptorsTypeDef*)&usb_descriptors, USB_PHY_FS_ID)) {
|
||||
return 1;
|
||||
}
|
||||
|
46
src/main.py
46
src/main.py
@ -10,6 +10,7 @@ from apps import homescreen
|
||||
from apps import management
|
||||
from apps import wallet
|
||||
from apps import ethereum
|
||||
from apps import fido_u2f
|
||||
|
||||
# Initialize all applications
|
||||
if __debug__:
|
||||
@ -18,6 +19,7 @@ homescreen.boot()
|
||||
management.boot()
|
||||
wallet.boot()
|
||||
ethereum.boot()
|
||||
fido_u2f.boot()
|
||||
|
||||
# HACK: keep storage loaded at all times
|
||||
from apps.common import storage
|
||||
@ -25,14 +27,46 @@ from apps.common import storage
|
||||
# Change backlight to white for better visibility
|
||||
ui.display.backlight(ui.BACKLIGHT_NORMAL)
|
||||
|
||||
# Just a demo to show how to register USB ifaces
|
||||
msg.set_interfaces([0xFF00, 0xFF01, 0xF1D0])
|
||||
# and list them
|
||||
for i, up in enumerate(msg.get_interfaces()):
|
||||
print("iface %d: usage_page 0x%04x" % (i + 1, up))
|
||||
# Register USB ifaces
|
||||
usb = msg.USB(
|
||||
vendor_id=0x1209,
|
||||
product_id=0x53C1,
|
||||
release_num=0x0002,
|
||||
manufacturer_str="manufacturer_str",
|
||||
product_str="product_str",
|
||||
serial_number_str="serial_number_str",
|
||||
configuration_str="configuration_str",
|
||||
interface_str="interface_str",
|
||||
)
|
||||
hid_wire_iface = const(0x00)
|
||||
hid_wire_rdesc = bytes([
|
||||
0x06, 0x00, 0xff, # USAGE_PAGE (Vendor Defined)
|
||||
0x09, 0x01, # USAGE (1)
|
||||
0xa1, 0x01, # COLLECTION (Application)
|
||||
0x09, 0x20, # USAGE (Input Report Data)
|
||||
0x15, 0x00, # LOGICAL_MINIMUM (0)
|
||||
0x26, 0xff, 0x00, # LOGICAL_MAXIMUM (255)
|
||||
0x75, 0x08, # REPORT_SIZE (8)
|
||||
0x95, 0x40, # REPORT_COUNT (64)
|
||||
0x81, 0x02, # INPUT (Data,Var,Abs)
|
||||
0x09, 0x21, # USAGE (Output Report Data)
|
||||
0x15, 0x00, # LOGICAL_MINIMUM (0)
|
||||
0x26, 0xff, 0x00, # LOGICAL_MAXIMUM (255)
|
||||
0x75, 0x08, # REPORT_SIZE (8)
|
||||
0x95, 0x40, # REPORT_COUNT (64)
|
||||
0x91, 0x02, # OUTPUT (Data,Var,Abs)
|
||||
0xc0, # END_COLLECTION
|
||||
])
|
||||
hid_wire = msg.HID(
|
||||
iface_num=hid_wire_iface,
|
||||
ep_in=0x81,
|
||||
ep_out=0x01,
|
||||
report_desc=hid_wire_rdesc,
|
||||
)
|
||||
msg.init_usb(usb, (hid_wire,))
|
||||
|
||||
# Initialize the wire codec pipeline
|
||||
wire.setup(0xFF00)
|
||||
wire.setup(hid_wire_iface)
|
||||
|
||||
# Load default homescreen
|
||||
from apps.homescreen.homescreen import layout_homescreen
|
||||
|
Loading…
Reference in New Issue
Block a user