Merge branch 'master' into fork/HiFiPhile/stm32_cache

This commit is contained in:
hathach
2025-07-03 17:07:52 +07:00
107 changed files with 3261 additions and 1893 deletions

View File

@@ -19,13 +19,12 @@ jobs:
echo "MATRIX_JSON=$MATRIX_JSON"
BUILDSYSTEM_TOOLCHAIN=(
"cmake aarch64-gcc"
"cmake arm-clang"
"cmake arm-gcc"
"cmake esp-idf"
"make aarch64-gcc"
"make arm-gcc"
"make msp430-gcc"
"make riscv-gcc"
"make rx-gcc"
"cmake msp430-gcc"
"cmake riscv-gcc"
)
# only build IAR if not forked PR, since IAR token is not shared
@@ -67,7 +66,7 @@ jobs:
FAMILY_LARGE=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[])))')
FAMILY=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[]) | not))')
if [[ $toolchain == esp-idf ]]; then
if [[ $toolchain == esp-idf || $toolchain == arm-iar ]]; then
gen_build_entry "$build_system" "$toolchain" "$FAMILY" "large"
else
gen_build_entry "$build_system" "$toolchain" "$FAMILY" "medium+"

View File

@@ -36,11 +36,6 @@ env:
HIL_JSON: test/hil/tinyusb.json
jobs:
# ---------------------------------------
#
# Build
#
# ---------------------------------------
set-matrix:
runs-on: ubuntu-latest
outputs:
@@ -63,28 +58,31 @@ jobs:
echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT
# ---------------------------------------
# Build CMake
# Build CMake: only build on push with one-per-family.
# Full built is done by CircleCI in PR
# ---------------------------------------
cmake:
if: github.event_name == 'push'
needs: set-matrix
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
toolchain:
# - 'arm-clang' is built by circle-ci in PR
- 'aarch64-gcc'
#- 'arm-clang'
- 'arm-gcc'
- 'esp-idf'
- 'msp430-gcc'
- 'riscv-gcc'
with:
build-system: 'cmake'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
one-per-family: ${{ github.event_name == 'push' }}
one-per-family: true
# ---------------------------------------
# Build Make (built by circle-ci in PR, only build on push here)
# Build Make: only build on push with one-per-family
# ---------------------------------------
make:
if: github.event_name == 'push'
@@ -94,36 +92,18 @@ jobs:
fail-fast: false
matrix:
toolchain:
# 'arm-clang'
- 'arm-gcc'
- 'aarch64-gcc'
#- 'arm-clang'
- 'arm-gcc'
- 'msp430-gcc'
- 'riscv-gcc'
- 'rx-gcc'
- 'esp-idf'
with:
build-system: 'make'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
one-per-family: true
# ---------------------------------------
# Build Make on Windows/MacOS
# ---------------------------------------
make-os:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
with:
os: ${{ matrix.os }}
build-system: 'make'
toolchain: 'arm-gcc'
build-args: '["stm32h7"]'
one-per-family: true
# ---------------------------------------
# Build IAR
# Since IAR Token secret is not passed to forked PR, only build non-forked PR with make.
@@ -146,6 +126,23 @@ jobs:
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }}
one-per-family: true
# ---------------------------------------
# Build Make on Windows/MacOS
# ---------------------------------------
make-os:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
with:
os: ${{ matrix.os }}
build-system: 'make'
toolchain: 'arm-gcc'
build-args: '["stm32h7"]'
one-per-family: true
# ---------------------------------------
# Zephyr
# ---------------------------------------
@@ -168,14 +165,9 @@ jobs:
west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
# ---------------------------------------
#
# Hardware in the loop (HIL)
# Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR
# ---------------------------------------
# ---------------------------------------
# Build arm-gcc
# ---------------------------------------
hil-build:
if: |
github.repository_owner == 'hathach' &&

View File

@@ -31,6 +31,13 @@ Notable contributors
- Most features development
`Heiko Kuester <https://github.com/IngHK>`__
--------------------------------------------
- Add CH34x and PL2303 support (CDC host)
- Improve FTDI and CP210x support (CDC host)
`Hristo Gochkov <https://github.com/me-no-dev>`__
-------------------------------------------------

View File

@@ -74,7 +74,7 @@ Host Stack
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Communication Device Class: CDC-ACM
- Vendor serial over USB: FTDI, CP210x, CH34x
- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303
- Hub with multiple-level support
Similar to the Device Stack, if you have a special requirement, ``usbh_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack.

View File

@@ -5,12 +5,12 @@ Getting Started
Add TinyUSB to your project
---------------------------
It is relatively simple to incorporate tinyusb to your project
To incorporate tinyusb to your project
* Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is ``your_project/tinyusb``
* Add all the ``.c`` in the ``tinyusb/src`` folder to your project
* Add ``your_project/tinyusb/src`` to your include path. Also make sure your current include path also contains the configuration file ``tusb_config.h``.
* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by IDE/compiler to maintain a unique configure for all boards).
* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by make/cmake to maintain a unique configure for all boards).
* If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud descriptor** callbacks for the stack to work.
* Add ``tusb_init(rhport, role)`` call to your reset initialization code.
* Call ``tusb_int_handler(rhport, in_isr)`` in your USB IRQ Handler
@@ -75,24 +75,36 @@ The hardware code is located in ``hw/bsp`` folder, and is organized by family/bo
.. code-block:: bash
$ cd examples/device/cdc_msc
$ make BOARD=raspberry_pi_pico get-deps
$ make BOARD=feather_nrf52840_express get-deps
You only need to do this once per family. Check out `complete list of dependencies and their designated path here <dependencies.rst>`_
Build
^^^^^
Build Examples
^^^^^^^^^^^^^^
To build example, first change directory to an example folder.
Examples support make and cmake build system for most MCUs, however some MCU families such as espressif or rp2040 only support cmake. First change directory to an example folder.
.. code-block:: bash
$ cd examples/device/cdc_msc
Then compile with ``make BOARD={board_name} all`` , for example
Then compile with make or cmake
.. code-block:: bash
$ make BOARD=raspberry_pi_pico all
$ # make
$ make BOARD=feather_nrf52840_express all
$ # cmake
$ mkdir build && cd build
$ cmake -DBOARD=raspberry_pi_pico ..
$ make
To list all available targets with cmake
.. code-block:: bash
$ cmake --build . --target help
Note: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy ``99-tinyusb.rules`` and reload your udev is good to go
@@ -104,20 +116,24 @@ Note: some examples especially those that uses Vendor class (e.g webUSB) may req
RootHub Port Selection
~~~~~~~~~~~~~~~~~~~~~~
If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``PORT=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use:
If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``RHPORT_DEVICE=x`` or ``RHPORT_HOST=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use:
.. code-block:: bash
$ make BOARD=stm32f746disco PORT=1 all
$ make BOARD=stm32f746disco RHPORT_DEVICE=1 all
$ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE=1 ..
Port Speed
~~~~~~~~~~
A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``SPEED=full/high`` e.g To force F723 operate at full instead of default high speed
A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` or ``RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` e.g To force F723 operate at full instead of default high speed
.. code-block:: bash
$ make BOARD=stm32f746disco SPEED=full all
$ make BOARD=stm32f746disco RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all
$ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED ..
Size Analysis
~~~~~~~~~~~~~
@@ -137,6 +153,8 @@ To compile for debugging add ``DEBUG=1``\ , for example
$ make BOARD=feather_nrf52840_express DEBUG=1 all
$ cmake -DBOARD=feather_nrf52840_express -DCMAKE_BUILD_TYPE=Debug ..
Log
~~~
@@ -146,6 +164,8 @@ Should you have an issue running example and/or submitting an bug report. You co
$ make BOARD=feather_nrf52840_express LOG=2 all
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 ..
Logger
~~~~~~
@@ -169,6 +189,9 @@ By default log message is printed via on-board UART which is slow and take lots
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=rtt ..
$ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=swo ..
Flash
^^^^^
@@ -179,11 +202,15 @@ Flash
$ make BOARD=feather_nrf52840_express flash
$ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flash
Since jlink can be used with most of the boards, there is also ``flash-jlink`` target for your convenience.
Since jlink/openocd can be used with most of the boards, there is also ``flash-jlink/openocd`` (make) and ``EXAMPLE-jlink/openocd`` target for your convenience. Note for stm32 board with stlink, you can use ``flash-stlink`` target as well.
.. code-block:: bash
$ make BOARD=feather_nrf52840_express flash-jlink
$ make BOARD=feather_nrf52840_express flash-openocd
$ cmake --build . --target cdc_msc-jlink
$ cmake --build . --target cdc_msc-openocd
Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with ``uf2`` target
@@ -191,17 +218,18 @@ Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can
$ make BOARD=feather_nrf52840_express all uf2
$ cmake --build . --target cdc_msc-uf2
IAR Support
-----------
^^^^^^^^^^^
Use project connection
^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~
IAR Project Connection files are provided to import TinyUSB stack into your project.
* A buildable project of your MCU need to be created in advance.
* Take example of STM32F0:
- You need ``stm32l0xx.h``, ``startup_stm32f0xx.s``, ``system_stm32f0xx.c``.
@@ -212,15 +240,13 @@ IAR Project Connection files are provided to import TinyUSB stack into your proj
Click ``New Group ...``, name it to ``TUSB``, Click ``Add Variable ...``, name it to ``TUSB_DIR``, change it's value to the path of your TinyUSB stack,
for example ``C:\\tinyusb``
Import stack only
~~~~~~~~~~~~~~~~~
**Import stack only**
1. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``.
Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``.
Run examples
~~~~~~~~~~~~
**Run examples**
1. (Python3 is needed) Run ``iar_gen.py`` to generate .ipcf files of examples:
1. Run ``iar_gen.py`` to generate .ipcf files of examples:
.. code-block::
@@ -230,8 +256,8 @@ Run examples
2. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\examples\\(.ipcf of example)``.
For example ``C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf``
Native CMake support (9.50.1+)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Native CMake support
~~~~~~~~~~~~~~~~~~~~
With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project.

View File

@@ -123,27 +123,24 @@ endif
ifeq (${MAX3421_HOST},1)
SRC_C += src/portable/analog/max3421/hcd_max3421.c
CFLAGS += -DCFG_TUH_MAX3421=1
CMAKE_DEFSYM += -DMAX3421_HOST=1
endif
# Log level is mapped to TUSB DEBUG option
ifneq ($(LOG),)
CMAKE_DEFSYM += -DLOG=$(LOG)
CFLAGS += -DCFG_TUSB_DEBUG=$(LOG)
endif
# Logger: default is uart, can be set to rtt or swo
ifneq ($(LOGGER),)
CMAKE_DEFSYM += -DLOGGER=$(LOGGER)
endif
ifeq ($(LOGGER),rtt)
CFLAGS += -DLOGGER_RTT -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
RTT_SRC = lib/SEGGER_RTT
INC += $(TOP)/$(RTT_SRC)/RTT
SRC_C += $(RTT_SRC)/RTT/SEGGER_RTT.c
else ifeq ($(LOGGER),swo)
CFLAGS += -DLOGGER_RTT
#CFLAGS += -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
INC += $(TOP)/$(lib/SEGGER_RTT)/RTT
SRC_C += $(lib/SEGGER_RTT)/RTT/SEGGER_RTT.c
endif
ifeq ($(LOGGER),swo)
CFLAGS += -DLOGGER_SWO
else
CFLAGS += -DLOGGER_UART
endif
# CPU specific flags

View File

@@ -39,7 +39,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -158,17 +158,16 @@ int main(void)
xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
void app_main(void)
{
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
#endif

View File

@@ -59,7 +59,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -38,7 +38,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -132,15 +132,15 @@ int main(void)
xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}

View File

