summaryrefslogtreecommitdiff
path: root/ports/stm32/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/stm32/usb.c')
-rw-r--r--ports/stm32/usb.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 5003bb27c..eba95de49 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -39,6 +39,7 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "lib/utils/mpirq.h"
#include "bufhelper.h"
#include "storage.h"
#include "sdcard.h"
@@ -70,6 +71,9 @@
#define MAX_ENDPOINT(dev_id) (8)
#endif
+// Constants for USB_VCP.irq trigger.
+#define USBD_CDC_IRQ_RX (1)
+
STATIC void pyb_usb_vcp_init0(void);
// this will be persistent across a soft-reset
@@ -219,6 +223,7 @@ const mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj = {
void pyb_usb_init0(void) {
for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) {
+ usb_device.usbd_cdc_itf[i].cdc_idx = i;
usb_device.usbd_cdc_itf[i].attached_to_repl = false;
}
#if MICROPY_HW_USB_HID
@@ -644,14 +649,42 @@ const pyb_usb_vcp_obj_t pyb_usb_vcp_obj[MICROPY_HW_USB_CDC_NUM] = {
#endif
};
+STATIC bool pyb_usb_vcp_irq_scheduled[MICROPY_HW_USB_CDC_NUM];
+
STATIC void pyb_usb_vcp_init0(void) {
+ for (size_t i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) {
+ MP_STATE_PORT(pyb_usb_vcp_irq)[i] = mp_const_none;
+ pyb_usb_vcp_irq_scheduled[i] = false;
+ }
+
// Activate USB_VCP(0) on dupterm slot 1 for the REPL
MP_STATE_VM(dupterm_objs[1]) = MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj[0]);
usb_vcp_attach_to_repl(&pyb_usb_vcp_obj[0], true);
}
+STATIC mp_obj_t pyb_usb_vcp_irq_run(mp_obj_t self_in) {
+ pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint8_t idx = self->cdc_itf->cdc_idx;
+ mp_obj_t callback = MP_STATE_PORT(pyb_usb_vcp_irq)[idx];
+ pyb_usb_vcp_irq_scheduled[idx] = false;
+ if (callback != mp_const_none && usbd_cdc_rx_num(self->cdc_itf)) {
+ mp_call_function_1(callback, self_in);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_irq_run_obj, pyb_usb_vcp_irq_run);
+
+void usbd_cdc_rx_event_callback(usbd_cdc_itf_t *cdc) {
+ uint8_t idx = cdc->cdc_idx;
+ mp_obj_t self = MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj[idx]);
+ mp_obj_t callback = MP_STATE_PORT(pyb_usb_vcp_irq)[idx];
+ if (callback != mp_const_none && !pyb_usb_vcp_irq_scheduled[idx]) {
+ pyb_usb_vcp_irq_scheduled[idx] = mp_sched_schedule(MP_OBJ_FROM_PTR(&pyb_usb_vcp_irq_run_obj), self);
+ }
+}
+
STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- int id = ((pyb_usb_vcp_obj_t *)MP_OBJ_TO_PTR(self_in))->cdc_itf - &usb_device.usbd_cdc_itf[0];
+ int id = ((pyb_usb_vcp_obj_t *)MP_OBJ_TO_PTR(self_in))->cdc_itf->cdc_idx;
mp_printf(print, "USB_VCP(%u)", id);
}
@@ -796,6 +829,40 @@ STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t *
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_recv_obj, 1, pyb_usb_vcp_recv);
+// irq(handler=None, trigger=0, hard=False)
+STATIC mp_obj_t pyb_usb_vcp_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
+ pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ if (n_args > 1 || kw_args->used != 0) {
+ // Check the handler.
+ mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
+ if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable"));
+ }
+
+ // Check the trigger.
+ mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
+ if (trigger == 0) {
+ handler = mp_const_none;
+ } else if (trigger != USBD_CDC_IRQ_RX) {
+ mp_raise_ValueError(MP_ERROR_TEXT("unsupported trigger"));
+ }
+
+ // Check hard/soft.
+ if (args[MP_IRQ_ARG_INIT_hard].u_bool) {
+ mp_raise_ValueError(MP_ERROR_TEXT("hard unsupported"));
+ }
+
+ // Reconfigure the IRQ.
+ MP_STATE_PORT(pyb_usb_vcp_irq)[self->cdc_itf->cdc_idx] = handler;
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_irq_obj, 1, pyb_usb_vcp_irq);
+
mp_obj_t pyb_usb_vcp___exit__(size_t n_args, const mp_obj_t *args) {
return mp_const_none;
}
@@ -814,6 +881,7 @@ STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_usb_vcp_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pyb_usb_vcp___exit___obj) },
@@ -821,6 +889,7 @@ STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = {
// class constants
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(USBD_CDC_FLOWCONTROL_RTS) },
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(USBD_CDC_FLOWCONTROL_CTS) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(USBD_CDC_IRQ_RX) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_table);