Start of USB host API
This allows you to list and explore connected USB devices. It only stubs out the methods to communicate to endpoints. That will come in a follow up once TinyUSB has it. (It's in progress.) Related to #5986
This commit is contained in:
parent
b439464627
commit
83593a1558
@ -1 +1 @@
|
||||
Subproject commit 3b09b82123a50bef6b18cf90c2734ae7581da4a3
|
||||
Subproject commit 73896a3b71c525a3ee4cefa7e35ce3b3a93786ef
|
@ -63,24 +63,25 @@ void init_usb_hardware(void) {
|
||||
|
||||
#ifdef SAMD21
|
||||
void USB_Handler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SAM_D5X_E5X
|
||||
// These are different subsets of USB interrupts, *NOT* different USB peripherals.
|
||||
void USB_0_Handler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
void USB_1_Handler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
void USB_2_Handler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
void USB_3_Handler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
#endif
|
||||
|
@ -60,7 +60,7 @@
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
CIRCUITPY_COMMON_ROOT_POINTERS
|
||||
|
||||
#define DEBUG_UART_TX (&pin_GPIO14)
|
||||
#define DEBUG_UART_RX (&pin_GPIO15)
|
||||
#define CIRCUITPY_DEBUG_UART_TX (&pin_GPIO14)
|
||||
#define CIRCUITPY_DEBUG_UART_RX (&pin_GPIO15)
|
||||
|
||||
#endif // __INCLUDED_MPCONFIGPORT_H
|
||||
|
@ -35,7 +35,7 @@
|
||||
uint32_t SystemCoreClock = 700 * 1000 * 1000;
|
||||
|
||||
void USB_IRQHandler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
void init_usb_hardware(void) {
|
||||
|
@ -49,8 +49,3 @@
|
||||
#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}}
|
||||
|
||||
#define DOUBLE_TAP_PIN (&pin_GPIO10)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_UART_RX (&pin_GPIO16)
|
||||
#define DEBUG_UART_TX (&pin_GPIO5)
|
||||
#endif
|
||||
|
@ -37,8 +37,8 @@
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO21)
|
||||
|
||||
// Serial over UART
|
||||
#define DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
#define CIRCUITPY_DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define CIRCUITPY_DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
|
||||
// For entering safe mode
|
||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9)
|
||||
|
@ -37,8 +37,8 @@
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO21)
|
||||
|
||||
// Serial over UART
|
||||
#define DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
#define CIRCUITPY_DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define CIRCUITPY_DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
|
||||
// For entering safe mode
|
||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9)
|
||||
|
@ -37,8 +37,8 @@
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO21)
|
||||
|
||||
// Serial over UART
|
||||
#define DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
#define CIRCUITPY_DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define CIRCUITPY_DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
|
||||
// For entering safe mode
|
||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO2)
|
||||
|
@ -44,8 +44,8 @@
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO21)
|
||||
|
||||
// Serial over UART
|
||||
#define DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
#define CIRCUITPY_DEBUG_UART_RX DEFAULT_UART_BUS_RX
|
||||
#define CIRCUITPY_DEBUG_UART_TX DEFAULT_UART_BUS_TX
|
||||
|
||||
// For entering safe mode
|
||||
#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9)
|
||||
|
@ -64,7 +64,7 @@ void isr(void) {
|
||||
nesting_count += 1;
|
||||
#ifdef CFG_TUSB_MCU
|
||||
if (irqs & (1 << USB_INTERRUPT)) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
#endif
|
||||
if (irqs & (1 << TIMER0_INTERRUPT)) {
|
||||
|
@ -164,6 +164,13 @@ SRC_C += \
|
||||
reset.c \
|
||||
supervisor/flexspi_nor_flash_ops.c
|
||||
|
||||
ifeq ($(CIRCUITPY_USB_HOST), 1)
|
||||
SRC_C += \
|
||||
lib/tinyusb/src/portable/chipidea/ci_hs/hcd_ci_hs.c \
|
||||
lib/tinyusb/src/portable/ehci/ehci.c \
|
||||
|
||||
endif
|
||||
|
||||
# TODO
|
||||
#ifeq ($(CIRCUITPY_AUDIOBUSIO),1)
|
||||
#SRC_C += peripherals/samd/i2s.c peripherals/samd/$(CHIP_FAMILY)/i2s.c
|
||||
@ -219,3 +226,13 @@ include $(TOP)/py/mkrules.mk
|
||||
# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
|
||||
print-%:
|
||||
@echo $* = $($*)
|
||||
|
||||
ifeq ($(CHIP_FAMILY), MIMXRT1062)
|
||||
PYOCD_TARGET = mimxrt1060
|
||||
endif
|
||||
|
||||
# Flash using pyocd
|
||||
PYOCD_OPTION ?=
|
||||
flash: $(BUILD)/firmware.hex
|
||||
pyocd flash -t $(PYOCD_TARGET) $(PYOCD_OPTION) $<
|
||||
pyocd reset -t $(PYOCD_TARGET)
|
||||
|
@ -7,8 +7,19 @@
|
||||
|
||||
#define BOARD_FLASH_SIZE (8 * 1024 * 1024)
|
||||
|
||||
#define MICROPY_HW_LED_STATUS (&pin_GPIO_AD_B0_09)
|
||||
|
||||
#define DEFAULT_I2C_BUS_SCL (&pin_GPIO_AD_B1_00)
|
||||
#define DEFAULT_I2C_BUS_SDA (&pin_GPIO_AD_B1_01)
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B1_07)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B1_06)
|
||||
|
||||
#define CIRCUITPY_DEBUG_UART_TX (&pin_GPIO_AD_B0_12)
|
||||
#define CIRCUITPY_DEBUG_UART_RX (&pin_GPIO_AD_B0_13)
|
||||
|
||||
|
||||
// Put host on the first USB so that right angle OTG adapters can fit. This is
|
||||
// the right port when looking at the board.
|
||||
#define CIRCUITPY_USB_DEVICE_INSTANCE 1
|
||||
#define CIRCUITPY_USB_HOST_INSTANCE 0
|
||||
|
@ -6,3 +6,5 @@ USB_MANUFACTURER = "NXP"
|
||||
CHIP_VARIANT = MIMXRT1062DVJ6A
|
||||
CHIP_FAMILY = MIMXRT1062
|
||||
FLASH = IS25WP064A
|
||||
|
||||
CIRCUITPY_USB_HOST = 1
|
||||
|
@ -125,6 +125,15 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_GPIO_AD_B0_15) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CAN_STBY), MP_ROM_PTR(&pin_GPIO_AD_B0_05) },
|
||||
|
||||
// USB
|
||||
#if CIRCUITPY_USB_HOST_INSTANCE == 0
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG1_DP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG1_DN) },
|
||||
#elif CIRCUITPY_USB_HOST_INSTANCE == 1
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG2_DP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG2_DN) },
|
||||
#endif
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
|
||||
};
|
||||
|
@ -16,3 +16,6 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B0_03)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B0_02)
|
||||
|
||||
#define CIRCUITPY_USB_DEVICE_INSTANCE 0
|
||||
#define CIRCUITPY_USB_HOST_INSTANCE 1
|
||||
|
@ -7,3 +7,4 @@ CHIP_VARIANT = MIMXRT1062DVJ6A
|
||||
CHIP_FAMILY = MIMXRT1062
|
||||
FLASH = W25Q64JV
|
||||
CIRCUITPY__EVE = 1
|
||||
CIRCUITPY_USB_HOST = 1
|
||||
|
@ -43,6 +43,7 @@
|
||||
// arrays use 0 based numbering: UART1 is stored at index 0
|
||||
#define MAX_UART 8
|
||||
STATIC bool reserved_uart[MAX_UART];
|
||||
STATIC bool never_reset_uart[MAX_UART];
|
||||
|
||||
#define UART_CLOCK_FREQ (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U)
|
||||
|
||||
@ -75,11 +76,22 @@ STATIC void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, stat
|
||||
|
||||
void uart_reset(void) {
|
||||
for (uint i = 0; i < MP_ARRAY_SIZE(mcu_uart_banks); i++) {
|
||||
if (never_reset_uart[i]) {
|
||||
continue;
|
||||
}
|
||||
reserved_uart[i] = false;
|
||||
LPUART_Deinit(mcu_uart_banks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
|
||||
never_reset_uart[self->index] = true;
|
||||
common_hal_never_reset_pin(self->tx);
|
||||
common_hal_never_reset_pin(self->rx);
|
||||
common_hal_never_reset_pin(self->rts);
|
||||
common_hal_never_reset_pin(self->cts);
|
||||
}
|
||||
|
||||
void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx,
|
||||
const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts,
|
||||
@ -103,6 +115,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
const uint32_t rx_count = MP_ARRAY_SIZE(mcu_uart_rx_list);
|
||||
const uint32_t tx_count = MP_ARRAY_SIZE(mcu_uart_tx_list);
|
||||
|
||||
const mcu_periph_obj_t *tx_config = NULL;
|
||||
const mcu_periph_obj_t *rx_config = NULL;
|
||||
const mcu_periph_obj_t *rts_config = NULL;
|
||||
const mcu_periph_obj_t *cts_config = NULL;
|
||||
|
||||
// RX loop handles rx only, or both rx and tx
|
||||
if (rx != NULL) {
|
||||
for (uint32_t i = 0; i < rx_count; ++i) {
|
||||
@ -121,11 +138,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
uart_taken = true;
|
||||
break;
|
||||
}
|
||||
self->rx = &mcu_uart_rx_list[i];
|
||||
self->tx = &mcu_uart_tx_list[j];
|
||||
rx_config = &mcu_uart_rx_list[i];
|
||||
tx_config = &mcu_uart_tx_list[j];
|
||||
break;
|
||||
}
|
||||
if (self->tx != NULL || uart_taken) {
|
||||
if (tx_config != NULL || uart_taken) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -133,7 +150,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
uart_taken = true;
|
||||
break;
|
||||
}
|
||||
self->rx = &mcu_uart_rx_list[i];
|
||||
rx_config = &mcu_uart_rx_list[i];
|
||||
}
|
||||
}
|
||||
} else if (tx != NULL) {
|
||||
@ -146,17 +163,17 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
uart_taken = true;
|
||||
break;
|
||||
}
|
||||
self->tx = &mcu_uart_tx_list[i];
|
||||
tx_config = &mcu_uart_tx_list[i];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mp_raise_ValueError(translate("Supply at least one UART pin"));
|
||||
}
|
||||
|
||||
if (rx && !self->rx) {
|
||||
if (rx && !rx_config) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RX);
|
||||
}
|
||||
if (tx && !self->tx) {
|
||||
if (tx && !tx_config) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_TX);
|
||||
}
|
||||
|
||||
@ -187,52 +204,58 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
|
||||
if (rts != NULL) {
|
||||
for (uint32_t i = 0; i < rts_count; ++i) {
|
||||
if (mcu_uart_rts_list[i].bank_idx == self->rx->bank_idx) {
|
||||
if (mcu_uart_rts_list[i].bank_idx == rx_config->bank_idx) {
|
||||
if (mcu_uart_rts_list[i].pin == rts) {
|
||||
self->rts = &mcu_uart_rts_list[i];
|
||||
rts_config = &mcu_uart_rts_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self->rts == NULL) {
|
||||
if (rts_config == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RTS);
|
||||
}
|
||||
}
|
||||
|
||||
if (cts != NULL) {
|
||||
for (uint32_t i = 0; i < cts_count; ++i) {
|
||||
if (mcu_uart_cts_list[i].bank_idx == self->rx->bank_idx) {
|
||||
if (mcu_uart_cts_list[i].bank_idx == tx_config->bank_idx) {
|
||||
if (mcu_uart_cts_list[i].pin == cts) {
|
||||
self->cts = &mcu_uart_cts_list[i];
|
||||
cts_config = &mcu_uart_cts_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self->cts == NULL) {
|
||||
if (cts == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_CTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (self->rx) {
|
||||
self->uart = mcu_uart_banks[self->rx->bank_idx - 1];
|
||||
self->index = rx_config->bank_idx - 1;
|
||||
} else {
|
||||
assert(self->tx);
|
||||
self->uart = mcu_uart_banks[self->tx->bank_idx - 1];
|
||||
self->index = tx_config->bank_idx - 1;
|
||||
}
|
||||
self->uart = mcu_uart_banks[self->index];
|
||||
|
||||
assert(self->uart);
|
||||
|
||||
if (self->rx) {
|
||||
config_periph_pin(self->rx);
|
||||
if (rx_config) {
|
||||
config_periph_pin(rx_config);
|
||||
self->rx = rx;
|
||||
}
|
||||
if (self->tx) {
|
||||
config_periph_pin(self->tx);
|
||||
if (tx_config) {
|
||||
config_periph_pin(tx_config);
|
||||
self->tx = tx;
|
||||
}
|
||||
if (self->rts) {
|
||||
config_periph_pin(self->rts);
|
||||
if (rts_config) {
|
||||
config_periph_pin(rts_config);
|
||||
self->rts = rts;
|
||||
}
|
||||
if (self->cts) {
|
||||
config_periph_pin(self->cts);
|
||||
if (cts_config) {
|
||||
config_periph_pin(cts_config);
|
||||
self->cts = cts;
|
||||
}
|
||||
|
||||
lpuart_config_t config = { 0 };
|
||||
@ -245,10 +268,10 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
config.enableRxRTS = self->rts != NULL;
|
||||
config.enableTxCTS = self->cts != NULL;
|
||||
if (self->rts != NULL) {
|
||||
claim_pin(self->rts->pin);
|
||||
claim_pin(self->rts);
|
||||
}
|
||||
if (self->cts != NULL) {
|
||||
claim_pin(self->cts->pin);
|
||||
claim_pin(self->cts);
|
||||
}
|
||||
|
||||
LPUART_Init(self->uart, &config, UART_CLOCK_FREQ);
|
||||
@ -265,12 +288,16 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
self->uart->MODIR = modir;
|
||||
|
||||
if (self->tx != NULL) {
|
||||
claim_pin(self->tx->pin);
|
||||
claim_pin(self->tx);
|
||||
}
|
||||
|
||||
if (self->rx != NULL) {
|
||||
// The LPUART ring buffer wastes one byte to distinguish between full and empty.
|
||||
self->ringbuf = gc_alloc(receiver_buffer_size + 1, false, true /*long-lived*/);
|
||||
if (receiver_buffer == NULL) {
|
||||
self->ringbuf = gc_alloc(receiver_buffer_size, false, true /*long-lived*/);
|
||||
} else {
|
||||
self->ringbuf = receiver_buffer;
|
||||
}
|
||||
|
||||
|
||||
if (!self->ringbuf) {
|
||||
LPUART_Deinit(self->uart);
|
||||
@ -280,9 +307,9 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
LPUART_TransferCreateHandle(self->uart, &self->handle, LPUART_UserCallback, self);
|
||||
// Pass actual allocated size; the LPUART routines are cognizant that
|
||||
// the capacity is one less than the size.
|
||||
LPUART_TransferStartRingBuffer(self->uart, &self->handle, self->ringbuf, receiver_buffer_size + 1);
|
||||
LPUART_TransferStartRingBuffer(self->uart, &self->handle, self->ringbuf, receiver_buffer_size);
|
||||
|
||||
claim_pin(self->rx->pin);
|
||||
claim_pin(self->rx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,19 +321,15 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
|
||||
if (common_hal_busio_uart_deinited(self)) {
|
||||
return;
|
||||
}
|
||||
if (self->rx) {
|
||||
reserved_uart[self->rx->bank_idx - 1] = false;
|
||||
} else {
|
||||
reserved_uart[self->tx->bank_idx - 1] = false;
|
||||
}
|
||||
|
||||
reserved_uart[self->index] = false;
|
||||
never_reset_uart[self->index] = false;
|
||||
|
||||
LPUART_Deinit(self->uart);
|
||||
gc_free(self->ringbuf);
|
||||
|
||||
|
||||
common_hal_reset_pin(self->rx->pin);
|
||||
common_hal_reset_pin(self->tx->pin);
|
||||
|
||||
common_hal_reset_pin(self->rx);
|
||||
common_hal_reset_pin(self->tx);
|
||||
|
||||
self->rx = NULL;
|
||||
self->tx = NULL;
|
||||
|
@ -41,14 +41,15 @@ typedef struct {
|
||||
LPUART_Type *uart;
|
||||
lpuart_handle_t handle;
|
||||
uint8_t *ringbuf;
|
||||
bool rx_ongoing;
|
||||
uint32_t baudrate;
|
||||
uint8_t character_bits;
|
||||
uint32_t timeout_ms;
|
||||
const mcu_periph_obj_t *rx;
|
||||
const mcu_periph_obj_t *tx;
|
||||
const mcu_periph_obj_t *cts;
|
||||
const mcu_periph_obj_t *rts;
|
||||
bool rx_ongoing;
|
||||
uint8_t character_bits;
|
||||
uint8_t index;
|
||||
const mcu_pin_obj_t *rx;
|
||||
const mcu_pin_obj_t *tx;
|
||||
const mcu_pin_obj_t *cts;
|
||||
const mcu_pin_obj_t *rts;
|
||||
} busio_uart_obj_t;
|
||||
|
||||
void uart_reset(void);
|
||||
|
@ -40,10 +40,12 @@ void reset_all_pins(void) {
|
||||
claimed_pins[i] = never_reset_pins[i];
|
||||
}
|
||||
for (uint8_t i = 0; i < IOMUXC_SW_PAD_CTL_PAD_COUNT; i++) {
|
||||
if (!never_reset_pins[i]) {
|
||||
IOMUXC->SW_MUX_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->mux_reset;
|
||||
IOMUXC->SW_PAD_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->pad_reset;
|
||||
mcu_pin_obj_t *pin = mcu_pin_globals.map.table[i].value;
|
||||
if (never_reset_pins[pin->mux_idx]) {
|
||||
continue;
|
||||
}
|
||||
*(uint32_t *)pin->mux_reg = pin->mux_reset;
|
||||
*(uint32_t *)pin->cfg_reg = pin->pad_reset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,6 +62,9 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
|
||||
}
|
||||
|
||||
void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
|
||||
if (pin == NULL) {
|
||||
return;
|
||||
}
|
||||
never_reset_pins[pin->mux_idx] = true;
|
||||
}
|
||||
|
||||
|
@ -286,6 +286,12 @@ STATIC const mp_rom_map_elem_t mcu_pin_global_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_09), MP_ROM_PTR(&pin_GPIO_SD_B1_09) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_10), MP_ROM_PTR(&pin_GPIO_SD_B1_10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GPIO_SD_B1_11), MP_ROM_PTR(&pin_GPIO_SD_B1_11) },
|
||||
#ifdef MIMXRT1062_SERIES
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_OTG1_DN), MP_ROM_PTR(&pin_USB_OTG1_DN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_OTG1_DP), MP_ROM_PTR(&pin_USB_OTG1_DP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_OTG2_DN), MP_ROM_PTR(&pin_USB_OTG2_DN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USB_OTG2_DP), MP_ROM_PTR(&pin_USB_OTG2_DP) },
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table);
|
||||
|
59
ports/mimxrt10xx/common-hal/usb_host/Port.c
Normal file
59
ports/mimxrt10xx/common-hal/usb_host/Port.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared-bindings/usb_host/Port.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
bool usb_host_init;
|
||||
|
||||
void common_hal_usb_host_port_construct(usb_host_port_obj_t *self, const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm) {
|
||||
const mcu_pin_obj_t *supported_dp;
|
||||
const mcu_pin_obj_t *supported_dm;
|
||||
if (CIRCUITPY_USB_HOST_INSTANCE == 0) {
|
||||
supported_dp = &pin_USB_OTG1_DP;
|
||||
supported_dm = &pin_USB_OTG1_DN;
|
||||
} else if (CIRCUITPY_USB_HOST_INSTANCE == 1) {
|
||||
supported_dp = &pin_USB_OTG2_DP;
|
||||
supported_dm = &pin_USB_OTG2_DN;
|
||||
}
|
||||
if (dp != supported_dp || dm != supported_dm) {
|
||||
mp_raise_ValueError(translate("Invalid pins"));
|
||||
}
|
||||
self->init = true;
|
||||
usb_host_init = true;
|
||||
}
|
||||
|
||||
void common_hal_usb_host_port_deinit(usb_host_port_obj_t *self) {
|
||||
self->init = false;
|
||||
usb_host_init = false;
|
||||
}
|
||||
|
||||
bool common_hal_usb_host_port_deinited(usb_host_port_obj_t *self) {
|
||||
return !self->init;
|
||||
}
|
41
ports/mimxrt10xx/common-hal/usb_host/Port.h
Normal file
41
ports/mimxrt10xx/common-hal/usb_host/Port.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
|
||||
#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bool init;
|
||||
} usb_host_port_obj_t;
|
||||
|
||||
// Cheater state so that the usb module knows if it should return the TinyUSB
|
||||
// state.
|
||||
extern bool usb_host_init;
|
||||
|
||||
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_USB_HOST_PORT_H
|
27
ports/mimxrt10xx/common-hal/usb_host/__init__.c
Normal file
27
ports/mimxrt10xx/common-hal/usb_host/__init__.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Nothing
|
@ -153,3 +153,8 @@ const mcu_pin_obj_t pin_GPIO_SD_B1_08 = PIN(GPIO3, 8, GPIO_SD_B1_08, NO_ADC, 0,
|
||||
const mcu_pin_obj_t pin_GPIO_SD_B1_09 = PIN(GPIO3, 9, GPIO_SD_B1_09, NO_ADC, 0, 0x00000005, 0x000010B0);
|
||||
const mcu_pin_obj_t pin_GPIO_SD_B1_10 = PIN(GPIO3, 10, GPIO_SD_B1_10, NO_ADC, 0, 0x00000005, 0x000010B0);
|
||||
const mcu_pin_obj_t pin_GPIO_SD_B1_11 = PIN(GPIO3, 11, GPIO_SD_B1_11, NO_ADC, 0, 0x00000005, 0x000010B0);
|
||||
|
||||
const mcu_pin_obj_t pin_USB_OTG1_DN = { { &mcu_pin_type }, };
|
||||
const mcu_pin_obj_t pin_USB_OTG1_DP = { { &mcu_pin_type }, };
|
||||
const mcu_pin_obj_t pin_USB_OTG2_DN = { { &mcu_pin_type }, };
|
||||
const mcu_pin_obj_t pin_USB_OTG2_DP = { { &mcu_pin_type }, };
|
||||
|
@ -158,6 +158,11 @@ extern const mcu_pin_obj_t pin_GPIO_SD_B1_09;
|
||||
extern const mcu_pin_obj_t pin_GPIO_SD_B1_10;
|
||||
extern const mcu_pin_obj_t pin_GPIO_SD_B1_11;
|
||||
|
||||
extern const mcu_pin_obj_t pin_USB_OTG1_DN;
|
||||
extern const mcu_pin_obj_t pin_USB_OTG1_DP;
|
||||
extern const mcu_pin_obj_t pin_USB_OTG2_DN;
|
||||
extern const mcu_pin_obj_t pin_USB_OTG2_DP;
|
||||
|
||||
extern const mcu_pin_obj_t mcu_pin_list[IOMUXC_SW_PAD_CTL_PAD_COUNT];
|
||||
|
||||
#endif // MICROPY_INCLUDED_MIMXRT10XX_PERIPHERALS_MIMXRT1062_PINS_H
|
||||
|
@ -29,30 +29,62 @@
|
||||
#include "tusb.h"
|
||||
#include "supervisor/usb.h"
|
||||
|
||||
void init_usb_hardware(void) {
|
||||
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
|
||||
|
||||
#ifdef USBPHY
|
||||
USBPHY_Type *usb_phy = USBPHY;
|
||||
STATIC void init_usb_instance(mp_int_t instance) {
|
||||
if (instance < 0) {
|
||||
return;
|
||||
}
|
||||
USBPHY_Type *usb_phy;
|
||||
#ifdef USBPHY2
|
||||
if (instance == 0) {
|
||||
usb_phy = USBPHY1;
|
||||
#else
|
||||
USBPHY_Type *usb_phy = USBPHY1;
|
||||
(void)instance;
|
||||
usb_phy = USBPHY;
|
||||
#endif
|
||||
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
|
||||
|
||||
#ifdef USBPHY2
|
||||
} else if (instance == 1) {
|
||||
CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||
CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
|
||||
usb_phy = USBPHY2;
|
||||
} else {
|
||||
// Unsupported instance
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enable PHY support for Low speed device + LS via FS Hub
|
||||
usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
|
||||
// Enable PHY support for Low speed device + LS via FS Hub
|
||||
usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
|
||||
|
||||
// Enable all power for normal operation
|
||||
usb_phy->PWD = 0;
|
||||
// Enable all power for normal operation
|
||||
usb_phy->PWD = 0;
|
||||
|
||||
// TX Timing
|
||||
uint32_t phytx = usb_phy->TX;
|
||||
phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
|
||||
phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
|
||||
usb_phy->TX = phytx;
|
||||
}
|
||||
// TX Timing
|
||||
uint32_t phytx = usb_phy->TX;
|
||||
phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
|
||||
phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
|
||||
usb_phy->TX = phytx;
|
||||
}
|
||||
|
||||
void USB_OTG1_IRQHandler(void);
|
||||
void USB_OTG1_IRQHandler(void) {
|
||||
usb_irq_handler();
|
||||
}
|
||||
void init_usb_hardware(void) {
|
||||
init_usb_instance(CIRCUITPY_USB_DEVICE_INSTANCE);
|
||||
// We can't dynamically start the USB Host port at the moment, so do it
|
||||
// up front.
|
||||
init_usb_instance(CIRCUITPY_USB_HOST_INSTANCE);
|
||||
}
|
||||
|
||||
// Provide the prototypes for the interrupt handlers. The iMX RT SDK doesn't.
|
||||
// The SDK only links to them from assembly.
|
||||
void USB_OTG1_IRQHandler(void);
|
||||
void USB_OTG1_IRQHandler(void) {
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
#ifdef USBPHY2
|
||||
void USB_OTG2_IRQHandler(void);
|
||||
void USB_OTG2_IRQHandler(void) {
|
||||
usb_irq_handler(1);
|
||||
}
|
||||
#endif
|
||||
|
@ -52,5 +52,5 @@
|
||||
#define BOOTLOADER_SETTING_SIZE (0)
|
||||
|
||||
#define BOARD_HAS_32KHZ_XTAL (0)
|
||||
#define DEBUG_UART_TX (&pin_P0_06)
|
||||
#define DEBUG_UART_RX (&pin_P1_08)
|
||||
#define CIRCUITPY_DEBUG_UART_TX (&pin_P0_06)
|
||||
#define CIRCUITPY_DEBUG_UART_RX (&pin_P1_08)
|
||||
|
@ -93,5 +93,5 @@ void init_usb_hardware(void) {
|
||||
|
||||
extern void USBD_IRQHandler(void);
|
||||
void USBD_IRQHandler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
@ -34,6 +34,10 @@
|
||||
void init_usb_hardware(void) {
|
||||
}
|
||||
|
||||
STATIC void _usb_irq_wrapper(void) {
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
void post_usb_init(void) {
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
|
||||
@ -41,7 +45,7 @@ void post_usb_init(void) {
|
||||
if (usb_handler) {
|
||||
irq_remove_handler(USBCTRL_IRQ, usb_handler);
|
||||
}
|
||||
irq_set_exclusive_handler(USBCTRL_IRQ, usb_irq_handler);
|
||||
irq_set_exclusive_handler(USBCTRL_IRQ, _usb_irq_wrapper);
|
||||
|
||||
irq_set_enabled(USBCTRL_IRQ, true);
|
||||
|
||||
|
@ -46,5 +46,5 @@
|
||||
#define BOARD_HSE_SOURCE (RCC_HSE_BYPASS) // ST boards use the STLink clock signal
|
||||
#define BOARD_HAS_LOW_SPEED_CRYSTAL (1)
|
||||
|
||||
#define DEBUG_UART_TX (&pin_PD08)
|
||||
#define DEBUG_UART_RX (&pin_PD09)
|
||||
#define CIRCUITPY_DEBUG_UART_TX (&pin_PD08)
|
||||
#define CIRCUITPY_DEBUG_UART_RX (&pin_PD09)
|
||||
|
@ -149,5 +149,5 @@ void init_usb_hardware(void) {
|
||||
}
|
||||
|
||||
void OTG_FS_IRQHandler(void) {
|
||||
usb_irq_handler();
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
@ -312,6 +312,9 @@ endif
|
||||
ifeq ($(CIRCUITPY_USB_HID),1)
|
||||
SRC_PATTERNS += usb_hid/%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_USB_HOST),1)
|
||||
SRC_PATTERNS += usb_host/% usb/%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_USB_MIDI),1)
|
||||
SRC_PATTERNS += usb_midi/%
|
||||
endif
|
||||
@ -422,6 +425,8 @@ SRC_COMMON_HAL_ALL = \
|
||||
ssl/SSLSocket.c \
|
||||
supervisor/Runtime.c \
|
||||
supervisor/__init__.c \
|
||||
usb_host/__init__.c \
|
||||
usb_host/Port.c \
|
||||
watchdog/WatchDogMode.c \
|
||||
watchdog/WatchDogTimer.c \
|
||||
watchdog/__init__.c \
|
||||
@ -577,6 +582,9 @@ SRC_SHARED_MODULE_ALL = \
|
||||
time/__init__.c \
|
||||
traceback/__init__.c \
|
||||
uheap/__init__.c \
|
||||
usb/__init__.c \
|
||||
usb/core/__init__.c \
|
||||
usb/core/Device.c \
|
||||
ustack/__init__.c \
|
||||
vectorio/Circle.c \
|
||||
vectorio/Polygon.c \
|
||||
|
@ -487,6 +487,20 @@ void supervisor_run_background_tasks_if_tick(void);
|
||||
|
||||
// USB settings
|
||||
|
||||
// Debug level for TinyUSB. Only outputs over debug UART so it doesn't cause
|
||||
// additional USB logging.
|
||||
#ifndef CIRCUITPY_DEBUG_TINYUSB
|
||||
#define CIRCUITPY_DEBUG_TINYUSB 0
|
||||
#endif
|
||||
|
||||
#ifndef CIRCUITPY_USB_DEVICE_INSTANCE
|
||||
#define CIRCUITPY_USB_DEVICE_INSTANCE 0
|
||||
#endif
|
||||
|
||||
#ifndef CIRCUITPY_USB_HOST_INSTANCE
|
||||
#define CIRCUITPY_USB_HOST_INSTANCE -1
|
||||
#endif
|
||||
|
||||
// If the port requires certain USB endpoint numbers, define these in mpconfigport.h.
|
||||
|
||||
#ifndef USB_CDC_EP_NUM_NOTIFICATION
|
||||
|
@ -415,6 +415,9 @@ CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
|
||||
CIRCUITPY_USB_HID_ENABLED_DEFAULT ?= $(USB_NUM_ENDPOINT_PAIRS_5_OR_GREATER)
|
||||
CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAULT)
|
||||
|
||||
CIRCUITPY_USB_HOST ?= 0
|
||||
CFLAGS += -DCIRCUITPY_USB_HOST=$(CIRCUITPY_USB_HOST)
|
||||
|
||||
# MIDI is available by default, but is not turned on if there are fewer than 8 endpoints.
|
||||
CIRCUITPY_USB_MIDI ?= $(CIRCUITPY_USB)
|
||||
CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
|
||||
|
52
shared-bindings/usb/__init__.c
Normal file
52
shared-bindings/usb/__init__.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/usb/__init__.h"
|
||||
#include "shared-bindings/usb/core/__init__.h"
|
||||
|
||||
//| """PyUSB-compatible USB host API
|
||||
//|
|
||||
//| The `usb` is a subset of PyUSB that allows you to communicate to USB devices.
|
||||
//| """
|
||||
//|
|
||||
|
||||
STATIC mp_rom_map_elem_t usb_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_core), MP_OBJ_FROM_PTR(&usb_core_module) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(usb_module_globals, usb_module_globals_table);
|
||||
|
||||
const mp_obj_module_t usb_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&usb_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_usb, usb_module, CIRCUITPY_USB_HOST);
|
27
shared-bindings/usb/__init__.h
Normal file
27
shared-bindings/usb/__init__.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
332
shared-bindings/usb/core/Device.c
Normal file
332
shared-bindings/usb/core/Device.c
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This file uses method signatures and comments derived from the PyUSB code
|
||||
// that has the below BSD-3 license.
|
||||
/* Copyright 2009-2017 Wander Lairson Costa
|
||||
* Copyright 2009-2021 PyUSB contributors
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "py/objproperty.h"
|
||||
#include "shared-bindings/usb/core/Device.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
//| class Device:
|
||||
//|
|
||||
//| def __init__(self) -> None:
|
||||
//| """User code cannot create Device objects. Instead, get them from
|
||||
//| `usb.core.find`.
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
|
||||
//| idVendor: int
|
||||
//| """The USB vendor ID of the device"""
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_obj_get_idVendor(mp_obj_t self_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idVendor(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idVendor_obj, usb_core_device_obj_get_idVendor);
|
||||
|
||||
const mp_obj_property_t usb_core_device_idVendor_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&usb_core_device_get_idVendor_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| idProduct: int
|
||||
//| """The USB product ID of the device"""
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_obj_get_idProduct(mp_obj_t self_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idProduct(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idProduct_obj, usb_core_device_obj_get_idProduct);
|
||||
|
||||
const mp_obj_property_t usb_core_device_idProduct_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&usb_core_device_get_idProduct_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| serial_number: str
|
||||
//| """The USB device's serial number string."""
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_obj_get_serial_number(mp_obj_t self_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return common_hal_usb_core_device_get_serial_number(self);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_serial_number_obj, usb_core_device_obj_get_serial_number);
|
||||
|
||||
const mp_obj_property_t usb_core_device_serial_number_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&usb_core_device_get_serial_number_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| product: str
|
||||
//| """The USB device's product string."""
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_obj_get_product(mp_obj_t self_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return common_hal_usb_core_device_get_product(self);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_product_obj, usb_core_device_obj_get_product);
|
||||
|
||||
const mp_obj_property_t usb_core_device_product_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&usb_core_device_get_product_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| manufacturer: str
|
||||
//| """The USB device's manufacturer string."""
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_obj_get_manufacturer(mp_obj_t self_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return common_hal_usb_core_device_get_manufacturer(self);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_manufacturer_obj, usb_core_device_obj_get_manufacturer);
|
||||
|
||||
const mp_obj_property_t usb_core_device_manufacturer_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&usb_core_device_get_manufacturer_obj,
|
||||
MP_ROM_NONE,
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
|
||||
//| def write(self, endpoint: int, data: ReadableBuffer, timeout = None) -> int:
|
||||
//| """Write data to a specific endpoint on the device.
|
||||
//|
|
||||
//| :param int endpoint: the bEndpointAddress you want to communicate with.
|
||||
//| :param ReadableBuffer data: the data to send
|
||||
//| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
|
||||
//| :returns: the number of bytes written
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_endpoint, ARG_data, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_write(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write);
|
||||
|
||||
|
||||
//| def read(self, endpoint: int, size_or_buffer: array.array, timeout = None) -> int:
|
||||
//| """Read data from the endpoint.
|
||||
//|
|
||||
//| :param int endpoint: the bEndpointAddress you want to communicate with.
|
||||
//| :param array.array size_or_buffer: the array to read data into. PyUSB also allows size but CircuitPython only support array to force deliberate memory use.
|
||||
//| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
|
||||
//| :returns: the number of bytes read
|
||||
//| """
|
||||
//| ...
|
||||
STATIC mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_size_or_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_read_obj, 2, usb_core_device_read);
|
||||
|
||||
//| def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
|
||||
//| data_or_wLength: array.array = None, timeout = None) -> int:
|
||||
//| """Do a control transfer on the endpoint 0. The parameters bmRequestType,
|
||||
//| bRequest, wValue and wIndex are the same of the USB Standard Control
|
||||
//| Request format.
|
||||
//|
|
||||
//| Control requests may or may not have a data payload to write/read.
|
||||
//| In cases which it has, the direction bit of the bmRequestType
|
||||
//| field is used to infer the desired request direction.
|
||||
//|
|
||||
//| For host to device requests (OUT), data_or_wLength parameter is
|
||||
//| the data payload to send, and it must be a sequence type convertible
|
||||
//| to an array object. In this case, the return value is the number
|
||||
//| of bytes written in the data payload.
|
||||
//|
|
||||
//| For device to host requests (IN), data_or_wLength is an array
|
||||
//| object which the data will be read to, and the return value is the
|
||||
//| number of bytes read.
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_ctrl_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_bmRequestType, ARG_bRequest, ARG_wValue, ARG_wIndex, ARG_data_or_wLength, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_bmRequestType, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_bRequest, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_wValue, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_wIndex, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_data_or_wLength, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
// check request type
|
||||
if ((args[ARG_bmRequestType].u_int & 0x80) != 0) {
|
||||
mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
} else {
|
||||
mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_READ);
|
||||
}
|
||||
|
||||
mp_int_t result = common_hal_usb_core_device_ctrl_transfer(self,
|
||||
args[ARG_bmRequestType].u_int, args[ARG_bRequest].u_int,
|
||||
args[ARG_wValue].u_int, args[ARG_wIndex].u_int,
|
||||
bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int);
|
||||
|
||||
return MP_OBJ_NEW_SMALL_INT(result);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_ctrl_transfer_obj, 2, usb_core_device_ctrl_transfer);
|
||||
|
||||
//| def is_kernel_driver_active(self, interface: int) -> bool:
|
||||
//| """Determine if CircuitPython is using the interface. If it is, the
|
||||
//| object will be unable to perform I/O.
|
||||
//|
|
||||
//| :param int interface: the device interface number to check
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_is_kernel_driver_active(mp_obj_t self_in, mp_obj_t interface_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t interface = mp_obj_get_int(interface_in);
|
||||
bool active = common_hal_usb_core_device_is_kernel_driver_active(self, interface);
|
||||
return mp_obj_new_bool(active);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_is_kernel_driver_active_obj, usb_core_device_is_kernel_driver_active);
|
||||
|
||||
//| def detach_kernel_driver(self, interface: int):
|
||||
//| """Stop CircuitPython from using the interface. If successful, you
|
||||
//| will then be able to perform I/O. CircuitPython will automatically
|
||||
//| re-start using the interface on reload.
|
||||
//|
|
||||
//| :param int interface: the device interface number to stop CircuitPython on
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_detach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t interface = mp_obj_get_int(interface_in);
|
||||
common_hal_usb_core_device_detach_kernel_driver(self, interface);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_detach_kernel_driver_obj, usb_core_device_detach_kernel_driver);
|
||||
|
||||
//| def attach_kernel_driver(self, interface: int):
|
||||
//| """Allow CircuitPython to use the interface if it wants to.
|
||||
//|
|
||||
//| :param int interface: the device interface number to allow CircuitPython to use
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_core_device_attach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
|
||||
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t interface = mp_obj_get_int(interface_in);
|
||||
common_hal_usb_core_device_attach_kernel_driver(self, interface);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_attach_kernel_driver_obj, usb_core_device_attach_kernel_driver);
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t usb_core_device_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_idVendor), MP_ROM_PTR(&usb_core_device_idVendor_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_idProduct), MP_ROM_PTR(&usb_core_device_idProduct_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_serial_number), MP_ROM_PTR(&usb_core_device_serial_number_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_product), MP_ROM_PTR(&usb_core_device_product_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_manufacturer), MP_ROM_PTR(&usb_core_device_manufacturer_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&usb_core_device_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&usb_core_device_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ctrl_transfer), MP_ROM_PTR(&usb_core_device_ctrl_transfer_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_is_kernel_driver_active), MP_ROM_PTR(&usb_core_device_is_kernel_driver_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_detach_kernel_driver), MP_ROM_PTR(&usb_core_device_detach_kernel_driver_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_attach_kernel_driver), MP_ROM_PTR(&usb_core_device_attach_kernel_driver_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(usb_core_device_locals_dict, usb_core_device_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t usb_core_device_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Device,
|
||||
.locals_dict = (mp_obj_t)&usb_core_device_locals_dict,
|
||||
};
|
53
shared-bindings/usb/core/Device.h
Normal file
53
shared-bindings/usb/core/Device.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
|
||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
|
||||
|
||||
#include "py/objarray.h"
|
||||
|
||||
#include "shared-module/usb/core/Device.h"
|
||||
|
||||
extern const mp_obj_type_t usb_core_device_type;
|
||||
|
||||
bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number);
|
||||
uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self);
|
||||
uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self);
|
||||
mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self);
|
||||
mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self);
|
||||
mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self);
|
||||
mp_obj_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout);
|
||||
mp_obj_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout);
|
||||
mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
|
||||
mp_int_t bmRequestType, mp_int_t bRequest,
|
||||
mp_int_t wValue, mp_int_t wIndex,
|
||||
uint8_t *buffer, mp_int_t len, mp_int_t timeout);
|
||||
|
||||
bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface);
|
||||
void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
|
||||
void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
|
192
shared-bindings/usb/core/__init__.c
Normal file
192
shared-bindings/usb/core/__init__.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/objexcept.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/usb/core/__init__.h"
|
||||
#include "shared-bindings/usb/core/Device.h"
|
||||
|
||||
//| """USB Core
|
||||
//|
|
||||
//| This is a subset of the PyUSB core module.
|
||||
//| """
|
||||
//|
|
||||
|
||||
//| class USBError(OSError):
|
||||
//| """Catchall exception for USB related errors."""
|
||||
//| ...
|
||||
MP_DEFINE_USB_CORE_EXCEPTION(USBError, OSError)
|
||||
NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_usb_core_USBError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
nlr_raise(exception);
|
||||
}
|
||||
|
||||
//| class USBTimeoutError(USBError):
|
||||
//| """Raised when a USB transfer times out."""
|
||||
//| ...
|
||||
//|
|
||||
MP_DEFINE_USB_CORE_EXCEPTION(USBTimeoutError, usb_core_USBError)
|
||||
NORETURN void mp_raise_usb_core_USBTimeoutError(void) {
|
||||
mp_raise_type(&mp_type_usb_core_USBTimeoutError);
|
||||
}
|
||||
|
||||
|
||||
//| def find(find_all=False, *, idVendor=None, idProduct=None):
|
||||
//| """Find the first device that matches the given requirements or, if
|
||||
//| find_all is True, return a generator of all matching devices.
|
||||
//|
|
||||
//| Returns None if no device matches.
|
||||
//| """
|
||||
//|
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_int_t vid;
|
||||
mp_int_t pid;
|
||||
mp_int_t next_index;
|
||||
} usb_core_devices_obj_t;
|
||||
|
||||
// This is an internal iterator type to use with find.
|
||||
STATIC mp_obj_t _next_device(usb_core_devices_obj_t *iter) {
|
||||
// Brute force check all possible device numbers for one that matches.
|
||||
usb_core_device_obj_t temp_device;
|
||||
for (size_t i = iter->next_index; i < 256; i++) {
|
||||
if (!common_hal_usb_core_device_construct(&temp_device, i)) {
|
||||
continue;
|
||||
}
|
||||
if (iter->vid < 0x10000 && iter->vid != common_hal_usb_core_device_get_idVendor(&temp_device)) {
|
||||
continue;
|
||||
}
|
||||
if (iter->pid < 0x10000 && iter->pid != common_hal_usb_core_device_get_idProduct(&temp_device)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We passed the filters. Now make a properly allocated object to
|
||||
// return to the user.
|
||||
usb_core_device_obj_t *self = m_new_obj(usb_core_device_obj_t);
|
||||
self->base.type = &usb_core_device_type;
|
||||
|
||||
mp_printf(&mp_plat_print, "USB device %d matches\n", i);
|
||||
|
||||
common_hal_usb_core_device_construct(self, i);
|
||||
iter->next_index = i + 1;
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
// Iter is done.
|
||||
iter->next_index = 256;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t usb_core_devices_iternext(mp_obj_t self_in) {
|
||||
mp_check_self(mp_obj_is_type(self_in, &usb_core_devices_type));
|
||||
usb_core_devices_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_t device = _next_device(self);
|
||||
if (device != mp_const_none) {
|
||||
return device;
|
||||
}
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
|
||||
const mp_obj_type_t usb_core_devices_type = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_USBDevices,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = usb_core_devices_iternext,
|
||||
),
|
||||
};
|
||||
|
||||
STATIC mp_obj_t usb_core_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_find_all, ARG_idVendor, ARG_idProduct };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_find_all, MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_idVendor, MP_ARG_INT, {.u_int = 0x10000} },
|
||||
{ MP_QSTR_idProduct, MP_ARG_INT, {.u_int = 0x10000} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
bool find_all = args[ARG_find_all].u_bool;
|
||||
usb_core_devices_obj_t temp_iter;
|
||||
usb_core_devices_obj_t *iter;
|
||||
if (find_all) {
|
||||
iter = m_new_obj(usb_core_devices_obj_t);
|
||||
iter->base.type = &usb_core_devices_type;
|
||||
} else {
|
||||
iter = &temp_iter;
|
||||
}
|
||||
iter->next_index = 1;
|
||||
iter->vid = args[ARG_idVendor].u_int;
|
||||
iter->pid = args[ARG_idProduct].u_int;
|
||||
if (!find_all) {
|
||||
return _next_device(iter);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(iter);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_find_obj, 0, usb_core_find);
|
||||
|
||||
|
||||
STATIC mp_rom_map_elem_t usb_core_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_dot_core) },
|
||||
// Functions
|
||||
{ MP_ROM_QSTR(MP_QSTR_find), MP_OBJ_FROM_PTR(&usb_core_find_obj) },
|
||||
|
||||
// Classes
|
||||
{ MP_ROM_QSTR(MP_QSTR_Device), MP_OBJ_FROM_PTR(&usb_core_device_type) },
|
||||
|
||||
// Errors
|
||||
{ MP_ROM_QSTR(MP_QSTR_USBError), MP_OBJ_FROM_PTR(&mp_type_usb_core_USBError) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USBTimeoutError), MP_OBJ_FROM_PTR(&mp_type_usb_core_USBTimeoutError) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(usb_core_module_globals, usb_core_module_globals_table);
|
||||
|
||||
void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
|
||||
bool is_subclass = kind & PRINT_EXC_SUBCLASS;
|
||||
if (!is_subclass && (k == PRINT_EXC)) {
|
||||
mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(usb_core_module_globals_table[0].value)));
|
||||
mp_print_str(print, ".");
|
||||
}
|
||||
mp_obj_exception_print(print, o_in, kind);
|
||||
}
|
||||
|
||||
const mp_obj_module_t usb_core_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&usb_core_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_usb_dot_core, usb_core_module, CIRCUITPY_USB_HOST);
|
54
shared-bindings/usb/core/__init__.h
Normal file
54
shared-bindings/usb/core/__init__.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
extern const mp_obj_module_t usb_core_module;
|
||||
|
||||
void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
|
||||
|
||||
#define MP_DEFINE_USB_CORE_EXCEPTION(exc_name, base_name) \
|
||||
const mp_obj_type_t mp_type_usb_core_##exc_name = { \
|
||||
{ &mp_type_type }, \
|
||||
.name = MP_QSTR_##exc_name, \
|
||||
.print = usb_core_exception_print, \
|
||||
.make_new = mp_obj_exception_make_new, \
|
||||
.attr = mp_obj_exception_attr, \
|
||||
.parent = &mp_type_##base_name, \
|
||||
};
|
||||
|
||||
extern const mp_obj_type_t mp_type_usb_core_USBError;
|
||||
extern const mp_obj_type_t mp_type_usb_core_USBTimeoutError;
|
||||
|
||||
NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...);
|
||||
NORETURN void mp_raise_usb_core_USBTimeoutError(void);
|
||||
|
||||
// Find is all Python object oriented so we don't need a separate common-hal API
|
||||
// for it. It uses the device common-hal instead.
|
103
shared-bindings/usb_host/Port.c
Normal file
103
shared-bindings/usb_host/Port.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared/runtime/context_manager_helpers.h"
|
||||
#include "shared-bindings/usb_host/Port.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
//| class Port:
|
||||
//| """USB host port. Also known as a root hub port."""
|
||||
//|
|
||||
//| def __init__(self, dp: microcontroller.Pin, dm: microcontroller.Pin) -> None:
|
||||
//| """Create a USB host port on the given pins. Access attached devices
|
||||
//| through the `usb` module. Keep this object referenced while
|
||||
//| interacting with devices, otherwise they will be disconnected.
|
||||
//|
|
||||
//| :param ~microcontroller.Pin dp: The data plus pin
|
||||
//| :param ~microcontroller.Pin dm: The data minus pin
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_host_port_make_new(const mp_obj_type_t *type,
|
||||
size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check number of arguments
|
||||
mp_arg_check_num(n_args, n_kw, 2, 2, false);
|
||||
|
||||
const mcu_pin_obj_t *dp = validate_obj_is_free_pin(args[0]);
|
||||
const mcu_pin_obj_t *dm = validate_obj_is_free_pin(args[1]);
|
||||
|
||||
usb_host_port_obj_t *self = m_new_obj(usb_host_port_obj_t);
|
||||
self->base.type = &usb_host_port_type;
|
||||
common_hal_usb_host_port_construct(self, dp, dm);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
//| def deinit(self) -> None:
|
||||
//| """Turn off the USB host port and release the pins for other use."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_host_port_obj_deinit(mp_obj_t self_in) {
|
||||
usb_host_port_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_usb_host_port_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_host_port_deinit_obj, usb_host_port_obj_deinit);
|
||||
|
||||
//| def __enter__(self) -> Port:
|
||||
//| """No-op used by Context Managers."""
|
||||
//| ...
|
||||
//|
|
||||
// Provided by context manager helper.
|
||||
|
||||
//| def __exit__(self) -> None:
|
||||
//| """Automatically deinitializes the hardware when exiting a context. See
|
||||
//| :ref:`lifetime-and-contextmanagers` for more info."""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_host_port_obj___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
common_hal_usb_host_port_deinit(MP_OBJ_TO_PTR(args[0]));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_host_port_obj___exit___obj, 4, 4, usb_host_port_obj___exit__);
|
||||
|
||||
STATIC const mp_rom_map_elem_t usb_host_port_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_host_port_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usb_host_port_obj___exit___obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(usb_host_port_locals_dict, usb_host_port_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t usb_host_port_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Port,
|
||||
.make_new = usb_host_port_make_new,
|
||||
.locals_dict = (mp_obj_t)&usb_host_port_locals_dict,
|
||||
};
|
42
shared-bindings/usb_host/Port.h
Normal file
42
shared-bindings/usb_host/Port.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
|
||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
|
||||
|
||||
#include "py/objarray.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
#include "common-hal/usb_host/Port.h"
|
||||
|
||||
extern const mp_obj_type_t usb_host_port_type;
|
||||
|
||||
void common_hal_usb_host_port_construct(usb_host_port_obj_t *self, const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm);
|
||||
void common_hal_usb_host_port_deinit(usb_host_port_obj_t *self);
|
||||
bool common_hal_usb_host_port_deinited(usb_host_port_obj_t *self);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
|
53
shared-bindings/usb_host/__init__.c
Normal file
53
shared-bindings/usb_host/__init__.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/usb_host/__init__.h"
|
||||
#include "shared-bindings/usb_host/Port.h"
|
||||
|
||||
//| """USB Host
|
||||
//|
|
||||
//| The `usb_host` module allows you to manage USB host ports. To communicate
|
||||
//| with devices use the `usb` module that is a subset of PyUSB's API.
|
||||
//| """
|
||||
//|
|
||||
|
||||
STATIC mp_map_elem_t usb_host_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_host) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Port), MP_OBJ_FROM_PTR(&usb_host_port_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(usb_host_module_globals, usb_host_module_globals_table);
|
||||
|
||||
const mp_obj_module_t usb_host_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&usb_host_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_usb_host, usb_host_module, CIRCUITPY_USB_HOST);
|
27
shared-bindings/usb_host/__init__.h
Normal file
27
shared-bindings/usb_host/__init__.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
27
shared-module/usb/__init__.c
Normal file
27
shared-module/usb/__init__.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Nothing here
|
239
shared-module/usb/core/Device.c
Normal file
239
shared-module/usb/core/Device.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared-bindings/usb/core/Device.h"
|
||||
|
||||
#include "tusb_config.h"
|
||||
|
||||
#include "lib/tinyusb/src/host/usbh.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared/runtime/interrupt_char.h"
|
||||
#include "shared-bindings/usb/core/__init__.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number) {
|
||||
if (device_number == 0 || device_number > CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) {
|
||||
return false;
|
||||
}
|
||||
if (!tuh_ready(device_number)) {
|
||||
return false;
|
||||
}
|
||||
self->device_number = device_number;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self) {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
tuh_vid_pid_get(self->device_number, &vid, &pid);
|
||||
mp_printf(&mp_plat_print, "%d vid %04x pid %04x\n", self->device_number, vid, pid);
|
||||
return vid;
|
||||
}
|
||||
|
||||
uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self) {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
tuh_vid_pid_get(self->device_number, &vid, &pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
STATIC xfer_result_t _get_string_result;
|
||||
STATIC bool _transfer_done_cb(uint8_t daddr, tusb_control_request_t const *request, xfer_result_t result) {
|
||||
(void)daddr;
|
||||
(void)request;
|
||||
_get_string_result = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
STATIC void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||
// TODO: Check for runover.
|
||||
(void)utf8_len;
|
||||
|
||||
for (size_t i = 0; i < utf16_len; i++) {
|
||||
uint16_t chr = utf16[i];
|
||||
if (chr < 0x80) {
|
||||
*utf8++ = chr & 0xff;
|
||||
} else if (chr < 0x800) {
|
||||
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
||||
} else if (chr < 0x10000) {
|
||||
// TODO: Verify surrogate.
|
||||
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
||||
} else {
|
||||
// TODO: Handle UTF-16 code points that take two entries.
|
||||
uint32_t hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */
|
||||
chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */
|
||||
chr = (hc | chr) + 0x10000;
|
||||
*utf8++ = (uint8_t)(0xF0 | (chr >> 18 & 0x07));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 12 & 0x3F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||
STATIC mp_int_t _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||
size_t total_bytes = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint16_t chr = buf[i];
|
||||
if (chr < 0x80) {
|
||||
total_bytes += 1;
|
||||
} else if (chr < 0x800) {
|
||||
total_bytes += 2;
|
||||
} else if (chr < 0x10000) {
|
||||
total_bytes += 3;
|
||||
} else {
|
||||
total_bytes += 4;
|
||||
}
|
||||
}
|
||||
return total_bytes;
|
||||
}
|
||||
|
||||
STATIC void _wait_for_callback(void) {
|
||||
while (!mp_hal_is_interrupted() &&
|
||||
_get_string_result == 0xff) {
|
||||
// The background tasks include TinyUSB which will call the function
|
||||
// we provided above. In other words, the callback isn't in an interrupt.
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t _get_string(const uint16_t *temp_buf) {
|
||||
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||
if (utf16_len == 0) {
|
||||
return mp_const_none;
|
||||
}
|
||||
size_t size = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, size + 1);
|
||||
byte *p = (byte *)vstr.buf;
|
||||
// Null terminate.
|
||||
p[size] = '\0';
|
||||
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, p, size);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self) {
|
||||
_get_string_result = 0xff;
|
||||
uint16_t temp_buf[127];
|
||||
if (!tuh_descriptor_string_serial_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
|
||||
return mp_const_none;
|
||||
}
|
||||
_wait_for_callback();
|
||||
return _get_string(temp_buf);
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self) {
|
||||
_get_string_result = 0xff;
|
||||
uint16_t temp_buf[127];
|
||||
if (!tuh_descriptor_string_product_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
|
||||
return mp_const_none;
|
||||
}
|
||||
_wait_for_callback();
|
||||
return _get_string(temp_buf);
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self) {
|
||||
_get_string_result = 0xff;
|
||||
uint16_t temp_buf[127];
|
||||
if (!tuh_descriptor_string_manufacturer_get(self->device_number, 0, temp_buf, MP_ARRAY_SIZE(temp_buf), _transfer_done_cb)) {
|
||||
return mp_const_none;
|
||||
}
|
||||
_wait_for_callback();
|
||||
return _get_string(temp_buf);
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
xfer_result_t control_result;
|
||||
STATIC bool _control_complete_cb(uint8_t dev_addr, tusb_control_request_t const *request, xfer_result_t result) {
|
||||
(void)dev_addr;
|
||||
(void)request;
|
||||
control_result = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
|
||||
mp_int_t bmRequestType, mp_int_t bRequest,
|
||||
mp_int_t wValue, mp_int_t wIndex,
|
||||
uint8_t *buffer, mp_int_t len, mp_int_t timeout) {
|
||||
// Timeout is in ms.
|
||||
|
||||
tusb_control_request_t request = {
|
||||
.bmRequestType = bmRequestType,
|
||||
.bRequest = bRequest,
|
||||
.wValue = wValue,
|
||||
.wIndex = wIndex,
|
||||
.wLength = len
|
||||
};
|
||||
control_result = XFER_RESULT_STALLED;
|
||||
bool result = tuh_control_xfer(self->device_number,
|
||||
&request,
|
||||
buffer,
|
||||
_control_complete_cb);
|
||||
if (!result) {
|
||||
mp_raise_usb_core_USBError(NULL);
|
||||
}
|
||||
uint32_t start_time = supervisor_ticks_ms32();
|
||||
while (supervisor_ticks_ms32() - start_time < (uint32_t)timeout &&
|
||||
!mp_hal_is_interrupted() &&
|
||||
control_result == XFER_RESULT_STALLED) {
|
||||
// The background tasks include TinyUSB which will call the function
|
||||
// we provided above. In other words, the callback isn't in an interrupt.
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
if (control_result == XFER_RESULT_STALLED) {
|
||||
mp_raise_usb_core_USBTimeoutError();
|
||||
}
|
||||
if (control_result == XFER_RESULT_SUCCESS) {
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface) {
|
||||
// TODO: Implement this when CP natively uses a keyboard.
|
||||
return false;
|
||||
}
|
||||
|
||||
void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
|
||||
// TODO: Implement this when CP natively uses a keyboard.
|
||||
}
|
||||
|
||||
void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface) {
|
||||
// TODO: Implement this when CP natively uses a keyboard.
|
||||
}
|
37
shared-module/usb/core/Device.h
Normal file
37
shared-module/usb/core/Device.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_MODULE_USB_CORE_DEVICE_H
|
||||
#define MICROPY_INCLUDED_SHARED_MODULE_USB_CORE_DEVICE_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
uint8_t device_number;
|
||||
} usb_core_device_obj_t;
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_MODULE_USB_CORE_DEVICE_H
|
27
shared-module/usb/core/__init__.c
Normal file
27
shared-module/usb/core/__init__.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Nothing implementation specific.
|
@ -48,7 +48,6 @@ char serial_read(void);
|
||||
bool serial_bytes_available(void);
|
||||
bool serial_connected(void);
|
||||
|
||||
// XXX used in nrf52-sleep debug
|
||||
int dbg_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
int debug_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
#endif // MICROPY_INCLUDED_SUPERVISOR_SERIAL_H
|
||||
|
@ -24,6 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
@ -49,7 +50,8 @@
|
||||
* Enabling on another platform will cause a crash.
|
||||
*/
|
||||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
#include "py/mpprint.h"
|
||||
#include "shared-bindings/busio/UART.h"
|
||||
busio_uart_obj_t debug_uart;
|
||||
byte buf_array[64];
|
||||
@ -59,17 +61,51 @@ byte buf_array[64];
|
||||
bool tud_vendor_connected(void);
|
||||
#endif
|
||||
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX)
|
||||
STATIC void debug_uart_print_strn(void *env, const char *str, size_t len) {
|
||||
(void)env;
|
||||
int uart_errcode;
|
||||
common_hal_busio_uart_write(&debug_uart, (const uint8_t *)str, len, &uart_errcode);
|
||||
}
|
||||
|
||||
const mp_print_t debug_uart_print = {NULL, debug_uart_print_strn};
|
||||
#endif
|
||||
|
||||
int debug_uart_printf(const char *fmt, ...) {
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX)
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = mp_vprintf(&debug_uart_print, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_early_init(void) {
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX) || defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
debug_uart.base.type = &busio_uart_type;
|
||||
|
||||
const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(DEBUG_UART_RX);
|
||||
const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(DEBUG_UART_TX);
|
||||
#if defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
const mcu_pin_obj_t *rx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_RX);
|
||||
#else
|
||||
const mcu_pin_obj_t *rx = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX)
|
||||
const mcu_pin_obj_t *tx = MP_OBJ_TO_PTR(CIRCUITPY_DEBUG_UART_TX);
|
||||
#else
|
||||
const mcu_pin_obj_t *tx = NULL;
|
||||
#endif
|
||||
|
||||
common_hal_busio_uart_construct(&debug_uart, tx, rx, NULL, NULL, NULL,
|
||||
false, 115200, 8, BUSIO_UART_PARITY_NONE, 1, 1.0f, 64,
|
||||
buf_array, true);
|
||||
common_hal_busio_uart_never_reset(&debug_uart);
|
||||
|
||||
// Do an initial print so that we can confirm the serial output is working.
|
||||
debug_uart_printf("Serial debug setup\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -84,7 +120,7 @@ bool serial_connected(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX) && defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@ -115,7 +151,7 @@ char serial_read(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
|
||||
int uart_errcode;
|
||||
char text;
|
||||
@ -148,7 +184,7 @@ bool serial_bytes_available(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_RX)
|
||||
if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
|
||||
return true;
|
||||
}
|
||||
@ -188,7 +224,7 @@ void serial_write_substring(const char *text, uint32_t length) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
|
||||
#if defined(CIRCUITPY_DEBUG_UART_TX)
|
||||
int uart_errcode;
|
||||
|
||||
common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
|
||||
|
@ -38,6 +38,8 @@
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -45,8 +47,11 @@ extern "C" {
|
||||
// --------------------------------------------------------------------+
|
||||
// COMMON CONFIGURATION
|
||||
// --------------------------------------------------------------------+
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
|
||||
// When debugging TinyUSB, only output to the UART debug link.
|
||||
#if CIRCUITPY_DEBUG_TINYUSB > 0 && defined(CIRCUITPY_DEBUG_UART_TX)
|
||||
#define CFG_TUSB_DEBUG CIRCUITPY_DEBUG_TINYUSB
|
||||
#define CFG_TUSB_DEBUG_PRINTF debug_uart_printf
|
||||
#endif
|
||||
|
||||
/*------------- RTOS -------------*/
|
||||
@ -59,11 +64,19 @@ extern "C" {
|
||||
// DEVICE CONFIGURATION
|
||||
// --------------------------------------------------------------------+
|
||||
|
||||
#if CIRCUITPY_USB_DEVICE_INSTANCE == 0
|
||||
#if USB_HIGHSPEED
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
|
||||
#else
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE)
|
||||
#endif
|
||||
#elif CIRCUITPY_USB_DEVICE_INSTANCE == 1
|
||||
#if USB_HIGHSPEED
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
|
||||
#else
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Vendor name included in Inquiry response, max 8 bytes
|
||||
#define CFG_TUD_MSC_VENDOR USB_MANUFACTURER_8
|
||||
@ -109,6 +122,43 @@ extern "C" {
|
||||
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(CIRCUITPY_TUSB_MEM_ALIGN)))
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// HOST CONFIGURATION
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#if CIRCUITPY_USB_HOST
|
||||
|
||||
#if CIRCUITPY_USB_HOST_INSTANCE == 0
|
||||
#if USB_HIGHSPEED
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
|
||||
#else
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST)
|
||||
#endif
|
||||
#elif CIRCUITPY_USB_HOST_INSTANCE == 1
|
||||
#if USB_HIGHSPEED
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
|
||||
#else
|
||||
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Size of buffer to hold descriptors and other data used for enumeration
|
||||
#ifndef CFG_TUH_ENUMERATION_BUFSIZE
|
||||
#define CFG_TUH_ENUMERATION_BUFSIZE 256
|
||||
#endif
|
||||
|
||||
#define CFG_TUH_HUB 1
|
||||
#define CFG_TUH_CDC 0
|
||||
#define CFG_TUH_MSC 0
|
||||
#define CFG_TUH_VENDOR 0
|
||||
|
||||
// max device support (excluding hub device)
|
||||
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
|
||||
|
||||
// Number of endpoints per device
|
||||
#define CFG_TUH_ENDPOINT_MAX 8
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -165,6 +165,9 @@ void usb_background(void) {
|
||||
if (usb_enabled()) {
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
tud_task();
|
||||
#if CIRCUITPY_USB_HOST
|
||||
tuh_task();
|
||||
#endif
|
||||
#endif
|
||||
// No need to flush if there's no REPL.
|
||||
#if CIRCUITPY_USB_CDC
|
||||
@ -185,8 +188,15 @@ void usb_background_schedule(void) {
|
||||
background_callback_add(&usb_callback, usb_background_do, NULL);
|
||||
}
|
||||
|
||||
void usb_irq_handler(void) {
|
||||
tud_int_handler(0);
|
||||
void usb_irq_handler(int instance) {
|
||||
if (instance == CIRCUITPY_USB_DEVICE_INSTANCE) {
|
||||
tud_int_handler(instance);
|
||||
} else if (instance == CIRCUITPY_USB_HOST_INSTANCE) {
|
||||
#if CIRCUITPY_USB_HOST
|
||||
tuh_int_handler(instance);
|
||||
#endif
|
||||
}
|
||||
|
||||
usb_background_schedule();
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,14 @@ else
|
||||
lib/tinyusb/src/class/vendor/vendor_device.c \
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(CIRCUITPY_USB_HOST), 1)
|
||||
SRC_SUPERVISOR += \
|
||||
lib/tinyusb/src/host/hub.c \
|
||||
lib/tinyusb/src/host/usbh.c \
|
||||
lib/tinyusb/src/host/usbh_control.c \
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
SRC_TINYUSB = $(filter lib/tinyusb/%.c, $(SRC_SUPERVISOR))
|
||||
|
@ -41,7 +41,7 @@ void usb_background(void);
|
||||
void usb_background_schedule(void);
|
||||
|
||||
// Ports must call this from their particular USB IRQ handler
|
||||
void usb_irq_handler(void);
|
||||
void usb_irq_handler(int instance);
|
||||
|
||||
// Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
|
||||
// TinyUSB.
|
||||
|
34
tests/circuitpython-manual/usb/basic_keyboard.py
Normal file
34
tests/circuitpython-manual/usb/basic_keyboard.py
Normal file
@ -0,0 +1,34 @@
|
||||
import array
|
||||
import usb.core
|
||||
import sys
|
||||
|
||||
# This is a WASD Code Keyboard with a generic controller in it.
|
||||
USB_VID = 0x04D9
|
||||
USB_PID = 0x0169
|
||||
# This is ordered by bit position.
|
||||
MODIFIERS = []
|
||||
|
||||
device = usb.core.find(idVendor=USB_VID, idProduct=USB_PID)
|
||||
|
||||
print(device.manufacturer, device.product)
|
||||
|
||||
# Test to see if the kernel is using the device and detach it.
|
||||
if device.is_kernel_driver_active(0):
|
||||
device.detach_kernel_driver(0)
|
||||
|
||||
# Boot keyboards have 8 byte reports
|
||||
buf = array.array("B", [0] * 8)
|
||||
report_count = 0
|
||||
while True:
|
||||
try:
|
||||
count = device.read(0x81, buf)
|
||||
except usb.core.USBTimeoutError:
|
||||
continue
|
||||
if report_count % 15 == 0:
|
||||
print("modifiers keys")
|
||||
print(buf[0], end=" ")
|
||||
for i in range(2, 8):
|
||||
if buf[i] > 0:
|
||||
print(buf[i], end=" ")
|
||||
print()
|
||||
report_count += 1
|
35
tests/circuitpython-manual/usb/basic_mouse.py
Normal file
35
tests/circuitpython-manual/usb/basic_mouse.py
Normal file
@ -0,0 +1,35 @@
|
||||
import array
|
||||
import usb.core
|
||||
import sys
|
||||
|
||||
# This is a basic Microsoft optical mouse with two buttons and a wheel that can
|
||||
# also be pressed.
|
||||
USB_VID = 0x045E
|
||||
USB_PID = 0x0040
|
||||
# This is ordered by bit position.
|
||||
BUTTONS = ["left", "right", "middle"]
|
||||
|
||||
device = usb.core.find(idVendor=USB_VID, idProduct=USB_PID)
|
||||
|
||||
print(device.manufacturer, device.product)
|
||||
|
||||
# Test to see if the kernel is using the device and detach it.
|
||||
if device.is_kernel_driver_active(0):
|
||||
device.detach_kernel_driver(0)
|
||||
|
||||
# Boot mice have 4 byte reports
|
||||
buf = array.array("b", [0] * 4)
|
||||
report_count = 0
|
||||
while True:
|
||||
try:
|
||||
count = device.read(0x81, buf)
|
||||
except usb.core.USBTimeoutError:
|
||||
continue
|
||||
if report_count % 15 == 0:
|
||||
print("x y wheel buttons")
|
||||
print(buf[1], buf[2], buf[3], end=" ")
|
||||
for i, button in enumerate(BUTTONS):
|
||||
if buf[0] & (1 << i) != 0:
|
||||
print(button, end=" ")
|
||||
print()
|
||||
report_count += 1
|
Loading…
Reference in New Issue
Block a user