@@ -59,7 +59,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -49,25 +49,34 @@ int main(void) {
while (1) {
uint32_t interval_ms = board_button_read() ? BLINK_PRESSED : BLINK_UNPRESSED;
int ch = board_getchar();
if (ch > 0) {
board_putchar(ch);
#ifndef LOGGER_UART
board_uart_write(&ch, 1);
#endif
}
// Blink and print every interval ms
if (!(board_millis() - start_ms < interval_ms)) {
board_uart_write(HELLO_STR, strlen(HELLO_STR));
start_ms = board_millis();
if (ch < 0) {
// skip if echoing
printf(HELLO_STR);
#ifndef LOGGER_UART
board_uart_write(HELLO_STR, strlen(HELLO_STR));
#endif
}
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
// echo
uint8_t ch;
if (board_uart_read(&ch, 1) > 0) {
board_uart_write(&ch, 1);
}
}
}
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}

View File

@@ -44,7 +44,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -98,27 +98,33 @@ void tud_umount_cb(void) {
blink_interval_ms = BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
static void cdc_task(void) {
uint8_t itf;
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
for (uint8_t itf = 0; itf < CFG_TUD_CDC; itf++) {
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_n_connected(itf) )
{
if (tud_cdc_n_available(itf)) {
uint8_t buf[64];
uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
// echo back to both serial ports
echo_serial_port(0, buf, count);
echo_serial_port(1, buf, count);
}
// Press on-board button to send Uart status notification
static uint32_t btn_prev = 0;
static cdc_notify_uart_state_t uart_state = { .value = 0 };
const uint32_t btn = board_button_read();
if (!btn_prev && btn) {
uart_state.dsr ^= 1;
tud_cdc_notify_uart_state(&uart_state);
}
btn_prev = btn;
}
}
}

View File

@@ -97,6 +97,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)

View File

@@ -42,8 +42,7 @@
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
tusb_desc_device_t const desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
@@ -68,16 +67,14 @@ tusb_desc_device_t const desc_device =
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
enum {
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_CDC_1,
@@ -130,36 +127,32 @@ enum
#define EPNUM_CDC_1_IN 0x84
#endif
uint8_t const desc_fs_configuration[] =
{
uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
uint8_t const desc_hs_configuration[] =
{
uint8_t const desc_hs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
};
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
tusb_desc_device_qualifier_t const desc_device_qualifier = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
@@ -177,34 +170,31 @@ tusb_desc_device_qualifier_t const desc_device_qualifier =
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
uint8_t const *tud_descriptor_device_qualifier_cb(void) {
return (uint8_t const *) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index;// for multiple configurations
// if link speed is high return fullspeed config, and vice versa
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
}
#endif // highspeed
#endif// highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
@@ -223,8 +213,7 @@ enum {
};
// array of pointer to string descriptors
char const *string_desc_arr[] =
{
char const *string_desc_arr[] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
@@ -254,14 +243,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
if ( chr_count > max_count ) chr_count = max_count;
if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -272,6 +261,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}

View File

@@ -119,6 +119,16 @@ void cdc_task(void) {
tud_cdc_write(buf, count);
tud_cdc_write_flush();
}
// Press on-board button to send Uart status notification
static uint32_t btn_prev = 0;
static cdc_notify_uart_state_t uart_state = { .value = 0 };
const uint32_t btn = board_button_read();
if (!btn_prev && btn) {
uart_state.dsr ^= 1;
tud_cdc_notify_uart_state(&uart_state);
}
btn_prev = btn;
}
}

View File

@@ -184,7 +184,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
}
// Check for overflow of offset + bufsize
if (offset + bufsize > DISK_BLOCK_SIZE) {
if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
return -1;
}

View File

@@ -87,7 +87,7 @@
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
@@ -97,6 +97,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)

View File

@@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = {
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
@@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -146,7 +145,7 @@ uint8_t const desc_hs_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
@@ -197,7 +196,6 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
@@ -256,14 +254,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
if ( chr_count > max_count ) chr_count = max_count;
if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -274,6 +272,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}

View File

@@ -30,7 +30,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -72,7 +72,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
static void usb_device_task(void *param);
void led_blinking_task(void* param);
void cdc_task(void *params);
extern void msc_disk_init(void);
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
@@ -91,15 +91,15 @@ int main(void) {
xTaskCreate(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
#if !TUSB_MCU_VENDOR_ESPRESSIF
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#ifndef ESP_PLATFORM
// only start scheduler for non-espressif mcu
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
@@ -123,6 +123,7 @@ static void usb_device_task(void *param) {
board_init_after_tusb();
}
msc_disk_init();
// RTOS forever loop
while (1) {
// put this thread to waiting state until there is new events
@@ -188,6 +189,16 @@ void cdc_task(void *params) {
}
tud_cdc_write_flush();
// Press on-board button to send Uart status notification
static uint32_t btn_prev = 0;
static cdc_notify_uart_state_t uart_state = { .value = 0 };
const uint32_t btn = board_button_read();
if (!btn_prev && btn) {
uart_state.dsr ^= 1;
tud_cdc_notify_uart_state(&uart_state);
}
btn_prev = btn;
}
// For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog

View File

@@ -28,6 +28,37 @@
#if CFG_TUD_MSC
// Use async IO in example or not
#define CFG_EXAMPLE_MSC_ASYNC_IO 1
// Simulate read/write operation delay
#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0
#if CFG_EXAMPLE_MSC_ASYNC_IO
#define IO_STACK_SIZE configMINIMAL_STACK_SIZE
typedef struct {
uint8_t lun;
bool is_read;
uint32_t lba;
uint32_t offset;
void* buffer;
uint32_t bufsize;
} io_ops_t;
QueueHandle_t io_queue;
#if configSUPPORT_STATIC_ALLOCATION
uint8_t io_queue_buf[sizeof(io_ops_t)];
StaticQueue_t io_queue_static;
StackType_t io_stack[IO_STACK_SIZE];
StaticTask_t io_taskdef;
#endif
static void io_task(void *params);
#endif
void msc_disk_init(void);
// whether host does safe-eject
static bool ejected = false;
@@ -40,8 +71,7 @@ static bool ejected = false;
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
enum
{
enum {
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
@@ -119,16 +149,52 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
README_CONTENTS
};
#if CFG_EXAMPLE_MSC_ASYNC_IO
void msc_disk_init() {
#if configSUPPORT_STATIC_ALLOCATION
io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static);
xTaskCreateStatic(io_task, "io", IO_STACK_SIZE, NULL, 2, io_stack, &io_taskdef);
#else
io_queue = xQueueCreate(1, sizeof(io_ops_t));
xTaskCreate(io_task, "io", IO_STACK_SIZE, NULL, 2, NULL);
#endif
}
static void io_task(void *params) {
(void) params;
io_ops_t io_ops;
while (1) {
if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) {
const uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset;
int32_t nbytes = io_ops.bufsize;
if (io_ops.is_read) {
memcpy(io_ops.buffer, addr, io_ops.bufsize);
} else {
#ifndef CFG_EXAMPLE_MSC_READONLY
memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize);
#else
nbytes = -1; // failed to write
#endif
}
tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
tud_msc_async_io_done(nbytes, false);
}
}
}
#else
void msc_disk_init() {}
#endif
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
@@ -136,8 +202,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
(void) lun;
// RAM disk is ready until ejected
@@ -152,10 +217,8 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun)
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
@@ -163,18 +226,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
if (load_eject) {
if (start) {
// load disk storage
}else
{
} else {
// unload disk storage
ejected = true;
}
@@ -185,90 +244,107 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) {
return -1;
if (lba >= DISK_BLOCK_NUM) {
return TUD_MSC_RET_ERROR;
}
// Check for overflow of offset + bufsize
if ( offset + bufsize > DISK_BLOCK_SIZE ) {
return -1;
if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
return TUD_MSC_RET_ERROR;
}
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
#if CFG_EXAMPLE_MSC_ASYNC_IO
io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
return (int32_t) bufsize;
// Send IO operation to IO task
TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
return TUD_MSC_RET_ASYNC;
#else
uint8_t const *addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return bufsize;
#endif
}
bool tud_msc_is_writable_cb (uint8_t lun)
{
bool tud_msc_is_writable_cb (uint8_t lun) {
(void) lun;
#ifdef CFG_EXAMPLE_MSC_READONLY
#ifdef CFG_EXAMPLE_MSC_READONLY
return false;
#else
#else
return true;
#endif
#endif
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
(void) lun;
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
if (lba >= DISK_BLOCK_NUM) {
return TUD_MSC_RET_ERROR;
}
#ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[lba] + offset;
// Check for overflow of offset + bufsize
if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
return TUD_MSC_RET_ERROR;
}
#ifdef CFG_EXAMPLE_MSC_READONLY
(void) lun;
(void) buffer;
return bufsize;
#endif
#if CFG_EXAMPLE_MSC_ASYNC_IO
io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
// Send IO operation to IO task
TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
return TUD_MSC_RET_ASYNC;
#else
uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void) lba; (void) offset; (void) buffer;
#endif
tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
return (int32_t) bufsize;
return bufsize;
#endif
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
void const *response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
switch (scsi_cmd[0]) {
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if (resplen > bufsize) { resplen = bufsize; }
if ( response && (resplen > 0) )
{
if(in_xfer)
{
if (response && (resplen > 0)) {
if (in_xfer) {
memcpy(buffer, response, (size_t) resplen);
}else
{
} else {
// SCSI output
}
}

View File

@@ -59,7 +59,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
@@ -104,6 +104,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)

View File

@@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = {
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
@@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -147,7 +146,7 @@ uint8_t const desc_hs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
@@ -176,16 +175,14 @@ tusb_desc_device_qualifier_t const desc_device_qualifier =
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
uint8_t const* tud_descriptor_device_qualifier_cb(void) {
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
@@ -204,13 +201,12 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
@@ -229,8 +225,7 @@ enum {
};
// array of pointer to string descriptors
char const *string_desc_arr[] =
{
char const *string_desc_arr[] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
@@ -261,14 +256,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
if ( chr_count > max_count ) chr_count = max_count;
if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -279,6 +274,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}

View File

@@ -31,7 +31,7 @@
#include "tusb.h"
#include "usb_descriptors.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -112,17 +112,16 @@ int main(void)
xTimerStart(blinky_tm, 0);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
void app_main(void)
{
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
#endif

View File

@@ -59,7 +59,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -40,7 +40,7 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -95,15 +95,15 @@ int main(void) {
xTaskCreate(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
#if !TUSB_MCU_VENDOR_ESPRESSIF
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#ifndef ESP_PLATFORM
// only start scheduler for non-espressif mcu
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += lib/lwip
include ../../build_system/make/make.mk
# suppress warning caused by lwip

View File

@@ -292,7 +292,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4)
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
int main(void);
void app_main(void) {
@@ -351,8 +351,8 @@ void freertos_init_task(void) {
xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}

View File

@@ -58,7 +58,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -300,7 +300,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4)
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
int main(void);
void app_main(void) {
@@ -359,8 +359,8 @@ void freertos_init_task(void) {
xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}

View File

@@ -58,7 +58,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -31,8 +31,7 @@ static size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
int ch = board_getchar();
if (ch <= 0) break;
if (ch <= 0) { break; }
buf[count] = (uint8_t) ch;
count++;
}
@@ -69,10 +68,15 @@ void tuh_cdc_rx_cb(uint8_t idx) {
uint32_t const bufsize = sizeof(buf) - 1;
// forward cdc interfaces -> console
uint32_t count = tuh_cdc_read(idx, buf, bufsize);
buf[count] = 0;
const uint32_t count = tuh_cdc_read(idx, buf, bufsize);
if (count) {
buf[count] = 0;
printf("%s", (char*) buf);
printf("%s", (char*) buf);
#ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
fflush(stdout);// flush right away, else nanolib will wait for newline
#endif
}
}
// Invoked when a device with CDC interface is mounted
@@ -88,7 +92,7 @@ void tuh_cdc_mount_cb(uint8_t idx) {
// If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack
// while eneumerating new cdc device
cdc_line_coding_t line_coding = {0};
if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
if (tuh_cdc_get_line_coding_local(idx, &line_coding)) {
printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
}

View File

@@ -103,10 +103,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
#define CFG_TUH_CDC 1 // CDC ACM
#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -122,7 +123,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width

View File

@@ -27,7 +27,7 @@
#include "tusb.h"
#include "bsp/board_api.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CDC_STACK_SZIE 2048
#else
#define CDC_STACK_SZIE (3*configMINIMAL_STACK_SIZE/2)

View File

@@ -30,7 +30,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USBH_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -86,15 +86,15 @@ int main(void) {
xTimerStart(blinky_tm, 0);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}

View File

@@ -44,7 +44,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
@@ -108,10 +108,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
#define CFG_TUH_CDC 1 // CDC ACM
#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -127,7 +128,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width

View File

@@ -268,7 +268,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define USB_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -285,7 +285,7 @@ StackType_t usb_stack[USB_STACK_SIZE];
StaticTask_t usb_taskdef;
#endif
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
@@ -308,8 +308,8 @@ void init_freertos_task(void) {
xTaskCreate(usb_host_task, "usbh", USB_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TUSB_MCU_VENDOR_ESPRESSIF
// only start scheduler for non-espressif mcu
#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}

View File

@@ -40,7 +40,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -40,7 +40,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif

View File

@@ -71,9 +71,8 @@ int main(void)
}
}
#if TUSB_MCU_VENDOR_ESPRESSIF
void app_main(void)
{
#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
#endif

View File

@@ -60,13 +60,11 @@ int sys_read(int fhdl, char *buf, size_t count) {
int rd = (int) SEGGER_RTT_Read(0, buf, count);
return (rd > 0) ? rd : -1;
}
#endif
#elif defined(LOGGER_SWO)
#define ITM_BASE 0xE0000000
#define ITM_STIM0 (*((volatile uint8_t*)(ITM_BASE + 0)))
#define ITM_TER *((volatile uint32_t*)(ITM_BASE + 0xE00))
#define ITM_TCR *((volatile uint32_t*)(ITM_BASE + 0xE80))
@@ -150,6 +148,9 @@ int board_getchar(void) {
return (sys_read(0, &c, 1) > 0) ? (int) c : (-1);
}
void board_putchar(int c) {
sys_write(0, (const char*)&c, 1);
}
uint32_t tusb_time_millis_api(void) {
return board_millis();
@@ -158,7 +159,7 @@ uint32_t tusb_time_millis_api(void) {
//--------------------------------------------------------------------
// FreeRTOS hooks
//--------------------------------------------------------------------
#if CFG_TUSB_OS == OPT_OS_FREERTOS && !TUSB_MCU_VENDOR_ESPRESSIF
#if CFG_TUSB_OS == OPT_OS_FREERTOS && !defined(ESP_PLATFORM)
#include "FreeRTOS.h"
#include "task.h"
@@ -240,5 +241,4 @@ void vApplicationSetupTimerInterrupt(void) {
}
#endif
#endif

View File

@@ -41,7 +41,7 @@ extern "C" {
#if CFG_TUSB_OS == OPT_OS_ZEPHYR
#include <zephyr/kernel.h>
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
#if TUSB_MCU_VENDOR_ESPRESSIF
#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -195,6 +195,7 @@ static inline void board_delay(uint32_t ms) {
// stdio getchar() is blocking, this is non-blocking version
int board_getchar(void);
void board_putchar(int c);
#ifdef __cplusplus
}

View File

@@ -13,7 +13,6 @@ else
# The submodule BRTSG-FOSS/ft90x-sdk contains header files and source
# code for the Bridgetek SDK. This can be used instead of the prebuilt
# library.
DEPS_SUBMODULES += hw/mcu/bridgetek/ft9xx/ft90x-sdk
# The SDK can be used to load specific files from the Bridgetek SDK.
FT9XX_SDK = hw/mcu/bridgetek/ft9xx/ft90x-sdk/Source
INC += "$(TOP)/$(FT9XX_SDK)/include"

View File

@@ -1,6 +1,5 @@
# Submodules
CH32F20X_SDK = hw/mcu/wch/ch32f20x
DEPS_SUBMODULES += $(CH32F20X_SDK)
# WCH-SDK paths
CH32F20X_SDK_SRC = $(CH32F20X_SDK)/EVT/EXAM/SRC

View File

@@ -156,6 +156,10 @@ int board_getchar(void) {
return getchar();
}
void board_putchar(int c) {
putchar(c);
}
//--------------------------------------------------------------------
// PHY Init
//--------------------------------------------------------------------

View File

@@ -1,5 +1,3 @@
cmake_minimum_required(VERSION 3.5)
# Apply board specific content i.e IDF_TARGET must be set before project.cmake is included
include("${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake")
string(TOUPPER ${IDF_TARGET} FAMILY_MCUS)

View File

@@ -1,34 +0,0 @@
#DEPS_SUBMODULES +=
UF2_FAMILY_ID_esp32s2 = 0xbfdd4eee
UF2_FAMILY_ID_esp32s3 = 0xc47e5767
BOARD_CMAKE := $(file < $(TOP)/$(BOARD_PATH)/board.cmake)
ifneq ($(findstring esp32s2,$(BOARD_CMAKE)),)
IDF_TARGET = esp32s2
else
ifneq ($(findstring esp32s3,$(BOARD_CMAKE)),)
IDF_TARGET = esp32s3
endif
endif
.PHONY: all clean flash bootloader-flash app-flash erase monitor dfu-flash dfu
all:
idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) build
build: all
fullclean:
if test -f sdkconfig; then $(RM) -f sdkconfig ; fi
if test -d $(BUILD); then $(RM) -rf $(BUILD) ; fi
idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@
clean flash bootloader-flash app-flash erase monitor dfu-flash dfu size size-components size-files:
idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@
uf2: $(BUILD)/$(PROJECT).uf2
$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).bin
@echo CREATE $@
$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0 -c -o $@ $^

View File

@@ -221,6 +221,8 @@ function(family_configure_common TARGET RTOS)
target_include_directories(${TARGET} PUBLIC ${TOP}/lib/SEGGER_RTT/RTT)
# target_compile_definitions(${TARGET} PUBLIC SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL)
endif ()
else ()
target_compile_definitions(${TARGET} PUBLIC LOGGER_UART)
endif ()
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")

View File

@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x4fb2d5bd
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk

View File

@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
MCU_DIR = $(SDK_DIR)/devices/${MCU_VARIANT}
include $(TOP)/$(BOARD_PATH)/board.mk

View File

@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
MCU_DIR = $(SDK_DIR)/devices/$(MCU)
include $(TOP)/$(BOARD_PATH)/board.mk

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
CFLAGS += \
-DCFG_TUSB_MEM_SECTION='__attribute__((section(".data.$$RAM2")))'

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
MCU_DIR = hw/mcu/nxp/lpcopen/lpc13xx/lpc_chip_13xx
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
MCU_DIR = hw/mcu/nxp/lpcopen/lpc175x_6x/lpc_chip_175x_6x
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3

View File

@@ -1,4 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
MCU_DIR = hw/mcu/nxp/lpcopen/lpc18xx/lpc_chip_18xx
include $(TOP)/$(BOARD_PATH)/board.mk

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
MCU_DIR = hw/mcu/nxp/lpcopen/lpc40xx/lpc_chip_40xx
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4

View File

@@ -1,4 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
SDK_DIR = hw/mcu/nxp/lpcopen/lpc43xx/lpc_chip_43xx
include ${TOP}/${BOARD_PATH}/board.mk

View File

@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4

View File

@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x2abc77ec
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += lib/CMSIS_5 lib/sct_neopixel $(SDK_DIR)
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m33

View File

@@ -1,8 +1,6 @@
UF2_FAMILY_ID = 0x2abc77ec
SDK_DIR = hw/mcu/nxp/mcux-sdk
DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk
# Default to Highspeed PORT1

View File

@@ -11,36 +11,37 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/msp430_${T
set(FAMILY_MCUS MSP430x5xx CACHE INTERNAL "")
#------------------------------------
# BOARD_TARGET
#------------------------------------
# only need to be built ONCE for all examples
function(add_board_target BOARD_TARGET)
if (NOT TARGET ${BOARD_TARGET})
add_library(${BOARD_TARGET} INTERFACE)
target_compile_definitions(${BOARD_TARGET} INTERFACE
CFG_TUD_ENDPOINT0_SIZE=8
CFG_EXAMPLE_VIDEO_READONLY
CFG_EXAMPLE_MSC_READONLY
)
target_include_directories(${BOARD_TARGET} INTERFACE
${CMAKE_CURRENT_FUNCTION_LIST_DIR}
${SDK_DIR}
)
if (TARGET ${BOARD_TARGET})
return()
endif ()
update_board(${BOARD_TARGET})
add_library(${BOARD_TARGET} INTERFACE)
target_compile_definitions(${BOARD_TARGET} INTERFACE
CFG_TUD_ENDPOINT0_SIZE=8
CFG_EXAMPLE_VIDEO_READONLY
CFG_EXAMPLE_MSC_READONLY
)
target_include_directories(${BOARD_TARGET} INTERFACE
${CMAKE_CURRENT_FUNCTION_LIST_DIR}
${SDK_DIR}
)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_link_options(${BOARD_TARGET} INTERFACE
"LINKER:--script=${LD_FILE_GNU}"
-L${SDK_DIR}
)
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
target_link_options(${BOARD_TARGET} INTERFACE
"LINKER:--config=${LD_FILE_IAR}"
)
endif ()
update_board(${BOARD_TARGET})
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_link_options(${BOARD_TARGET} INTERFACE
"LINKER:--script=${LD_FILE_GNU}"
-L${SDK_DIR}
)
elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
target_link_options(${BOARD_TARGET} INTERFACE
"LINKER:--config=${LD_FILE_IAR}"
)
endif ()
endfunction()
@@ -75,7 +76,6 @@ function(family_configure_example TARGET RTOS)
)
target_link_libraries(${TARGET} PUBLIC board_${BOARD})
# Flashing
family_add_bin_hex(${TARGET})
family_flash_msp430flasher(${TARGET})

View File

@@ -1,5 +1,4 @@
CROSS_COMPILE = msp430-elf-
DEPS_SUBMODULES += hw/mcu/ti
SKIP_NANOLIB = 1
SDK_DIR = hw/mcu/ti/msp430/msp430-gcc-support-files/include

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nuvoton
CFLAGS += \
-flto \
-mthumb \

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nuvoton
CFLAGS += \
-flto \
-mthumb \

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nuvoton
CFLAGS += \
-flto \
-mthumb \

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nuvoton
CFLAGS += \
-flto \
-mthumb \

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/nuvoton
CFLAGS += \
-flto \
-mthumb \

View File

@@ -254,7 +254,7 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) {
int board_uart_read(uint8_t *buf, int len) {
#ifdef UART_DEV
int count = 0;
while ( (count < len) && uart_is_readable(uart_inst) ) {
while ((count < len) && uart_is_readable(uart_inst)) {
buf[count] = uart_getc(uart_inst);
count++;
}
@@ -282,6 +282,10 @@ int board_getchar(void) {
return getchar_timeout_us(0);
}
void board_putchar(int c) {
stdio_putchar(c);
}
//--------------------------------------------------------------------+
// USB Interrupt Handler
// rp2040 implementation will install appropriate handler when initializing

View File

@@ -1,18 +0,0 @@
JLINK_DEVICE = rp2040_m0_0
PYOCD_TARGET = rp2040
DEPS_SUBMODULES += hw/mcu/raspberry_pi/Pico-PIO-USB
ifeq ($(DEBUG), 1)
CMAKE_DEFSYM += -DCMAKE_BUILD_TYPE=Debug
endif
$(BUILD):
cmake -S . -B $(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) -DPICO_BUILD_DOCS=0 $(CMAKE_DEFSYM)
all: $(BUILD)
$(MAKE) -C $(BUILD)
flash: flash-pyocd
flash-uf2:
@$(CP) $(BUILD)/$(PROJECT).uf2 /media/$(USER)/RPI-RP2

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/renesas/rx
# Cross Compiler for RX
CROSS_COMPILE = rx-elf-

View File

@@ -1,4 +1,3 @@
DEPS_SUBMODULES += hw/mcu/microchip
ASF_DIR = hw/mcu/microchip/same70
CFLAGS += \

View File

@@ -1,4 +1,3 @@
DEPS_SUBMODULES += hw/mcu/microchip
ASF_DIR = hw/mcu/microchip/same70
CFLAGS += \

View File

@@ -16,9 +16,6 @@ CFLAGS += \
SILABS_FAMILY = efm32gg12b
SILABS_CMSIS = hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY)/Device/SiliconLabs/$(shell echo $(SILABS_FAMILY) | tr a-z A-Z)
DEPS_SUBMODULES += hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY)
DEPS_SUBMODULES += lib/CMSIS_5
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
# All source paths should be relative to the top level.

View File

@@ -1,5 +1,3 @@
DEPS_SUBMODULES += hw/mcu/sony/cxd56/spresense-exported-sdk
# Platforms are: Linux, Darwin, MSYS, CYGWIN
PLATFORM := $(firstword $(subst _, ,$(shell uname -s 2>/dev/null)))

View File

@@ -1,6 +1,4 @@
ST_FAMILY = c0
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,7 +1,5 @@
UF2_FAMILY_ID = 0x647824b6
ST_FAMILY = f0
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,6 +1,4 @@
ST_FAMILY = f1
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_${ST_FAMILY} hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_${ST_FAMILY}
ST_HAL_DRIVER = hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver

View File

@@ -2,11 +2,6 @@ ST_FAMILY = f2
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
DEPS_SUBMODULES += \
lib/CMSIS_5 \
$(ST_CMSIS) \
$(ST_HAL_DRIVER)
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3

View File

@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x53b80f00
ST_FAMILY = f7
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,5 +1,4 @@
ST_FAMILY = g0
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,5 +1,4 @@
ST_FAMILY = l4
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,5 +1,4 @@
ST_FAMILY = u5
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver

View File

@@ -1,8 +1,6 @@
UF2_FAMILY_ID = 0x00
SDK_DIR = hw/mcu/infineon/mtb-xmclib-cat3
DEPS_SUBMODULES += ${SDK_DIR}
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4

View File

@@ -1003,20 +1003,22 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
ep_fb = desc_ep->bEndpointAddress;
}
#endif
// Data EP
if (desc_ep->bmAttributes.usage == 0) {
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
#if CFG_TUD_AUDIO_ENABLE_EP_IN
ep_in = desc_ep->bEndpointAddress;
ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
#endif
} else {
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
ep_out = desc_ep->bEndpointAddress;
ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
#endif
}
// Data or data with implicit feedback IN EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
&& (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
ep_in = desc_ep->bEndpointAddress;
ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
// Data OUT EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT
&& desc_ep->bmAttributes.usage == 0) {
ep_out = desc_ep->bEndpointAddress;
ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
}
#endif
}
}
@@ -1052,10 +1054,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
if (desc_ep->bmAttributes.usage == 0) {
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
_audiod_fct[i].interval_tx = desc_ep->bInterval;
}
// For data or data with implicit feedback IN EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
&& (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
_audiod_fct[i].interval_tx = desc_ep->bInterval;
}
}
} else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) {
@@ -1227,7 +1229,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
usbd_edpt_clear_stall(rhport, ep_addr);
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP
// For data or data with implicit feedback IN EP
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2))
{
// Save address
audio->ep_in = ep_addr;

View File

@@ -192,6 +192,11 @@ typedef enum {
CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits
} cdc_line_coding_stopbits_t;
#define CDC_LINE_CODING_STOP_BITS_TEXT(STOP_BITS) ( \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?" )
// TODO Backward compatible for typos. Maybe removed in the future release
#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1
#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5
@@ -205,22 +210,31 @@ typedef enum {
CDC_LINE_CODING_PARITY_SPACE = 4,
} cdc_line_coding_parity_t;
#define CDC_LINE_CODING_PARITY_CHAR(PARITY) ( \
PARITY == CDC_LINE_CODING_PARITY_NONE ? 'N' : \
PARITY == CDC_LINE_CODING_PARITY_ODD ? 'O' : \
PARITY == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \
PARITY == CDC_LINE_CODING_PARITY_MARK ? 'M' : \
PARITY == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?' )
//--------------------------------------------------------------------+
// Management Element Notification (Notification Endpoint)
//--------------------------------------------------------------------+
#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface
/// 6.3 Notification Codes
typedef enum {
CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status.
CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request.
CDC_NOTIF_NETWORK_CONNECTION = 0x00, // notify the host about network connection status.
CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, // notify the host that a response is available.
CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,
CDC_NOTIF_RING_DETECT = 0x09,
CDC_NOTIF_SERIAL_STATE = 0x20,
CDC_NOTIF_CALL_STATE_CHANGE = 0x28,
CDC_NOTIF_LINE_STATE_CHANGE = 0x29,
CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, // notify the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,
}cdc_notification_request_t;
} cdc_notify_request_t;
//--------------------------------------------------------------------+
// Class Specific Functional Descriptor (Communication Interface)
@@ -231,8 +245,7 @@ TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
/// Header Functional Descriptor (Communication Interface)
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_
@@ -240,8 +253,7 @@ typedef struct TU_ATTR_PACKED
}cdc_desc_func_header_t;
/// Union Functional Descriptor (Communication Interface)
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -259,14 +271,13 @@ typedef struct TU_ATTR_PACKED
}
/// Country Selection Functional Descriptor (Communication Interface)
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes.
uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country.
}cdc_desc_func_country_selection_t;
} cdc_desc_func_country_selection_t;
#define cdc_desc_func_country_selection_n_t(no_country) \
struct TU_ATTR_PACKED { \
@@ -283,8 +294,7 @@ typedef struct TU_ATTR_PACKED
/// \brief Call Management Functional Descriptor
/// \details This functional descriptor describes the processing of calls for the Communications Class interface.
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -298,8 +308,7 @@ typedef struct TU_ATTR_PACKED
uint8_t bDataInterface;
}cdc_desc_func_call_management_t;
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature.
uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State.
uint8_t support_send_break : 1; ///< Device supports the request Send_Break
@@ -311,8 +320,7 @@ TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compile
/// Abstract Control Management Functional Descriptor
/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -321,8 +329,7 @@ typedef struct TU_ATTR_PACKED
/// \brief Direct Line Management Functional Descriptor
/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -384,16 +391,14 @@ typedef struct TU_ATTR_PACKED
}cdc_desc_func_telephone_call_state_reporting_capabilities_t;
// TODO remove
static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc)
{
TU_ATTR_ALWAYS_INLINE static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) {
return p_desc[2];
}
//--------------------------------------------------------------------+
// Requests
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint32_t bit_rate;
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
@@ -402,15 +407,58 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
typedef struct TU_ATTR_PACKED
{
uint16_t dtr : 1;
uint16_t rts : 1;
uint16_t : 6;
uint16_t : 8;
typedef union TU_ATTR_PACKED {
struct TU_ATTR_PACKED {
uint8_t dtr : 1;
uint8_t rts : 1;
uint8_t : 6;
};
uint8_t value;
} cdc_line_control_state_t;
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct");
//--------------------------------------------------------------------+
// Notifications
//--------------------------------------------------------------------+
// PSTN 1.2 section 6.5.4 table 31
typedef union TU_ATTR_PACKED {
struct TU_ATTR_PACKED {
uint16_t bRxCarrier : 1; // DCD
uint16_t bTxCarrier : 1; // DSR
uint16_t bBreak : 1; // Break Detected
uint16_t bRingSignal : 1;
uint16_t bFraming : 1;
uint16_t bParity : 1;
uint16_t bOverRun : 1;
uint16_t : 9;
};
struct TU_ATTR_PACKED {
uint16_t dcd : 1;
uint16_t dsr : 1;
uint16_t brk : 1;
uint16_t :13;
};
uint16_t value;
} cdc_notify_uart_state_t;
TU_VERIFY_STATIC(sizeof(cdc_notify_uart_state_t) == 2, "size is not correct");
// CDC 1.2 section 6.3.3 table 21
typedef struct TU_ATTR_PACKED {
uint32_t upstream_bitrate;
uint32_t downstream_bitrate;
} cdc_notify_conn_speed_change_t;
typedef struct TU_ATTR_PACKED {
tusb_control_request_t request;
union {
cdc_notify_uart_state_t serial_state;
cdc_notify_conn_speed_change_t conn_speed_change;
};
} cdc_notify_msg_t;
TU_VERIFY_STATIC(sizeof(cdc_notify_msg_t) == 16, "size is not correct");
TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END

View File

@@ -46,13 +46,13 @@
#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
typedef struct {
uint8_t rhport;
uint8_t itf_num;
uint8_t ep_notif;
uint8_t ep_in;
uint8_t ep_out;
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
uint8_t line_state;
uint8_t ep_notify;
uint8_t line_state; // Bit 0: DTR, Bit 1: RTS
/*------------- From this point, data is not cleared by bus reset -------------*/
char wanted_char;
@@ -74,6 +74,10 @@ typedef struct {
typedef struct {
TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE);
TUD_EPBUF_DEF(epin, CFG_TUD_CDC_EP_BUFSIZE);
#if CFG_TUD_CDC_NOTIFY
TUD_EPBUF_TYPE_DEF(cdc_notify_msg_t, epnotify);
#endif
} cdcd_epbuf_t;
//--------------------------------------------------------------------+
@@ -101,7 +105,7 @@ static bool _prep_out_transaction(uint8_t itf) {
TU_VERIFY(available >= CFG_TUD_CDC_EP_BUFSIZE);
// claim endpoint
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out));
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_out));
// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);
@@ -110,7 +114,7 @@ static bool _prep_out_transaction(uint8_t itf) {
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE);
} else {
// Release endpoint since we don't make any transfer
usbd_edpt_release(rhport, p_cdc->ep_out);
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out);
return false;
}
}
@@ -118,7 +122,6 @@ static bool _prep_out_transaction(uint8_t itf) {
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) {
TU_VERIFY(driver_cfg);
_cdcd_cfg = *driver_cfg;
@@ -142,6 +145,42 @@ void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
(*coding) = _cdcd_itf[itf].line_coding;
}
#if CFG_TUD_CDC_NOTIFY
bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *state) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
notify_msg->request.bRequest = CDC_NOTIF_SERIAL_STATE;
notify_msg->request.wValue = 0;
notify_msg->request.wIndex = p_cdc->itf_num;
notify_msg->request.wLength = sizeof(cdc_notify_uart_state_t);
notify_msg->serial_state = *state;
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_uart_state_t));
}
bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
notify_msg->request.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE;
notify_msg->request.wValue = 0;
notify_msg->request.wIndex = p_cdc->itf_num;
notify_msg->request.wLength = sizeof(cdc_notify_conn_speed_change_t);
notify_msg->conn_speed_change = *conn_speed_change;
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_conn_speed_change_t));
}
#endif
void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) {
_cdcd_itf[itf].wanted_char = wanted;
}
@@ -192,30 +231,25 @@ uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) {
uint32_t tud_cdc_n_write_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
// Skip if usb is not ready yet
TU_VERIFY(tud_ready(), 0);
TU_VERIFY(tud_ready(), 0); // Skip if usb is not ready yet
// No data to send
if (!tu_fifo_count(&p_cdc->tx_ff)) {
return 0;
}
const uint8_t rhport = 0;
// Claim the endpoint
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0);
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0); // Claim the endpoint
// Pull data from FIFO
const uint16_t count = tu_fifo_read_n(&p_cdc->tx_ff, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE);
if (count) {
TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_epbuf->epin, count), 0);
TU_ASSERT(usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_epbuf->epin, count), 0);
return count;
} else {
// Release endpoint since we don't make any transfer
// Note: data is dropped if terminal is not connected
usbd_edpt_release(rhport, p_cdc->ep_in);
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in);
return 0;
}
}
@@ -319,6 +353,7 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16
TU_ASSERT(cdc_id < CFG_TUD_CDC, 0);
//------------- Control Interface -------------//
p_cdc->rhport = rhport;
p_cdc->itf_num = itf_desc->bInterfaceNumber;
uint16_t drv_len = sizeof(tusb_desc_interface_t);
@@ -333,9 +368,8 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
// notification endpoint
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
p_cdc->ep_notif = desc_ep->bEndpointAddress;
p_cdc->ep_notify = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
@@ -455,7 +489,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Identify which interface to use
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
p_cdc = &_cdcd_itf[itf];
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) {
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notify)) {
break;
}
}
@@ -504,7 +538,12 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
}
// nothing to do with notif endpoint for now
// Sent notification to host
if (ep_addr == p_cdc->ep_notify) {
if (tud_cdc_notify_complete_cb) {
tud_cdc_notify_complete_cb(itf);
}
}
return true;
}

View File

@@ -32,6 +32,10 @@
//--------------------------------------------------------------------+
// Class Driver Configuration
//--------------------------------------------------------------------+
#ifndef CFG_TUD_CDC_NOTIFY
#define CFG_TUD_CDC_NOTIFY 0
#endif
#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE)
#warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name
#define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE
@@ -126,6 +130,23 @@ uint32_t tud_cdc_n_write_available(uint8_t itf);
// Clear the transmit FIFO
bool tud_cdc_n_write_clear(uint8_t itf);
#if CFG_TUD_CDC_NOTIFY
// Send UART status notification: DCD, DSR etc ..
bool tud_cdc_n_notify_uart_state(uint8_t itf, const cdc_notify_uart_state_t *state);
// Send connection speed change notification
bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change);
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_uart_state(const cdc_notify_uart_state_t* state) {
return tud_cdc_n_notify_uart_state(0, state);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_conn_speed_change(const cdc_notify_conn_speed_change_t* conn_speed_change) {
return tud_cdc_n_notify_conn_speed_change(0, conn_speed_change);
}
#endif
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
@@ -195,7 +216,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) {
}
//--------------------------------------------------------------------+
// Application Callback API (weak is optional)
// Application Callback API
//--------------------------------------------------------------------+
// Invoked when received new data
@@ -207,6 +228,9 @@ TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
// Invoked when a TX is complete and therefore space becomes available in TX buffer
TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
// Invoked when a notification is sent to host
TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf);
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);

File diff suppressed because it is too large Load Diff

View File

@@ -37,16 +37,6 @@
// Class Driver Configuration
//--------------------------------------------------------------------+
// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1)
#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0
#endif
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
//#endif
// RX FIFO size
#ifndef CFG_TUH_CDC_RX_BUFSIZE
#define CFG_TUH_CDC_RX_BUFSIZE TUH_EPSIZE_BULK_MPS
@@ -79,14 +69,27 @@ uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num);
// return true if index is correct and interface is currently mounted
bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info);
// Check if a interface is mounted
// Check if an interface is mounted
bool tuh_cdc_mounted(uint8_t idx);
// Get local (cached) line state
// This function should return correct values if tuh_cdc_set_control_line_state() / tuh_cdc_get_control_line_state()
// are invoked previously or CFG_TUH_CDC_LINE_STATE_ON_ENUM is defined.
bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state);
// Get current DTR status
bool tuh_cdc_get_dtr(uint8_t idx);
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_dtr(uint8_t idx) {
uint16_t line_state;
TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
return (line_state & CDC_CONTROL_LINE_STATE_DTR) != 0;
}
// Get current RTS status
bool tuh_cdc_get_rts(uint8_t idx);
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_rts(uint8_t idx) {
uint16_t line_state;
TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
return (line_state & CDC_CONTROL_LINE_STATE_RTS) != 0;
}
// Check if interface is connected (DTR active)
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
@@ -97,7 +100,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding()
// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined.
// NOTE: This function does not make any USB transfer request to device.
bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding);
bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t* line_coding);
#define tuh_cdc_get_local_line_coding tuh_cdc_get_line_coding_local // backward compatibility
//--------------------------------------------------------------------+
// Write API
@@ -132,18 +137,31 @@ bool tuh_cdc_peek(uint8_t idx, uint8_t* ch);
bool tuh_cdc_read_clear (uint8_t idx);
//--------------------------------------------------------------------+
// Control Endpoint (Request) API
// Control Request API
// Each Function will make a USB control transfer request to/from device
// - If complete_cb is provided, the function will return immediately and invoke
// the callback when request is complete.
// - If complete_cb is NULL, the function will block until request is complete.
// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result.
// - The function will return true if transfer is successful, false otherwise.
// In this case, user_data should be usb_xfer_result_t* to hold the transfer result.
//--------------------------------------------------------------------+
// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Request to Set DTR
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
cdc_line_control_state_t line_state = { .dtr = dtr_state };
line_state.rts = tuh_cdc_get_rts(idx);
return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
}
// Request to Set RTS
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
cdc_line_control_state_t line_state = { .rts = rts_state };
line_state.dtr = tuh_cdc_get_dtr(idx);
return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
}
// Request to set baudrate
bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
@@ -160,17 +178,52 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding,
// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding);
// Connect by set both DTR, RTS
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data);
}
// Disconnect by clear both DTR, RTS
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data);
}
//--------------------------------------------------------------------+
// Control Request Sync API
// Each Function will make a USB control transfer request to/from device the function will block until request is
// complete. The function will return the transfer request result
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_control_line_state_sync(uint8_t idx, uint16_t line_state) {
TU_API_SYNC(tuh_cdc_set_control_line_state, idx, line_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_dtr_sync(uint8_t idx, bool dtr_state) {
TU_API_SYNC(tuh_cdc_set_dtr, idx, dtr_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_rts_sync(uint8_t idx, bool rts_state) {
TU_API_SYNC(tuh_cdc_set_rts, idx, rts_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_baudrate_sync(uint8_t idx, uint32_t baudrate) {
TU_API_SYNC(tuh_cdc_set_baudrate, idx, baudrate);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_data_format_sync(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits) {
TU_API_SYNC(tuh_cdc_set_data_format, idx, stop_bits, parity, data_bits);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_line_coding_sync(uint8_t idx, cdc_line_coding_t const* line_coding) {
TU_API_SYNC(tuh_cdc_set_line_coding, idx, line_coding);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_connect_sync(uint8_t idx) {
TU_API_SYNC(tuh_cdc_connect, idx);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(uint8_t idx) {
TU_API_SYNC(tuh_cdc_disconnect, idx);
}
//--------------------------------------------------------------------+
// CDC APPLICATION CALLBACKS
//--------------------------------------------------------------------+

View File

@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _CH34X_H_
#define _CH34X_H_
#ifndef TUSB_CH34X_H
#define TUSB_CH34X_H
// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found
// - https://github.com/WCHSoftGroup/ch341ser_linux
@@ -34,51 +34,51 @@
// set line_coding @ enumeration
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM
#else // this default is necessary to work properly
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
#endif
// USB requests
#define CH34X_REQ_READ_VERSION 0x5F // dec 95
#define CH34X_REQ_WRITE_REG 0x9A // dec 154
#define CH34X_REQ_READ_REG 0x95 // dec 149
#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
#define CH34X_REQ_READ_VERSION 0x5F // dec 95
#define CH34X_REQ_WRITE_REG 0x9A // dec 154
#define CH34X_REQ_READ_REG 0x95 // dec 149
#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
// registers
#define CH34X_REG_BREAK 0x05
#define CH34X_REG_PRESCALER 0x12
#define CH34X_REG_DIVISOR 0x13
#define CH34X_REG_LCR 0x18
#define CH34X_REG_LCR2 0x25
#define CH34X_REG_MCR_MSR 0x06
#define CH34X_REG_MCR_MSR2 0x07
#define CH34X_NBREAK_BITS 0x01
#define CH34X_REG_BREAK 0x05
#define CH34X_REG_PRESCALER 0x12
#define CH34X_REG_DIVISOR 0x13
#define CH34X_REG_LCR 0x18
#define CH34X_REG_LCR2 0x25
#define CH34X_REG_MCR_MSR 0x06
#define CH34X_REG_MCR_MSR2 0x07
#define CH34X_NBREAK_BITS 0x01
#define CH341_REG_0x0F 0x0F // undocumented register
#define CH341_REG_0x2C 0x2C // undocumented register
#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts)
#define CH341_REG_0x0F 0x0F // undocumented register
#define CH341_REG_0x2C 0x2C // undocumented register
#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts)
#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER)
#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR)
#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER)
#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR)
// modem control bits
#define CH34X_BIT_RTS ( 1 << 6 )
#define CH34X_BIT_DTR ( 1 << 5 )
#define CH34X_BIT_RTS (1 << 6)
#define CH34X_BIT_DTR (1 << 5)
// line control bits
#define CH34X_LCR_ENABLE_RX 0x80
#define CH34X_LCR_ENABLE_TX 0x40
#define CH34X_LCR_MARK_SPACE 0x20
#define CH34X_LCR_PAR_EVEN 0x10
#define CH34X_LCR_ENABLE_PAR 0x08
#define CH34X_LCR_PAR_MASK 0x38 // all parity bits
#define CH34X_LCR_STOP_BITS_2 0x04
#define CH34X_LCR_CS8 0x03
#define CH34X_LCR_CS7 0x02
#define CH34X_LCR_CS6 0x01
#define CH34X_LCR_CS5 0x00
#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
#define CH34X_LCR_ENABLE_RX 0x80
#define CH34X_LCR_ENABLE_TX 0x40
#define CH34X_LCR_MARK_SPACE 0x20
#define CH34X_LCR_PAR_EVEN 0x10
#define CH34X_LCR_ENABLE_PAR 0x08
#define CH34X_LCR_PAR_MASK 0x38 // all parity bits
#define CH34X_LCR_STOP_BITS_2 0x04
#define CH34X_LCR_CS8 0x03
#define CH34X_LCR_CS7 0x02
#define CH34X_LCR_CS6 0x01
#define CH34X_LCR_CS5 0x00
#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
#endif /* _CH34X_H_ */
#endif // TUSB_CH34X_H

View File

@@ -28,9 +28,10 @@
// Protocol details can be found at AN571: CP210x Virtual COM Port Interface
// https://www.silabs.com/documents/public/application-notes/AN571.pdf
#define TU_CP210X_VID 0x10C4
// parts are overtaken from vendors driver
// https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz
/* Config request codes */
// Config request codes
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
@@ -59,4 +60,55 @@
#define CP210X_SET_BAUDRATE 0x1E
#define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device
// SILABSER_IFC_ENABLE_REQUEST_CODE
#define CP210X_UART_ENABLE 0x0001
#define CP210X_UART_DISABLE 0x0000
// SILABSER_SET_BAUDDIV_REQUEST_CODE
#define CP210X_BAUD_RATE_GEN_FREQ 0x384000
// SILABSER_SET_LINE_CTL_REQUEST_CODE
#define CP210X_BITS_DATA_MASK 0x0f00
#define CP210X_BITS_DATA_5 0x0500
#define CP210X_BITS_DATA_6 0x0600
#define CP210X_BITS_DATA_7 0x0700
#define CP210X_BITS_DATA_8 0x0800
#define CP210X_BITS_DATA_9 0x0900
#define CP210X_BITS_PARITY_MASK 0x00f0
#define CP210X_BITS_PARITY_NONE 0x0000
#define CP210X_BITS_PARITY_ODD 0x0010
#define CP210X_BITS_PARITY_EVEN 0x0020
#define CP210X_BITS_PARITY_MARK 0x0030
#define CP210X_BITS_PARITY_SPACE 0x0040
#define CP210X_BITS_STOP_MASK 0x000f
#define CP210X_BITS_STOP_1 0x0000
#define CP210X_BITS_STOP_1_5 0x0001
#define CP210X_BITS_STOP_2 0x0002
// SILABSER_SET_BREAK_REQUEST_CODE
#define CP210X_BREAK_ON 0x0001
#define CP210X_BREAK_OFF 0x0000
// SILABSER_SET_MHS_REQUEST_CODE
#define CP210X_MCR_DTR 0x0001
#define CP210X_MCR_RTS 0x0002
#define CP210X_MCR_ALL 0x0003
#define CP210X_MSR_CTS 0x0010
#define CP210X_MSR_DSR 0x0020
#define CP210X_MSR_RING 0x0040
#define CP210X_MSR_DCD 0x0080
#define CP210X_MSR_ALL 0x00F0
#define CP210X_CONTROL_WRITE_DTR 0x0100UL
#define CP210X_CONTROL_WRITE_RTS 0x0200UL
#define CP210X_LSR_BREAK 0x0001
#define CP210X_LSR_FRAMING_ERROR 0x0002
#define CP210X_LSR_HW_OVERRUN 0x0004
#define CP210X_LSR_QUEUE_OVERRUN 0x0008
#define CP210X_LSR_PARITY_ERROR 0x0010
#define CP210X_LSR_ALL 0x001F
#endif //TUSB_CP210X_H

View File

@@ -25,222 +25,207 @@
#ifndef TUSB_FTDI_SIO_H
#define TUSB_FTDI_SIO_H
// VID for matching FTDI devices
#define TU_FTDI_VID 0x0403
#include <stdint.h>
// Commands
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
#define FTDI_SIO_RESET 0 // Reset the port
#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register
#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register
#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate
#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port
#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register
#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character
#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character
#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer
#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer
#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode
#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins
#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM
/* FTDI_SIO_RESET */
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
// Channel indices for FT2232, FT2232H and FT4232H devices
#define CHANNEL_A 1
#define CHANNEL_B 2
#define CHANNEL_C 3
#define CHANNEL_D 4
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_RESET
* wValue: Control Value
* 0 = Reset SIO
* 1 = Purge RX buffer
* 2 = Purge TX buffer
* wIndex: Port
* wLength: 0
* Data: None
*
* The Reset SIO command has this effect:
*
* Sets flow control set to 'none'
* Event char = $0D
* Event trigger = disabled
* Purge RX buffer
* Purge TX buffer
* Clear DTR
* Clear RTS
* baud and data format not reset
*
* The Purge RX and TX buffer commands affect nothing except the buffers
*
*/
// Port Identifier Table
#define PIT_DEFAULT 0 // SIOA
#define PIT_SIOA 1 // SIOA
// The device this driver is tested with one has only one port
#define PIT_SIOB 2 // SIOB
#define PIT_PARALLEL 3 // Parallel
/* FTDI_SIO_MODEM_CTRL */
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_MODEM_CTRL
* wValue: ControlValue (see below)
* wIndex: Port
* wLength: 0
* Data: None
*
* NOTE: If the device is in RTS/CTS flow control, the RTS set by this
* command will be IGNORED without an error being returned
* Also - you can not set DTR and RTS with one control message
*/
// FTDI_SIO_RESET
#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
#define FTDI_SIO_RESET_REQUEST_TYPE 0x40
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
// FTDI_SIO_SET_BAUDRATE
#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
/*
* ControlValue
* B0 DTR state
* 0 = reset
* 1 = set
* B1 RTS state
* 0 = reset
* 1 = set
* B2..7 Reserved
* B8 DTR state enable
* 0 = ignore
* 1 = use DTR state
* B9 RTS state enable
* 0 = ignore
* 1 = use RTS state
* B10..15 Reserved
*/
enum ftdi_sio_baudrate {
ftdi_sio_b300 = 0,
ftdi_sio_b600 = 1,
ftdi_sio_b1200 = 2,
ftdi_sio_b2400 = 3,
ftdi_sio_b4800 = 4,
ftdi_sio_b9600 = 5,
ftdi_sio_b19200 = 6,
ftdi_sio_b38400 = 7,
ftdi_sio_b57600 = 8,
ftdi_sio_b115200 = 9
};
/* FTDI_SIO_SET_FLOW_CTRL */
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
// FTDI_SIO_SET_DATA
#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) // same coding as ACM
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) // 1.5 not supported, for future use?
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
/*
* BmRequestType: 0100 0000b
* bRequest: FTDI_SIO_SET_FLOW_CTRL
* wValue: Xoff/Xon
* wIndex: Protocol/Port - hIndex is protocol / lIndex is port
* wLength: 0
* Data: None
*
* hIndex protocol is:
* B0 Output handshaking using RTS/CTS
* 0 = disabled
* 1 = enabled
* B1 Output handshaking using DTR/DSR
* 0 = disabled
* 1 = enabled
* B2 Xon/Xoff handshaking
* 0 = disabled
* 1 = enabled
*
* A value of zero in the hIndex field disables handshaking
*
* If Xon/Xoff handshaking is specified, the hValue field should contain the
* XOFF character and the lValue field contains the XON character.
*/
// FTDI_SIO_MODEM_CTRL
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
/* FTDI_SIO_SET_BAUD_RATE */
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_BAUDRATE
* wValue: BaudDivisor value - see below
* wIndex: Port
* wLength: 0
* Data: None
* The BaudDivisor values are calculated as follows (too complicated):
*/
#define FTDI_SIO_SET_DTR_MASK 0x1UL
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1UL)
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0UL)
#define FTDI_SIO_SET_RTS_MASK 0x2UL
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2UL)
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0UL)
/* FTDI_SIO_SET_DATA */
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
// FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_DATA
* wValue: Data characteristics (see below)
* wIndex: Port
* wLength: 0
* Data: No
*
* Data characteristics
*
* B0..7 Number of data bits
* B8..10 Parity
* 0 = None
* 1 = Odd
* 2 = Even
* 3 = Mark
* 4 = Space
* B11..13 Stop Bits
* 0 = 1
* 1 = 1.5
* 2 = 2
* B14
* 1 = TX ON (break)
* 0 = TX OFF (normal state)
* B15 Reserved
*
*/
// FTDI_SIO_GET_LATENCY_TIMER
#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER
#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0
/*
* DATA FORMAT
*
* IN Endpoint
*
* The device reserves the first two bytes of data on this endpoint to contain
* the current values of the modem and line status registers. In the absence of
* data, the device generates a message consisting of these two status bytes
* every 40 ms
*
* Byte 0: Modem Status
*
* Offset Description
* B0 Reserved - must be 1
* B1 Reserved - must be 0
* B2 Reserved - must be 0
* B3 Reserved - must be 0
* B4 Clear to Send (CTS)
* B5 Data Set Ready (DSR)
* B6 Ring Indicator (RI)
* B7 Receive Line Signal Detect (RLSD)
*
* Byte 1: Line Status
*
* Offset Description
* B0 Data Ready (DR)
* B1 Overrun Error (OE)
* B2 Parity Error (PE)
* B3 Framing Error (FE)
* B4 Break Interrupt (BI)
* B5 Transmitter Holding Register (THRE)
* B6 Transmitter Empty (TEMT)
* B7 Error in RCVR FIFO
*
*/
#define FTDI_RS0_CTS (1 << 4)
#define FTDI_RS0_DSR (1 << 5)
#define FTDI_RS0_RI (1 << 6)
#define FTDI_RS0_RLSD (1 << 7)
// FTDI_SIO_SET_LATENCY_TIMER
#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER
#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40
#define FTDI_RS_DR 1
#define FTDI_RS_OE (1<<1)
#define FTDI_RS_PE (1<<2)
#define FTDI_RS_FE (1<<3)
#define FTDI_RS_BI (1<<4)
#define FTDI_RS_THRE (1<<5)
#define FTDI_RS_TEMT (1<<6)
#define FTDI_RS_FIFO (1<<7)
// FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
// FTDI_SIO_GET_MODEM_STATUS
#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0
#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
// FTDI_SIO_SET_BITMODE
#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
// Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST
#define FTDI_SIO_BITMODE_RESET 0x00
#define FTDI_SIO_BITMODE_CBUS 0x20
// FTDI_SIO_READ_PINS
#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0
#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
// FTDI_SIO_READ_EEPROM
#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
#define FTDI_FTX_CBUS_MUX_GPIO 0x8
#define FTDI_FT232R_CBUS_MUX_GPIO 0xa
#define FTDI_RS0_CTS (1 << 4)
#define FTDI_RS0_DSR (1 << 5)
#define FTDI_RS0_RI (1 << 6)
#define FTDI_RS0_RLSD (1 << 7)
#define FTDI_RS_DR 1
#define FTDI_RS_OE (1 << 1)
#define FTDI_RS_PE (1 << 2)
#define FTDI_RS_FE (1 << 3)
#define FTDI_RS_BI (1 << 4)
#define FTDI_RS_THRE (1 << 5)
#define FTDI_RS_TEMT (1 << 6)
#define FTDI_RS_FIFO (1 << 7)
// chip types and names
typedef enum ftdi_chip_type {
FTDI_SIO = 0,
// FTDI_FT232A,
FTDI_FT232B,
FTDI_FT2232C,
FTDI_FT232R,
FTDI_FT232H,
FTDI_FT2232H,
FTDI_FT4232H,
FTDI_FT4232HA,
FTDI_FT232HP,
FTDI_FT233HP,
FTDI_FT2232HP,
FTDI_FT2233HP,
FTDI_FT4232HP,
FTDI_FT4233HP,
FTDI_FTX,
FTDI_UNKNOWN
} ftdi_chip_type_t;
#define FTDI_CHIP_NAMES \
[FTDI_SIO] = "SIO", /* the serial part of FT8U100AX */ \
/* [FTDI_FT232A] = "FT232A", */ \
[FTDI_FT232B] = "FT232B", \
[FTDI_FT2232C] = "FT2232C/D", \
[FTDI_FT232R] = "FT232R", \
[FTDI_FT232H] = "FT232H", \
[FTDI_FT2232H] = "FTDI_FT2232H", \
[FTDI_FT4232H] = "FT4232H", \
[FTDI_FT4232HA] = "FT4232HA", \
[FTDI_FT232HP] = "FT232HP", \
[FTDI_FT233HP] = "FT233HP", \
[FTDI_FT2232HP] = "FT2232HP", \
[FTDI_FT2233HP] = "FT2233HP", \
[FTDI_FT4232HP] = "FT4232HP", \
[FTDI_FT4233HP] = "FT4233HP", \
[FTDI_FTX] = "FT-X", \
[FTDI_UNKNOWN] = "UNKNOWN"
// private interface data
typedef struct ftdi_private {
ftdi_chip_type_t chip_type;
uint8_t channel; // channel index, or 0 for legacy types
} ftdi_private_t;
#define FTDI_OK true
#define FTDI_FAIL false
#define FTDI_NOT_POSSIBLE -1
#define FTDI_REQUESTED -2
// division and round function overtaken from math.h
#define DIV_ROUND_CLOSEST(x, divisor)( \
{ \
typeof(x) __x = x; \
typeof(divisor) __d = divisor; \
(((typeof(x))-1) > 0 || \
((typeof(divisor))-1) > 0 || \
(((__x) > 0) == ((__d) > 0))) ? \
(((__x) + ((__d) / 2)) / (__d)) : \
(((__x) - ((__d) / 2)) / (__d)); \
} \
)
#endif //TUSB_FTDI_SIO_H

View File

@@ -0,0 +1,159 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2024 Heiko Kuester
*
* 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 is part of the TinyUSB stack.
*/
#ifndef TUSB_PL2303_H
#define TUSB_PL2303_H
#include <stdbool.h>
#include <stdint.h>
// There is no official documentation for the PL2303 chips.
// Reference can be found
// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.h and
// https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c
// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c
// quirks
#define PL2303_QUIRK_UART_STATE_IDX0 1
#define PL2303_QUIRK_LEGACY 2
#define PL2303_QUIRK_ENDPOINT_HACK 4
// requests and bits
#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_SET_LINE_REQUEST 0x20 // dec 32
#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34
#define PL2303_CONTROL_DTR 0x01 // dec 1
#define PL2303_CONTROL_RTS 0x02 // dec 2
#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_BREAK_REQUEST 0x23 // dec 35
#define PL2303_BREAK_ON 0xffff
#define PL2303_BREAK_OFF 0x0000
#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface
#define PL2303_GET_LINE_REQUEST 0x21 // dec 33
#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface
#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1
#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128
#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface
#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1
#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129
#define PL2303_UART_STATE_INDEX 8
#define PL2303_UART_STATE_MSR_MASK 0x8b
#define PL2303_UART_STATE_TRANSIENT_MASK 0x74
#define PL2303_UART_DCD 0x01
#define PL2303_UART_DSR 0x02
#define PL2303_UART_BREAK_ERROR 0x04
#define PL2303_UART_RING 0x08
#define PL2303_UART_FRAME_ERROR 0x10
#define PL2303_UART_PARITY_ERROR 0x20
#define PL2303_UART_OVERRUN_ERROR 0x40
#define PL2303_UART_CTS 0x80
#define PL2303_FLOWCTRL_MASK 0xf0
#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint
// registers via vendor read/write requests
#define PL2303_READ_TYPE_HX_STATUS 0x8080
#define PL2303_HXN_RESET_REG 0x07
#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
#define PL2303_HXN_FLOWCTRL_REG 0x0a
#define PL2303_HXN_FLOWCTRL_MASK 0x1c
#define PL2303_HXN_FLOWCTRL_NONE 0x1c
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
// type data
typedef enum pl2303_type {
PL2303_TYPE_H = 0, // 0
PL2303_TYPE_HX, // 1
PL2303_TYPE_TA, // 2
PL2303_TYPE_TB, // 3
PL2303_TYPE_HXD, // 4
PL2303_TYPE_HXN, // 5
PL2303_TYPE_COUNT,
PL2303_TYPE_NEED_SUPPORTS_HX_STATUS,
PL2303_TYPE_UNKNOWN,
} pl2303_type_t;
typedef struct pl2303_type_data {
uint32_t max_baud_rate;
uint8_t quirks;
uint8_t no_autoxonxoff : 1;
uint8_t no_divisors : 1;
uint8_t alt_divisors : 1;
} pl2303_type_data_t;
#define PL2303_TYPE_DATA \
[PL2303_TYPE_H] = { \
.max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, \
.no_autoxonxoff = 1, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_HX] = { \
.max_baud_rate = 6000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_TA] = { \
.max_baud_rate = 6000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
}, \
[PL2303_TYPE_TB] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
}, \
[PL2303_TYPE_HXD] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_HXN] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 1, .alt_divisors = 0 \
}
typedef struct TU_ATTR_PACKED {
pl2303_type_t type;
uint8_t quirks;
bool supports_hx_status;
} pl2303_private_t;
// buffer sizes for line coding data
#define PL2303_LINE_CODING_BUFSIZE 7
#define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4
// bulk endpoints
#define PL2303_OUT_EP 0x02
#define PL2303_IN_EP 0x83
#endif // TUSB_PL2303_H

View File

@@ -53,23 +53,26 @@ enum {
};
typedef struct {
TU_ATTR_ALIGNED(4) msc_cbw_t cbw;
TU_ATTR_ALIGNED(4) msc_csw_t csw;
TU_ATTR_ALIGNED(4) msc_cbw_t cbw; // 31 bytes
uint8_t rhport;
TU_ATTR_ALIGNED(4) msc_csw_t csw; // 13 bytes
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
// Bulk Only Transfer (BOT) Protocol
uint8_t stage;
uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw
uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
// Sense Response Data
// Bulk Only Transfer (BOT) Protocol
uint8_t stage;
// SCSI Sense Response Data
uint8_t sense_key;
uint8_t add_sense_code;
uint8_t add_sense_qualifier;
uint8_t pending_io; // pending async IO
}mscd_interface_t;
static mscd_interface_t _mscd_itf;
@@ -82,31 +85,36 @@ CFG_TUD_MEM_SECTION static struct {
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize);
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes);
static void proc_read10_cmd(mscd_interface_t* p_msc);
static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes);
static void proc_write10_cmd(mscd_interface_t* p_msc);
static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes);
static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes);
static bool proc_stage_status(mscd_interface_t* p_msc);
TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) {
return tu_bit_test(dir, 7);
}
static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) {
static inline bool send_csw(mscd_interface_t* p_msc) {
// Data residue is always = host expect - actual transferred
uint8_t rhport = p_msc->rhport;
p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
p_msc->stage = MSC_STAGE_STATUS_SENT;
memcpy(_mscd_epbuf.buf, &p_msc->csw, sizeof(msc_csw_t));
return usbd_edpt_xfer(rhport, p_msc->ep_in , _mscd_epbuf.buf, sizeof(msc_csw_t));
}
static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) {
static inline bool prepare_cbw(mscd_interface_t* p_msc) {
uint8_t rhport = p_msc->rhport;
p_msc->stage = MSC_STAGE_CMD;
return usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, sizeof(msc_cbw_t));
}
static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) {
static void fail_scsi_op(mscd_interface_t* p_msc, uint8_t status) {
msc_cbw_t const * p_cbw = &p_msc->cbw;
msc_csw_t * p_csw = &p_msc->csw;
uint8_t rhport = p_msc->rhport;
p_csw->status = status;
p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
@@ -177,6 +185,33 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) {
return status;
}
static bool proc_stage_status(mscd_interface_t *p_msc) {
uint8_t rhport = p_msc->rhport;
msc_cbw_t const *p_cbw = &p_msc->cbw;
// skip status if epin is currently stalled, will do it when received Clear Stall request
if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) {
if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) {
// 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
// TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
usbd_edpt_stall(rhport, p_msc->ep_in);
} else {
TU_ASSERT(send_csw(p_msc));
}
}
#if TU_CHECK_MCU(OPT_MCU_CXD56)
// WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
// There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
// hope everything will work
if (usbd_edpt_stalled(rhport, p_msc->ep_in)) {
usbd_edpt_clear_stall(rhport, p_msc->ep_in);
send_csw(p_msc);
}
#endif
return true;
}
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
@@ -214,15 +249,51 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
return true;
}
static inline void set_sense_medium_not_present(uint8_t lun) {
TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lun) {
// default sense is NOT READY, MEDIUM NOT PRESENT
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);
}
static void proc_async_io_done(void *bytes_io) {
mscd_interface_t *p_msc = &_mscd_itf;
TU_VERIFY(p_msc->pending_io, );
const int32_t nbytes = (int32_t) (intptr_t) bytes_io;
const uint8_t cmd = p_msc->cbw.command[0];
p_msc->pending_io = 0;
switch (cmd) {
case SCSI_CMD_READ_10:
proc_read_io_data(p_msc, nbytes);
break;
case SCSI_CMD_WRITE_10:
proc_write_io_data(p_msc, (uint32_t) nbytes, nbytes);
break;
default: break;
}
// send status if stage is transitioned to STATUS
if (p_msc->stage == MSC_STAGE_STATUS) {
proc_stage_status(p_msc);
}
}
bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) {
// Precheck to avoid queueing multiple RW done callback
TU_VERIFY(_mscd_itf.pending_io);
if (bytes_io == 0) {
bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no reason to call this with BUSY here
}
usbd_defer_func(proc_async_io_done, (void *) (intptr_t) bytes_io, in_isr);
return true;
}
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void mscd_init(void) {
TU_LOG_INT(CFG_TUD_MSC_LOG_LEVEL, sizeof(mscd_interface_t));
tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
}
@@ -245,12 +316,13 @@ uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
mscd_interface_t * p_msc = &_mscd_itf;
p_msc->itf_num = itf_desc->bInterfaceNumber;
p_msc->rhport = rhport;
// Open endpoint pair
TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0);
// Prepare for Command Block Wrapper
TU_ASSERT(prepare_cbw(rhport, p_msc), drv_len);
TU_ASSERT(prepare_cbw(p_msc), drv_len);
return drv_len;
}
@@ -289,14 +361,14 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
if (ep_addr == p_msc->ep_in) {
if (p_msc->stage == MSC_STAGE_STATUS) {
// resume sending SCSI status if we are in this stage previously before stalled
TU_ASSERT(send_csw(rhport, p_msc));
TU_ASSERT(send_csw(p_msc));
}
} else if (ep_addr == p_msc->ep_out) {
if (p_msc->stage == MSC_STAGE_CMD) {
// part of reset recovery (probably due to invalid CBW) -> prepare for new command
// Note: skip if already queued previously
if (usbd_edpt_ready(rhport, p_msc->ep_out)) {
TU_ASSERT(prepare_cbw(rhport, p_msc));
TU_ASSERT(prepare_cbw(p_msc));
}
}
}
@@ -382,12 +454,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
uint8_t const status = rdwr10_validate_cmd(p_cbw);
if (status != MSC_CSW_STATUS_PASSED) {
fail_scsi_op(rhport, p_msc, status);
fail_scsi_op(p_msc, status);
} else if (p_cbw->total_bytes) {
if (SCSI_CMD_READ_10 == p_cbw->command[0]) {
proc_read10_cmd(rhport, p_msc);
proc_read10_cmd(p_msc);
} else {
proc_write10_cmd(rhport, p_msc);
proc_write10_cmd(p_msc);
}
} else {
// no data transfer, only exist in complaint test suite
@@ -400,7 +472,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ((p_cbw->total_bytes > 0) && !is_data_in(p_cbw->dir)) {
if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE) {
TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n");
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
// but it is OK to just receive data then responded with failed status
@@ -418,12 +490,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (resplen < 0) {
// unsupported command
TU_LOG_DRV(" SCSI unsupported or failed command\r\n");
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else if (resplen == 0) {
if (p_cbw->total_bytes) {
// 6.7 The 13 Cases: case 4 (Hi > Dn)
// TU_LOG_DRV(" SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// case 1 Hn = Dn: all good
p_msc->stage = MSC_STAGE_STATUS;
@@ -432,7 +504,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (p_cbw->total_bytes == 0) {
// 6.7 The 13 Cases: case 2 (Hn < Di)
// TU_LOG_DRV(" SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// cannot return more than host expect
p_msc->total_len = tu_min32((uint32_t)resplen, p_cbw->total_bytes);
@@ -456,10 +528,10 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Data Stage is complete
p_msc->stage = MSC_STAGE_STATUS;
}else {
proc_read10_cmd(rhport, p_msc);
proc_read10_cmd(p_msc);
}
} else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) {
proc_write10_new_data(rhport, p_msc, xferred_bytes);
proc_write10_host_data(p_msc, xferred_bytes);
} else {
p_msc->xferred_len += xferred_bytes;
@@ -470,7 +542,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ( cb_result < 0 ) {
// unsupported command
TU_LOG_DRV(" SCSI unsupported command\r\n");
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
}else {
// TODO haven't implement this scenario any further yet
}
@@ -491,7 +563,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
case MSC_STAGE_STATUS_SENT:
// Wait for the Status phase to complete
// Status phase is complete
if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) {
TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
// TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2);
@@ -519,9 +591,9 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
}
TU_ASSERT(prepare_cbw(rhport, p_msc));
TU_ASSERT(prepare_cbw(p_msc));
} else {
// Any xfer ended here is consider unknown error, ignore it
// Any xfer ended here is considered unknown error, ignore it
TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n");
}
break;
@@ -530,26 +602,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
}
if (p_msc->stage == MSC_STAGE_STATUS) {
// skip status if epin is currently stalled, will do it when received Clear Stall request
if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) {
if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) {
// 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
// TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
usbd_edpt_stall(rhport, p_msc->ep_in);
} else {
TU_ASSERT(send_csw(rhport, p_msc));
}
}
#if TU_CHECK_MCU(OPT_MCU_CXD56)
// WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
// There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
// hope everything will work
if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) {
usbd_edpt_clear_stall(rhport, p_msc->ep_in);
send_csw(rhport, p_msc);
}
#endif
TU_ASSERT(proc_stage_status(p_msc));
}
return true;
@@ -646,8 +699,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_READ_FORMAT_CAPACITY: {
scsi_read_format_capacity_data_t read_fmt_capa =
{
scsi_read_format_capacity_data_t read_fmt_capa = {
.list_length = 8,
.block_num = 0,
.descriptor_type = 2, // formatted media
@@ -679,8 +731,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_INQUIRY: {
scsi_inquiry_resp_t inquiry_rsp =
{
scsi_inquiry_resp_t inquiry_rsp = {
.is_removable = 1,
.version = 2,
.response_data_format = 2,
@@ -700,8 +751,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_MODE_SENSE_6: {
scsi_mode_sense6_resp_t mode_resp =
{
scsi_mode_sense6_resp_t mode_resp = {
.data_len = 3,
.medium_type = 0,
.write_protected = false,
@@ -722,8 +772,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_REQUEST_SENSE: {
scsi_sense_fixed_resp_t sense_rsp =
{
scsi_sense_fixed_resp_t sense_rsp = {
.response_code = 0x70, // current, fixed format
.valid = 1
};
@@ -753,39 +802,49 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
return resplen;
}
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
static void proc_read10_cmd(mscd_interface_t* p_msc) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
// block size already verified not zero
uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
// Adjust lba with transferred bytes
uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
// Adjust lba & offset with transferred bytes
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
uint32_t const offset = p_msc->xferred_len % block_sz;
// remaining bytes capped at class buffer
int32_t nbytes = (int32_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
// Application can consume smaller bytes
uint32_t const offset = p_msc->xferred_len % block_sz;
p_msc->pending_io = 1;
nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes);
if (nbytes < 0) {
// negative means error -> endpoint is stalled & status in CSW set to failed
TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n");
// set sense
set_sense_medium_not_present(p_cbw->lun);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
} else if (nbytes == 0) {
// zero means not ready -> simulate an transfer complete so that this driver callback will fired again
dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
} else {
TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),);
if (nbytes != TUD_MSC_RET_ASYNC) {
p_msc->pending_io = 0;
proc_read_io_data(p_msc, nbytes);
}
}
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
const uint8_t rhport = p_msc->rhport;
if (nbytes > 0) {
TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),);
} else {
// nbytes is status
switch (nbytes) {
case TUD_MSC_RET_ERROR:
// error -> endpoint is stalled & status in CSW set to failed
TU_LOG_DRV(" IO read() failed\r\n");
set_sense_medium_not_present(p_msc->cbw.lun);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
break;
case TUD_MSC_RET_BUSY:
// not ready yet -> fake a transfer complete so that this driver callback will fire again
dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
break;
default: break;
}
}
}
static void proc_write10_cmd(mscd_interface_t* p_msc) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
bool writable = true;
@@ -797,51 +856,56 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
// Not writable, complete this SCSI op with error
// Sense = Write protected
tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
return;
}
// remaining bytes capped at class buffer
uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
// Write10 callback will be called later when usb transfer complete
TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),);
TU_ASSERT(usbd_edpt_xfer(p_msc->rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),);
}
// process new data arrived from WRITE10
static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) {
static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
// block size already verified not zero
uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
// Adjust lba with transferred bytes
// Adjust lba & offset with transferred bytes
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
// Invoke callback to consume new data
uint32_t const offset = p_msc->xferred_len % block_sz;
int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes);
p_msc->pending_io = 1;
int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes);
if (nbytes != TUD_MSC_RET_ASYNC) {
p_msc->pending_io = 0;
proc_write_io_data(p_msc, xferred_bytes, nbytes);
}
}
static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) {
if (nbytes < 0) {
// negative means error -> failed this scsi op
TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n");
// nbytes is status
switch (nbytes) {
case TUD_MSC_RET_ERROR:
// IO error -> failed this scsi op
TU_LOG_DRV(" IO write() failed\r\n");
set_sense_medium_not_present(p_msc->cbw.lun);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
break;
// update actual byte before failed
p_msc->xferred_len += xferred_bytes;
set_sense_medium_not_present(p_cbw->lun);
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
default: break;
}
} else {
if ((uint32_t)nbytes < xferred_bytes) {
// Application consume less than what we got (including zero)
// Application consume less than what we got including TUD_MSC_RET_BUSY (0)
const uint32_t left_over = xferred_bytes - (uint32_t)nbytes;
if (nbytes > 0) {
p_msc->xferred_len += (uint16_t)nbytes;
memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over);
}
// simulate a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter
dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
// fake a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameters
dcd_event_xfer_complete(p_msc->rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
} else {
// Application consume all bytes in our buffer
p_msc->xferred_len += xferred_bytes;
@@ -851,7 +915,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
p_msc->stage = MSC_STAGE_STATUS;
} else {
// prepare to receive more data from host
proc_write10_cmd(rhport, p_msc);
proc_write10_cmd(p_msc);
}
}
}

