Merge remote-tracking branch 'tinyusb/master' into hcd_fsdev

This commit is contained in:
Zixun LI
2025-12-02 12:00:59 +01:00
21 changed files with 503 additions and 429 deletions

View File

@ -13,12 +13,6 @@ outputs:
runs:
using: "composite"
steps:
- name: Install ARM GCC
if: inputs.toolchain == 'arm-gcc'
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: '14.2.Rel1'
- name: Pull ESP-IDF docker
if: inputs.toolchain == 'esp-idf'
uses: ./.github/actions/setup_toolchain/espressif
@ -26,9 +20,7 @@ runs:
toolchain: ${{ inputs.toolchain }}
- name: Get Toolchain URL
if: >-
inputs.toolchain != 'arm-gcc' &&
inputs.toolchain != 'esp-idf'
if: inputs.toolchain != 'esp-idf'
id: set-toolchain-url
env:
TOOLCHAIN: ${{ inputs.toolchain }}
@ -39,9 +31,7 @@ runs:
shell: bash
- name: Download Toolchain
if: >-
inputs.toolchain != 'arm-gcc' &&
inputs.toolchain != 'esp-idf'
if: inputs.toolchain != 'esp-idf'
uses: ./.github/actions/setup_toolchain/download
with:
toolchain: ${{ inputs.toolchain }}

View File

