Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions extmod/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include "extmod/modmachine.h"
#include "shared/runtime/pyexec.h"

#if MICROPY_HW_USB_CDC_STREAM
#include "shared/tinyusb/mp_usbd_cdc.h"
#endif

#if MICROPY_PY_MACHINE_DHT_READINTO
#include "drivers/dht/dht.h"
#endif
Expand Down Expand Up @@ -237,6 +241,9 @@ static const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
{ MP_ROM_QSTR(MP_QSTR_USBDevice), MP_ROM_PTR(&machine_usb_device_type) },
#endif
#if MICROPY_HW_USB_CDC_STREAM
{ MP_ROM_QSTR(MP_QSTR_USBD_CDC), MP_ROM_PTR(&machine_usbd_cdc_type) },
#endif
#if MICROPY_PY_MACHINE_WDT
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
#endif
Expand Down
4 changes: 4 additions & 0 deletions ports/stm32/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#if MICROPY_HW_TINYUSB_STACK
#include "usbd_conf.h"
#include "shared/tinyusb/mp_usbd.h"
#include "shared/tinyusb/mp_usbd_cdc.h"
#endif

#if MICROPY_PY_THREAD
Expand Down Expand Up @@ -687,6 +688,9 @@ void stm32_main(uint32_t reset_mode) {

#if MICROPY_HW_TINYUSB_STACK && MICROPY_HW_ENABLE_USBDEV
mp_usbd_init();
#if MICROPY_HW_USB_CDC_STREAM
MP_STATE_VM(dupterm_objs[1]) = MP_OBJ_FROM_PTR(&machine_usbd_cdc_obj);
#endif
#endif

#if MICROPY_HW_HAS_MMA7660
Expand Down
6 changes: 6 additions & 0 deletions ports/stm32/modos.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "extmod/modmachine.h"
#include "usb.h"
#include "uart.h"
#if MICROPY_HW_USB_CDC_STREAM
#include "shared/tinyusb/mp_usbd_cdc.h"
#endif

bool mp_os_dupterm_is_builtin_stream(mp_const_obj_t stream) {
const mp_obj_type_t *type = mp_obj_get_type(stream);
Expand All @@ -38,6 +41,9 @@ bool mp_os_dupterm_is_builtin_stream(mp_const_obj_t stream) {
#if MICROPY_HW_STM_USB_STACK
|| type == &pyb_usb_vcp_type
#endif
#if MICROPY_HW_USB_CDC_STREAM
|| type == &machine_usbd_cdc_type
#endif
;
}

Expand Down
4 changes: 4 additions & 0 deletions ports/stm32/mpconfigboard_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@
#ifndef MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
#define MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE (1) // Support machine.USBDevice
#endif

#ifndef MICROPY_HW_USB_CDC_STREAM
#define MICROPY_HW_USB_CDC_STREAM (1)
#endif
#endif

// Configure maximum number of CDC VCP interfaces, and whether MSC/HID are supported
Expand Down
8 changes: 5 additions & 3 deletions ports/stm32/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
#if MICROPY_HW_TINYUSB_STACK
#include "shared/tinyusb/mp_usbd_cdc.h"

#if !MICROPY_HW_USB_CDC_STREAM
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
#define MICROPY_HW_STDIN_BUFFER_LEN 512
#endif

static uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0 };
#endif // !MICROPY_HW_USB_CDC_STREAM
#endif

// this table converts from HAL_StatusTypeDef to POSIX errno
Expand All @@ -38,7 +40,7 @@ MP_NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {

MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK && !MICROPY_HW_USB_CDC_STREAM
ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
#endif
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
Expand Down Expand Up @@ -68,7 +70,7 @@ MP_WEAK int mp_hal_stdin_rx_chr(void) {
if (dupterm_c >= 0) {
return dupterm_c;
}
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK && !MICROPY_HW_USB_CDC_STREAM
mp_usbd_cdc_poll_interfaces(0);
int c = ringbuf_get(&stdin_ringbuf);
if (c != -1) {
Expand All @@ -86,7 +88,7 @@ MP_WEAK mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
did_write = true;
}
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
#if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK && !MICROPY_HW_USB_CDC_STREAM
mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
if (cdc_res > 0) {
did_write = true;
Expand Down
2 changes: 2 additions & 0 deletions ports/stm32/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) {
return -mp_hal_status_to_errno_table[status];
}

#if MICROPY_HW_TINYUSB_STACK && !MICROPY_HW_USB_CDC_STREAM
extern ringbuf_t stdin_ringbuf;
#endif

MP_NORETURN void mp_hal_raise(HAL_StatusTypeDef status);
void mp_hal_set_interrupt_char(int c); // -1 to disable
Expand Down
134 changes: 134 additions & 0 deletions shared/tinyusb/mp_usbd_cdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,30 @@

#if MICROPY_HW_USB_CDC && MICROPY_HW_ENABLE_USBDEV && !MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC

#if !MICROPY_HW_USB_CDC_STREAM
static uint8_t cdc_itf_pending; // keep track of cdc interfaces which need attention to poll
#endif
static int8_t cdc_connected_flush_delay = 0;

uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags) {
uintptr_t ret = 0;
#if MICROPY_HW_USB_CDC_STREAM
mp_usbd_task();
#if MICROPY_KBD_EXCEPTION
{
// Lazily sync the TinyUSB wanted_char with mp_interrupt_char so that
// Ctrl-C detection works without coupling interrupt_char.c to TinyUSB.
static int last_interrupt_char = -1;
if (mp_interrupt_char != last_interrupt_char) {
last_interrupt_char = mp_interrupt_char;
tud_cdc_set_wanted_char(mp_interrupt_char);
}
}
#endif
if ((poll_flags & MP_STREAM_POLL_RD) && tud_cdc_available()) {
ret |= MP_STREAM_POLL_RD;
}
#else
if (!cdc_itf_pending) {
// Explicitly run the USB stack as the scheduler may be locked (eg we are in
// an interrupt handler) while there is data pending.
Expand All @@ -59,6 +78,7 @@ uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags) {
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
ret |= MP_STREAM_POLL_RD;
}
#endif
if ((poll_flags & MP_STREAM_POLL_WR) &&
(!tud_cdc_connected() || (tud_cdc_connected() && tud_cdc_write_available() > 0))) {
// Always allow write when not connected, fifo will retain latest.
Expand All @@ -69,6 +89,10 @@ uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags) {
}

void MICROPY_WRAP_TUD_CDC_RX_CB(tud_cdc_rx_cb)(uint8_t itf) {
#if MICROPY_HW_USB_CDC_STREAM
// Data stays in TinyUSB FIFO, read via USBD_CDC stream.
(void)itf;
#else
// consume pending USB data immediately to free usb buffer and keep the endpoint from stalling.
// in case the ringbuffer is full, mark the CDC interface that need attention later on for polling
cdc_itf_pending &= ~(1 << itf);
Expand All @@ -92,8 +116,118 @@ void MICROPY_WRAP_TUD_CDC_RX_CB(tud_cdc_rx_cb)(uint8_t itf) {
return;
}
}
#endif
}

#if MICROPY_HW_USB_CDC_STREAM

const machine_usbd_cdc_obj_t machine_usbd_cdc_obj = {{&machine_usbd_cdc_type}};

static mp_obj_t machine_usbd_cdc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
(void)type;
(void)args;
mp_arg_check_num(n_args, n_kw, 0, 0, false);
return MP_OBJ_FROM_PTR(&machine_usbd_cdc_obj);
}

static void machine_usbd_cdc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)self_in;
(void)kind;
mp_printf(print, "USBD_CDC()");
}