View File

@@ -48,6 +48,13 @@
#error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better
#endif
// Return value of callback functions
enum {
TUD_MSC_RET_BUSY = 0, // Busy, e.g disk I/O is not ready
TUD_MSC_RET_ERROR = -1,
TUD_MSC_RET_ASYNC = -2, // Asynchronous IO
};
TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct");
//--------------------------------------------------------------------+
@@ -57,38 +64,30 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct");
// Set SCSI sense response
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
// Called by Application once asynchronous I/O operation is done
// bytes_io is number of bytes in I/O op, typically the bufsize in read/write_cb() or
// TUD_MSC_RET_ERROR (-1) for error. Note TUD_MSC_RET_BUSY (0) will be treated as error as well.
bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr);
//--------------------------------------------------------------------+
// Application Callbacks (WEAK is optional)
//--------------------------------------------------------------------+
// Invoked when received SCSI READ10 command
// - Address = lba * BLOCK_SIZE + offset
// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
//
// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If
// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data.
//
// - read == 0 : Indicate application is not ready yet e.g disk I/O busy.
// Callback invoked again with the same parameters later on.
//
// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed
// and return failed status in command status wrapper phase.
/*
Invoked when received SCSI READ10/WRITE10 command
- Address = lba * BLOCK_SIZE + offset
- offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
- Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status.
- 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data.
- TUD_MSC_RET_BUSY
Application is buys e.g disk I/O not ready. Callback will be invoked again with the same parameters later on.
- TUD_MSC_RET_ERROR
error such as invalid address. This request will be STALLed and scsi command will be failed
- TUD_MSC_RET_ASYNC
Data I/O will be done asynchronously in a background task. Application should return immediately.
tud_msc_async_io_done() must be called once IO/ is done to signal completion.
*/
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
// Invoked when received SCSI WRITE10 command
// - Address = lba * BLOCK_SIZE + offset
// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
//
// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If
// - write < bufsize : callback invoked again with remaining data later on.
//
// - write == 0 : Indicate application is not ready yet e.g disk I/O busy.
// Callback invoked again with the same parameters later on.
//
// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed
// and return failed status in command status wrapper phase.
//
// TODO change buffer to const uint8_t*
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
// Invoked when received SCSI_CMD_INQUIRY