@ -26,6 +26,7 @@ runs:
TOOLCHAIN_URL: ${{ inputs.toolchain_url }}
run: |
mkdir -p ~/cache/${TOOLCHAIN}
FILE_EXT="${TOOLCHAIN_URL##*.}"
if [[ ${TOOLCHAIN} == rx-gcc ]]; then
wget --progress=dot:giga ${TOOLCHAIN_URL} -O toolchain.run
@ -34,9 +35,16 @@ runs:
elif [[ ${TOOLCHAIN} == arm-iar ]]; then
wget --progress=dot:giga https://netstorage.iar.com/FileStore/STANDARD/001/003/926/iar-lmsc-tools_1.8_amd64.deb -O ~/cache/${TOOLCHAIN}/iar-lmsc-tools.deb
wget --progress=dot:giga ${TOOLCHAIN_URL} -O ~/cache/${TOOLCHAIN}/cxarm.deb
else
elif [[ ${FILE_EXT} == zip ]]; then
curl -L "$TOOLCHAIN_URL" -o toolchain.zip
unzip -q toolchain.zip -d ~/cache/${TOOLCHAIN}
~/cache/${TOOLCHAIN}/xpack-arm-none-eabi-gcc-14.2.1-1.1/bin/arm-none-eabi-gcc.exe --version
elif [[ ${FILE_EXT} == gz ]]; then
wget --progress=dot:giga ${TOOLCHAIN_URL} -O toolchain.tar.gz
tar -C ~/cache/${TOOLCHAIN} -xaf toolchain.tar.gz
else
echo "Unsupported toolchain file extension: ${FILE_EXT}"
exit 1
fi
shell: bash
@ -47,8 +55,19 @@ runs:
if [[ ${TOOLCHAIN} == arm-iar ]]; then
sudo dpkg -i ~/cache/${TOOLCHAIN}/iar-lmsc-tools.deb
sudo apt install -y ~/cache/${TOOLCHAIN}/cxarm.deb
echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin"
TOOLCHAIN_PATH="/opt/iar/cxarm/arm/bin"
else
echo >> $GITHUB_PATH `echo ~/cache/${TOOLCHAIN}/*/bin`
# Find the single toolchain bin directory
TOOLCHAIN_BIN_DIRS=(~/cache/${TOOLCHAIN}/*/bin)
if [[ ${#TOOLCHAIN_BIN_DIRS[@]} -ne 1 ]]; then
echo "Error: Expected exactly one toolchain bin directory, found ${#TOOLCHAIN_BIN_DIRS[@]}"
exit 1
fi
TOOLCHAIN_PATH="${TOOLCHAIN_BIN_DIRS[0]}"
fi
# Convert to native path for Windows compatibility
if [[ "$RUNNER_OS" == "Windows" ]]; then
TOOLCHAIN_PATH=$(cygpath -w "$TOOLCHAIN_PATH")
fi
echo "$TOOLCHAIN_PATH" >> $GITHUB_PATH
shell: bash

View File

@ -2,6 +2,8 @@
"aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
"arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
"arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz",
"arm-gcc-macos-latest": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-darwin-arm64.tar.gz",
"arm-gcc-windows-latest": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-win32-x64.zip",
"msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
"riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
"rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run",

View File

@ -15,7 +15,6 @@ on:
- '.github/workflows/build_util.yml'
- '.github/workflows/ci_set_matrix.py'
pull_request:
branches: [ master ]
paths:
- 'src/**'
- 'examples/**'
@ -49,7 +48,7 @@ jobs:
id: set-matrix-json
run: |
# build matrix
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)/
echo "matrix=$MATRIX_JSON"
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
# hil matrix
@ -127,19 +126,20 @@ jobs:
one-per-family: true
# ---------------------------------------
# Build Make on Windows/MacOS
# Build Make/CMake on Windows/MacOS
# ---------------------------------------
make-os:
build-os:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
build-system: [ 'make', 'cmake' ]
with:
os: ${{ matrix.os }}
build-system: 'make'
toolchain: 'arm-gcc'
build-system: ${{ matrix.build-system }}
toolchain: 'arm-gcc-${{ matrix.os }}'
build-args: '["stm32h7"]'
one-per-family: true

13
.idea/cmake.xml generated
View File

@ -56,6 +56,13 @@
</envs>
</ADDITIONAL_GENERATION_ENVIRONMENT>
</configuration>
<configuration PROFILE_NAME="espressif_s3_devkitc-DMA" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=espressif_s3_devkitc -DLOG=1 -DCFLAGS_CLI=&quot;-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1&quot;">
<ADDITIONAL_GENERATION_ENVIRONMENT>
<envs>
<env name="ESPBAUD" value="1500000" />
</envs>
</ADDITIONAL_GENERATION_ENVIRONMENT>
</configuration>
<configuration PROFILE_NAME="espressif_p4_function_ev" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=espressif_p4_function_ev -DLOG=1">
<ADDITIONAL_GENERATION_ENVIRONMENT>
<envs>
@ -90,9 +97,9 @@
<configuration PROFILE_NAME="same54_xplained" ENABLED="false" GENERATION_OPTIONS="-DBOARD=same54_xplained -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="samg55_xplained" ENABLED="false" GENERATION_OPTIONS="-DBOARD=samg55_xplained" />
<configuration PROFILE_NAME="feather_nrf52840_express" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=feather_nrf52840_express -DLOG=1 -DLOGGER=RTT -DMAX3421_HOST=1" />
<configuration PROFILE_NAME="pca10056" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pca10056 -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="pca10056-zephyr" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pca10056 -DLOG=1 -DTRACE_ETM=1 -DRTOS=zephyr" BUILD_OPTIONS="-v" />
<configuration PROFILE_NAME="pca10095" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pca10095 -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="nrf52840dk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=nrf52840dk -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="nrf52840dk-zephyr" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=nrf52840dk -DLOG=1 -DTRACE_ETM=1 -DRTOS=zephyr" BUILD_OPTIONS="-v" />
<configuration PROFILE_NAME="nrf5340dk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=nrf5340dk -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="metro m7 1011 sd" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011_sd -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="metro_m7_1011" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011 -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="rt1010 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1010_evk -DLOG=1 -DLOGGER=RTT" />

View File

@ -3,4 +3,3 @@ CONFIG_FPU=y
CONFIG_NO_OPTIMIZATIONS=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_NRFX_POWER=y
CONFIG_NRFX_UARTE0=y

View File

@ -124,6 +124,7 @@ void cdc_task(void) {
if ((btn_prev == 0u) && (btn != 0u)) {
uart_state.dsr ^= 1;
uart_state.dcd ^= 1;
tud_cdc_notify_uart_state(&uart_state);
}
btn_prev = btn;

View File

@ -3,4 +3,3 @@ CONFIG_FPU=y
CONFIG_NO_OPTIMIZATIONS=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_NRFX_POWER=y
CONFIG_NRFX_UARTE0=y

View File

@ -101,7 +101,7 @@ int main(void) {
while (1) {
tud_task(); // tinyusb device task
cdc_task();
tud_cdc_write_flush();
led_blinking_task();
}
}
@ -116,13 +116,7 @@ static void echo_all(const uint8_t buf[], uint32_t count) {
// echo to cdc
if (tud_cdc_connected()) {
for (uint32_t i = 0; i < count; i++) {
tud_cdc_write_char(buf[i]);
if (buf[i] == '\r') {
tud_cdc_write_char('\n');
}
}
tud_cdc_write_flush();
tud_cdc_write(buf, count);
}
}
@ -162,7 +156,9 @@ void tud_resume_cb(void) {
// return false to stall control endpoint (e.g unsupported request)
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP) return true;
if (stage != CONTROL_STAGE_SETUP) {
return true;
}
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
@ -215,33 +211,21 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
return false;
}
void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) {
(void) itf;
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
(void)idx;
(void)buffer;
(void)bufsize;
echo_all(buffer, bufsize);
// if using RX buffered is enabled, we need to flush the buffer to make room for new data
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
tud_vendor_read_flush();
#endif
while (tud_vendor_available()) {
uint8_t buf[64];
const uint32_t count = tud_vendor_read(buf, sizeof(buf));
echo_all(buf, count);
}
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
void cdc_task(void) {
if (tud_cdc_connected()) {
// connected and there are data available
if (tud_cdc_available()) {
uint8_t buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
// echo back to both web serial and cdc
echo_all(buf, count);
}
}
}
// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
@ -255,8 +239,13 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
}
// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf) {
(void)itf;
void tud_cdc_rx_cb(uint8_t idx) {
(void)idx;
while (tud_cdc_available()) {
uint8_t buf[64];
const uint32_t count = tud_cdc_read(buf, sizeof(buf));
echo_all(buf, count); // echo back to both web serial and cdc
}
}
//--------------------------------------------------------------------+
@ -267,7 +256,9 @@ void led_blinking_task(void) {
static bool led_state = false;
// Blink every interval ms
if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
if (board_millis() - start_ms < blink_interval_ms) {
return; // not enough time
}
start_ms += blink_interval_ms;
board_led_write(led_state);

View File

@ -100,7 +100,9 @@ static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(120);
#define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk
#endif
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0);
#endif
void USBD_IRQHandler(void) {
tud_int_handler(0);
@ -163,6 +165,7 @@ void board_init(void) {
irq_enable(DT_INST_IRQN(0));
#endif
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
// UART
nrfx_uarte_config_t uart_cfg = {
.txd_pin = UART_TX_PIN,
@ -179,6 +182,7 @@ void board_init(void) {
};
nrfx_uarte_init(&_uart_id, &uart_cfg, NULL);
#endif
//------------- USB -------------//
#if CFG_TUD_ENABLED
@ -276,8 +280,13 @@ int board_uart_read(uint8_t* buf, int len) {
}
int board_uart_write(void const* buf, int len) {
#if CFG_TUSB_OS == OPT_OS_ZEPHYR
(void) buf;
return len;
#else
nrfx_err_t err = nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len ,0);
return (NRFX_SUCCESS == err) ? len : 0;
#endif
}
#if CFG_TUSB_OS == OPT_OS_NONE

View File

@ -127,7 +127,9 @@ function(family_configure_example TARGET RTOS)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
)
if (NOT RTOS STREQUAL zephyr)
if (RTOS STREQUAL zephyr)
target_include_directories(${TARGET} PUBLIC ${ZEPHYR_HAL_NORDIC_MODULE_DIR}/nrfx/bsp/stable/mdk)
else ()
target_sources(${TARGET} PRIVATE ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}})
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")

View File

@ -266,9 +266,8 @@ void cdcd_init(void) {
uint8_t *epout_buf = NULL;
uint8_t *epin_buf = NULL;
#else
cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[i];
uint8_t *epout_buf = p_epbuf->epout;
uint8_t *epin_buf = p_epbuf->epin;
uint8_t *epout_buf = _cdcd_epbuf[i].epout;
uint8_t *epin_buf = _cdcd_epbuf[i].epin;
#endif
tu_edpt_stream_init(&p_cdc->stream.rx, false, false, false, p_cdc->stream.rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE,
@ -516,11 +515,9 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
// Data sent to host, we continue to fetch from tx fifo to send.
// Note: This will cause incorrect baudrate set in line coding.
// Though maybe the baudrate is not really important !!!
// Note: This will cause incorrect baudrate set in line coding. Though maybe the baudrate is not really important !
if (ep_addr == stream_tx->ep_addr) {
// invoke transmit callback to possibly refill tx fifo
tud_cdc_tx_complete_cb(itf);
tud_cdc_tx_complete_cb(itf); // invoke callback to possibly refill tx fifo
if (0 == tu_edpt_stream_write_xfer(rhport, stream_tx)) {
// If there is no data left, a ZLP should be sent if needed

View File

@ -42,43 +42,51 @@ typedef struct {
/*------------- From this point, data is not cleared by bus reset -------------*/
struct {
tu_edpt_stream_t stream;
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
uint8_t ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
#endif
} tx;
tu_edpt_stream_t tx;
tu_edpt_stream_t rx;
struct {
tu_edpt_stream_t stream;
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
uint8_t ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
#endif
} rx;
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
#endif
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
#endif
} stream;
} vendord_interface_t;
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
typedef struct {
// Skip local EP buffer if dedicated hw FIFO is supported
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
#endif
// Skip local EP buffer if dedicated hw FIFO is supported
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
#endif
} vendord_epbuf_t;
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
#endif
//--------------------------------------------------------------------+
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) {
(void) itf;
(void) buffer;
(void) bufsize;
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
(void)idx;
(void)buffer;
(void)bufsize;
}
TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
(void) itf;
TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
(void)idx;
(void) sent_bytes;
}
@ -86,60 +94,79 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
// Application API
//--------------------------------------------------------------------
bool tud_vendor_n_mounted(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_VENDOR);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return p_itf->rx.stream.ep_addr || p_itf->tx.stream.ep_addr;
bool tud_vendor_n_mounted(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return p_itf->stream.rx.ep_addr || p_itf->stream.tx.ep_addr;
}
//--------------------------------------------------------------------+
// Read API
//--------------------------------------------------------------------+
uint32_t tud_vendor_n_available(uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_read_available(&p_itf->rx.stream);
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
uint32_t tud_vendor_n_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_read_available(&p_itf->stream.rx);
}
bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) {
TU_VERIFY(itf < CFG_TUD_VENDOR);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_peek(&p_itf->rx.stream, u8);
bool tud_vendor_n_peek(uint8_t idx, uint8_t *u8) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_peek(&p_itf->stream.rx, u8);
}
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) {
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_read(p_itf->rhport, &p_itf->rx.stream, buffer, bufsize);
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_read(p_itf->rhport, &p_itf->stream.rx, buffer, bufsize);
}
void tud_vendor_n_read_flush (uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_VENDOR, );
vendord_interface_t* p_itf = &_vendord_itf[itf];
tu_edpt_stream_clear(&p_itf->rx.stream);
tu_edpt_stream_read_xfer(p_itf->rhport, &p_itf->rx.stream);
uint32_t tud_vendor_n_read_discard(uint8_t idx, uint32_t count) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_discard(&p_itf->stream.rx, count);
}
void tud_vendor_n_read_flush(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, );
vendord_interface_t *p_itf = &_vendord_itf[idx];
tu_edpt_stream_clear(&p_itf->stream.rx);
tu_edpt_stream_read_xfer(p_itf->rhport, &p_itf->stream.rx);
}
#endif
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
bool tud_vendor_n_read_xfer(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_read_xfer(p_itf->rhport, &p_itf->stream.rx);
}
#endif
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
uint32_t tud_vendor_n_write (uint8_t itf, const void* buffer, uint32_t bufsize) {
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_write(p_itf->rhport, &p_itf->tx.stream, buffer, (uint16_t)bufsize);
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_write(p_itf->rhport, &p_itf->stream.tx, buffer, (uint16_t)bufsize);
}
uint32_t tud_vendor_n_write_flush (uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_write_xfer(p_itf->rhport, &p_itf->tx.stream);
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
uint32_t tud_vendor_n_write_flush(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_write_xfer(p_itf->rhport, &p_itf->stream.tx);
}
uint32_t tud_vendor_n_write_available (uint8_t itf) {
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
return tu_edpt_stream_write_available(p_itf->rhport, &p_itf->tx.stream);
uint32_t tud_vendor_n_write_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
return tu_edpt_stream_write_available(p_itf->rhport, &p_itf->stream.tx);
}
#endif
//--------------------------------------------------------------------+
// USBD Driver API
@ -149,35 +176,45 @@ void vendord_init(void) {
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
vendord_epbuf_t* p_epbuf = &_vendord_epbuf[i];
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0 // non-fifo rx still need ep buffer
uint8_t *epout_buf = _vendord_epbuf[i].epout;
#else
uint8_t *epout_buf = NULL;
#endif
uint8_t *epin_buf = NULL;
#else
uint8_t *epout_buf = _vendord_epbuf[i].epout;
uint8_t *epin_buf = _vendord_epbuf[i].epin;
#endif
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
uint8_t *rx_ff_buf = p_itf->rx.ff_buf;
uint8_t *rx_ff_buf = p_itf->stream.rx_ff_buf;
#else
uint8_t *rx_ff_buf = NULL;
#endif
tu_edpt_stream_init(&p_itf->rx.stream, false, false, false,
rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE,
p_epbuf->epout, CFG_TUD_VENDOR_EPSIZE);
tu_edpt_stream_init(&p_itf->stream.rx, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
CFG_TUD_VENDOR_EPSIZE);
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
uint8_t *tx_ff_buf = p_itf->tx.ff_buf;
uint8_t *tx_ff_buf = p_itf->stream.tx_ff_buf;
#else
uint8_t* tx_ff_buf = NULL;
uint8_t *tx_ff_buf = NULL;
#endif
tu_edpt_stream_init(&p_itf->tx.stream, false, true, false,
tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE,
p_epbuf->epin, CFG_TUD_VENDOR_EPSIZE);
tu_edpt_stream_init(&p_itf->stream.tx, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
CFG_TUD_VENDOR_EPSIZE);
}
}
bool vendord_deinit(void) {
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
tu_edpt_stream_deinit(&p_itf->rx.stream);
tu_edpt_stream_deinit(&p_itf->tx.stream);
tu_edpt_stream_deinit(&p_itf->stream.rx);
tu_edpt_stream_deinit(&p_itf->stream.tx);
}
return true;
}
@ -188,30 +225,42 @@ void vendord_reset(uint8_t rhport) {
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
tu_edpt_stream_clear(&p_itf->rx.stream);
tu_edpt_stream_close(&p_itf->rx.stream);
tu_edpt_stream_clear(&p_itf->tx.stream);
tu_edpt_stream_close(&p_itf->tx.stream);
tu_edpt_stream_clear(&p_itf->stream.rx);
tu_edpt_stream_close(&p_itf->stream.rx);
tu_edpt_stream_clear(&p_itf->stream.tx);
tu_edpt_stream_close(&p_itf->stream.tx);
}
}
uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) {
// Find vendor interface by endpoint address
static uint8_t find_vendor_itf(uint8_t ep_addr) {
for (uint8_t idx = 0; idx < CFG_TUD_VENDOR; idx++) {
const vendord_interface_t *p_vendor = &_vendord_itf[idx];
if (ep_addr == 0) {
// find unused: require both ep == 0
if (p_vendor->stream.rx.ep_addr == 0 && p_vendor->stream.tx.ep_addr == 0) {
return idx;
}
} else if (ep_addr == p_vendor->stream.rx.ep_addr || ep_addr == p_vendor->stream.tx.ep_addr) {
return idx;
} else {
// nothing to do
}
}
return 0xff;
}
uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint16_t max_len) {
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0);
const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len;
const uint8_t* p_desc = tu_desc_next(desc_itf);
// Find available interface
vendord_interface_t* p_vendor = NULL;
uint8_t itf;
for(itf=0; itf<CFG_TUD_VENDOR; itf++) {
if (!tud_vendor_n_mounted(itf)) {
p_vendor = &_vendord_itf[itf];
break;
}
}
TU_VERIFY(p_vendor, 0);
const uint8_t idx = find_vendor_itf(0);
TU_ASSERT(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_vendor = &_vendord_itf[idx];
p_vendor->rhport = rhport;
p_vendor->itf_num = desc_itf->bInterfaceNumber;
@ -225,16 +274,18 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin
// open endpoint stream, skip if already opened (multiple IN/OUT endpoints)
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
tu_edpt_stream_t *stream_tx = &p_vendor->tx.stream;
tu_edpt_stream_t *stream_tx = &p_vendor->stream.tx;
if (stream_tx->ep_addr == 0) {
tu_edpt_stream_open(stream_tx, desc_ep);
tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data
}
} else {
tu_edpt_stream_t *stream_rx = &p_vendor->rx.stream;
tu_edpt_stream_t *stream_rx = &p_vendor->stream.rx;
if (stream_rx->ep_addr == 0) {
tu_edpt_stream_open(stream_rx, desc_ep);
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
TU_ASSERT(tu_edpt_stream_read_xfer(rhport, stream_rx) > 0, 0); // prepare for incoming data
#endif
}
}
}
@ -247,38 +298,35 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result;
const uint8_t idx = find_vendor_itf(ep_addr);
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_vendor = &_vendord_itf[idx];
uint8_t itf;
vendord_interface_t* p_vendor;
for (itf = 0; itf < CFG_TUD_VENDOR; itf++) {
p_vendor = &_vendord_itf[itf];
if ((ep_addr == p_vendor->rx.stream.ep_addr) || (ep_addr == p_vendor->tx.stream.ep_addr)) {
break;
}
}
TU_VERIFY(itf < CFG_TUD_VENDOR);
vendord_epbuf_t* p_epbuf = &_vendord_epbuf[itf];
if ( ep_addr == p_vendor->rx.stream.ep_addr ) {
if (ep_addr == p_vendor->stream.rx.ep_addr) {
// Received new data: put into stream's fifo
tu_edpt_stream_read_xfer_complete(&p_vendor->rx.stream, xferred_bytes);
tu_edpt_stream_read_xfer_complete(&p_vendor->stream.rx, xferred_bytes);
// Invoked callback if any
tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes);
// invoke callback
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0
tud_vendor_rx_cb(idx, p_vendor->stream.rx.ep_buf, xferred_bytes);
#else
tud_vendor_rx_cb(idx, NULL, 0);
#endif
tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream);
} else if ( ep_addr == p_vendor->tx.stream.ep_addr ) {
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
tu_edpt_stream_read_xfer(rhport, &p_vendor->stream.rx); // prepare next data
#endif
} else if (ep_addr == p_vendor->stream.tx.ep_addr) {
// Send complete
tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
// try to send more if possible
if ( 0 == tu_edpt_stream_write_xfer(rhport, &p_vendor->tx.stream) ) {
if (0 == tu_edpt_stream_write_xfer(rhport, &p_vendor->stream.tx)) {
// If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero
tu_edpt_stream_write_zlp_if_needed(rhport, &p_vendor->tx.stream, xferred_bytes);
tu_edpt_stream_write_zlp_if_needed(rhport, &p_vendor->stream.tx, xferred_bytes);
}
#endif
#endif
}
return true;

View File

@ -27,87 +27,133 @@
#ifndef TUSB_VENDOR_DEVICE_H_
#define TUSB_VENDOR_DEVICE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common/tusb_common.h"
//--------------------------------------------------------------------+
// Configuration
//--------------------------------------------------------------------+
#ifndef CFG_TUD_VENDOR_EPSIZE
#define CFG_TUD_VENDOR_EPSIZE 64
#define CFG_TUD_VENDOR_EPSIZE 64
#endif
// RX FIFO can be disabled by setting this value to 0
#ifndef CFG_TUD_VENDOR_RX_BUFSIZE
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
#endif
// TX FIFO can be disabled by setting this value to 0
#ifndef CFG_TUD_VENDOR_TX_BUFSIZE
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
#endif
#ifdef __cplusplus
extern "C" {
// Application will manually schedule RX transfer. This can be useful when using with non-fifo (buffered) mode
// i.e. CFG_TUD_VENDOR_RX_BUFSIZE = 0
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
#endif
//--------------------------------------------------------------------+
// Application API (Multiple Interfaces) i.e CFG_TUD_VENDOR > 1
//--------------------------------------------------------------------+
bool tud_vendor_n_mounted (uint8_t itf);
uint32_t tud_vendor_n_available (uint8_t itf);
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8);
void tud_vendor_n_read_flush (uint8_t itf);
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
uint32_t tud_vendor_n_write_flush (uint8_t itf);
uint32_t tud_vendor_n_write_available (uint8_t itf);
// Return whether the vendor interface is mounted
bool tud_vendor_n_mounted(uint8_t idx);
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str);
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
// Return number of available bytes for reading
uint32_t tud_vendor_n_available(uint8_t idx);
// Peek a byte from RX buffer
bool tud_vendor_n_peek(uint8_t idx, uint8_t *ui8);
// Read from RX FIFO
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize);
// Discard count bytes in RX FIFO
uint32_t tud_vendor_n_read_discard(uint8_t idx, uint32_t count);
// Flush (clear) RX FIFO
void tud_vendor_n_read_flush(uint8_t idx);
#endif
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
// Start a new RX transfer to fill the RX FIFO, return false if previous transfer is still ongoing
bool tud_vendor_n_read_xfer(uint8_t idx);
#endif
// Write to TX FIFO. This can be buffered and not sent immediately unless buffered bytes >= USB endpoint size
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize);
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
// Force sending buffered data, return number of bytes sent
uint32_t tud_vendor_n_write_flush(uint8_t idx);
// Return number of bytes available for writing in TX FIFO
uint32_t tud_vendor_n_write_available(uint8_t idx);
#endif
// Write a null-terminated string to TX FIFO
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str(uint8_t idx, const char *str) {
return tud_vendor_n_write(idx, str, strlen(str));
}
// backward compatible
#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf)
#define tud_vendor_n_flush(idx) tud_vendor_n_write_flush(idx)
//--------------------------------------------------------------------+
// Application API (Single Port) i.e CFG_TUD_VENDOR = 1
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str(uint8_t itf, char const* str) {
return tud_vendor_n_write(itf, str, strlen(str));
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) {
return tud_vendor_n_mounted(0);
return tud_vendor_n_mounted(0);
}
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) {
return tud_vendor_n_available(0);
return tud_vendor_n_available(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void* buffer, uint32_t bufsize) {
return tud_vendor_n_read(0, buffer, bufsize);
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_peek(uint8_t *ui8) {
return tud_vendor_n_peek(0, ui8);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_peek(uint8_t* ui8) {
return tud_vendor_n_peek(0, ui8);
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void *buffer, uint32_t bufsize) {
return tud_vendor_n_read(0, buffer, bufsize);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read_discard(uint32_t count) {
return tud_vendor_n_read_discard(0, count);
}
TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) {
tud_vendor_n_read_flush(0);
tud_vendor_n_read_flush(0);
}
#endif
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_read_xfer(void) {
return tud_vendor_n_read_xfer(0);
}
#endif
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write(const void *buffer, uint32_t bufsize) {
return tud_vendor_n_write(0, buffer, bufsize);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write(void const* buffer, uint32_t bufsize) {
return tud_vendor_n_write(0, buffer, bufsize);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(char const* str) {
return tud_vendor_n_write_str(0, str);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
return tud_vendor_n_write_flush(0);
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(const char *str) {
return tud_vendor_n_write_str(0, str);
}
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
return tud_vendor_n_write_flush(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
return tud_vendor_n_write_available(0);
return tud_vendor_n_write_available(0);
}
#endif
@ -118,15 +164,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
// Application Callback API (weak is optional)
//--------------------------------------------------------------------+
// Invoked when received new data
void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize);
// Invoked when last rx transfer finished
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
//--------------------------------------------------------------------+
// Inline Functions
//--------------------------------------------------------------------+
// Invoked when received new data.
// - CFG_TUD_VENDOR_RX_BUFSIZE > 0; buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
// - CFG_TUD_VENDOR_RX_BUFSIZE = 0: Buffer and bufsize are valid
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
// Invoked when tx transfer is finished
void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes);
//--------------------------------------------------------------------+
// Internal Class Driver API
@ -134,11 +178,11 @@ void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
void vendord_init(void);
bool vendord_deinit(void);
void vendord_reset(uint8_t rhport);
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *idx_desc, uint16_t max_len);
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
#ifdef __cplusplus
}
}
#endif
#endif /* TUSB_VENDOR_DEVICE_H_ */

View File

@ -56,6 +56,9 @@ TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) {
#endif
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) {
// Limit index space to 2*depth - this allows for a fast "modulo" calculation
// but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
@ -80,6 +83,36 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si
return true;
}
// clear fifo by resetting read and write indices
bool tu_fifo_clear(tu_fifo_t *f) {
ff_lock(f->mutex_wr);
ff_lock(f->mutex_rd);
f->rd_idx = 0;
f->wr_idx = 0;
ff_unlock(f->mutex_wr);
ff_unlock(f->mutex_rd);
return true;
}
// Change the fifo overwritable mode
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
if (f->overwritable == overwritable) {
return true;
}
ff_lock(f->mutex_wr);
ff_lock(f->mutex_rd);
f->overwritable = overwritable;
ff_unlock(f->mutex_wr);
ff_unlock(f->mutex_rd);
return true;
}
//--------------------------------------------------------------------+
// Pull & Push
// copy data to/from fifo without updating read/write pointers
@ -295,49 +328,27 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t correct_read_index(tu_fifo_t *f, ui
return rd_idx;
}
// peek() using local write/read index. Be careful, caller must not lock mutex, since this Will also try to lock mutex
// in case of overflowed to correct read index
static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_idx) {
const uint16_t ovf_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (ovf_count == 0) {
return false; // nothing to peek
}
// Correct read index if overflow
if (ovf_count > f->depth) {
ff_lock(f->mutex_rd);
rd_idx = correct_read_index(f, wr_idx);
ff_unlock(f->mutex_rd);
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size);
return true;
}
//--------------------------------------------------------------------+
// Application API
// n-API
//--------------------------------------------------------------------+
// Works on local copies of w and r
// Must be protected by mutexes since in case of an overflow read pointer gets modified
// Must be protected by read mutex since in case of an overflow read pointer gets modified
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
tu_fifo_access_mode_t access_mode) {
uint16_t ovf_cnt = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (ovf_cnt == 0) {
uint16_t count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (count == 0) {
return 0; // nothing to peek
}
// Check overflow and correct if required
if (ovf_cnt > f->depth) {
if (count > f->depth) {
rd_idx = correct_read_index(f, wr_idx);
ovf_cnt = f->depth;
count = f->depth;
}
if (ovf_cnt < n) {
n = ovf_cnt; // limit to available count
if (count < n) {
n = count; // limit to available count
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
@ -346,6 +357,27 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
return n;
}
// Read n items without removing it from the FIFO, correct read pointer if overflowed
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) {
ff_lock(f->mutex_rd);
const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8);
ff_unlock(f->mutex_rd);
return ret;
}
// Read n items from fifo with access mode
uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) {
ff_lock(f->mutex_rd);
// Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
n = tu_fifo_peek_n_access_mode(f, buffer, n, f->wr_idx, f->rd_idx, access_mode);
f->rd_idx = advance_index(f->depth, f->rd_idx, n);
ff_unlock(f->mutex_rd);
return n;
}
// Write n items to fifo with access mode
uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) {
if (n == 0) {
return 0;
@ -419,40 +451,41 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
return n;
}
uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) {
uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n) {
const uint16_t count = tu_min16(n, tu_fifo_count(f)); // limit to available count
ff_lock(f->mutex_rd);
// Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
n = tu_fifo_peek_n_access_mode(f, buffer, n, f->wr_idx, f->rd_idx, access_mode);
f->rd_idx = advance_index(f->depth, f->rd_idx, n);
f->rd_idx = advance_index(f->depth, f->rd_idx, count);
ff_unlock(f->mutex_rd);
return n;
return count;
}
// Only use in case tu_fifo_overflow() returned true!
void tu_fifo_correct_read_pointer(tu_fifo_t *f) {
ff_lock(f->mutex_rd);
correct_read_index(f, f->wr_idx);
ff_unlock(f->mutex_rd);
//--------------------------------------------------------------------+
// One API
//--------------------------------------------------------------------+
// peek() using local write/read index, correct read index if overflowed
// Be careful, caller must not lock mutex, since this Will also try to lock mutex
static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_idx) {
const uint16_t ovf_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (ovf_count == 0) {
return false; // nothing to peek
}
// Correct read index if overflow
if (ovf_count > f->depth) {
ff_lock(f->mutex_rd);
rd_idx = correct_read_index(f, wr_idx);
ff_unlock(f->mutex_rd);
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size);
return true;
}
/******************************************************************************/
/*!
@brief Read one element out of the buffer.
This function will return the element located at the array index of the
read pointer, and then increment the read pointer index.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] buffer
Pointer to the place holder for data read from the buffer
@returns TRUE if the queue is not empty
*/
/******************************************************************************/
// Read one element out of the buffer, correct read index if overflowed
bool tu_fifo_read(tu_fifo_t *f, void *buffer) {
// Peek the data
// f->rd_idx might get modified in case of an overflow so we can not use a local variable
@ -466,61 +499,12 @@ bool tu_fifo_read(tu_fifo_t *f, void *buffer) {
return ret;
}
/******************************************************************************/
/*!
@brief Read one item without removing it from the FIFO.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] p_buffer
Pointer to the place holder for data read from the buffer
@returns TRUE if the queue is not empty
*/
/******************************************************************************/
// Read one item without removing it from the FIFO, correct read index if overflowed
bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) {
return ff_peek_local(f, p_buffer, f->wr_idx, f->rd_idx);
}
/******************************************************************************/
/*!
@brief Read n items without removing it from the FIFO
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] p_buffer
Pointer to the place holder for data read from the buffer
@param[in] n
Number of items to peek
@returns Number of bytes written to p_buffer
*/
/******************************************************************************/
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) {
ff_lock(f->mutex_rd);
const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8);
ff_unlock(f->mutex_rd);
return ret;
}
/******************************************************************************/
/*!
@brief Write one element into the buffer.
This function will write one element into the array index specified by
the write pointer and increment the write index.
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] data
The byte to add to the FIFO
@returns TRUE if the data was written to the FIFO (overwrittable
FIFO will always return TRUE)
*/
/******************************************************************************/
// Write one element into the buffer
bool tu_fifo_write(tu_fifo_t *f, const void *data) {
bool ret;
ff_lock(f->mutex_wr);
@ -541,51 +525,9 @@ bool tu_fifo_write(tu_fifo_t *f, const void *data) {
return ret;
}
/******************************************************************************/
/*!
@brief Clear the fifo read and write pointers
@param[in] f
Pointer to the FIFO buffer to manipulate
*/
/******************************************************************************/
bool tu_fifo_clear(tu_fifo_t *f) {
ff_lock(f->mutex_wr);
ff_lock(f->mutex_rd);
f->rd_idx = 0;
f->wr_idx = 0;
ff_unlock(f->mutex_wr);
ff_unlock(f->mutex_rd);
return true;
}
/******************************************************************************/
/*!
@brief Change the fifo mode to overwritable or not overwritable
@param[in] f
Pointer to the FIFO buffer to manipulate
@param[in] overwritable
Overwritable mode the fifo is set to
*/
/******************************************************************************/
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
if (f->overwritable == overwritable) {
return true;
}
ff_lock(f->mutex_wr);
ff_lock(f->mutex_rd);
f->overwritable = overwritable;
ff_unlock(f->mutex_wr);
ff_unlock(f->mutex_rd);
return true;
}
//--------------------------------------------------------------------+
// Index API
//--------------------------------------------------------------------+
/******************************************************************************/
/*!
@ -607,6 +549,13 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n) {
f->wr_idx = advance_index(f->depth, f->wr_idx, n);
}
// Correct the read index in case tu_fifo_overflow() returned true!
void tu_fifo_correct_read_pointer(tu_fifo_t *f) {
ff_lock(f->mutex_rd);
correct_read_index(f, f->wr_idx);
ff_unlock(f->mutex_rd);
}
/******************************************************************************/
/*!
@brief Advance read pointer - intended to be used in combination with DMA.

View File

@ -156,9 +156,9 @@ typedef enum {
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable);
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
bool tu_fifo_clear(tu_fifo_t *f);
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
#if OSAL_MUTEX_REQUIRED
TU_ATTR_ALWAYS_INLINE static inline
@ -170,6 +170,22 @@ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_m
#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
#endif
//--------------------------------------------------------------------+
// Index API
//--------------------------------------------------------------------+
void tu_fifo_correct_read_pointer(tu_fifo_t *f);
// Pointer modifications intended to be used in combinations with DMAs.
// USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n);
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n);
// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies
// to handle a possible wrapping part. These functions deliver a pointer to start
// reading/writing from/to and a valid linear length along which no wrap occurs.
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
//--------------------------------------------------------------------+
// Peek API
// peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo
@ -189,6 +205,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *
return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8);
}
// discard first n items from fifo i.e advance read pointer by n with mutex
// return number of discarded items
uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n);
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
@ -198,22 +218,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const
return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8);
}
//--------------------------------------------------------------------+
// Index API
//--------------------------------------------------------------------+
void tu_fifo_correct_read_pointer(tu_fifo_t *f);
// Pointer modifications intended to be used in combinations with DMAs.
// USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n);
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n);
// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies
// to handle a possible wrapping part. These functions deliver a pointer to start
// reading/writing from/to and a valid linear length along which no wrap occurs.
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
//--------------------------------------------------------------------+
// Internal Helper Local
// work on local copies of read/write indices in order to only access them once for re-entrancy

View File

@ -172,6 +172,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_peek(tu_edpt_stream_t *s
return tu_fifo_peek(&s->ff, ch);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_edpt_stream_discard(tu_edpt_stream_t *s, uint32_t len) {
return (uint32_t)tu_fifo_discard_n(&s->ff, (uint16_t)len);
}
#ifdef __cplusplus
}
#endif

View File

@ -323,6 +323,11 @@ typedef struct {
tusb_speed_t speed;
} tusb_rhport_init_t;
typedef struct {
uint16_t len;
uint8_t *buffer;
} tusb_buffer_t;
//--------------------------------------------------------------------+
// USB Descriptors
//--------------------------------------------------------------------+

View File

@ -59,21 +59,26 @@
/* Try to detect nrfx version if not configured with CFG_TUD_NRF_NRFX_VERSION
* nrfx v1 and v2 are concurrently developed. There is no NRFX_VERSION only MDK VERSION which is as follows:
* - v3.0.0: 8.53.1 (conflict with v2.11.0), v3.1.0: 8.55.0 ...
* - v2.11.0: 8.53.1, v2.6.0: 8.44.1, v2.5.0: 8.40.2, v2.4.0: 8.37.0, v2.3.0: 8.35.0, v2.2.0: 8.32.1, v2.1.0: 8.30.2, v2.0.0: 8.29.0
* - v2.11.0: 8.53.1, v2.6.0: 8.44.1, v2.5.0: 8.40.2, v2.4.0: 8.37.0, v2.3.0: 8.35.0, v2.2.0: 8.32.1, v2.1.0: 8.30.2,
* v2.0.0: 8.29.0
* - v1.9.0: 8.40.3, v1.8.6: 8.35.0 (conflict with v2.3.0), v1.8.5: 8.32.3, v1.8.4: 8.32.1 (conflict with v2.2.0),
* v1.8.2: 8.32.1 (conflict with v2.2.0), v1.8.1: 8.27.1
* Therefore the check for v1 would be:
* - MDK < 8.29.0 (v2.0), MDK == 8.32.3, 8.40.3
* - in case of conflict User of those version must upgrade to other 1.x version or set CFG_TUD_NRF_NRFX_VERSION
*/
*/
#ifndef CFG_TUD_NRF_NRFX_VERSION
#define _MDK_VERSION (10000*MDK_MAJOR_VERSION + 100*MDK_MINOR_VERSION + MDK_MICRO_VERSION)
#define MDK_VERSION (10000 * MDK_MAJOR_VERSION + 100 * MDK_MINOR_VERSION + MDK_MICRO_VERSION)
#if _MDK_VERSION < 82900 || _MDK_VERSION == 83203 || _MDK_VERSION == 84003
#if MDK_VERSION < 82900 || MDK_VERSION == 83203 || MDK_VERSION == 84003
// nrfx <= 1.8.1, or 1.8.5 or 1.9.0
#define CFG_TUD_NRF_NRFX_VERSION 1
#else
#elif MDK_VERSION < 85301
#define CFG_TUD_NRF_NRFX_VERSION 2
#elif MDK_VERSION < 87300
#define CFG_TUD_NRF_NRFX_VERSION 3
#else
#define CFG_TUD_NRF_NRFX_VERSION 4
#endif
#endif
@ -845,19 +850,19 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_sd_enabled(void) {
#endif
static bool hfclk_running(void) {
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() ) {
#ifdef SOFTDEVICE_PRESENT
if (is_sd_enabled()) {
uint32_t is_running = 0;
(void) sd_clock_hfclk_is_running(&is_running);
(void)sd_clock_hfclk_is_running(&is_running);
return (is_running ? true : false);
}
#endif
#endif
#if CFG_TUD_NRF_NRFX_VERSION == 1
#if CFG_TUD_NRF_NRFX_VERSION == 1
return nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY);
#else
return nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
#endif
#else
return nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, NULL);
#endif
}
static void hfclk_enable(void) {
@ -867,22 +872,24 @@ static void hfclk_enable(void) {
#else
// already running, nothing to do
if (hfclk_running()) return;
if (hfclk_running()) {
return;
}
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() ) {
#ifdef SOFTDEVICE_PRESENT
if (is_sd_enabled()) {
(void)sd_clock_hfclk_request();
return;
}
#endif
#endif
#if CFG_TUD_NRF_NRFX_VERSION == 1
#if CFG_TUD_NRF_NRFX_VERSION == 1
nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
#else
#else
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
#endif
#endif
#endif
}

View File

@ -450,12 +450,19 @@ uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t *s, const void *buf
TU_VERIFY(bufsize > 0); // TODO support ZLP
if (0 == tu_fifo_depth(&s->ff)) {
// non-fifo mode, ep_buf must be valid
TU_VERIFY(s->ep_buf != NULL, 0);
// non-fifo mode
TU_VERIFY(stream_claim(hwid, s), 0);
const uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize);
memcpy(s->ep_buf, buffer, xact_len);
uint32_t xact_len;
if (s->ep_buf != NULL) {
// using ep buf
xact_len = tu_min32(bufsize, s->ep_bufsize);
memcpy(s->ep_buf, buffer, xact_len);
} else {
// using hwfifo
xact_len = bufsize;
}
TU_ASSERT(stream_xfer(hwid, s, (uint16_t) xact_len), 0);
return xact_len;
} else {
const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
@ -494,7 +501,8 @@ uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s) {
//--------------------------------------------------------------------+
uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) {
if (0 == tu_fifo_depth(&s->ff)) {
// non-fifo mode
// non-fifo mode: RX need ep buffer
TU_VERIFY(s->ep_buf != NULL, 0);
TU_VERIFY(stream_claim(hwid, s), 0);
TU_ASSERT(stream_xfer(hwid, s, s->ep_bufsize), 0);
return s->ep_bufsize;
@ -507,11 +515,8 @@ uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) {
// and slowly move it to the FIFO when read().
// This pre-check reduces endpoint claiming
TU_VERIFY(available >= mps);
TU_VERIFY(stream_claim(hwid, s), 0);
// get available again since fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&s->ff);
available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
if (available >= mps) {
// multiple of packet size limit by ep bufsize
@ -528,15 +533,7 @@ uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) {
}
uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) {
uint32_t num_read;
if (tu_fifo_depth(&s->ff) > 0) {
num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t)bufsize);
} else {
// non-fifo mode
memcpy(buffer, s->ep_buf, bufsize);
num_read = bufsize;
}
const uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t)bufsize);
tu_edpt_stream_read_xfer(hwid, s);
return num_read;
}

View File

@ -246,7 +246,7 @@ deps_optional = {
'imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x '
'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 '
'stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 '
'stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32u0 stm32u5 stm32wb stm32wba'
'stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32u0 stm32u5 stm32wb stm32wba '
'sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg '
'tm4c '],
'lib/CMSIS_6': ['https://github.com/ARM-software/CMSIS_6.git',
@ -343,7 +343,7 @@ def main():
for f in families:
for d in deps_optional:
if d not in deps and f in deps_optional[d][2]:
if d not in deps and f in deps_optional[d][2].split():
deps.append(d)
if print_only: