2016-04-04 14:12:13 +00:00
|
|
|
/*
|
2017-04-19 15:10:17 +00:00
|
|
|
* Copyright (c) Pavol Rusnak, Jan Pochyla, SatoshiLabs
|
2016-04-04 14:12:13 +00:00
|
|
|
*
|
2016-05-28 12:37:32 +00:00
|
|
|
* Licensed under TREZOR License
|
|
|
|
* see LICENSE file for details
|
2016-04-04 14:12:13 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include "py/runtime.h"
|
2016-04-29 01:15:18 +00:00
|
|
|
#include "py/mphal.h"
|
2016-10-07 11:57:21 +00:00
|
|
|
#include "py/objstr.h"
|
2016-04-04 14:12:13 +00:00
|
|
|
|
|
|
|
#if MICROPY_PY_TREZORMSG
|
|
|
|
|
2017-04-17 15:57:42 +00:00
|
|
|
#if defined TREZOR_STM32
|
|
|
|
#include "modtrezormsg-stm32.h"
|
2017-04-19 15:10:17 +00:00
|
|
|
#include "pendsv.h"
|
2017-04-17 15:57:42 +00:00
|
|
|
#elif defined TREZOR_UNIX
|
2016-04-29 01:15:18 +00:00
|
|
|
#include "modtrezormsg-unix.h"
|
|
|
|
#else
|
2017-04-17 15:57:42 +00:00
|
|
|
#error Unsupported TREZOR port. Only STM32 and UNIX ports are supported.
|
2016-04-29 01:15:18 +00:00
|
|
|
#endif
|
2016-04-04 14:12:13 +00:00
|
|
|
|
2017-05-09 14:10:27 +00:00
|
|
|
/*
|
|
|
|
* USB HID interface configuration
|
|
|
|
*/
|
2017-04-19 15:10:17 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2017-05-09 14:10:27 +00:00
|
|
|
/*
|
|
|
|
* USB VCP interface configuration
|
|
|
|
*/
|
|
|
|
|
2017-04-19 15:10:17 +00:00
|
|
|
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,
|
|
|
|
};
|
2016-10-11 10:33:02 +00:00
|
|
|
|
2017-05-09 14:10:27 +00:00
|
|
|
/*
|
|
|
|
* USB device configuration
|
|
|
|
*/
|
|
|
|
|
|
|
|
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 ((len >= min_len) && (len <= max_len)) {
|
|
|
|
if (len == 0 && s == NULL) {
|
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
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_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
|
|
|
|
{ MP_QSTR_interface_str, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
|
|
|
|
};
|
|
|
|
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, 0, 32);
|
|
|
|
const char *product_str = get_0str(vals[4].u_obj, 0, 32);
|
|
|
|
const char *serial_number_str = get_0str(vals[5].u_obj, 0, 32);
|
|
|
|
const char *configuration_str = get_0str(vals[6].u_obj, 0, 32);
|
|
|
|
const char *interface_str = get_0str(vals[7].u_obj, 0, 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,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Msg class
|
|
|
|
*/
|
|
|
|
|
2016-04-04 14:12:13 +00:00
|
|
|
typedef struct _mp_obj_Msg_t {
|
|
|
|
mp_obj_base_t base;
|
2017-04-19 15:10:17 +00:00
|
|
|
mp_obj_t usb_info;
|
|
|
|
mp_obj_t usb_ifaces;
|
2016-04-04 14:12:13 +00:00
|
|
|
} 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) {
|
2016-04-15 19:13:27 +00:00
|
|
|
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
2016-04-29 01:15:18 +00:00
|
|
|
msg_init();
|
2016-04-04 14:12:13 +00:00
|
|
|
mp_obj_Msg_t *o = m_new_obj(mp_obj_Msg_t);
|
|
|
|
o->base.type = type;
|
2017-04-19 15:10:17 +00:00
|
|
|
o->usb_info = mp_const_none;
|
|
|
|
o->usb_ifaces = mp_const_none;
|
2016-04-04 14:12:13 +00:00
|
|
|
return MP_OBJ_FROM_PTR(o);
|
|
|
|
}
|
|
|
|
|
2017-04-19 15:10:17 +00:00
|
|
|
/// def trezor.msg.init_usb(usb_info, usb_ifaces) -> None:
|
2016-06-06 08:18:55 +00:00
|
|
|
/// '''
|
2017-04-19 15:10:17 +00:00
|
|
|
/// Registers passed interfaces and initializes the USB stack
|
2016-06-06 08:18:55 +00:00
|
|
|
/// '''
|
2017-04-19 15:10:17 +00:00
|
|
|
STATIC mp_obj_t mod_TrezorMsg_Msg_init_usb(mp_obj_t self, mp_obj_t usb_info, mp_obj_t usb_ifaces) {
|
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
|
|
|
if (o->usb_info != mp_const_none || o->usb_ifaces != mp_const_none) {
|
|
|
|
mp_raise_msg(&mp_type_RuntimeError, "already initialized");
|
2017-04-19 15:10:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t iface_cnt;
|
|
|
|
mp_obj_t *iface_objs;
|
|
|
|
mp_obj_get_array(usb_ifaces, &iface_cnt, &iface_objs);
|
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
// Initialize the USB stack
|
|
|
|
if (MP_OBJ_IS_TYPE(usb_info, &mod_TrezorMsg_USB_type)) {
|
|
|
|
mp_obj_USB_t *usb = MP_OBJ_TO_PTR(usb_info);
|
|
|
|
if (usb_init(&usb->info) != 0) {
|
|
|
|
mp_raise_msg(&mp_type_RuntimeError, "failed to initialize USB");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mp_raise_TypeError("expected USB type");
|
|
|
|
}
|
|
|
|
|
2017-05-09 14:10:27 +00:00
|
|
|
int vcp_iface_num = -1;
|
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
// Add all interfaces
|
2017-04-06 16:36:30 +00:00
|
|
|
for (size_t i = 0; i < iface_cnt; i++) {
|
2017-04-19 15:10:17 +00:00
|
|
|
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);
|
2017-04-21 12:22:51 +00:00
|
|
|
if (usb_hid_add(&hid->info) != 0) {
|
2017-04-19 15:10:17 +00:00
|
|
|
usb_deinit();
|
2017-04-21 12:22:51 +00:00
|
|
|
mp_raise_msg(&mp_type_RuntimeError, "failed to add HID interface");
|
2017-04-19 15:10:17 +00:00
|
|
|
}
|
|
|
|
} else if (MP_OBJ_IS_TYPE(iface, &mod_TrezorMsg_VCP_type)) {
|
|
|
|
mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface);
|
2017-04-21 12:22:51 +00:00
|
|
|
if (usb_vcp_add(&vcp->info) != 0) {
|
2017-04-19 15:10:17 +00:00
|
|
|
usb_deinit();
|
2017-04-21 12:22:51 +00:00
|
|
|
mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface");
|
2017-04-19 15:10:17 +00:00
|
|
|
}
|
2017-05-09 14:10:27 +00:00
|
|
|
vcp_iface_num = vcp->info.iface_num;
|
2017-04-19 15:10:17 +00:00
|
|
|
} else {
|
|
|
|
usb_deinit();
|
2017-04-21 12:22:51 +00:00
|
|
|
mp_raise_TypeError("expected HID or VCP type");
|
2017-04-19 15:10:17 +00:00
|
|
|
}
|
2016-05-25 00:38:10 +00:00
|
|
|
}
|
2016-10-11 10:33:02 +00:00
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
// Start the USB stack
|
|
|
|
if (usb_start() != 0) {
|
2017-04-19 15:10:17 +00:00
|
|
|
usb_deinit();
|
2017-04-21 12:22:51 +00:00
|
|
|
mp_raise_msg(&mp_type_RuntimeError, "failed to start USB");
|
2016-10-11 10:33:02 +00:00
|
|
|
}
|
2017-04-19 15:10:17 +00:00
|
|
|
|
2017-05-09 14:10:27 +00:00
|
|
|
// If we found any VCP interfaces, use the last one for stdio,
|
|
|
|
// otherwise disable the stdio support
|
|
|
|
mp_hal_set_vcp_iface(vcp_iface_num);
|
|
|
|
|
2017-04-19 15:10:17 +00:00
|
|
|
o->usb_info = usb_info;
|
|
|
|
o->usb_ifaces = usb_ifaces;
|
|
|
|
|
|
|
|
return mp_const_none;
|
2016-10-11 10:33:02 +00:00
|
|
|
}
|
2017-04-19 15:10:17 +00:00
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_init_usb_obj, mod_TrezorMsg_Msg_init_usb);
|
2016-05-25 00:38:10 +00:00
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
/// def trezor.msg.deinit_usb() -> None:
|
|
|
|
/// '''
|
|
|
|
/// Cleans up the USB stack
|
|
|
|
/// '''
|
|
|
|
STATIC mp_obj_t mod_TrezorMsg_Msg_deinit_usb(mp_obj_t self) {
|
|
|
|
|
|
|
|
usb_stop();
|
|
|
|
usb_deinit();
|
|
|
|
|
|
|
|
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
|
|
|
o->usb_info = mp_const_none;
|
|
|
|
o->usb_ifaces = mp_const_none;
|
|
|
|
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorMsg_Msg_deinit_usb_obj, mod_TrezorMsg_Msg_deinit_usb);
|
|
|
|
|
2017-04-19 15:10:17 +00:00
|
|
|
/// def trezor.msg.send(iface: int, message: bytes) -> int:
|
2016-06-06 08:18:55 +00:00
|
|
|
/// '''
|
|
|
|
/// Sends message using USB HID (device) or UDP (emulator).
|
|
|
|
/// '''
|
2017-04-19 15:10:17 +00:00
|
|
|
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);
|
2016-04-04 14:12:13 +00:00
|
|
|
}
|
2016-05-23 15:53:42 +00:00
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_send_obj, mod_TrezorMsg_Msg_send);
|
2016-04-04 14:12:13 +00:00
|
|
|
|
2016-04-29 12:49:47 +00:00
|
|
|
#define TICK_RESOLUTION 1000
|
2017-05-09 14:11:32 +00:00
|
|
|
#define TOUCH_IFACE 255
|
2017-03-16 18:14:12 +00:00
|
|
|
extern uint32_t touch_read(void); // defined in HAL
|
2016-04-29 12:49:47 +00:00
|
|
|
|
2016-09-23 15:25:34 +00:00
|
|
|
/// def trezor.msg.select(timeout_us: int) -> tuple:
|
2016-06-06 08:18:55 +00:00
|
|
|
/// '''
|
|
|
|
/// Polls the event queue and returns the event object.
|
|
|
|
/// Function returns None if timeout specified in microseconds is reached.
|
|
|
|
/// '''
|
2016-04-29 12:49:47 +00:00
|
|
|
STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) {
|
2017-04-19 15:10:17 +00:00
|
|
|
// mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
2016-05-02 16:55:32 +00:00
|
|
|
int timeout = mp_obj_get_int(timeout_us);
|
|
|
|
if (timeout < 0) {
|
|
|
|
timeout = 0;
|
2016-04-29 12:49:47 +00:00
|
|
|
}
|
2017-04-19 15:10:17 +00:00
|
|
|
for (;;) {
|
2017-03-16 18:14:12 +00:00
|
|
|
uint32_t e = touch_read();
|
2016-04-29 01:15:18 +00:00
|
|
|
if (e) {
|
2016-05-30 14:29:06 +00:00
|
|
|
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
|
|
|
|
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(TOUCH_IFACE);
|
|
|
|
tuple->items[1] = MP_OBJ_NEW_SMALL_INT((e & 0xFF0000) >> 16); // event type
|
|
|
|
tuple->items[2] = MP_OBJ_NEW_SMALL_INT((e & 0xFF00) >> 8); // x position
|
|
|
|
tuple->items[3] = MP_OBJ_NEW_SMALL_INT((e & 0xFF)); // y position
|
2016-04-29 01:15:18 +00:00
|
|
|
return MP_OBJ_FROM_PTR(tuple);
|
|
|
|
}
|
2017-04-19 15:10:17 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-10-11 11:13:14 +00:00
|
|
|
}
|
2016-05-02 16:55:32 +00:00
|
|
|
if (timeout <= 0) {
|
2016-04-29 15:29:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-08 00:26:09 +00:00
|
|
|
mp_hal_delay_us(TICK_RESOLUTION);
|
2016-05-02 16:55:32 +00:00
|
|
|
timeout -= TICK_RESOLUTION;
|
2016-04-29 01:15:18 +00:00
|
|
|
}
|
2016-04-04 14:12:13 +00:00
|
|
|
return mp_const_none;
|
|
|
|
}
|
2016-04-29 01:15:18 +00:00
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorMsg_Msg_select_obj, mod_TrezorMsg_Msg_select);
|
2016-04-04 14:12:13 +00:00
|
|
|
|
2017-04-21 12:22:51 +00:00
|
|
|
STATIC mp_obj_t mod_TrezorMsg_Msg___del__(mp_obj_t self) {
|
|
|
|
mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self);
|
|
|
|
if (o->usb_info != mp_const_none || o->usb_ifaces != mp_const_none) {
|
|
|
|
usb_stop();
|
|
|
|
usb_deinit();
|
|
|
|
}
|
|
|
|
return mp_const_none;
|
|
|
|
}
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorMsg_Msg___del___obj, mod_TrezorMsg_Msg___del__);
|
|
|
|
|
2016-04-04 14:12:13 +00:00
|
|
|
STATIC const mp_rom_map_elem_t mod_TrezorMsg_Msg_locals_dict_table[] = {
|
2017-04-21 12:22:51 +00:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_TrezorMsg_Msg___del___obj) },
|
2017-04-19 15:10:17 +00:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_init_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_init_usb_obj) },
|
2017-04-21 12:22:51 +00:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_deinit_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_deinit_usb_obj) },
|
2016-04-04 14:12:13 +00:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&mod_TrezorMsg_Msg_send_obj) },
|
2017-04-19 15:10:17 +00:00
|
|
|
{ MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mod_TrezorMsg_Msg_select_obj) },
|
2016-04-04 14:12:13 +00:00
|
|
|
};
|
|
|
|
STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_Msg_locals_dict, mod_TrezorMsg_Msg_locals_dict_table);
|
|
|
|
|
|
|
|
STATIC const mp_obj_type_t mod_TrezorMsg_Msg_type = {
|
|
|
|
{ &mp_type_type },
|
|
|
|
.name = MP_QSTR_Msg,
|
|
|
|
.make_new = mod_TrezorMsg_Msg_make_new,
|
|
|
|
.locals_dict = (void*)&mod_TrezorMsg_Msg_locals_dict,
|
|
|
|
};
|
|
|
|
|
|
|
|
STATIC const mp_rom_map_elem_t mp_module_TrezorMsg_globals_table[] = {
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_TrezorMsg) },
|
2017-04-19 15:10:17 +00:00
|
|
|
{ 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) },
|
2016-04-04 14:12:13 +00:00
|
|
|
{ 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 = {
|
|
|
|
.base = { &mp_type_module },
|
|
|
|
.globals = (mp_obj_dict_t*)&mp_module_TrezorMsg_globals,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // MICROPY_PY_TREZORMSG
|