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:
Scott Shawcroft 2022-02-18 17:57:54 -08:00
parent b439464627
commit 83593a1558
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
56 changed files with 1823 additions and 114 deletions

@ -1 +1 @@
Subproject commit 3b09b82123a50bef6b18cf90c2734ae7581da4a3
Subproject commit 73896a3b71c525a3ee4cefa7e35ce3b3a93786ef

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)) {

View File

@ -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)

View File

@ -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

View File

@ -6,3 +6,5 @@ USB_MANUFACTURER = "NXP"
CHIP_VARIANT = MIMXRT1062DVJ6A
CHIP_FAMILY = MIMXRT1062
FLASH = IS25WP064A
CIRCUITPY_USB_HOST = 1

View File

@ -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) },
};

View File

@ -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

View File

@ -7,3 +7,4 @@ CHIP_VARIANT = MIMXRT1062DVJ6A
CHIP_FAMILY = MIMXRT1062
FLASH = W25Q64JV
CIRCUITPY__EVE = 1
CIRCUITPY_USB_HOST = 1

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View 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;
}

View 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

View 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

View File

@ -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 }, };

View File

@ -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

View File

@ -29,14 +29,30 @@
#include "tusb.h"
#include "supervisor/usb.h"
void init_usb_hardware(void) {
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
(void)instance;
usb_phy = USBPHY;
#endif
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
#ifdef USBPHY
USBPHY_Type *usb_phy = USBPHY;
#else
USBPHY_Type *usb_phy = USBPHY1;
#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
@ -50,9 +66,25 @@ void init_usb_hardware(void) {
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

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -149,5 +149,5 @@ void init_usb_hardware(void) {
}
void OTG_FS_IRQHandler(void) {
usb_irq_handler();
usb_irq_handler(0);
}

View File

@ -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 \

View File

@ -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

View File

@ -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)

View 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);

View 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

View 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,
};

View 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

View 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);

View 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.

View 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,
};

View 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

View 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);

View 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

View 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

View 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.
}

View 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

View 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.

View File

@ -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

View File

@ -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);

View File

@ -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
}

View File

@ -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();
}

View File

@ -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))

View File

@ -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.

View 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

View 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