mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-04 12:25:28 +00:00
Merge remote-tracking branch 'tinyusb/master' into hcd_fsdev
This commit is contained in:
14
.github/actions/setup_toolchain/action.yml
vendored
14
.github/actions/setup_toolchain/action.yml
vendored
@ -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 }}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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",
|
||||
|
||||
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -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
13
.idea/cmake.xml
generated
@ -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="-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1"">
|
||||
<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" />
|
||||
|
||||
@ -3,4 +3,3 @@ CONFIG_FPU=y
|
||||
CONFIG_NO_OPTIMIZATIONS=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_NRFX_POWER=y
|
||||
CONFIG_NRFX_UARTE0=y
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -3,4 +3,3 @@ CONFIG_FPU=y
|
||||
CONFIG_NO_OPTIMIZATIONS=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_NRFX_POWER=y
|
||||
CONFIG_NRFX_UARTE0=y
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
|
||||
254
src/class/vendor/vendor_device.c
vendored
254
src/class/vendor/vendor_device.c
vendored
@ -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;
|
||||
|
||||
140
src/class/vendor/vendor_device.h
vendored
140
src/class/vendor/vendor_device.h
vendored
@ -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_ */
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
33
src/tusb.c
33
src/tusb.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
Reference in New Issue
Block a user