View File

@@ -278,6 +278,8 @@ typedef enum {
XFER_RESULT_INVALID
} xfer_result_t;
#define tusb_xfer_result_t xfer_result_t
// TODO remove
enum {
DESC_OFFSET_LEN = 0,
@@ -345,7 +347,6 @@ typedef struct TU_ATTR_PACKED {
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
uint8_t iProduct ; ///< Index of string descriptor describing product.
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
uint8_t bNumConfigurations ; ///< Number of possible configurations.
} tusb_desc_device_t;

View File

@@ -465,13 +465,30 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
return true; // skip if already initialized
}
TU_ASSERT(rh_init);
TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport,
rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
char const* speed_str = 0;
switch (rh_init->speed) {
case TUSB_SPEED_HIGH:
speed_str = "High";
break;
case TUSB_SPEED_FULL:
speed_str = "Full";
break;
case TUSB_SPEED_LOW:
speed_str = "Low";
break;
case TUSB_SPEED_AUTO:
speed_str = "Auto";
break;
default:
break;
}
TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, speed_str);
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t));
#endif
tu_varclr(&_usbd_dev);
_usbd_queued_setup = 0;

View File

@@ -244,7 +244,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint Out */\

View File

@@ -94,6 +94,20 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
typedef struct {
tuh_bus_info_t bus_info;
// Device Descriptor
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
// Device State
struct TU_ATTR_PACKED {
volatile uint8_t connected : 1; // After 1st transfer
@@ -103,18 +117,6 @@ typedef struct {
// volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh
};
// Device Descriptor
uint8_t ep0_size;
uint16_t idVendor;
uint16_t idProduct;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
// Configuration Descriptor
// uint8_t interface_count; // bNumInterfaces alias
// Endpoint & Interface
uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
@@ -373,6 +375,28 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) {
return true;
}
bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device) {
usbh_device_t *dev = get_device(daddr);
TU_VERIFY(dev && desc_device);
desc_device->bLength = sizeof(tusb_desc_device_t);
desc_device->bDescriptorType = TUSB_DESC_DEVICE;
desc_device->bcdUSB = dev->bcdUSB;
desc_device->bDeviceClass = dev->bDeviceClass;
desc_device->bDeviceSubClass = dev->bDeviceSubClass;
desc_device->bDeviceProtocol = dev->bDeviceProtocol;
desc_device->bMaxPacketSize0 = dev->bMaxPacketSize0;
desc_device->idVendor = dev->idVendor;
desc_device->idProduct = dev->idProduct;
desc_device->bcdDevice = dev->bcdDevice;
desc_device->iManufacturer = dev->iManufacturer;
desc_device->iProduct = dev->iProduct;
desc_device->iSerialNumber = dev->iSerialNumber;
desc_device->bNumConfigurations = dev->bNumConfigurations;
return true;
}
tusb_speed_t tuh_speed_get(uint8_t daddr) {
tuh_bus_info_t bus_info;
tuh_bus_info_get(daddr, &bus_info);
@@ -414,9 +438,26 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
if (tuh_rhport_is_active(rhport)) {
return true; // skip if already initialized
}
TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport,
rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
char const* speed_str = 0;
switch (rh_init->speed) {
case TUSB_SPEED_HIGH:
speed_str = "High";
break;
case TUSB_SPEED_FULL:
speed_str = "Full";
break;
case TUSB_SPEED_LOW:
speed_str = "Low";
break;
case TUSB_SPEED_AUTO:
speed_str = "Auto";
break;
default:
break;
}
TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport, speed_str);
#endif
// Init host stack if not already
if (!tuh_inited()) {
@@ -1068,8 +1109,9 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
// generic helper to get a descriptor
// if blocking, user_data is pointed to xfer_result
static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_ATTR_ALWAYS_INLINE static inline
bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_DEVICE,
@@ -1110,7 +1152,6 @@ bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer
}
//------------- String Descriptor -------------//
bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data);
@@ -1248,47 +1289,6 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
return tuh_control_xfer(&xfer);
}
//--------------------------------------------------------------------+
// Descriptor Sync
//--------------------------------------------------------------------+
#define _CONTROL_SYNC_API(_async_func, ...) \
xfer_result_t result = XFER_RESULT_INVALID;\
TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
return (uint8_t) result
uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
}
uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len);
}
uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len);
}
uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
}
uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
}
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+
@@ -1579,7 +1579,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
usbh_device_t* new_dev = get_device(new_addr);
new_dev->bus_info = *dev0_bus;
new_dev->connected = 1;
new_dev->ep0_size = desc_device->bMaxPacketSize0;
new_dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0;
TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),);
break;
@@ -1596,7 +1596,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
usbh_device_close(dev0_bus->rhport, 0); // close dev0
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
@@ -1609,8 +1609,14 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_GET_STRING_LANGUAGE_ID_LEN: {
// save the received device descriptor
tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl;
dev->bcdUSB = desc_device->bcdUSB;
dev->bDeviceClass = desc_device->bDeviceClass;
dev->bDeviceSubClass = desc_device->bDeviceSubClass;
dev->bDeviceProtocol = desc_device->bDeviceProtocol;
dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0;
dev->idVendor = desc_device->idVendor;
dev->idProduct = desc_device->idProduct;
dev->bcdDevice = desc_device->bcdDevice;
dev->iManufacturer = desc_device->iManufacturer;
dev->iProduct = desc_device->iProduct;
dev->iSerialNumber = desc_device->iSerialNumber;

Some files were not shown because too many files have changed in this diff Show More