static mp_obj_t machine_usbd_cdc_any(mp_obj_t self_in) {
(void)self_in;
mp_usbd_task();
return mp_obj_new_bool(tud_cdc_available());
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_usbd_cdc_any_obj, machine_usbd_cdc_any);

static mp_obj_t machine_usbd_cdc_isconnected(mp_obj_t self_in) {
(void)self_in;
return mp_obj_new_bool(tud_cdc_connected());
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_usbd_cdc_isconnected_obj, machine_usbd_cdc_isconnected);

static mp_uint_t machine_usbd_cdc_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
(void)self_in;
// Process pending USB events. Interrupt char (Ctrl-C) is detected by
// tud_cdc_rx_wanted_cb() which fires during mp_usbd_task() before
// tud_cdc_read() can return the data — guaranteed by TinyUSB's
// cdcd_xfer_cb() which checks for wanted_char before tud_cdc_rx_cb().
mp_usbd_task();
uint32_t n = tud_cdc_read(buf_in, size);
if (n == 0) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
return n;
}

static mp_uint_t machine_usbd_cdc_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
(void)self_in;
mp_uint_t n = mp_usbd_cdc_tx_strn((const char *)buf_in, size);
if (n == 0) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
return n;
}

static mp_uint_t machine_usbd_cdc_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
(void)self_in;
if (request == MP_STREAM_POLL) {
return mp_usbd_cdc_poll_interfaces(arg);
} else if (request == MP_STREAM_CLOSE) {
return 0;
}
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}

static const mp_stream_p_t machine_usbd_cdc_stream_p = {
.read = machine_usbd_cdc_stream_read,
.write = machine_usbd_cdc_stream_write,
.ioctl = machine_usbd_cdc_stream_ioctl,
};

static const mp_rom_map_elem_t machine_usbd_cdc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ 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_any), MP_ROM_PTR(&machine_usbd_cdc_any_obj) },
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&machine_usbd_cdc_isconnected_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(&mp_stream___exit___obj) },
};

static MP_DEFINE_CONST_DICT(machine_usbd_cdc_locals_dict, machine_usbd_cdc_locals_dict_table);

MP_DEFINE_CONST_OBJ_TYPE(
machine_usbd_cdc_type,
MP_QSTR_USBD_CDC,
MP_TYPE_FLAG_ITER_IS_STREAM,
make_new, machine_usbd_cdc_make_new,
print, machine_usbd_cdc_print,
protocol, &machine_usbd_cdc_stream_p,
locals_dict, &machine_usbd_cdc_locals_dict
);

#if MICROPY_KBD_EXCEPTION
void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
(void)itf;
(void)wanted_char;
tud_cdc_read_flush();
mp_sched_keyboard_interrupt();
}
#endif

#endif // MICROPY_HW_USB_CDC_STREAM

mp_uint_t mp_usbd_cdc_tx_strn(const char *str, mp_uint_t len) {
if (!tusb_inited()) {
return 0;
Expand Down
13 changes: 13 additions & 0 deletions shared/tinyusb/mp_usbd_cdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,21 @@
#define MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER (0)
#endif

#ifndef MICROPY_HW_USB_CDC_STREAM
#define MICROPY_HW_USB_CDC_STREAM (0)
#endif

uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags);
void MICROPY_WRAP_TUD_CDC_RX_CB(tud_cdc_rx_cb)(uint8_t itf);
mp_uint_t mp_usbd_cdc_tx_strn(const char *str, mp_uint_t len);

#if MICROPY_HW_USB_CDC_STREAM
typedef struct {
mp_obj_base_t base;
} machine_usbd_cdc_obj_t;

extern const mp_obj_type_t machine_usbd_cdc_type;
extern const machine_usbd_cdc_obj_t machine_usbd_cdc_obj;
#endif

#endif // MICROPY_INCLUDED_SHARED_TINYUSB_MP_USBD_CDC_H
Loading