48 Commits

Author SHA1 Message Date
sakumisu
c746f57ddc docs: bump version to v1.5.3
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 14:23:48 +08:00
sakumisu
3882560646 update: remove ununsed osal
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 14:22:49 +08:00
Zhihong Chen
9cf680148e port: update hpmicro port files for otg
Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2025-11-25 14:22:15 +08:00
sakumisu
e25c12f6a8 fix warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 14:22:15 +08:00
sakumisu
f09198704b refactor(otg): refactor otg framework
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 14:22:08 +08:00
sakumisu
af519ac42c feat(class): support more match flags for cdc acm & rndis
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-25 14:18:36 +08:00
sakumisu
c34cbc5bfb update(core): change assert with USB_ASSERT_MSG
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-24 20:34:16 +08:00
sakumisu
38dff565cf update(platform/daplink): sync with cherrydap
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-24 20:34:01 +08:00
sakumisu
6067343775 fix(osal/usb_osal_ucosiii): fix msleep opt
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-23 21:37:29 +08:00
sakumisu
6c34938883 feat(core/usbh_core): support interfacenum match flag
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-23 21:37:23 +08:00
sakumisu
7cd4ff71d7 update(port/dwc2/usb_glue_st): increase ep1 tx fifo for audio demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-19 22:21:54 +08:00
sakumisu
999ddb1a9d update(core/usbh_core): print interface num when load driver
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-13 22:05:52 +08:00
sakumisu
01b22bb138 docs: update rst
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-13 22:04:44 +08:00
sakumisu
e0dc9c9890 refactor(core/usbh_core): refactor lsusb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-11 22:45:49 +08:00
sakumisu
6105d7a1d6 ci: update bl & hpm demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-10 20:34:16 +08:00
sakumisu
757187e967 fix(port/dwc2/usb_dc_dwc2): invalid cache before all read setup
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-09 22:28:52 +08:00
蒙蒙plus
a33396fa93 fix(usb_dc_dwc2): add unaligned read/write macros for IAR compiler 2025-11-09 22:28:02 +08:00
Rbb666
ab8efcb07d fix:Fix RNDIS DHCP dependency,and delay implementation 2025-11-09 22:27:51 +08:00
sakumisu
5c9550d00e fix(osal/usb_osal_threadx): delete self in another thread
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:42:07 +08:00
sakumisu
c8a713a49a update(platform/rtthread): change LWIP_NO_RX_THREAD check error to warning
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:42:07 +08:00
sakumisu
87c49f9359 ci: enable all class
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-05 20:42:07 +08:00
sakumisu
6e8a63fd77 feat(platform/idf): add fatfs port for host msc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 23:03:50 +08:00
sakumisu
71a966bbd5 fix(osal/usb_osal_ucosiii): lock before free
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:58:34 +08:00
sakumisu
32cf0e0b3c fix(class/hub): delete thread before delete mq
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:58:34 +08:00
sakumisu
88b1158b4f update(platform/rtthread): add more check for chip cache
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-04 21:58:34 +08:00
sakumisu
38a4c5e375 fix(osal/usb_osal_ucosiii): memset after malloc
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:19:13 +08:00
sakumisu
b758fa814a feat(osal): add ucosiii osal
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:18:55 +08:00
sakumisu
9730f63b2c feat: support custom ep0 mps
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:17:43 +08:00
sakumisu
0365aa0d63 feat(demo): add mongoose rndis demo
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:17:10 +08:00
sakumisu
649ad6686b update(core/usbh_core): add retry for control transfer, some devices are flakey
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 22:01:45 +08:00
sakumisu
868dbee668 chore: add build ci
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-03 21:45:57 +08:00
sakumisu
84b1d3feeb update(port/chipidea): add dcache support for device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-11-01 00:22:19 +08:00
MDLZCOOL
1045f877c8 refactor(usb_osal_threadx): optimize the creation and deletion of threads
- Allocate only once at `usb_osal_thread_create`.
- Fixed a null pointer crash in `usb_osal_thread_delete`.
- Standardized the return value of `usb_osal_sem_give`.
2025-10-27 17:40:42 +08:00
HalfSweet
12694eed49 feat: Add MUSB IP without multipoint feature support 2025-10-27 17:40:42 +08:00
sakumisu
ed344579ff update(port/hpmicro): add dcache support for device
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-27 17:40:42 +08:00
sakumisu
c3b01eed25 update(demo/cdc_acm_rttchardev): add finsh & console switch with usb
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-27 17:40:42 +08:00
sakumisu
f087e0777a update(platform): remove CONFIG_USB_DCACHE_ENABLE, always check align size
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-27 17:40:42 +08:00
sakumisu
82487c80aa update(port/dwc2/usb_glue_hc): update hc port
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:30:56 +08:00
sakumisu
86e9422e06 update(hub/usbh_hub): add check for nports
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:30:56 +08:00
sakumisu
6c239e175f feat(class/video/usbh_video): support bulk mode
Signed-off-by: sakumisu <1203593632@qq.com>
2025-10-09 21:30:56 +08:00
sakumisu
1b973b5cc5 fix(port/ehci): clear iaad status before set
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-27 22:21:15 +08:00
LiPeng
102af3be37 fix: Remove usb component private requirement for idf v6 2025-09-11 16:58:55 +08:00
sakumisu
347df77372 fix(demo): fix missing ecm mac address string
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-01 20:04:09 +08:00
sakumisu
778465654b docs: remove ununsed code
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-01 20:03:59 +08:00
sakumisu
e2791c7d04 refactor(core/usbh_core): refactor devaddr allocation, use auto increment
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-01 20:03:45 +08:00
sakumisu
7902c1c352 style: remove printf with USB_LOG_XXX
Signed-off-by: sakumisu <1203593632@qq.com>
2025-09-01 20:03:19 +08:00
LiPeng
1768079a89 bugfix: Fix support for idf versions lower than 5.3 2025-09-01 20:03:07 +08:00
LiPeng
c77557510e bugfix: Fix some compilation errors 2025-09-01 20:01:50 +08:00
103 changed files with 9000 additions and 1126 deletions

83
.github/workflows/build_tests.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: Build Tests
on:
push:
branches:
- master
- release/v1.5
pull_request:
branches:
- master
- release/v1.5
jobs:
build_hpmicro:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build
- name: Download hpm_sdk
run: |
cd ~
git clone https://github.com/hpmicro/hpm_sdk.git
- name: Download RISC-V toolchain
run: |
cd ~
wget https://github.com/hpmicro/riscv-gnu-toolchain/releases/download/2023.10.18/rv32imac_zicsr_zifencei_multilib_b_ext-linux.tar.gz
tar -xzf rv32imac_zicsr_zifencei_multilib_b_ext-linux.tar.gz
- name: Build hpm demo
run: |
cd tests/hpmicro
export HPM_SDK_BASE=~/hpm_sdk
export GNURISCV_TOOLCHAIN_PATH=~/rv32imac_zicsr_zifencei_multilib_b_ext-linux
export HPM_SDK_TOOLCHAIN_VARIANT=
cmake -S . -B build -GNinja -DBOARD=hpm6800evk -DHPM_BUILD_TYPE=flash_sdram_xip -DCMAKE_BUILD_TYPE=debug -DEXTRA_C_FLAGS="-Werror";cmake --build build
build_bouffalolab:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y cmake make
- name: Download bouffalo_sdk
run: |
cd ~
git clone https://github.com/bouffalolab/bouffalo_sdk.git
- name: Download RISC-V toolchain
run: |
cd ~
git clone https://github.com/bouffalolab/toolchain_gcc_t-head_linux.git
- name: Build bouffalo demo
run: |
cd tests/bouffalolab
export BL_SDK_BASE=~/bouffalo_sdk
export PATH=~/toolchain_gcc_t-head_linux/bin:$PATH
make CHIP=bl616 BOARD=bl616dk -j12
build_espressif:
strategy:
matrix:
idf_ver: ["latest"]
runs-on: ubuntu-latest
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Build espressif demo
shell: bash
run: |
. ${IDF_PATH}/export.sh
pip install idf-component-manager ruamel.yaml idf-build-apps --upgrade
idf-build-apps build -p ./tests/espressif --recursive --target esp32s3

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vscode
build
**/Drivers/**
**/MDK-ARM/DebugConfig/**
**/MDK-ARM/RTE/**

View File

@@ -64,6 +64,14 @@ elseif(ESP_PLATFORM)
idf_component_get_property(freertos_include freertos ORIG_INCLUDE_PATH)
if(CONFIG_CHERRYUSB_HOST_MSC)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/idf/usbh_fatfs.c)
endif()
set(priv_req esp_mm esp_netif esp_timer fatfs)
if(${IDF_VERSION_MAJOR} LESS 6)
list(APPEND priv_req usb)
endif()
idf_component_register(
SRCS
${cherryusb_srcs}
@@ -71,7 +79,7 @@ elseif(ESP_PLATFORM)
${cherryusb_incs}
${freertos_include}
PRIV_REQUIRES
usb esp_mm esp_netif esp_timer
${priv_req}
LDFRAGMENTS
${ldfragments}
)

View File

@@ -118,6 +118,7 @@ if CHERRYUSB
config CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
depends on !IDF_CMAKE
default n
config CHERRYUSB_DEVICE_MTP
@@ -338,6 +339,7 @@ if CHERRYUSB
config CHERRYUSB_HOST_BLUETOOTH
bool
prompt "Enable usb bluetooth driver"
depends on !IDF_CMAKE
default n
config CHERRYUSB_HOST_ASIX

View File

@@ -465,12 +465,14 @@ if PKG_USING_CHERRYUSB
choice
prompt "Version"
default PKG_USING_CHERRYUSB_V010502
default PKG_USING_CHERRYUSB_V010503
help
Select the package version
config PKG_USING_CHERRYUSB_LATEST_VERSION
bool "latest"
config PKG_USING_CHERRYUSB_V010502
bool "v1.5.3"
config PKG_USING_CHERRYUSB_V010502
bool "v1.5.2"
config PKG_USING_CHERRYUSB_V010501
@@ -490,6 +492,7 @@ if PKG_USING_CHERRYUSB
config PKG_CHERRYUSB_VER
string
default "latest" if PKG_USING_CHERRYUSB_LATEST_VERSION
default "v1.5.3" if PKG_USING_CHERRYUSB_V010503
default "v1.5.2" if PKG_USING_CHERRYUSB_V010502
default "v1.5.1" if PKG_USING_CHERRYUSB_V010501
default "v1.5.0" if PKG_USING_CHERRYUSB_V010500

View File

@@ -197,7 +197,7 @@ TODO
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Official ongoing |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |

View File

@@ -197,7 +197,7 @@ TODO
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Official ongoing |
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |

View File

@@ -1,5 +1,5 @@
VERSION_MAJOR = 1
VERSION_MINOR = 5
PATCHLEVEL = 2
PATCHLEVEL = 3
VERSION_TWEAK = 0
EXTRAVERSION = 0

View File

@@ -340,6 +340,10 @@ if(CONFIG_CHERRYUSB_HOST)
endif()
endif()
if(CONFIG_CHERRYUSB_DEVICE AND CONFIG_CHERRYUSB_HOST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbotg_core.c)
endif()
if(DEFINED CONFIG_CHERRYUSB_OSAL)
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_freertos.c)

View File

@@ -301,6 +301,7 @@
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_PIPE_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
// #define CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode,
* the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS.
@@ -317,4 +318,7 @@
#define usb_ramaddr2phyaddr(addr) (addr)
#endif
/* Enable OTG support, only support hpmicro now */
// #define CONFIG_USB_OTG_ENABLE
#endif

View File

@@ -176,9 +176,6 @@ int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *repo
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len)
{
struct usb_setup_packet *setup;
int ret;
uint8_t len;
uint32_t offset;
if (!aoa_class || !aoa_class->hport) {
return -USB_ERR_INVAL;
@@ -198,7 +195,6 @@ int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *ev
static int usbh_aoa_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
struct usbh_aoa *aoa_class = &g_aoa_class;

View File

@@ -266,11 +266,20 @@ const struct usbh_class_driver cdc_data_class_driver = {
.disconnect = usbh_cdc_data_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_none_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = 0x00,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
.id_table = NULL,
.class_driver = &cdc_acm_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_at_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
.id_table = NULL,
.class_driver = &cdc_acm_class_driver
};

View File

@@ -106,7 +106,6 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
{
struct usb_setup_packet *req = setup;
uint32_t addr;
uint8_t *phaddr;
/* Data setup request */
if (req->wLength > 0U) {
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
@@ -143,7 +142,7 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
/* Return the physical address where data are stored */
phaddr = dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
/* Send the status data over EP0 */
memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);

View File

@@ -106,7 +106,7 @@ int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
if (ret < 8) {
return ret;
}
memcpy(buffer, g_hid_buf[hid_class->minor], MIN(ret - 8, 1));
memcpy(buffer, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
return ret;
}
@@ -148,7 +148,7 @@ int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol)
if (ret < 8) {
return ret;
}
memcpy(protocol, g_hid_buf[hid_class->minor], MIN(ret - 8, 1));
memcpy(protocol, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
return ret;
}
@@ -190,7 +190,7 @@ int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t
if (ret < 8) {
return ret;
}
memcpy(buffer, g_hid_buf[hid_class->minor], MIN(ret - 8, buflen));
memcpy(buffer, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, buflen));
return ret;
}

View File

@@ -373,6 +373,11 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
hub->tt_think = ((hub->hub_desc.wHubCharacteristics & HUB_CHAR_TTTT_MASK) >> 5);
}
if (hub->nports > CONFIG_USBHOST_MAX_EHPORTS) {
USB_LOG_ERR("Hub nports %u overflow\r\n", hub->nports);
return -USB_ERR_NOMEM;
}
for (uint8_t port = 0; port < hub->nports; port++) {
hub->child[port].port = port + 1;
hub->child[port].parent = hub;
@@ -708,7 +713,6 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
{
struct usbh_hubport *hport;
struct usbh_hub *hub;
size_t flags;
hub = &bus->hcd.roothub;
for (uint8_t port = 0; port < hub->nports; port++) {
@@ -717,14 +721,10 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
usbh_hubport_release(hport);
}
flags = usb_osal_enter_critical_section();
usb_hc_deinit(bus);
usb_osal_leave_critical_section(flags);
usb_osal_mq_delete(bus->hub_mq);
usb_osal_thread_delete(bus->hub_thread);
usb_osal_mq_delete(bus->hub_mq);
return 0;
}

View File

@@ -1034,17 +1034,17 @@ static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t si
static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen,
uint16_t size, void *data, uint16_t type)
{
int ret;
int ret = -USB_ERR_INVAL;
uint16_t byteen_start, byteen_end, byen;
uint16_t limit = 512;
uint8_t *buf = data;
/* both size and indix must be 4 bytes align */
if ((size & 3) || !size || (index & 3) || !buf)
return -USB_ERR_INVAL;
return ret;
if ((uint32_t)index + (uint32_t)size > 0xffff)
return -USB_ERR_INVAL;
return ret;
byteen_start = byteen & BYTE_EN_START_MASK;
byteen_end = byteen & BYTE_EN_END_MASK;

View File

@@ -122,12 +122,12 @@ int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class)
return usbh_video_get(video_class, VIDEO_REQUEST_GET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex, uint32_t dwFrameInterval)
{
video_class->probe.bFormatIndex = formatindex;
video_class->probe.bFrameIndex = frameindex;
video_class->probe.dwMaxPayloadTransferSize = 0;
video_class->probe.dwFrameInterval = 333333;
video_class->probe.dwFrameInterval = dwFrameInterval;
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
}
@@ -136,7 +136,6 @@ int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t f
memcpy(&video_class->commit, &video_class->probe, sizeof(struct video_probe_and_commit_controls));
video_class->commit.bFormatIndex = formatindex;
video_class->commit.bFrameIndex = frameindex;
video_class->commit.dwFrameInterval = 333333;
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
}
@@ -154,6 +153,7 @@ int usbh_video_open(struct usbh_video *video_class,
bool found = false;
uint8_t formatidx = 0;
uint8_t frameidx = 0;
uint32_t dwDefaultFrameInterval = 0;
uint8_t step;
if (!video_class || !video_class->hport) {
@@ -172,6 +172,7 @@ int usbh_video_open(struct usbh_video *video_class,
if ((wWidth == video_class->format[i].frame[j].wWidth) &&
(wHeight == video_class->format[i].frame[j].wHeight)) {
frameidx = j + 1;
dwDefaultFrameInterval = video_class->format[i].frame[j].dwDefaultFrameInterval;
found = true;
break;
}
@@ -204,7 +205,7 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 1;
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx, dwDefaultFrameInterval);
if (ret < 0) {
goto errout;
}
@@ -228,7 +229,7 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 5;
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx, dwDefaultFrameInterval);
if (ret < 0) {
goto errout;
}
@@ -246,26 +247,30 @@ int usbh_video_open(struct usbh_video *video_class,
}
step = 8;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
if (!video_class->is_bulk) {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = altsetting;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
goto errout;
}
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
goto errout;
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
video_class->isoin_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoin, ep_desc);
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
video_class->isoin_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoin, ep_desc);
} else {
return -USB_ERR_NODEV;
}
} else {
video_class->isoout_mps = mps * (mult + 1);
USBH_EP_INIT(video_class->isoout, ep_desc);
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[0].ep[0].ep_desc;
USBH_EP_INIT(video_class->bulkin, ep_desc);
}
USB_LOG_INFO("Open video and select formatidx:%u, frameidx:%u, altsetting:%u\r\n", formatidx, frameidx, altsetting);
@@ -292,54 +297,62 @@ int usbh_video_close(struct usbh_video *video_class)
video_class->is_opened = false;
if (video_class->isoin) {
video_class->isoin = NULL;
if (video_class->is_bulk) {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_ENDPOINT;
setup->bRequest = USB_REQUEST_CLEAR_FEATURE;
setup->wValue = USB_FEATURE_ENDPOINT_HALT;
setup->wIndex = video_class->bulkin->bEndpointAddress;
setup->wLength = 0;
} else {
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
}
if (video_class->isoout) {
video_class->isoout = NULL;
}
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = USB_REQUEST_SET_INTERFACE;
setup->wValue = 0;
setup->wIndex = video_class->data_intf;
setup->wLength = 0;
ret = usbh_control_transfer(video_class->hport, setup, NULL);
if (ret < 0) {
return ret;
}
return ret;
}
void usbh_video_list_info(struct usbh_video *video_class)
{
struct usb_endpoint_descriptor *ep_desc;
uint8_t mult;
uint16_t mps;
USB_LOG_INFO("============= Video device information ===================\r\n");
USB_LOG_RAW("bcdVDC:%04x\r\n", video_class->bcdVDC);
USB_LOG_RAW("Num of altsettings:%u\r\n", video_class->num_of_intf_altsettings);
USB_LOG_RAW("Num of altsettings:%u (%s mode)\r\n", video_class->num_of_intf_altsettings, video_class->num_of_intf_altsettings == 1 ? "bulk" : "iso");
for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
if (i == 0) {
USB_LOG_RAW("Ingore altsetting 0\r\n");
continue;
video_class->is_bulk = video_class->num_of_intf_altsettings == 1 ? true : false;
if (video_class->is_bulk) {
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[0].ep[0].ep_desc;
USB_LOG_RAW("Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize),
ep_desc->bInterval,
USB_GET_MULT(ep_desc->wMaxPacketSize));
} else {
for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
if (i == 0) {
USB_LOG_RAW("Ingore altsetting 0\r\n");
continue;
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
USB_LOG_RAW("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
i,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize),
ep_desc->bInterval,
USB_GET_MULT(ep_desc->wMaxPacketSize));
}
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
USB_LOG_RAW("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
i,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
mps,
ep_desc->bInterval,
mult);
}
USB_LOG_RAW("bNumFormats:%u\r\n", video_class->num_of_formats);
@@ -350,9 +363,10 @@ void usbh_video_list_info(struct usbh_video *video_class)
USB_LOG_RAW(" Resolution:\r\n");
for (uint8_t j = 0; j < video_class->format[i].num_of_frames; j++) {
USB_LOG_RAW(" FrameIndex:%u\r\n", j + 1);
USB_LOG_RAW(" wWidth: %d, wHeight: %d\r\n",
video_class->format[i].frame[j].wWidth,
video_class->format[i].frame[j].wHeight);
USB_LOG_RAW(" wWidth: %d, wHeight: %d, fps: %d\r\n",
video_class->format[i].frame[j].wWidth,
video_class->format[i].frame[j].wHeight,
(1000 / (video_class->format[i].frame[j].dwDefaultFrameInterval / 10000)));
}
}
@@ -438,12 +452,14 @@ static int usbh_video_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wWidth;
video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wHeight;
video_class->format[format_index - 1].frame[frame_index - 1].dwDefaultFrameInterval = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->dwDefaultFrameInterval;
break;
case VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE:
frame_index = p[DESC_bFrameIndex];
video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wWidth;
video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wHeight;
video_class->format[format_index - 1].frame[frame_index - 1].dwDefaultFrameInterval = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->dwDefaultFrameInterval;
break;
default:
break;
@@ -476,12 +492,6 @@ static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
struct usbh_video *video_class = (struct usbh_video *)hport->config.intf[intf].priv;
if (video_class) {
if (video_class->isoin) {
}
if (video_class->isoout) {
}
if (hport->config.intf[intf].devname[0] != '\0') {
usb_osal_thread_schedule_other();
USB_LOG_INFO("Unregister Video Class:%s\r\n", hport->config.intf[intf].devname);

View File

@@ -14,6 +14,7 @@
struct usbh_video_resolution {
uint16_t wWidth;
uint16_t wHeight;
uint32_t dwDefaultFrameInterval;
};
struct usbh_video_format {
@@ -40,7 +41,7 @@ struct usbh_videostreaming {
struct usbh_video {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *isoin; /* ISO IN endpoint */
struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
uint8_t ctrl_intf; /* interface number */
uint8_t data_intf; /* interface number */
@@ -48,9 +49,9 @@ struct usbh_video {
struct video_probe_and_commit_controls probe;
struct video_probe_and_commit_controls commit;
uint16_t isoin_mps;
uint16_t isoout_mps;
bool is_opened;
uint8_t current_format;
bool is_bulk;
uint16_t bcdVDC;
uint8_t num_of_intf_altsettings;
uint8_t num_of_formats;

View File

@@ -602,3 +602,12 @@ CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
.id_table = NULL,
.class_driver = &rndis_class_driver
};
CLASS_INFO_DEFINE const struct usbh_class_info rndis_cdcacm_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
.bInterfaceProtocol = 0xff,
.id_table = NULL,
.class_driver = &rndis_class_driver
};

View File

@@ -12,6 +12,10 @@
extern "C" {
#endif
#define USBOTG_MODE_HOST 0
#define USBOTG_MODE_DEVICE 1
#define USBOTG_MODE_OTG 2
/**
* @brief usb otg controller hardware or gpio id simulator init.
*
@@ -24,12 +28,6 @@ int usb_otg_init(uint8_t busid);
* @return On success will return 0, and others indicate fail.
*/
int usb_otg_deinit(uint8_t busid);
/**
* @brief get current role mode.
*
* @return return USBOTG_MODE_HOST or USBOTG_MODE_DEVICE.
*/
uint8_t usbotg_get_current_mode(uint8_t busid);
/* called by user */
void USBOTG_IRQHandler(uint8_t busid);

View File

@@ -15,7 +15,7 @@
#undef CHERRYUSB_VERSION_STR
#endif
#define CHERRYUSB_VERSION 0x010502
#define CHERRYUSB_VERSION_STR "v1.5.2"
#define CHERRYUSB_VERSION 0x010503
#define CHERRYUSB_VERSION_STR "v1.5.3"
#endif

View File

@@ -1145,18 +1145,26 @@ void usbd_event_suspend_handler(uint8_t busid)
void usbd_event_reset_handler(uint8_t busid)
{
struct usb_endpoint_descriptor ep0;
usbd_set_address(busid, 0);
g_usbd_core[busid].device_address = 0;
g_usbd_core[busid].configuration = 0;
g_usbd_core[busid].ep0_next_state = USBD_EP0_STATE_SETUP;
#ifdef CONFIG_USBDEV_ADVANCE_DESC
g_usbd_core[busid].speed = USB_SPEED_UNKNOWN;
USB_ASSERT_MSG(g_usbd_core[busid].descriptors->device_descriptor_callback != NULL,
"device_descriptor_callback is NULL\r\n");
struct usb_device_descriptor *device_desc = (struct usb_device_descriptor *)g_usbd_core[busid].descriptors->device_descriptor_callback(g_usbd_core[busid].speed);
ep0.wMaxPacketSize = device_desc->bMaxPacketSize0;
#else
ep0.wMaxPacketSize = USB_CTRL_EP_MPS;
#endif
struct usb_endpoint_descriptor ep0;
ep0.bLength = 7;
ep0.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT;
ep0.wMaxPacketSize = USB_CTRL_EP_MPS;
ep0.bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
ep0.bEndpointAddress = USB_CONTROL_IN_EP0;
ep0.bInterval = 0;
@@ -1536,11 +1544,7 @@ int usbd_initialize(uint8_t busid, uintptr_t reg_base, void (*event_handler)(uin
int ret;
struct usbd_bus *bus;
if (busid >= CONFIG_USBDEV_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n");
bus = &g_usbdev_bus[busid];
bus->reg_base = reg_base;
@@ -1569,23 +1573,18 @@ int usbd_initialize(uint8_t busid, uintptr_t reg_base, void (*event_handler)(uin
int usbd_deinitialize(uint8_t busid)
{
if (busid >= CONFIG_USBDEV_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n");
g_usbd_core[busid].event_handler(busid, USBD_EVENT_DEINIT);
usbd_class_event_notify_handler(busid, USBD_EVENT_DEINIT, NULL);
usb_dc_deinit(busid);
g_usbd_core[busid].intf_offset = 0;
#ifdef CONFIG_USBDEV_EP0_THREAD
if (g_usbd_core[busid].usbd_ep0_mq) {
usb_osal_mq_delete(g_usbd_core[busid].usbd_ep0_mq);
}
if (g_usbd_core[busid].usbd_ep0_thread) {
usb_osal_thread_delete(g_usbd_core[busid].usbd_ep0_thread);
}
if (g_usbd_core[busid].usbd_ep0_mq) {
usb_osal_mq_delete(g_usbd_core[busid].usbd_ep0_mq);
}
#endif
return 0;

View File

@@ -33,29 +33,27 @@ struct usbh_bus g_usbhost_bus[CONFIG_USBHOST_MAX_BUS];
static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen)
{
uint8_t startaddr = devgen->next;
uint8_t devaddr;
uint8_t lastaddr = devgen->last;
uint8_t devaddr = lastaddr;
int index;
int bitno;
for (;;) {
devaddr = devgen->next;
if (devgen->next >= 0x7f) {
devgen->next = 2;
} else {
devgen->next++;
devaddr++;
if (devaddr > 0x7f) {
devaddr = 2;
}
if (devaddr == lastaddr) {
return -USB_ERR_NOMEM;
}
index = devaddr >> 5;
bitno = devaddr & 0x1f;
if ((devgen->alloctab[index] & (1 << bitno)) == 0) {
devgen->alloctab[index] |= (1 << bitno);
if ((devgen->alloctab[index] & (1ul << bitno)) == 0) {
devgen->alloctab[index] |= (1ul << bitno);
devgen->last = devaddr;
return (int)devaddr;
}
if (startaddr == devaddr) {
return -USB_ERR_NOMEM;
}
}
}
@@ -69,15 +67,11 @@ static int __usbh_free_devaddr(struct usbh_devaddr_map *devgen, uint8_t devaddr)
bitno = devaddr & USB_DEV_ADDR_MARK_MASK;
/* Free the address */
if ((devgen->alloctab[index] |= (1 << bitno)) != 0) {
devgen->alloctab[index] &= ~(1 << bitno);
if ((devgen->alloctab[index] & (1ul << bitno)) != 0) {
devgen->alloctab[index] &= ~(1ul << bitno);
} else {
return -1;
}
if (devaddr < devgen->next) {
devgen->next = devaddr;
}
}
return 0;
@@ -91,7 +85,7 @@ static int usbh_free_devaddr(struct usbh_hubport *hport)
return 0;
}
static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subclass, uint8_t protocol,
static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uint8_t subclass, uint8_t protocol, uint8_t intf,
uint16_t vid, uint16_t pid)
{
struct usbh_class_info *index = NULL;
@@ -106,6 +100,9 @@ static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uin
if ((index->match_flags & USB_CLASS_MATCH_INTF_PROTOCOL) && !(index->bInterfaceProtocol == protocol)) {
continue;
}
if ((index->match_flags & USB_CLASS_MATCH_INTF_NUM) && !(index->bInterfaceNumber == intf)) {
continue;
}
if (index->match_flags & USB_CLASS_MATCH_VID_PID && index->id_table) {
/* scan id table */
uint32_t i;
@@ -275,60 +272,6 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config
return 0;
}
static void usbh_print_hubport_info(struct usbh_hubport *hport)
{
USB_LOG_RAW("Device Descriptor:\r\n");
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->device_desc.bLength);
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
USB_LOG_RAW("bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
USB_LOG_RAW("bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
USB_LOG_RAW("bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
USB_LOG_RAW("bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
USB_LOG_RAW("bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
USB_LOG_RAW("idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
USB_LOG_RAW("idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
USB_LOG_RAW("bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
USB_LOG_RAW("iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
USB_LOG_RAW("iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
USB_LOG_RAW("iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
USB_LOG_RAW("bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
USB_LOG_RAW("Config Descriptor:\r\n");
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
USB_LOG_RAW("wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
USB_LOG_RAW("bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
USB_LOG_RAW("bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
USB_LOG_RAW("iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
USB_LOG_RAW("bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
USB_LOG_RAW("bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
for (uint8_t j = 0; j < hport->config.intf[i].altsetting_num; j++) {
USB_LOG_RAW("\tInterface Descriptor:\r\n");
USB_LOG_RAW("\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bLength);
USB_LOG_RAW("\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bDescriptorType);
USB_LOG_RAW("\tbInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceNumber);
USB_LOG_RAW("\tbAlternateSetting: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bAlternateSetting);
USB_LOG_RAW("\tbNumEndpoints: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints);
USB_LOG_RAW("\tbInterfaceClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceClass);
USB_LOG_RAW("\tbInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceSubClass);
USB_LOG_RAW("\tbInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceProtocol);
USB_LOG_RAW("\tiInterface: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.iInterface);
for (uint8_t k = 0; k < hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints; k++) {
USB_LOG_RAW("\t\tEndpoint Descriptor:\r\n");
USB_LOG_RAW("\t\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bLength);
USB_LOG_RAW("\t\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bDescriptorType);
USB_LOG_RAW("\t\tbEndpointAddress: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bEndpointAddress);
USB_LOG_RAW("\t\tbmAttributes: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bmAttributes);
USB_LOG_RAW("\t\twMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.wMaxPacketSize);
USB_LOG_RAW("\t\tbInterval: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bInterval);
}
}
}
}
static void usbh_print_setup(struct usb_setup_packet *setup)
{
(void)setup;
@@ -603,18 +546,25 @@ int usbh_enumerate(struct usbh_hubport *hport)
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
intf_desc = &hport->config.intf[i].altsetting[0].intf_desc;
struct usbh_class_driver *class_driver = (struct usbh_class_driver *)usbh_find_class_driver(intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol, hport->device_desc.idVendor, hport->device_desc.idProduct);
USB_ASSERT_MSG(intf_desc->bInterfaceNumber == i, "Interface number mismatch, do not support non-standard device\r\n");
struct usbh_class_driver *class_driver = (struct usbh_class_driver *)usbh_find_class_driver(intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass,
intf_desc->bInterfaceProtocol,
intf_desc->bInterfaceNumber,
hport->device_desc.idVendor,
hport->device_desc.idProduct);
if (class_driver == NULL) {
USB_LOG_ERR("do not support Class:0x%02x,Subclass:0x%02x,Protocl:0x%02x\r\n",
USB_LOG_ERR("Do not support Class:0x%02x, Subclass:0x%02x, Protocl:0x%02x on interface %u\r\n",
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass,
intf_desc->bInterfaceProtocol);
intf_desc->bInterfaceProtocol,
i);
continue;
}
hport->config.intf[i].class_driver = class_driver;
USB_LOG_INFO("Loading %s class driver\r\n", class_driver->driver_name);
USB_LOG_INFO("Loading %s class driver on interface %u\r\n", class_driver->driver_name, i);
ret = CLASS_CONNECT(hport, i);
}
@@ -630,6 +580,7 @@ void usbh_hubport_release(struct usbh_hubport *hport)
{
if (hport->connected) {
hport->connected = false;
usbh_kill_urb(&hport->ep0_urb);
usbh_free_devaddr(hport);
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
if (hport->config.intf[i].class_driver && hport->config.intf[i].class_driver->disconnect) {
@@ -637,7 +588,6 @@ void usbh_hubport_release(struct usbh_hubport *hport)
}
}
hport->config.config_desc.bNumInterfaces = 0;
usbh_kill_urb(&hport->ep0_urb);
if (hport->mutex) {
usb_osal_mutex_delete(hport->mutex);
}
@@ -652,7 +602,7 @@ static void usbh_bus_init(struct usbh_bus *bus, uint8_t busid, uintptr_t reg_bas
bus->hcd.reg_base = reg_base;
/* devaddr 1 is for roothub */
bus->devgen.next = 2;
bus->devgen.last = 0x7f;
usb_slist_add_tail(&g_bus_head, &bus->list);
}
@@ -661,11 +611,7 @@ int usbh_initialize(uint8_t busid, uintptr_t reg_base)
{
struct usbh_bus *bus;
if (busid >= CONFIG_USBHOST_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n");
bus = &g_usbhost_bus[busid];
@@ -693,11 +639,7 @@ int usbh_deinitialize(uint8_t busid)
{
struct usbh_bus *bus;
if (busid >= CONFIG_USBHOST_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
while (1) {
}
}
USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n");
bus = &g_usbhost_bus[busid];
@@ -711,6 +653,7 @@ int usbh_deinitialize(uint8_t busid)
int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *setup, uint8_t *buffer)
{
struct usbh_urb *urb;
volatile uint8_t retry = 3;
int ret;
if (!hport || !setup) {
@@ -723,12 +666,21 @@ int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *s
usbh_print_setup(setup);
resubmit:
usbh_control_urb_fill(urb, hport, setup, buffer, setup->wLength, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
if (ret < 0 && (ret != -USB_ERR_TIMEOUT)) {
retry--;
if (retry > 0) {
USB_LOG_WRN("Control transfer failed, errorcode %d, retrying...\r\n", ret);
goto resubmit;
}
}
usb_osal_mutex_give(hport->mutex);
return ret;
}
@@ -816,73 +768,6 @@ static void *usbh_list_all_interface_name(struct usbh_hub *hub, const char *devn
return NULL;
}
static void usbh_list_all_interface_driver(struct usbh_hub *hub)
{
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
for (uint8_t j = 0; j < hub->index; j++) {
USB_LOG_RAW("\t");
}
USB_LOG_RAW("|__Port %u, dev addr:0x%02x, If %u, ClassDriver=%s, %s\r\n",
hport->port,
hport->dev_addr,
itf,
hport->config.intf[itf].class_driver->driver_name,
speed_table[hport->speed]);
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
usbh_list_all_interface_driver(hub_next);
}
}
}
}
}
}
}
static void usbh_list_all_interface_desc(struct usbh_bus *bus, struct usbh_hub *hub)
{
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
USB_LOG_RAW("\r\nBus %u, Hub %u, Port %u, dev addr:0x%02x, VID:PID 0x%04x:0x%04x\r\n",
bus->busid,
hub->index,
hport->port,
hport->dev_addr,
hport->device_desc.idVendor,
hport->device_desc.idProduct);
usbh_print_hubport_info(hport);
for (uint8_t itf = 0; itf < hport->config.config_desc.bNumInterfaces; itf++) {
if (hport->config.intf[itf].class_driver && hport->config.intf[itf].class_driver->driver_name) {
if (strcmp(hport->config.intf[itf].class_driver->driver_name, "hub") == 0) {
hub_next = hport->config.intf[itf].priv;
if (hub_next && hub_next->connected) {
usbh_list_all_interface_desc(bus, hub_next);
}
}
}
}
}
}
}
static struct usbh_hubport *usbh_list_all_hubport(struct usbh_hub *hub, uint8_t hub_index, uint8_t hub_port)
{
struct usbh_hubport *hport;
@@ -960,64 +845,341 @@ struct usbh_hubport *usbh_find_hubport(uint8_t busid, uint8_t hub_index, uint8_t
return hport;
}
static void usbh_print_hubport_info(struct usbh_hubport *hport)
{
USB_LOG_RAW("Device Descriptor:\r\n");
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->device_desc.bLength);
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
USB_LOG_RAW("bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
USB_LOG_RAW("bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
USB_LOG_RAW("bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
USB_LOG_RAW("bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
USB_LOG_RAW("bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
USB_LOG_RAW("idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
USB_LOG_RAW("idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
USB_LOG_RAW("bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
USB_LOG_RAW("iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
USB_LOG_RAW("iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
USB_LOG_RAW("iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
USB_LOG_RAW("bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
USB_LOG_RAW("Config Descriptor:\r\n");
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
USB_LOG_RAW("wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
USB_LOG_RAW("bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
USB_LOG_RAW("bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
USB_LOG_RAW("iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
USB_LOG_RAW("bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
USB_LOG_RAW("bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
for (uint8_t j = 0; j < hport->config.intf[i].altsetting_num; j++) {
USB_LOG_RAW("\tInterface Descriptor:\r\n");
USB_LOG_RAW("\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bLength);
USB_LOG_RAW("\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bDescriptorType);
USB_LOG_RAW("\tbInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceNumber);
USB_LOG_RAW("\tbAlternateSetting: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bAlternateSetting);
USB_LOG_RAW("\tbNumEndpoints: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints);
USB_LOG_RAW("\tbInterfaceClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceClass);
USB_LOG_RAW("\tbInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceSubClass);
USB_LOG_RAW("\tbInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceProtocol);
USB_LOG_RAW("\tiInterface: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.iInterface);
for (uint8_t k = 0; k < hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints; k++) {
USB_LOG_RAW("\t\tEndpoint Descriptor:\r\n");
USB_LOG_RAW("\t\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bLength);
USB_LOG_RAW("\t\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bDescriptorType);
USB_LOG_RAW("\t\tbEndpointAddress: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bEndpointAddress);
USB_LOG_RAW("\t\tbmAttributes: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bmAttributes);
USB_LOG_RAW("\t\twMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.wMaxPacketSize);
USB_LOG_RAW("\t\tbInterval: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bInterval);
}
}
}
}
static void usbh_list_device(struct usbh_hub *hub, bool astree, bool verbose, int dev_addr, int vid, int pid)
{
static const char *speed_table[] = {
"UNKNOWN",
"low-speed",
"full-speed",
"high-speed",
"wireless",
"super-speed",
"super-speed-plus",
};
static const char *root_speed_table[] = {
"UNKNOWN",
"1.1",
"1.1",
"2.0",
"2.5",
"3.0",
"3.0",
};
static const uint16_t speed_baud[] = {
0,
12,
12,
480,
480,
5000,
10000,
};
struct usbh_bus *bus;
struct usbh_hubport *hport;
struct usbh_hub *hub_next;
uint8_t imbuf[64];
uint8_t ipbuf[64];
const char *pimstr;
const char *pipstr;
bool imvalid = false;
bool ipvalid = false;
int ret;
bus = hub->bus;
(void)speed_table;
if (hub->is_roothub) {
if (astree) {
USB_LOG_RAW("/: Bus %02u.Port 1: Dev %u, Class=root_hub, Driver=hcd, %uM\r\n",
bus->busid, hub->hub_addr, speed_baud[hub->speed]);
} else {
if ((dev_addr < 0) || (hub->hub_addr == dev_addr)) {
if (((vid < 0) || (vid == 0xffff)) && ((pid < 0) || (pid == 0xffff))) {
USB_LOG_RAW("Bus %03u Device %03u: ID %04x:%04x %s %s root hub\r\n",
bus->busid, hub->hub_addr, 0xffff, 0xffff,
"Cherry-Embedded", root_speed_table[hub->speed]);
}
}
}
}
for (uint8_t port = 0; port < hub->nports; port++) {
hport = &hub->child[port];
if (hport->connected) {
ret = 0;
if (hport->device_desc.iManufacturer) {
memset(imbuf, 0, sizeof(imbuf));
ret = usbh_get_string_desc(hport, hport->device_desc.iManufacturer, imbuf, sizeof(imbuf));
if (ret == 0) {
imvalid = true;
}
}
if (hport->device_desc.iProduct) {
memset(ipbuf, 0, sizeof(ipbuf));
ret = usbh_get_string_desc(hport, hport->device_desc.iProduct, ipbuf, sizeof(ipbuf));
if (ret == 0) {
ipvalid = true;
}
}
if (imvalid) {
pimstr = (const char *)imbuf;
} else {
pimstr = "Not specified Manufacturer";
}
if (ipvalid) {
pipstr = (const char *)ipbuf;
} else {
pipstr = "Not specified Product";
}
if (!astree) {
if ((dev_addr < 0) || (hport->dev_addr == dev_addr)) {
if (((vid < 0) || (vid == hport->device_desc.idVendor)) && ((pid < 0) || (pid == hport->device_desc.idProduct))) {
USB_LOG_RAW("Bus %03u Device %03u: ID %04x:%04x %s %s\r\n",
bus->busid, hport->dev_addr, hport->device_desc.idVendor, hport->device_desc.idProduct,
pimstr, pipstr);
if (verbose) {
usbh_print_hubport_info(hport);
}
}
}
}
for (uint8_t intf = 0; intf < hport->config.config_desc.bNumInterfaces; intf++) {
if (hport->config.intf[intf].class_driver && hport->config.intf[intf].class_driver->driver_name) {
if (astree) {
for (uint8_t j = 0; j < hub->index; j++) {
USB_LOG_RAW(" ");
}
USB_LOG_RAW("|__ Port %u: Dev %u, If %u, ClassDriver=%s, %uM\r\n",
hport->port, hport->dev_addr, intf, hport->config.intf[intf].class_driver->driver_name, speed_baud[hport->speed]);
}
if (!strcmp(hport->config.intf[intf].class_driver->driver_name, "hub")) {
hub_next = hport->config.intf[intf].priv;
if (hub_next && hub_next->connected) {
usbh_list_device(hub_next, astree, verbose, dev_addr, vid, pid);
}
}
} else if (astree) {
for (uint8_t j = 0; j < hub->index; j++) {
USB_LOG_RAW(" ");
}
USB_LOG_RAW("|__ Port %u: Dev %u, If 0 ClassDriver=none, %uM\r\n",
hport->port, hport->dev_addr, speed_baud[hport->speed]);
}
}
}
}
}
void lsusb_help(void)
{
USB_LOG_RAW("List USB Devices\r\n"
"Usage: lsusb [options]...\r\n"
"\r\n"
"-v, --verbose\r\n"
" - increase verbosity (show descriptors)\r\n"
"-s [[bus]:][dev_addr]\r\n"
" - show only devices with specified device and/or\r\n"
" bus numbers (in decimal)\r\n"
"-d vendor:[product]\r\n"
" - show only devices with the specified vendor and\r\n"
" product ID numbers (in hexadecimal)\r\n"
"-t, --tree\r\n"
" - dump the physical USB device hierarchy as a tree\r\n"
"-V, --version\r\n"
" - show version of the cherryusb\r\n"
"-h, --help\r\n"
" - show usage and help information\r\n");
}
int lsusb(int argc, char **argv)
{
usb_slist_t *bus_list;
struct usbh_hub *hub;
struct usbh_bus *bus;
size_t flags;
int busid = -1;
int dev_addr = -1;
int vid = -1;
int pid = -1;
bool astree = false;
bool verbose = false;
if (argc < 2) {
USB_LOG_RAW("Usage: lsusb [options]...\r\n");
USB_LOG_RAW("List USB devices\r\n");
USB_LOG_RAW(" -v, --verbose\r\n");
USB_LOG_RAW(" Increase verbosity (show descriptors)\r\n");
// USB_LOG_RAW(" -s [[bus]:[devnum]]\r\n");
// USB_LOG_RAW(" Show only devices with specified device and/or bus numbers (in decimal)\r\n");
// USB_LOG_RAW(" -d vendor:[product]\r\n");
// USB_LOG_RAW(" Show only devices with the specified vendor and product ID numbers (in hexadecimal)\r\n");
USB_LOG_RAW(" -t, --tree\r\n");
USB_LOG_RAW(" Dump the physical USB device hierachy as a tree\r\n");
USB_LOG_RAW(" -V, --version\r\n");
USB_LOG_RAW(" Show version of program\r\n");
USB_LOG_RAW(" -h, --help\r\n");
USB_LOG_RAW(" Show usage and help\r\n");
return 0;
}
if (argc > 3) {
lsusb_help();
return 0;
}
flags = usb_osal_enter_critical_section();
while (argc > 1) {
argc--;
argv++;
if (strcmp(argv[1], "-V") == 0) {
USB_LOG_RAW("CherryUSB Version %s\r\n", CHERRYUSB_VERSION_STR);
}
if (!strcmp(*argv, "-V") || !strcmp(*argv, "--version")) {
USB_LOG_RAW("CherryUSB version %s\r\n", CHERRYUSB_VERSION_STR);
return 0;
} else if (!strcmp(*argv, "-h") || !strcmp(*argv, "--help")) {
lsusb_help();
return 0;
} else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose")) {
verbose = true;
} else if (!strcmp(*argv, "-t") || !strcmp(*argv, "--tree")) {
astree = true;
} else if (!strcmp(*argv, "-s")) {
if (argc > 1) {
argc--;
argv++;
if (strcmp(argv[1], "-t") == 0) {
usb_slist_for_each(bus_list, &g_bus_head)
{
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
hub = &bus->hcd.roothub;
if (*argv[0] == '-') {
continue;
}
USB_LOG_RAW("/: Bus %u, Hub %u, ports=%u, is roothub\r\n",
bus->busid,
hub->index,
hub->nports);
usbh_list_all_interface_driver(hub);
char *endptr;
const char *colon = strchr(*argv, ':');
(void)endptr;
if (colon != NULL) {
const char *str;
if (colon > *argv) {
busid = strtol(*argv, &endptr, 10);
}
str = colon + 1;
if (*str != '\0') {
dev_addr = strtol(str, &endptr, 10);
if (dev_addr <= 0 || dev_addr >= 128) {
dev_addr = -1;
}
}
} else {
dev_addr = strtol(*argv, &endptr, 10);
if (dev_addr <= 0 || dev_addr >= 128) {
dev_addr = -1;
}
}
}
} else if (!strcmp(*argv, "-d")) {
if (argc > 1) {
argc--;
argv++;
if (*argv[0] == '-') {
continue;
}
char *endptr;
const char *colon = strchr(*argv, ':');
(void)endptr;
if (colon == NULL) {
continue;
}
const char *str;
vid = strtol(*argv, &endptr, 16);
if (vid < 0 || vid > 0xffff) {
vid = -1;
continue;
}
str = colon + 1;
if (*str != '\0') {
pid = strtol(str, &endptr, 16);
if (pid < 0 || pid > 0xffff) {
pid = -1;
}
}
}
}
}
if (strcmp(argv[1], "-v") == 0) {
usb_slist_for_each(bus_list, &g_bus_head)
{
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
hub = &bus->hcd.roothub;
usbh_list_all_interface_desc(bus, hub);
}
if (astree) {
busid = -1;
dev_addr = -1;
vid = -1;
pid = -1;
verbose = false;
}
usb_slist_for_each(bus_list, &g_bus_head)
{
bus = usb_slist_entry(bus_list, struct usbh_bus, list);
if (busid >= 0) {
if (bus->busid != busid) {
continue;
}
}
usbh_list_device(&bus->hcd.roothub, astree, verbose, dev_addr, vid, pid);
}
usb_osal_leave_critical_section(flags);
return 0;
}

View File

@@ -33,6 +33,7 @@ extern "C" {
#define USB_CLASS_MATCH_INTF_CLASS 0x0004
#define USB_CLASS_MATCH_INTF_SUBCLASS 0x0008
#define USB_CLASS_MATCH_INTF_PROTOCOL 0x0010
#define USB_CLASS_MATCH_INTF_NUM 0x0020
#define USB_CLASS_MATCH_VID_PID (USB_CLASS_MATCH_VENDOR | USB_CLASS_MATCH_PRODUCT)
#define CLASS_CONNECT(hport, i) ((hport)->config.intf[i].class_driver->connect(hport, i))
@@ -65,6 +66,7 @@ struct usbh_class_info {
uint8_t bInterfaceClass; /* Base device class code */
uint8_t bInterfaceSubClass; /* Sub-class, depends on base class. Eg. */
uint8_t bInterfaceProtocol; /* Protocol, depends on base class. Eg. */
uint8_t bInterfaceNumber; /* Interface number */
const uint16_t (*id_table)[2]; /* List of Vendor/Product ID pairs */
const struct usbh_class_driver *class_driver;
};
@@ -150,7 +152,7 @@ struct usbh_devaddr_map {
* alloctab[3]:addr from 96~127
*
*/
uint8_t next; /* Next device address */
uint8_t last; /* Last device address */
uint32_t alloctab[4]; /* Bit allocation table */
};

View File

@@ -5,39 +5,57 @@
*/
#include "usbotg_core.h"
#ifdef CONFIG_USB_OTG_ENABLE
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbotg_core"
#include "usb_log.h"
#define CONFIG_USB_OTG_MAX_BUS CONFIG_USBHOST_MAX_BUS
struct usbotg_core_priv {
uint8_t busid;
uint32_t reg_base;
usb_osal_sem_t change_sem;
usb_osal_thread_t change_thread;
bool usbh_initialized;
bool usbd_initialized;
int (*usbh_initialize)(uint8_t busid, uint32_t reg_base);
int (*usbd_initialize)(uint8_t busid, uint32_t reg_base);
} g_usbotg_core[CONFIG_USBHOST_MAX_BUS];
void *device_event_callback;
void *host_event_callback;
uint8_t current_mode;
usb_osal_sem_t change_sem;
usb_osal_thread_t change_thread;
} g_usbotg_core[CONFIG_USB_OTG_MAX_BUS];
static void usbotg_host_initialize(uint8_t busid)
{
if (g_usbotg_core[busid].usbh_initialized) {
return;
}
if (g_usbotg_core[busid].usbd_initialized) {
g_usbotg_core[busid].usbd_initialized = false;
usbd_deinitialize(busid);
}
if (g_usbotg_core[busid].usbh_initialize && !g_usbotg_core[busid].usbh_initialized) {
g_usbotg_core[busid].usbh_initialized = true;
g_usbotg_core[busid].usbh_initialize(g_usbotg_core[busid].busid, g_usbotg_core[busid].reg_base);
}
USB_LOG_INFO("Switch to HOST mode\r\n");
usbh_initialize(busid, g_usbotg_core[busid].reg_base);
g_usbotg_core[busid].usbh_initialized = true;
}
static void usbotg_device_initialize(uint8_t busid)
{
if (g_usbotg_core[busid].usbd_initialized) {
return;
}
if (g_usbotg_core[busid].usbh_initialized) {
g_usbotg_core[busid].usbh_initialized = false;
usbh_deinitialize(busid);
}
if (g_usbotg_core[busid].usbd_initialize && !g_usbotg_core[busid].usbd_initialize) {
g_usbotg_core[busid].usbd_initialized = true;
g_usbotg_core[busid].usbd_initialize(g_usbotg_core[busid].busid, g_usbotg_core[busid].reg_base);
}
USB_LOG_INFO("Switch to DEVICE mode\r\n");
usbd_initialize(g_usbotg_core[busid].busid, g_usbotg_core[busid].reg_base, g_usbotg_core[busid].device_event_callback);
g_usbotg_core[busid].usbd_initialized = true;
}
static void usbotg_rolechange_thread(void *argument)
@@ -48,58 +66,49 @@ static void usbotg_rolechange_thread(void *argument)
while (1) {
if (usb_osal_sem_take(g_usbotg_core[busid].change_sem, USB_OSAL_WAITING_FOREVER) == 0) {
if (usbotg_get_current_mode(busid) == USBOTG_MODE_HOST) {
if (g_usbotg_core[busid].current_mode == USBOTG_MODE_HOST) {
usbotg_host_initialize(busid);
} else if (usbotg_get_current_mode(busid) == USBOTG_MODE_DEVICE) {
} else if (g_usbotg_core[busid].current_mode == USBOTG_MODE_DEVICE) {
usbotg_device_initialize(busid);
}
}
}
}
int usbotg_initialize(uint8_t otg_mode, uint8_t busid, uint32_t reg_base,
int (*usbh_initialize)(uint8_t busid, uint32_t reg_base),
int (*usbd_initialize)(uint8_t busid, uint32_t reg_base))
int usbotg_initialize(uint8_t busid, uint32_t reg_base, void *device_event_callback, void *host_event_callback, uint8_t default_role)
{
char thread_name[32] = { 0 };
if (busid >= CONFIG_USBHOST_MAX_BUS) {
USB_LOG_ERR("bus overflow\r\n");
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
g_usbotg_core[busid].busid = busid;
g_usbotg_core[busid].reg_base = reg_base;
g_usbotg_core[busid].device_event_callback = device_event_callback;
g_usbotg_core[busid].host_event_callback = host_event_callback;
g_usbotg_core[busid].change_sem = usb_osal_sem_create(0);
if (g_usbotg_core[busid].change_sem == NULL) {
USB_LOG_ERR("Failed to create change_sem\r\n");
while (1) {
}
}
g_usbotg_core[busid].busid = busid;
g_usbotg_core[busid].reg_base = reg_base;
g_usbotg_core[busid].usbh_initialize = usbh_initialize;
g_usbotg_core[busid].usbd_initialize = usbd_initialize;
if (otg_mode == USBOTG_MODE_OTG) {
g_usbotg_core[busid].change_sem = usb_osal_sem_create(0);
if (g_usbotg_core[busid].change_sem == NULL) {
USB_LOG_ERR("Failed to create change_sem\r\n");
return -1;
}
snprintf(thread_name, 32, "usbotg%u", busid);
g_usbotg_core[busid].change_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbotg_rolechange_thread, (void *)(uintptr_t)busid);
if (g_usbotg_core[busid].change_thread == NULL) {
USB_LOG_ERR("Failed to create usbotg thread\r\n");
return -1;
}
} else {
if (otg_mode == USBOTG_MODE_HOST) {
usbotg_host_initialize(busid);
} else if (otg_mode == USBOTG_MODE_DEVICE) {
usbotg_device_initialize(busid);
snprintf(thread_name, 32, "usbotg%u", busid);
g_usbotg_core[busid].change_thread = usb_osal_thread_create(thread_name, 2048, 10, usbotg_rolechange_thread, (void *)(uintptr_t)busid);
if (g_usbotg_core[busid].change_thread == NULL) {
USB_LOG_ERR("Failed to create usbotg thread\r\n");
while (1) {
}
}
usbotg_trigger_role_change(busid, default_role);
return 0;
}
int usbotg_deinitialize(uint8_t busid, uint32_t reg_base)
int usbotg_deinitialize(uint8_t busid)
{
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
if (g_usbotg_core[busid].usbd_initialized) {
g_usbotg_core[busid].usbd_initialized = false;
usbd_deinitialize(busid);
@@ -110,28 +119,37 @@ int usbotg_deinitialize(uint8_t busid, uint32_t reg_base)
usbh_deinitialize(busid);
}
if (g_usbotg_core[busid].change_thread) {
usb_osal_thread_delete(g_usbotg_core[busid].change_thread);
}
if (g_usbotg_core[busid].change_sem) {
usb_otg_deinit(busid);
usb_osal_sem_delete(g_usbotg_core[busid].change_sem);
}
if (g_usbotg_core[busid].change_thread) {
usb_osal_thread_delete(g_usbotg_core[busid].change_thread);
}
return 0;
}
void usbotg_trigger_role_change(uint8_t busid)
void usbotg_trigger_role_change(uint8_t busid, uint8_t mode)
{
usb_osal_sem_give(g_usbotg_core[busid].change_sem);
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
g_usbotg_core[busid].current_mode = mode;
if (g_usbotg_core[busid].change_sem) {
usb_osal_sem_give(g_usbotg_core[busid].change_sem);
}
}
void USBOTG_IRQHandler(uint8_t busid)
{
if (usbotg_get_current_mode(busid) == USBOTG_MODE_HOST) {
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
if (g_usbotg_core[busid].current_mode == USBOTG_MODE_HOST && g_usbotg_core[busid].usbh_initialized) {
USBH_IRQHandler(busid);
} else if (usbotg_get_current_mode(busid) == USBOTG_MODE_DEVICE) {
} else if (g_usbotg_core[busid].current_mode == USBOTG_MODE_DEVICE && g_usbotg_core[busid].usbd_initialized) {
USBD_IRQHandler(busid);
}
}
}
#endif /* CONFIG_USB_OTG_ENABLE */

View File

@@ -10,22 +10,15 @@
extern "C" {
#endif
#define USBOTG_MODE_UNKNOWN 0
#define USBOTG_MODE_OTG 1
#define USBOTG_MODE_HOST 2
#define USBOTG_MODE_DEVICE 3
#include "usbd_core.h"
#include "usbh_core.h"
#include "usb_otg.h"
int usbotg_initialize(uint8_t otg_mode, uint8_t busid, uint32_t reg_base,
int (*usbh_initialize)(uint8_t busid, uint32_t reg_base),
int (*usbd_initialize)(uint8_t busid, uint32_t reg_base));
int usbotg_deinitialize(uint8_t busid, uint32_t reg_base);
int usbotg_initialize(uint8_t busid, uint32_t reg_base, void *device_event_callback, void *host_event_callback, uint8_t default_role);
int usbotg_deinitialize(uint8_t busid);
/* called by user */
void usbotg_trigger_role_change(uint8_t busid);
void usbotg_trigger_role_change(uint8_t busid, uint8_t mode);
#ifdef __cplusplus
}

View File

@@ -288,7 +288,7 @@ void cherryadb_init(uint8_t busid, uint32_t reg_base)
/* shell_init() must be called in-task */
if (0 != shell_init(false)) {
/* shell failed to be initialized */
printf("Failed to initialize shell\r\n");
USB_LOG_RAW("Failed to initialize shell\r\n");
for (;;) {
;
}

View File

@@ -297,11 +297,11 @@ void usbd_audio_open(uint8_t busid, uint8_t intf)
AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value); /* uac1 can only use 10.14 */
usbd_ep_start_write(busid, AUDIO_OUT_FEEDBACK_EP, s_speaker_feedback_buffer, FEEDBACK_ENDP_PACKET_SIZE);
#endif
printf("OPEN1\r\n");
USB_LOG_INFO("OPEN1\r\n");
} else {
tx_flag = 1;
ep_tx_busy_flag = false;
printf("OPEN2\r\n");
USB_LOG_INFO("OPEN2\r\n");
}
}
@@ -309,11 +309,11 @@ void usbd_audio_close(uint8_t busid, uint8_t intf)
{
if (intf == 1) {
rx_flag = 0;
printf("CLOSE1\r\n");
USB_LOG_INFO("CLOSE1\r\n");
} else {
tx_flag = 0;
ep_tx_busy_flag = false;
printf("CLOSE2\r\n");
USB_LOG_INFO("CLOSE2\r\n");
}
}

View File

@@ -205,4 +205,28 @@ void cdc_acm_chardev_init(uint8_t busid, uintptr_t reg_base)
#endif
usbd_cdc_acm_serial_init(busid, CDC_IN_EP, CDC_OUT_EP);
usbd_initialize(busid, reg_base, usbd_event_handler);
}
}
static int cdc_acm_enter(int argc, char **argv)
{
(void)argc;
(void)argv;
finsh_set_device("usb-acm0");
rt_console_set_device("usb-acm0");
return 0;
}
MSH_CMD_EXPORT(cdc_acm_enter, cdc_acm_enter);
static int cdc_acm_exit(int argc, char **argv)
{
(void)argc;
(void)argv;
finsh_set_device(RT_CONSOLE_DEVICE_NAME);
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
return 0;
}
MSH_CMD_EXPORT(cdc_acm_exit, cdc_acm_exit);

View File

@@ -68,6 +68,7 @@ static const char *string_descriptors[] = {
"CherryUSB", /* Manufacturer */
"CherryUSB CDC ECM DEMO", /* Product */
"2022123456", /* Serial Number */
"aabbccddeeff", /* ecm mac address */
};
static const uint8_t *device_descriptor_callback(uint8_t speed)

View File

@@ -189,14 +189,14 @@ void usbd_rndis_data_send_done(uint32_t len)
#error rndis must enable RT_LWIP_DHCP
#endif
#ifndef LWIP_USING_DHCPD
#error rndis must enable LWIP_USING_DHCPD
#ifdef LWIP_USING_DHCPD
#include <dhcp_server.h>
#endif
#include <rtthread.h>
#include <rtdevice.h>
#include <netif/ethernetif.h>
#include <dhcp_server.h>
#include <netdev.h>
struct eth_device rndis_dev;
@@ -250,7 +250,14 @@ void rndis_lwip_init(void)
eth_device_init(&rndis_dev, "u0");
eth_device_linkchange(&rndis_dev, RT_TRUE);
#ifdef LWIP_USING_DHCPD
dhcpd_start("u0");
#else
struct netdev *netdev = netdev_get_by_name("u0");
if (netdev) {
netdev_dhcp_enabled(netdev, RT_TRUE);
}
#endif
}
void usbd_rndis_data_recv_done(uint32_t len)

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_rndis.h"
#include "rndis_protocol.h"
#include "mongoose.h"
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
#error Do not define CONFIG_USBDEV_RNDIS_USING_LWIP in this demo
#endif
/*!< endpoint address */
#define CDC_IN_EP 0x81
#define CDC_OUT_EP 0x02
#define CDC_INT_EP 0x83
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_RNDIS_DESCRIPTOR_LEN)
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
};
static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
};
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
};
static const uint8_t other_speed_config_descriptor_hs[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
};
static const uint8_t other_speed_config_descriptor_fs[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
};
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"CherryUSB", /* Manufacturer */
"CherryUSB RNDIS MONGOOSE DEMO", /* Product */
"2025123456", /* Serial Number */
};
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
(void)speed;
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
if (speed == USB_SPEED_HIGH) {
return config_descriptor_hs;
} else if (speed == USB_SPEED_FULL) {
return config_descriptor_fs;
} else {
return NULL;
}
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
(void)speed;
return device_quality_descriptor;
}
static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
{
if (speed == USB_SPEED_HIGH) {
return other_speed_config_descriptor_hs;
} else if (speed == USB_SPEED_FULL) {
return other_speed_config_descriptor_fs;
} else {
return NULL;
}
}
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
(void)speed;
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
return string_descriptors[index];
}
const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
};
static uint8_t rndis_mac[6] = { 0x20, 0x89, 0x84, 0x6A, 0x96, 0xAA };
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[USB_ALIGN_UP(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[USB_ALIGN_UP(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE, CONFIG_USB_ALIGN_SIZE)];
volatile bool g_rndis_tx_busy_flag = false;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
(void)busid;
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
g_rndis_tx_busy_flag = false;
usbd_rndis_start_read(g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
static struct mg_tcpip_if *s_ifp;
void usbd_rndis_data_recv_done(uint32_t len)
{
(void)len;
rndis_data_packet_t *hdr;
uint8_t *buf;
hdr = (rndis_data_packet_t *)g_rndis_rx_buffer;
buf = (uint8_t *)hdr + hdr->DataOffset + sizeof(rndis_generic_msg_t);
mg_tcpip_qwrite((void *)buf, hdr->DataLength, s_ifp);
usbd_rndis_start_read(g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
}
void usbd_rndis_data_send_done(uint32_t len)
{
(void)len;
g_rndis_tx_busy_flag = false;
}
static size_t usb_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp)
{
(void)ifp;
rndis_data_packet_t *hdr;
if (!usb_device_is_configured(0))
return 0;
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
hdr->MessageLength = sizeof(rndis_data_packet_t) + len;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = len;
memcpy(g_rndis_tx_buffer + sizeof(rndis_data_packet_t), buf, len);
g_rndis_tx_busy_flag = true;
usbd_rndis_start_write(g_rndis_tx_buffer, sizeof(rndis_data_packet_t) + len);
while (g_rndis_tx_busy_flag) {
}
return len;
}
static bool usb_poll(struct mg_tcpip_if *ifp, bool s1)
{
(void)ifp;
return s1 ? usb_device_is_configured(0) : false;
}
struct mg_tcpip_driver driver = { .tx = usb_tx, .poll = usb_poll };
struct usbd_interface intf0;
struct usbd_interface intf1;
struct mg_mgr mgr; // Initialise Mongoose event manager
void cdc_rndis_mongoose_init(uint8_t busid, uint32_t reg_base)
{
mg_mgr_init(&mgr); // and attach it to the interface
static struct mg_tcpip_if mif = { .mac = { 2, 0, 1, 2, 3, 0x77 },
.enable_dhcp_server = true,
.driver = &driver,
.recv_queue.size = 4096 };
s_ifp = &mif;
mif.ip = mg_htonl(MG_U32(192, 168, 7, 1));
mif.mask = mg_htonl(MG_U32(255, 255, 255, 0));
mg_tcpip_init(&mgr, &mif);
web_init(&mgr);
usbd_desc_register(busid, &cdc_descriptor);
usbd_add_interface(busid, usbd_rndis_init_intf(&intf0, CDC_OUT_EP, CDC_IN_EP, CDC_INT_EP, rndis_mac));
usbd_add_interface(busid, usbd_rndis_init_intf(&intf1, CDC_OUT_EP, CDC_IN_EP, CDC_INT_EP, rndis_mac));
usbd_initialize(busid, reg_base, usbd_event_handler);
}
// call mg_mgr_poll(&mgr, 0); in main loop

BIN
demo/mongoose/mongoose.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View File

@@ -0,0 +1,22 @@
#pragma once
// See https://mongoose.ws/documentation/#build-options
#define MG_ARCH MG_ARCH_CUSTOM
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_PACKED_FS 1
#define MG_IO_SIZE 1460

View File

@@ -236,7 +236,7 @@ int usb_msc_fatfs_test()
while (write_size > 0) {
res_sd = f_write(&fnew, read_write_buffer, BUF_SIZE, (UINT*)&fnum);
if (res_sd != FR_OK) {
printf("Write file failed, cause: %s\n", res_sd);
USB_LOG_RAW("Write file failed, cause: %s\n", res_sd);
goto unmount;
}
write_size -= BUF_SIZE;
@@ -262,7 +262,7 @@ int usb_msc_fatfs_test()
while (write_size > 0) {
res_sd = f_read(&fnew, read_write_buffer, BUF_SIZE, (UINT*)&fnum);
if (res_sd != FR_OK) {
printf("Read file failed, cause: %s\n", res_sd);
USB_LOG_RAW("Read file failed, cause: %s\n", res_sd);
goto unmount;
}
write_size -= BUF_SIZE;

View File

@@ -469,11 +469,11 @@ void usbd_audio_open(uint8_t busid, uint8_t intf)
audio_rx_flag = 1;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, AUDIO_OUT_EP, audio_read_buffer, AUDIO_OUT_PACKET);
printf("OPEN1\r\n");
USB_LOG_RAW("OPEN1\r\n");
} else if (intf == 4) {
audio_tx_flag = 1;
audio_iso_tx_busy = false;
printf("OPEN2\r\n");
USB_LOG_RAW("OPEN2\r\n");
}
}
@@ -481,11 +481,11 @@ void usbd_audio_close(uint8_t busid, uint8_t intf)
{
if (intf == 3) {
audio_rx_flag = 0;
printf("CLOSE1\r\n");
USB_LOG_RAW("CLOSE1\r\n");
} else if (intf == 4) {
audio_tx_flag = 0;
audio_iso_tx_busy = false;
printf("CLOSE2\r\n");
USB_LOG_RAW("CLOSE2\r\n");
}
}

View File

@@ -6,8 +6,8 @@ project = 'CherryUSB'
copyright = '2022 ~ 2025, sakumisu'
author = 'sakumisu'
release = '1.5.2'
version = '1.5.2'
release = '1.5.3'
version = '1.5.3'
# -- General configuration

View File

@@ -1,2 +1,5 @@
usbd_audiov1
===============
.. note:: 在使用windows 时当修改描述符任意参数时必须同步修改字符串描述符并且卸载驱动否则windows会认为设备未更改继续使用旧的驱动导致无法识别设备。Linux 不受此限制。

View File

@@ -1,2 +1,6 @@
usbd_audiov2
===============
.. note:: 在使用windows 时当修改描述符任意参数时必须同步修改字符串描述符并且卸载驱动否则windows会认为设备未更改继续使用旧的驱动导致无法识别设备。Linux 不受此限制。
.. note:: windows 10 uac2.0 功能不完善,请使用 windows 11 测试uac2.0 功能。Linux 不受此限制。

View File

@@ -150,21 +150,6 @@ USB Device 移植要点
.. figure:: img/stm32_8.png
- 如果使用 dwc2 ip需要增加 **dwc2/usb_glue_st.c** 文件,并在 `usb_config.h` 中实现以下宏:
.. code-block:: C
// 以下细节如有出入,请对照 stm32xxx.h 文件修改
// 需要根据硬件实际的 fifo 深度进行修改,默认是最基础的配置
#define CONFIG_USBDEV_EP_NUM 6
#define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1012 - 16 * 6)
#define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX1_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX4_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX5_FIFO_SIZE (64 / 4)
- 如果使用 fsdev ipV1.5.0 开始需要增加 **fsdev/usb_glue_st.c**`usb_config.h` 中实现以下宏,具体数值不同芯片不一样:
.. code-block:: C

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

View File

@@ -88,6 +88,13 @@ USB Host ASIX 网卡
.. figure:: img/usbhost_ax88772_1.png
.. figure:: img/usbhost_ax88772_2.png
USB Host RNDIS 网卡
-----------------------
演示 USB Host 驱动手机,手机开启 USB 共享网络即可使用 RNDIS 。
.. figure:: img/usbhost_rndis.png
USB Host WIFI
-----------------------

View File

@@ -148,4 +148,18 @@ v1.5.2
- musb 对于标准的 IP 结构采用独立 EP 控制寄存器组,不使用 EPIDX 寄存器去控制
- 删除所有 CONFIG_USBDEV_EP_NUM & CONFIG_USBHOST_PIPE_NUM不再使用因为 IP 本身会携带这些信息,或者厂家 SDK 提供了对应的宏
- CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 默认使用 2 减少内存,只有 UVC 和UAC 使用(商业收费),所以不需要开很大
- urb interval 从 u8 改 u32最大支持 2^15 * 125us
- urb interval 从 u8 改 u32最大支持 2^15 * 125us
v1.5.3
----------------------
- 增加 mongoose demo
- **从机支持自定义 ep0 mps仅支持商业性 IP**
- 主机增加 UVC bulk支持 **接口号匹配驱动功能** **主机分配地址功能改成循环自增模式** ,重构 lsusb 命令
- 主机控制传输增加 retry 机制,部分 device 通信不稳定retry 次数参考 linux
- **主机 rndis 驱动增加非标 02/02/ff 接口驱动匹配**
- musb IP 关闭 multipoint feature 支持
- hpmicro、chipidea dcache 支持
- idf host msc 支持
- otg 框架重构,当前 port 仅支持 hpmicro
- CI 编译功能,支持 hpmicro/espressif/bouffalolab

View File

@@ -1,4 +1,4 @@
version: "1.5.2"
version: "1.5.3"
description: CherryUSB is a tiny and portable USB Stack (device & host) for embedded system with USB IP
tags:
- usb

View File

@@ -28,7 +28,12 @@
// #define CONFIG_USB_DCACHE_ENABLE
/* attribute data into no cache ram */
/* attribute data into no cache ram
* DRAM_DMA_ALIGNED_ATTR was introduced in IDF 5.3. If not defined, it falls back to DMA_ATTR
*/
#ifndef DRAM_DMA_ALIGNED_ATTR
#define DRAM_DMA_ALIGNED_ATTR DMA_ATTR
#endif
#define USB_NOCACHE_RAM_SECTION DRAM_DMA_ALIGNED_ATTR
/* use usb_memcpy default for high performance but cost more flash memory.
@@ -144,9 +149,6 @@
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1

View File

@@ -1,165 +0,0 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef __rtems__
#include "usb_osal.h"
#include "usb_errno.h"
#include <rtems.h>
#define SYS_USB_MBOX_SIZE (sizeof(void *))
usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args)
{
rtems_id id = 0;
rtems_status_code res;
res = rtems_task_create(
rtems_build_name(name[0], name[1], name[2], name[3]),
prio,
stack_size,
RTEMS_PREEMPT,
0,
&id);
if (res != RTEMS_SUCCESSFUL) {
return NULL;
}
res = rtems_task_start(id, (rtems_task_entry)entry, (rtems_task_argument)args);
if (res != RTEMS_SUCCESSFUL) {
rtems_task_delete(id);
return NULL;
}
return (usb_osal_thread_t)id;
}
void usb_osal_thread_delete(usb_osal_thread_t thread)
{
rtems_task_delete(thread);
}
usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count)
{
rtems_id semaphore = 0;
rtems_status_code ret = rtems_semaphore_create(
rtems_build_name('U', 'S', 'B', 's'),
initial_count,
RTEMS_COUNTING_SEMAPHORE,
0,
&semaphore);
return semaphore;
}
void usb_osal_sem_delete(usb_osal_sem_t sem)
{
rtems_semaphore_delete(sem);
}
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
{
rtems_status_code status;
status = rtems_semaphore_obtain(sem, RTEMS_WAIT, timeout);
return status == RTEMS_SUCCESSFUL ? 0 : -USB_ERR_TIMEOUT;
}
int usb_osal_sem_give(usb_osal_sem_t sem)
{
rtems_status_code status = rtems_semaphore_release(sem);
return (status == RTEMS_SUCCESSFUL) ? 0 : -USB_ERR_TIMEOUT;
}
usb_osal_mutex_t usb_osal_mutex_create(void)
{
rtems_id mutex;
rtems_status_code ret = rtems_semaphore_create(
rtems_build_name('U', 'S', 'B', 'm'),
1,
RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_LOCAL,
0,
&mutex);
return mutex;
}
void usb_osal_mutex_delete(usb_osal_mutex_t mutex)
{
rtems_semaphore_delete(mutex);
}
int usb_osal_mutex_take(usb_osal_mutex_t mutex)
{
return (rtems_semaphore_obtain(mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT) == RTEMS_SUCCESSFUL) ? 0 : -USB_ERR_TIMEOUT;
}
int usb_osal_mutex_give(usb_osal_mutex_t mutex)
{
return (rtems_semaphore_release(mutex) == RTEMS_SUCCESSFUL) ? 0 : -USB_ERR_TIMEOUT;
}
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs)
{
rtems_status_code ret;
rtems_id mailbox = 0;
ret = rtems_message_queue_create(
rtems_build_name('U', 'S', 'B', 'q'),
max_msgs,
SYS_USB_MBOX_SIZE,
RTEMS_DEFAULT_ATTRIBUTES,
&mailbox);
return mailbox;
}
int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr)
{
rtems_status_code ret;
ret = rtems_message_queue_send(mq, &addr, SYS_USB_MBOX_SIZE);
return (ret == RTEMS_SUCCESSFUL) ? 0 : -USB_ERR_TIMEOUT;
}
int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout)
{
size_t size;
rtems_status_code sc;
sc = rtems_message_queue_receive(
mq,
addr,
&size,
RTEMS_WAIT,
timeout);
return (sc == RTEMS_SUCCESSFUL) ? 0 : -USB_ERR_TIMEOUT;
}
uint32_t usb_osal_enter_critical_section(void)
{
rtems_interrupt_level pval;
#if RTEMS_SMP
rtems_recursive_mutex_lock(&sys_arch_lock);
#else
rtems_interrupt_disable(pval);
#endif
return pval;
}
void usb_osal_leave_critical_section(size_t flag)
{
#if RTEMS_SMP
rtems_recursive_mutex_unlock(&sys_arch_lock);
#else
rtems_interrupt_enable(flag);
#endif
}
void usb_osal_msleep(uint32_t delay)
{
rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(delay));
}
#endif

View File

@@ -9,35 +9,23 @@
#include "usb_log.h"
#include "tx_api.h"
/* create bytepool in tx_application_define
*
* tx_byte_pool_create(&usb_byte_pool, "usb byte pool", memory_area, 65536);
*/
extern TX_BYTE_POOL usb_byte_pool; // define usb_byte_pool and call usb_osal_init first
extern TX_BYTE_POOL usb_byte_pool;
usb_osal_mq_t usb_osal_mq;
usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args)
{
CHAR *pointer = TX_NULL;
TX_THREAD *thread_ptr = TX_NULL;
tx_byte_allocate(&usb_byte_pool, (VOID **)&thread_ptr, sizeof(TX_THREAD), TX_NO_WAIT);
tx_byte_allocate(&usb_byte_pool, (VOID **)&thread_ptr, USB_ALIGN_UP(sizeof(TX_THREAD), 4) + stack_size, TX_NO_WAIT);
if (thread_ptr == TX_NULL) {
USB_LOG_ERR("Create thread %s failed\r\n", name);
while (1) {
}
}
tx_byte_allocate(&usb_byte_pool, (VOID **)&pointer, stack_size, TX_NO_WAIT);
if (pointer == TX_NULL) {
USB_LOG_ERR("Create thread %s failed\r\n", name);
while (1) {
}
}
tx_thread_create(thread_ptr, (CHAR *)name, (VOID(*)(ULONG))entry, (uintptr_t)args,
pointer, stack_size,
((CHAR *)thread_ptr + USB_ALIGN_UP(sizeof(TX_THREAD), 4)), stack_size,
prio, prio, TX_NO_TIME_SLICE, TX_AUTO_START);
return (usb_osal_thread_t)thread_ptr;
@@ -45,27 +33,17 @@ usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size,
void usb_osal_thread_delete(usb_osal_thread_t thread)
{
TX_THREAD *thread_ptr = NULL;
if (thread == NULL) {
/* Call the tx_thread_identify to get the control block pointer of the
currently executing thread. */
thread_ptr = tx_thread_identify();
thread = tx_thread_identify();
/* Check if the current running thread pointer is not NULL */
if (thread_ptr != NULL) {
/* Call the tx_thread_terminate to terminates the specified application
thread regardless of whether the thread is suspended or not. A thread
may call this service to terminate itself. */
tx_thread_terminate(thread_ptr);
tx_byte_release(thread_ptr->tx_thread_stack_start);
tx_byte_release(thread_ptr);
}
usb_osal_mq_send(usb_osal_mq, (uintptr_t)thread);
tx_thread_terminate(thread);
return;
}
tx_thread_terminate(thread);
tx_byte_release(thread_ptr->tx_thread_stack_start);
tx_thread_delete(thread);
tx_byte_release(thread);
}
@@ -86,7 +64,6 @@ usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count)
TX_SEMAPHORE *sem_ptr = TX_NULL;
tx_byte_allocate(&usb_byte_pool, (VOID **)&sem_ptr, sizeof(TX_SEMAPHORE), TX_NO_WAIT);
if (sem_ptr == TX_NULL) {
USB_LOG_ERR("Create semaphore failed\r\n");
while (1) {
@@ -121,7 +98,7 @@ int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
int usb_osal_sem_give(usb_osal_sem_t sem)
{
return (int)tx_semaphore_put((TX_SEMAPHORE *)sem);
return (tx_semaphore_put((TX_SEMAPHORE *)sem) == TX_SUCCESS) ? 0 : -USB_ERR_INVAL;
}
void usb_osal_sem_reset(usb_osal_sem_t sem)
@@ -134,14 +111,13 @@ usb_osal_mutex_t usb_osal_mutex_create(void)
TX_MUTEX *mutex_ptr = TX_NULL;
tx_byte_allocate(&usb_byte_pool, (VOID **)&mutex_ptr, sizeof(TX_MUTEX), TX_NO_WAIT);
if (mutex_ptr == TX_NULL) {
USB_LOG_ERR("Create mutex failed\r\n");
while (1) {
}
}
tx_mutex_create(mutex_ptr, "usbh_mutx", TX_INHERIT);
tx_mutex_create(mutex_ptr, "usbh_mutex", TX_INHERIT);
return (usb_osal_mutex_t)mutex_ptr;
}
@@ -169,38 +145,27 @@ int usb_osal_mutex_take(usb_osal_mutex_t mutex)
int usb_osal_mutex_give(usb_osal_mutex_t mutex)
{
return (int)(tx_mutex_put((TX_MUTEX *)mutex) == TX_SUCCESS) ? 0 : -USB_ERR_INVAL;
return (tx_mutex_put((TX_MUTEX *)mutex) == TX_SUCCESS) ? 0 : -USB_ERR_INVAL;
}
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs)
{
CHAR *pointer = TX_NULL;
TX_QUEUE *queue_ptr = TX_NULL;
tx_byte_allocate(&usb_byte_pool, (VOID **)&queue_ptr, sizeof(TX_QUEUE), TX_NO_WAIT);
tx_byte_allocate(&usb_byte_pool, (VOID **)&queue_ptr, USB_ALIGN_UP(sizeof(TX_QUEUE), 4) + sizeof(uintptr_t) * max_msgs, TX_NO_WAIT);
if (queue_ptr == TX_NULL) {
USB_LOG_ERR("Create TX_QUEUE failed\r\n");
while (1) {
}
}
tx_byte_allocate(&usb_byte_pool, (VOID **)&pointer, sizeof(uintptr_t) * max_msgs, TX_NO_WAIT);
if (pointer == TX_NULL) {
USB_LOG_ERR("Create mq failed\r\n");
while (1) {
}
}
tx_queue_create(queue_ptr, "usbh_mq", sizeof(uintptr_t) / 4, pointer, sizeof(uintptr_t) * max_msgs);
tx_queue_create(queue_ptr, "usbh_mq", sizeof(uintptr_t) / 4, (CHAR *)queue_ptr + USB_ALIGN_UP(sizeof(TX_QUEUE), 4), sizeof(uintptr_t) * max_msgs);
return (usb_osal_mq_t)queue_ptr;
}
void usb_osal_mq_delete(usb_osal_mq_t mq)
{
tx_queue_delete((TX_QUEUE *)mq);
tx_byte_release(((TX_QUEUE *)mq)->tx_queue_start);
tx_byte_release(mq);
}
@@ -231,7 +196,6 @@ struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_
struct usb_osal_timer *timer;
tx_byte_allocate(&usb_byte_pool, (VOID **)&timer, sizeof(struct usb_osal_timer), TX_NO_WAIT);
if (timer == TX_NULL) {
USB_LOG_ERR("Create usb_osal_timer failed\r\n");
while (1) {
@@ -240,7 +204,6 @@ struct usb_osal_timer *usb_osal_timer_create(const char *name, uint32_t timeout_
memset(timer, 0, sizeof(struct usb_osal_timer));
tx_byte_allocate(&usb_byte_pool, (VOID **)&timer_ptr, sizeof(TX_TIMER), TX_NO_WAIT);
if (timer_ptr == TX_NULL) {
USB_LOG_ERR("Create TX_TIMER failed\r\n");
while (1) {
@@ -269,8 +232,8 @@ void usb_osal_timer_start(struct usb_osal_timer *timer)
{
if (tx_timer_change((TX_TIMER *)timer->timer, timer->timeout_ms, timer->is_period ? timer->timeout_ms : 0) == TX_SUCCESS) {
/* Call the tx_timer_activate to activates the specified application
timer. The expiration routines of timers that expire at the same
time are executed in the order they were activated. */
timer. The expiration routines of timers that expire at the same
time are executed in the order they were activated. */
if (tx_timer_activate((TX_TIMER *)timer->timer) == TX_SUCCESS) {
/* Return osOK for success */
} else {
@@ -296,7 +259,7 @@ size_t usb_osal_enter_critical_section(void)
void usb_osal_leave_critical_section(size_t flag)
{
int interrupt_save;
TX_INTERRUPT_SAVE_AREA
interrupt_save = flag;
TX_RESTORE
@@ -322,4 +285,40 @@ void *usb_osal_malloc(size_t size)
void usb_osal_free(void *ptr)
{
tx_byte_release(ptr);
}
}
static void usb_osal_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
int ret;
usb_osal_thread_t thread;
while (1) {
ret = usb_osal_mq_recv(usb_osal_mq, (uintptr_t *)&thread, TX_WAIT_FOREVER);
if (ret < 0) {
continue;
}
tx_thread_delete(thread);
tx_byte_release(thread);
}
}
void usb_osal_init(uint8_t *mem, uint32_t mem_size)
{
usb_osal_thread_t thread;
tx_byte_pool_create(&usb_byte_pool, "usb byte pool", mem, mem_size);
thread = usb_osal_thread_create("usb_osal", 2048, 10, usb_osal_thread, NULL);
if (thread == NULL) {
USB_LOG_ERR("Create usb_osal_thread failed\r\n");
while (1) {
}
}
usb_osal_mq = usb_osal_mq_create(32);
if (usb_osal_mq == NULL) {
USB_LOG_ERR("Create usb_osal_mq failed\r\n");
while (1) {
}
}
}

View File

@@ -1,135 +0,0 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usb_osal.h"
#include "usb_errno.h"
#include <aos/kernel.h>
#include <csi_core.h>
usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size, uint32_t prio, usb_thread_entry_t entry, void *args)
{
aos_task_t task_handle = NULL;
aos_task_new_ext(&task_handle, name, entry, args, stack_size, prio + AOS_DEFAULT_APP_PRI - 4);
return task_handle;
}
void usb_osal_thread_delete(usb_osal_thread_t thread)
{
aos_task_exit(0);
}
usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count)
{
aos_sem_t sem = NULL;
aos_sem_new(&sem, initial_count);
return sem;
}
void usb_osal_sem_delete(usb_osal_sem_t sem)
{
aos_sem_free((aos_sem_t *)&sem);
}
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
{
if (timeout == USB_OSAL_WAITING_FOREVER) {
return aos_sem_wait((aos_sem_t *)&sem, AOS_WAIT_FOREVER);
} else {
return aos_sem_wait((aos_sem_t *)&sem, timeout);
}
}
int usb_osal_sem_give(usb_osal_sem_t sem)
{
aos_sem_signal((aos_sem_t *)&sem);
return 0;
}
void usb_osal_sem_reset(usb_osal_sem_t sem)
{
}
usb_osal_mutex_t usb_osal_mutex_create(void)
{
aos_mutex_t mutex = NULL;
aos_mutex_new(&mutex);
return (usb_osal_mutex_t)mutex;
}
void usb_osal_mutex_delete(usb_osal_mutex_t mutex)
{
aos_mutex_free(((aos_mutex_t *)&mutex));
}
int usb_osal_mutex_take(usb_osal_mutex_t mutex)
{
return aos_mutex_lock(((aos_mutex_t *)&mutex), AOS_WAIT_FOREVER);
}
int usb_osal_mutex_give(usb_osal_mutex_t mutex)
{
return aos_mutex_unlock(((aos_mutex_t *)&mutex));
}
usb_osal_mq_t usb_osal_mq_create(uint32_t max_msgs)
{
aos_queue_t queue = NULL;
aos_queue_create(&queue, sizeof(uintptr_t), max_msgs, 0);
return (usb_osal_mq_t)queue;
}
void usb_osal_mq_delete(usb_osal_mq_t mq)
{
aos_queue_free((aos_queue_t)mq);
}
int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr)
{
return aos_queue_send((aos_queue_t *)&mq, &addr, sizeof(uintptr_t));
}
int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout)
{
size_t recv_size;
if (timeout == USB_OSAL_WAITING_FOREVER) {
return aos_queue_recv((aos_queue_t *)&mq, AOS_WAIT_FOREVER, addr, &recv_size);
} else {
return aos_queue_recv((aos_queue_t *)&mq, timeout, addr, &recv_size);
}
}
size_t usb_osal_enter_critical_section(void)
{
return csi_irq_save();
}
void usb_osal_leave_critical_section(size_t flag)
{
csi_irq_restore(flag);
}
void usb_osal_msleep(uint32_t delay)
{
aos_msleep(delay);
}
void *usb_osal_malloc(size_t size)
{
return aos_malloc(size);
}
void usb_osal_free(void *ptr)
{
aos_free(ptr);
}

View File

@@ -5,175 +5,313 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "dap_main.h"
#include "DAP_config.h"
#include "DAP.h"
#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN + CONFIG_MSC_DESCRIPTOR_LEN)
#define INTF_NUM (2 + 1 + CONFIG_MSC_INTF_NUM)
#define CMSIS_DAP_INTERFACE_SIZE (9 + 7 + 7)
#define CUSTOM_HID_LEN (9 + 9 + 7 + 7)
#define HIDRAW_INTERVAL 4
#define HID_CUSTOM_REPORT_DESC_SIZE 53
#define USBD_WINUSB_VENDOR_CODE 0x20
#define USBD_WEBUSB_VENDOR_CODE 0x21
#define USBD_WEBUSB_ENABLE 1
#define USBD_BULK_ENABLE 1
#define USBD_WINUSB_ENABLE 1
/* WinUSB Microsoft OS 2.0 descriptor sizes */
#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
#define FUNCTION_SUBSET_LEN 160
#define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132
#define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN)
#define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE)
#define USBD_WEBUSB_DESC_LEN 24
#define USBD_WINUSB_DESC_LEN 28
#define USBD_BOS_WTOTALLENGTH (0x05 + \
USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \
USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE)
#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN + \
CONFIG_CHERRYDAP_USE_CUSTOM_HID * CUSTOM_HID_LEN + \
CONFIG_CHERRYDAP_USE_MSC * MSC_DESCRIPTOR_LEN + USBD_WEBUSB_ENABLE * 9)
#define INTF_NUM (1 + 2 + CONFIG_CHERRYDAP_USE_CUSTOM_HID + CONFIG_CHERRYDAP_USE_MSC + USBD_WEBUSB_ENABLE)
#define MSC_INTF_NUM (3 + CONFIG_CHERRYDAP_USE_CUSTOM_HID)
#define WEBUSB_INTF_NUM (3 + CONFIG_CHERRYDAP_USE_CUSTOM_HID + CONFIG_CHERRYDAP_USE_MSC)
#define WEBUSB_URL_STRINGS \
'c', 'h', 'e', 'r', 'r', 'y', 'd', 'a', 'p', '.', 'c', 'h', 'e', 'r', 'r', 'y', '-', 'e', 'm', 'b', 'e', 'd', 'd', 'e', 'd', '.', 'o', 'r', 'g',
__ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[] = {
WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
#if (USBD_WEBUSB_ENABLE)
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType
0, // bFirstInterface USBD_WINUSB_IF_NUM
0, // bReserved
WBVAL(FUNCTION_SUBSET_LEN), // wSubsetLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), // wLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), // wDescriptorType
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // CompatibleId
0, 0, 0, 0, 0, 0, 0, 0, // SubCompatibleId
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), // wDescriptorType
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType
WBVAL(42), // wPropertyNameLength
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), // wPropertyDataLength
'{', 0,
'9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0,
'9', 0, 'C', 0, '7', 0, '7', 0, '-', 0,
'4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0,
'9', 0, '3', 0, '3', 0, 'B', 0, '-',
0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0,
'}', 0, 0, 0, 0, 0
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType
WEBUSB_INTF_NUM, // bFirstInterface USBD_WINUSB_IF_NUM
0, // bReserved
WBVAL(FUNCTION_SUBSET_LEN), // wSubsetLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), // wLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), // wDescriptorType
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // CompatibleId
0, 0, 0, 0, 0, 0, 0, 0, // SubCompatibleId
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), // wDescriptorType
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType
WBVAL(42), // wPropertyNameLength
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), // wPropertyDataLength
'{', 0,
'9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0,
'9', 0, 'C', 0, '7', 0, '7', 0, '-', 0,
'4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0,
'9', 0, '3', 0, '3', 0, 'B', 0, '-',
0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0,
'}', 0, 0, 0, 0, 0,
#endif
#if USBD_BULK_ENABLE
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */
0, /* bFirstInterface USBD_BULK_IF_NUM*/
0, /* bReserved */
WBVAL(FUNCTION_SUBSET_LEN), /* wSubsetLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/
0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */
WBVAL(42), /* wPropertyNameLength */
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), /* wPropertyDataLength */
'{', 0,
'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0,
'2', 0, '9', 0, '3', 0, 'B', 0, '-', 0,
'4', 0, '6', 0, '6', 0, '3', 0, '-', 0,
'A', 0, 'A', 0, '3', 0, '6', 0, '-',
0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0,
'}', 0, 0, 0, 0, 0
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */
0, /* bFirstInterface USBD_BULK_IF_NUM*/
0, /* bReserved */
WBVAL(FUNCTION_SUBSET_LEN), /* wSubsetLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/
0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */
WBVAL(42), /* wPropertyNameLength */
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), /* wPropertyDataLength */
'{', 0,
'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0,
'2', 0, '9', 0, '3', 0, 'B', 0, '-', 0,
'4', 0, '6', 0, '6', 0, '3', 0, '-', 0,
'A', 0, 'A', 0, '3', 0, '6', 0, '-',
0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0,
'}', 0, 0, 0, 0, 0
#endif
};
__ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = {
0x05, /* bLength */
0x0f, /* bDescriptorType */
WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */
USBD_NUM_DEV_CAPABILITIES, /* bNumDeviceCaps */
0x05, /* bLength */
0x0f, /* bDescriptorType */
WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */
USBD_NUM_DEV_CAPABILITIES, /* bNumDeviceCaps */
#if (USBD_WEBUSB_ENABLE)
USBD_WEBUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0x38, 0xB6, 0x08, 0x34, /* PlatformCapabilityUUID */
0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76,
0x88, 0x15, 0xB6, 0x65,
WBVAL(0x0100), /* 1.00 */ /* bcdVersion */
USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
0, /* iLandingPage */
USBD_WEBUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0x38, 0xB6, 0x08, 0x34, /* PlatformCapabilityUUID */
0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76,
0x88, 0x15, 0xB6, 0x65,
WBVAL(0x0100), /* 1.00 */ /* bcdVersion */
USBD_WEBUSB_VENDOR_CODE, /* bVendorCode */
1, /* iLandingPage */
#endif
#if (USBD_WINUSB_ENABLE)
USBD_WINUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0xDF, 0x60, 0xDD, 0xD8, /* PlatformCapabilityUUID */
0x89, 0x45, 0xC7, 0x4C,
0x9C, 0xD2, 0x65, 0x9D,
0x9E, 0x64, 0x8A, 0x9F,
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
0, /* bAltEnumCode */
USBD_WINUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0xDF, 0x60, 0xDD, 0xD8, /* PlatformCapabilityUUID */
0x89, 0x45, 0xC7, 0x4C,
0x9C, 0xD2, 0x65, 0x9D,
0x9E, 0x64, 0x8A, 0x9F,
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
0, /* bAltEnumCode */
#endif
};
#define URL_DESCRIPTOR_LENGTH (3 + 29)
const uint8_t USBD_WebUSBURLDescriptor[URL_DESCRIPTOR_LENGTH] = {
URL_DESCRIPTOR_LENGTH,
WEBUSB_URL_TYPE,
WEBUSB_URL_SCHEME_HTTPS,
WEBUSB_URL_STRINGS
};
// clang-format off
#define HID_DESC() \
/************** Descriptor of Custom interface *****************/ \
0x09, /* bLength: Interface Descriptor size */ \
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
0X03, /* bInterfaceNumber: Number of Interface */ \
0x00, /* bAlternateSetting: Alternate setting */ \
0x02, /* bNumEndpoints */ \
0x03, /* bInterfaceClass: HID */ \
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ \
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ \
0, /* iInterface: Index of string descriptor */ /******************** Descriptor of Custom HID ********************/ \
0x09, /* bLength: HID Descriptor size */ \
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */ \
0x11, /* bcdHID: HID Class Spec release number */ \
0x01, \
0x00, /* bCountryCode: Hardware target country */ \
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */ \
0x22, /* bDescriptorType */ \
HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */ \
0x00, /******************** Descriptor of Custom in endpoint ********************/ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
HID_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ \
HIDRAW_INTERVAL, /* bInterval: Polling Interval */ /******************** Descriptor of Custom out endpoint ********************/ \
0x07, /* bLength: Endpoint Descriptor size */ \
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
HID_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */ \
0x03, /* bmAttributes: Interrupt endpoint */ \
WBVAL(HID_PACKET_SIZE), /* wMaxPacketSize: 4 Byte max */ \
HIDRAW_INTERVAL /* bInterval: Polling Interval */
// clang-format on
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
};
static const uint8_t config_descriptor[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
/* Interface 0 */
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
/* Endpoint OUT 2 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
/* Endpoint IN 1 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00),
#ifdef CONFIG_CHERRYDAP_USE_MSC
MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00),
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
/* Interface 0 */
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
/* Endpoint OUT 2 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
/* Endpoint IN 1 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00),
#if CONFIG_CHERRYDAP_USE_CUSTOM_HID
HID_DESC(),
#endif
#if CONFIG_CHERRYDAP_USE_MSC
MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00),
#endif
#if USBD_WEBUSB_ENABLE
USB_INTERFACE_DESCRIPTOR_INIT(WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x04),
#endif
};
static const uint8_t other_speed_config_descriptor[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
/* Interface 0 */
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
/* Endpoint OUT 2 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
/* Endpoint IN 1 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00),
#ifdef CONFIG_CHERRYDAP_USE_MSC
MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00),
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
/* Interface 0 */
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
/* Endpoint OUT 2 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
/* Endpoint IN 1 */
USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00),
CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00),
#if CONFIG_CHERRYDAP_USE_CUSTOM_HID
HID_DESC(),
#endif
#if CONFIG_CHERRYDAP_USE_MSC
MSC_DESCRIPTOR_INIT(0x04, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00),
#endif
#if USBD_WEBUSB_ENABLE
USB_INTERFACE_DESCRIPTOR_INIT(WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x04),
#endif
};
/*!< custom hid report descriptor */
const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
0x09, 0x01, /* USAGE (Vendor Usage 1) */
0xa1, 0x01, /* COLLECTION (Application) */
0x85, 0x02, /* REPORT ID (0x02) */
0x09, 0x02, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0xff, /*LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x96, 0xff, 0x03, /* REPORT_COUNT (1023) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
/* <___________________________________________________> */
0x85, 0x01, /* REPORT ID (0x01) */
0x09, 0x03, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x96, 0xff, 0x03, /* REPORT_COUNT (1023) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* <___________________________________________________> */
0x85, 0x03, /* REPORT ID (0x03) */
0x09, 0x04, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x96, 0xff, 0x03, /* REPORT_COUNT (1023) */
0xb1, 0x02, /* FEATURE (Data,Var,Abs) */
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
char serial_number_dynamic[36] = "00000000000000000123456789ABCDEF"; // Dynamic serial number
char *string_descriptors[] = {
(char[]) {0x09, 0x04}, /* Langid */
"CherryUSB", /* Manufacturer */
"CherryUSB CMSIS-DAP", /* Product */
"00000000000000000123456789ABCDEF", /* Serial Number */
(char[]){ 0x09, 0x04 }, /* Langid */
"CherryUSB", /* Manufacturer */
"CherryUSB CMSIS-DAP", /* Product */
"00000000000000000123456789ABCDEF", /* Serial Number */
"CherryUSB WebUSB",
};
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, 0x01),
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, 0x01),
};
__WEAK const uint8_t *device_descriptor_callback(uint8_t speed)
{
(void) speed;
(void)speed;
return device_descriptor;
}
__WEAK const uint8_t *config_descriptor_callback(uint8_t speed)
{
(void) speed;
(void)speed;
return config_descriptor;
}
__WEAK const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
(void) speed;
(void)speed;
return device_quality_descriptor;
}
__WEAK const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
{
(void) speed;
(void)speed;
return other_speed_config_descriptor;
}
__WEAK const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
(void) speed;
(void)speed;
if (index == 3) {
return serial_number_dynamic;
}
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
@@ -214,7 +352,7 @@ USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_usbrx;
void usbd_event_handler(uint8_t busid, uint8_t event)
{
(void) busid;
(void)busid;
switch (event) {
case USBD_EVENT_RESET:
usbrx_idle_flag = 0;
@@ -250,7 +388,7 @@ void usbd_event_handler(uint8_t busid, uint8_t event)
void dap_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void) busid;
(void)busid;
if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) {
DAP_TransferAbort = 1U;
} else {
@@ -262,7 +400,7 @@ void dap_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
}
// Start reception of next request packet
if ((uint16_t) (USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE);
} else {
USB_RequestIdle = 1U;
@@ -271,7 +409,7 @@ void dap_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
void dap_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void) busid;
(void)busid;
if (USB_ResponseCountI != USB_ResponseCountO) {
// Load data from response buffer to be sent back
usbd_ep_start_write(0, DAP_IN_EP, USB_Response[USB_ResponseIndexO], USB_RespSize[USB_ResponseIndexO]);
@@ -287,7 +425,7 @@ void dap_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void) busid;
(void)busid;
chry_ringbuffer_write(&g_usbrx, usb_tmpbuffer, nbytes);
if (chry_ringbuffer_get_free(&g_usbrx) >= DAP_PACKET_SIZE) {
usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE);
@@ -298,7 +436,7 @@ void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void) busid;
(void)busid;
uint32_t size;
uint8_t *buffer;
@@ -317,52 +455,110 @@ void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
}
struct usbd_endpoint dap_out_ep = {
.ep_addr = DAP_OUT_EP,
.ep_cb = dap_out_callback
.ep_addr = DAP_OUT_EP,
.ep_cb = dap_out_callback
};
struct usbd_endpoint dap_in_ep = {
.ep_addr = DAP_IN_EP,
.ep_cb = dap_in_callback
.ep_addr = DAP_IN_EP,
.ep_cb = dap_in_callback
};
struct usbd_endpoint cdc_out_ep = {
.ep_addr = CDC_OUT_EP,
.ep_cb = usbd_cdc_acm_bulk_out
.ep_addr = CDC_OUT_EP,
.ep_cb = usbd_cdc_acm_bulk_out
};
struct usbd_endpoint cdc_in_ep = {
.ep_addr = CDC_IN_EP,
.ep_cb = usbd_cdc_acm_bulk_in
.ep_addr = CDC_IN_EP,
.ep_cb = usbd_cdc_acm_bulk_in
};
#if CONFIG_CHERRYDAP_USE_CUSTOM_HID
struct usbd_endpoint hid_custom_in_ep = {
.ep_addr = HID_IN_EP,
.ep_cb = usbd_hid_custom_in_callback,
};
struct usbd_endpoint hid_custom_out_ep = {
.ep_addr = HID_OUT_EP,
.ep_cb = usbd_hid_custom_out_callback,
};
#endif
struct usbd_interface dap_intf;
struct usbd_interface intf1;
struct usbd_interface intf2;
struct usbd_interface intf3;
#if CONFIG_CHERRYDAP_USE_CUSTOM_HID
struct usbd_interface hid_intf;
#endif
#if CONFIG_CHERRYDAP_USE_MSC
struct usbd_interface intf3;
#endif
struct usb_msosv2_descriptor msosv2_desc = {
.vendor_code = USBD_WINUSB_VENDOR_CODE,
.compat_id = USBD_WinUSBDescriptorSetDescriptor,
.compat_id_len = USBD_WINUSB_DESC_SET_LEN,
.vendor_code = USBD_WINUSB_VENDOR_CODE,
.compat_id = USBD_WinUSBDescriptorSetDescriptor,
.compat_id_len = USBD_WINUSB_DESC_SET_LEN,
};
struct usb_bos_descriptor bos_desc = {
.string = USBD_BinaryObjectStoreDescriptor,
.string_len = USBD_BOS_WTOTALLENGTH
.string = USBD_BinaryObjectStoreDescriptor,
.string_len = USBD_BOS_WTOTALLENGTH
};
struct usb_webusb_descriptor webusb_url_desc = {
.vendor_code = USBD_WEBUSB_VENDOR_CODE,
.string = USBD_WebUSBURLDescriptor,
.string_len = URL_DESCRIPTOR_LENGTH
};
const struct usb_descriptor cmsisdap_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.bos_descriptor = &bos_desc,
.msosv2_descriptor = &msosv2_desc,
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.bos_descriptor = &bos_desc,
.msosv2_descriptor = &msosv2_desc,
.webusb_url_descriptor = &webusb_url_desc
};
void chry_dap_init(uint8_t busid, uint32_t reg_base)
{
chry_ringbuffer_init(&g_uartrx, uartrx_ringbuffer, CONFIG_UARTRX_RINGBUF_SIZE);
chry_ringbuffer_init(&g_usbrx, usbrx_ringbuffer, CONFIG_USBRX_RINGBUF_SIZE);
DAP_Setup();
usbd_desc_register(0, &cmsisdap_descriptor);
/*!< winusb */
usbd_add_interface(0, &dap_intf);
usbd_add_endpoint(0, &dap_out_ep);
usbd_add_endpoint(0, &dap_in_ep);
/*!< cdc acm */
usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf1));
usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf2));
usbd_add_endpoint(0, &cdc_out_ep);
usbd_add_endpoint(0, &cdc_in_ep);
#if CONFIG_CHERRYDAP_USE_CUSTOM_HID
/*!< hid */
usbd_add_interface(0, usbd_hid_init_intf(0, &hid_intf, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE));
hid_intf.notify_handler = hid_custom_notify_handler;
usbd_add_endpoint(0, &hid_custom_in_ep);
usbd_add_endpoint(0, &hid_custom_out_ep);
#endif
#if CONFIG_CHERRYDAP_USE_MSC
usbd_add_interface(0, usbd_msc_init_intf(0, &intf3, MSC_OUT_EP, MSC_IN_EP));
#endif
usbd_initialize(busid, reg_base, usbd_event_handler);
}
void chry_dap_handle(void)
{
uint32_t n;
@@ -387,7 +583,7 @@ void chry_dap_handle(void)
// Execute DAP Command (process request and prepare response)
USB_RespSize[USB_ResponseIndexI] =
(uint16_t) DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]);
(uint16_t)DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]);
// Update Request Index and Count
USB_RequestIndexO++;
@@ -397,7 +593,7 @@ void chry_dap_handle(void)
USB_RequestCountO++;
if (USB_RequestIdle) {
if ((uint16_t) (USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
if ((uint16_t)(USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) {
USB_RequestIdle = 0U;
usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE);
}
@@ -427,9 +623,9 @@ void chry_dap_handle(void)
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void) busid;
if (memcmp(line_coding, (uint8_t *) &g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) {
memcpy((uint8_t *) &g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding));
(void)busid;
if (memcmp(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) {
memcpy((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding));
config_uart = 1;
config_uart_transfer = 0;
}
@@ -437,8 +633,8 @@ void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_c
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void) busid;
memcpy(line_coding, (uint8_t *) &g_cdc_lincoding, sizeof(struct cdc_line_coding));
(void)busid;
memcpy(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding));
}
void chry_dap_usb2uart_handle(void)
@@ -450,7 +646,7 @@ void chry_dap_usb2uart_handle(void)
/* disable irq here */
config_uart = 0;
/* config uart here */
chry_dap_usb2uart_uart_config_callback((struct cdc_line_coding *) &g_cdc_lincoding);
chry_dap_usb2uart_uart_config_callback((struct cdc_line_coding *)&g_cdc_lincoding);
usbtx_idle_flag = 1;
uarttx_idle_flag = 1;
config_uart_transfer = 1;
@@ -521,7 +717,7 @@ __WEAK void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len)
{
}
#ifdef CONFIG_CHERRYDAP_USE_MSC
#if CONFIG_CHERRYDAP_USE_MSC
#define BLOCK_SIZE 512
#define BLOCK_COUNT 10

View File

@@ -10,6 +10,7 @@
#include "usbd_core.h"
#include "usbd_cdc.h"
#include "usbd_msc.h"
#include "usbd_hid.h"
#include "chry_ringbuffer.h"
#include "DAP_config.h"
#include "DAP.h"
@@ -24,23 +25,14 @@
#define MSC_IN_EP 0x86
#define MSC_OUT_EP 0x07
#define HID_IN_EP 0x88
#define HID_OUT_EP 0x09
#define USBD_VID 0x0D28
#define USBD_PID 0x0204
#define USBD_MAX_POWER 500
#define USBD_LANGID_STRING 1033
#define CMSIS_DAP_INTERFACE_SIZE (9 + 7 + 7)
#ifdef CONFIG_CHERRYDAP_USE_MSC
#define CONFIG_MSC_DESCRIPTOR_LEN CDC_ACM_DESCRIPTOR_LEN
#define CONFIG_MSC_INTF_NUM 1
#define MSC_INTF_NUM (0x02 + 1)
#else
#define CONFIG_MSC_DESCRIPTOR_LEN 0
#define CONFIG_MSC_INTF_NUM 0
#define MSC_INTF_NUM (0x02)
#endif
#ifdef CONFIG_USB_HS
#if DAP_PACKET_SIZE != 512
#error "DAP_PACKET_SIZE must be 512 in hs"
@@ -51,99 +43,57 @@
#endif
#endif
#define USBD_WINUSB_VENDOR_CODE 0x20
#define USBD_WEBUSB_ENABLE 0
#define USBD_BULK_ENABLE 1
#define USBD_WINUSB_ENABLE 1
/* WinUSB Microsoft OS 2.0 descriptor sizes */
#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
#define FUNCTION_SUBSET_LEN 160
#define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132
#define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN)
#define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE)
#define USBD_WEBUSB_DESC_LEN 24
#define USBD_WINUSB_DESC_LEN 28
#define USBD_BOS_WTOTALLENGTH (0x05 + \
USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \
USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE)
#ifdef CONFIG_USB_HS
#define HID_PACKET_SIZE 1024
#else
#define HID_PACKET_SIZE 64
#endif
#define CONFIG_UARTRX_RINGBUF_SIZE (8 * 1024)
#define CONFIG_USBRX_RINGBUF_SIZE (8 * 1024)
#ifdef __cplusplus
extern "C"
{
#ifndef CONFIG_CHERRYDAP_USE_MSC
#define CONFIG_CHERRYDAP_USE_MSC 0
#endif
extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t uartrx_ringbuffer[CONFIG_UARTRX_RINGBUF_SIZE];
extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usbrx_ringbuffer[CONFIG_USBRX_RINGBUF_SIZE];
extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tmpbuffer[DAP_PACKET_SIZE];
#ifndef CONFIG_CHERRYDAP_USE_CUSTOM_HID
#define CONFIG_CHERRYDAP_USE_CUSTOM_HID 0
#endif
extern const struct usb_descriptor cmsisdap_descriptor;
extern __ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[];
extern __ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[];
extern char *string_descriptors[];
#ifdef __cplusplus
extern "C" {
#endif
extern char serial_number_dynamic[36];
extern struct usbd_interface dap_intf;
extern struct usbd_interface intf1;
extern struct usbd_interface intf2;
extern struct usbd_interface intf3;
extern struct usbd_interface hid_intf;
extern struct usbd_endpoint dap_out_ep;
extern struct usbd_endpoint dap_in_ep;
extern struct usbd_endpoint cdc_out_ep;
extern struct usbd_endpoint cdc_in_ep;
extern chry_ringbuffer_t g_uartrx;
extern chry_ringbuffer_t g_usbrx;
__STATIC_INLINE void chry_dap_init(uint8_t busid, uint32_t reg_base)
{
chry_ringbuffer_init(&g_uartrx, uartrx_ringbuffer, CONFIG_UARTRX_RINGBUF_SIZE);
chry_ringbuffer_init(&g_usbrx, usbrx_ringbuffer, CONFIG_USBRX_RINGBUF_SIZE);
DAP_Setup();
usbd_desc_register(0, &cmsisdap_descriptor);
/*!< winusb */
usbd_add_interface(0, &dap_intf);
usbd_add_endpoint(0, &dap_out_ep);
usbd_add_endpoint(0, &dap_in_ep);
/*!< cdc acm */
usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf1));
usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf2));
usbd_add_endpoint(0, &cdc_out_ep);
usbd_add_endpoint(0, &cdc_in_ep);
#ifdef CONFIG_CHERRYDAP_USE_MSC
usbd_add_interface(0, usbd_msc_init_intf(0, &intf3, MSC_OUT_EP, MSC_IN_EP));
#endif
extern void usbd_event_handler(uint8_t busid, uint8_t event);
usbd_initialize(busid, reg_base, usbd_event_handler);
}
void chry_dap_init(uint8_t busid, uint32_t reg_base);
void chry_dap_handle(void);
void chry_dap_usb2uart_handle(void);
void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding);
/* implment by user */
extern void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding);
void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len);
/* implment by user */
extern void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len);
void chry_dap_usb2uart_uart_send_complete(uint32_t size);
/* implment by user */
extern void hid_custom_notify_handler(uint8_t busid, uint8_t event, void *arg);
/* implment by user */
extern void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes);
/* implment by user */
extern void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes);
#ifdef __cplusplus
}
#endif

View File

@@ -34,7 +34,7 @@ int USB_disk_read(BYTE *buff, LBA_t sector, UINT count)
uint8_t *align_buf;
align_buf = (uint8_t *)buff;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
@@ -42,19 +42,19 @@ int USB_disk_read(BYTE *buff, LBA_t sector, UINT count)
return -USB_ERR_NOMEM;
}
}
#endif
ret = usbh_msc_scsi_read10(active_msc_class, sector, align_buf, count);
if (ret < 0) {
ret = RES_ERROR;
} else {
ret = RES_OK;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
usb_memcpy(buff, align_buf, count * active_msc_class->blocksize);
free(align_buf);
}
#endif
return ret;
}
@@ -64,7 +64,7 @@ int USB_disk_write(const BYTE *buff, LBA_t sector, UINT count)
uint8_t *align_buf;
align_buf = (uint8_t *)buff;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
@@ -73,18 +73,18 @@ int USB_disk_write(const BYTE *buff, LBA_t sector, UINT count)
}
usb_memcpy(align_buf, buff, count * active_msc_class->blocksize);
}
#endif
ret = usbh_msc_scsi_write10(active_msc_class, sector, align_buf, count);
if (ret < 0) {
ret = RES_ERROR;
} else {
ret = RES_OK;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
free(align_buf);
}
#endif
return ret;
}

296
platform/idf/usbh_fatfs.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "diskio_impl.h"
#include "ffconf.h"
#include "ff.h"
#include "esp_vfs_fat.h"
#include "usbh_core.h"
#include "usbh_msc.h"
static char *TAG = "MSC";
#define DRIVE_STR_LEN 3
typedef struct msc_host_vfs {
uint8_t pdrv;
FATFS *fs;
char base_path[0];
} msc_host_vfs_t;
static struct usbh_msc *s_mscs[FF_VOLUMES] = { NULL };
static DSTATUS usb_disk_initialize(BYTE pdrv)
{
return RES_OK;
}
static DSTATUS usb_disk_status(BYTE pdrv)
{
return RES_OK;
}
static DRESULT usb_disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
struct usbh_msc *msc_class;
assert(pdrv < FF_VOLUMES);
msc_class = s_mscs[pdrv];
assert(msc_class);
if (sector >= msc_class->blocknum - count) {
ESP_LOGW(TAG, "%s: sector 0x%"PRIX32" out of range", __FUNCTION__, (uint32_t)sector);
return RES_PARERR;
}
uint8_t *dma_buff = buff;
size_t len = msc_class->blocksize * count;
if (((uint32_t)dma_buff & (CONFIG_USB_ALIGN_SIZE - 1)) || (len & (CONFIG_USB_ALIGN_SIZE - 1))) {
dma_buff = heap_caps_aligned_alloc(CONFIG_USB_ALIGN_SIZE, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (dma_buff == NULL) {
return RES_ERROR;
}
}
int ret = usbh_msc_scsi_read10(msc_class, sector, dma_buff, count);
if (dma_buff != buff) {
if (ret == 0) {
memcpy(buff, dma_buff, len);
}
heap_caps_free(dma_buff);
}
if (ret != 0) {
ESP_LOGE(TAG, "usbh_msc_scsi_read10 failed (%d)", ret);
return RES_ERROR;
}
return RES_OK;
}
static DRESULT usb_disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
struct usbh_msc *msc_class;
assert(pdrv < FF_VOLUMES);
msc_class = s_mscs[pdrv];
assert(msc_class);
if (sector >= msc_class->blocknum - count) {
ESP_LOGW(TAG, "%s: sector 0x%"PRIX32" out of range", __FUNCTION__, (uint32_t)sector);
return RES_PARERR;
}
const uint8_t *dma_buff = buff;
size_t len = msc_class->blocksize * count;
if (((uint32_t)dma_buff & (CONFIG_USB_ALIGN_SIZE - 1)) || (len & (CONFIG_USB_ALIGN_SIZE - 1))) {
dma_buff = heap_caps_aligned_alloc(CONFIG_USB_ALIGN_SIZE, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (dma_buff == NULL) {
return RES_ERROR;
}
memcpy((uint8_t *)dma_buff, buff, len);
}
int ret = usbh_msc_scsi_write10(msc_class, sector, dma_buff, count);
if (dma_buff != buff) {
heap_caps_free((uint8_t *)dma_buff);
}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "usbh_msc_scsi_write10 failed (%d)", ret);
return RES_ERROR;
}
return RES_OK;
}
static DRESULT usb_disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
struct usbh_msc *msc_class;
assert(pdrv < FF_VOLUMES);
msc_class = s_mscs[pdrv];
assert(msc_class);
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *) buff) = msc_class->blocknum;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *) buff) = msc_class->blocksize;
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
}
return RES_ERROR;
}
void ff_diskio_register_msc(BYTE pdrv, struct usbh_msc *msc_class)
{
assert(pdrv < FF_VOLUMES);
static const ff_diskio_impl_t usb_disk_impl = {
.init = &usb_disk_initialize,
.status = &usb_disk_status,
.read = &usb_disk_read,
.write = &usb_disk_write,
.ioctl = &usb_disk_ioctl
};
s_mscs[pdrv] = msc_class;
ff_diskio_register(pdrv, &usb_disk_impl);
}
BYTE ff_diskio_get_pdrv_disk(const struct usbh_msc *msc_class)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (msc_class == s_mscs[i]) {
return i;
}
}
return 0xff;
}
static esp_err_t msc_host_format(struct usbh_msc *msc_class, size_t allocation_size)
{
ESP_RETURN_ON_FALSE((msc_class != NULL && msc_class->user_data != NULL), ESP_ERR_INVALID_ARG, TAG, "");
void *workbuf = NULL;
const size_t workbuf_size = 4096;
msc_host_vfs_t *vfs = (msc_host_vfs_t *)msc_class->user_data;
char drive[DRIVE_STR_LEN] = {(char)('0' + vfs->pdrv), ':', 0};
ESP_RETURN_ON_FALSE((workbuf = ff_memalloc(workbuf_size)), ESP_ERR_NO_MEM, TAG, "");
// Valid value of cluster size is between sector_size and 128 * sector_size.
size_t cluster_size = MIN(MAX(allocation_size, msc_class->blocksize), 128 * msc_class->blocksize);
ESP_LOGW(TAG, "Formatting card, allocation unit size=%d", cluster_size);
f_mount(0, drive, 0);
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
FRESULT err = f_mkfs(drive, FM_ANY | FM_SFD, cluster_size, workbuf, workbuf_size);
#else
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, cluster_size};
FRESULT err = f_mkfs(drive, &opt, workbuf, workbuf_size);
#endif
free(workbuf);
if (err != FR_OK || (err = f_mount(vfs->fs, drive, 0)) != FR_OK) {
ESP_LOGE(TAG, "Formatting failed with error: %d", err);
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t msc_host_vfs_register(struct usbh_msc *msc_class,
const char *base_path,
const esp_vfs_fat_mount_config_t *mount_config)
{
ESP_RETURN_ON_FALSE((msc_class != NULL && msc_class->user_data == NULL && base_path != NULL && mount_config != NULL), ESP_ERR_INVALID_ARG, TAG, "");
FATFS *fs = NULL;
BYTE pdrv;
if (ff_diskio_get_drive(&pdrv) != ESP_OK) {
ESP_LOGW(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
esp_err_t ret;
msc_host_vfs_t *vfs = malloc(sizeof(msc_host_vfs_t) + strlen(base_path) + 1);
ESP_RETURN_ON_FALSE(vfs != NULL, ESP_ERR_NO_MEM, TAG, "");
ff_diskio_register_msc(pdrv, msc_class);
char drive[DRIVE_STR_LEN] = {(char)('0' + pdrv), ':', 0};
strcpy(vfs->base_path, base_path);
vfs->pdrv = pdrv;
ret = esp_vfs_fat_register(base_path, drive, mount_config->max_files, &fs);
ESP_GOTO_ON_ERROR(ret, fail, TAG, "Failed to register filesystem, error=%s", esp_err_to_name(ret));
vfs->fs = fs;
msc_class->user_data = vfs;
if (f_mount(fs, drive, 1) != FR_OK) {
if ((!mount_config->format_if_mount_failed) || msc_host_format(msc_class, mount_config->allocation_unit_size) != ESP_OK) {
ret = ESP_FAIL;
goto fail;
}
}
return ESP_OK;
fail:
msc_class->user_data = NULL;
if (fs) {
f_mount(NULL, drive, 0);
}
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
s_mscs[pdrv] = NULL;
return ret;
}
esp_err_t msc_host_vfs_unregister(struct usbh_msc *msc_class)
{
ESP_RETURN_ON_FALSE((msc_class != NULL && ff_diskio_get_pdrv_disk(msc_class) != 0XFF), ESP_ERR_INVALID_ARG, TAG, "");
msc_host_vfs_t *vfs = (msc_host_vfs_t *)msc_class->user_data;
msc_class->user_data = NULL;
char drive[DRIVE_STR_LEN] = {(char)('0' + vfs->pdrv), ':', 0};
f_mount(NULL, drive, 0);
ff_diskio_unregister(vfs->pdrv);
s_mscs[vfs->pdrv] = NULL;
esp_vfs_fat_unregister_path(vfs->base_path);
heap_caps_free(vfs);
return ESP_OK;
}
static void usbh_msc_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
struct usbh_msc *msc_class = (struct usbh_msc *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
int ret;
ret = usbh_msc_scsi_init(msc_class);
if (ret < 0) {
ESP_LOGE(TAG, "scsi_init error,ret:%d", ret);
return;
}
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 4 * 1024
};
ESP_LOGI(TAG, "Mounting msc host filesystem");
if (msc_host_vfs_register(msc_class, "/usb", &mount_config) != ESP_OK) {
ESP_LOGE(TAG, "msc_host_vfs_register fail");
return;
}
ESP_LOGI(TAG, "MSC host filesystem mounted");
usb_osal_thread_delete(NULL);
}
void usbh_msc_run(struct usbh_msc *msc_class)
{
usb_osal_thread_create("usbh_msc", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_msc_thread, msc_class);
}
void usbh_msc_stop(struct usbh_msc *msc_class)
{
msc_host_vfs_unregister(msc_class);
}

View File

@@ -17,8 +17,11 @@
#endif
#endif
#if defined(ARCH_ARM_CORTEX_M7) || \
defined(SOC_HPM6000) || defined(SOC_HPM6E00) || defined(SOC_HPM6P00) || \
#if defined(ARCH_ARM_CORTEX_M7) || \
defined(ARCH_ARM_CORTEX_A) || \
defined(ARCH_RISCV64) || \
defined(SOC_HPM6200) || defined(SOC_HPM6300) || defined(SOC_HPM6700) || defined(SOC_HPM6800) || \
defined(SOC_HPM6E00) || defined(SOC_HPM6P00) || \
defined(BSP_USING_BL61X) || defined(BSP_USING_BL808)
#ifndef RT_USING_CACHE
#error RT_USING_CACHE must be enabled in this chip
@@ -27,6 +30,6 @@
#ifdef RT_USING_CACHE
#ifndef CONFIG_USB_DCACHE_ENABLE
#warning CONFIG_USB_DCACHE_ENABLE must be enabled if you do not config nocache ram
#error CONFIG_USB_DCACHE_ENABLE must be enabled if you do not config nocache ram
#endif
#endif

View File

@@ -76,9 +76,8 @@ static rt_err_t usbd_serial_open(struct rt_device *dev, rt_uint16_t oflag)
serial = (struct usbd_serial *)dev;
if (!usb_device_is_configured(serial->busid)) {
USB_LOG_ERR("USB device is not configured\n");
return -RT_EPERM;
while(!usb_device_is_configured(serial->busid)) {
rt_thread_mdelay(10);
}
usbd_ep_start_read(serial->busid, serial->out_ep,
@@ -123,9 +122,8 @@ static rt_ssize_t usbd_serial_write(struct rt_device *dev,
}
align_buf = (rt_uint8_t *)buffer;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = rt_malloc_align(size, CONFIG_USB_ALIGN_SIZE);
align_buf = rt_malloc_align(USB_ALIGN_UP(size, CONFIG_USB_ALIGN_SIZE), CONFIG_USB_ALIGN_SIZE);
if (!align_buf) {
USB_LOG_ERR("serial get align buf failed\n");
return 0;
@@ -133,7 +131,7 @@ static rt_ssize_t usbd_serial_write(struct rt_device *dev,
usb_memcpy(align_buf, buffer, size);
}
#endif
usb_osal_sem_reset(serial->tx_done);
usbd_ep_start_write(serial->busid, serial->in_ep, align_buf, size);
ret = usb_osal_sem_take(serial->tx_done, 3000);
@@ -144,11 +142,9 @@ static rt_ssize_t usbd_serial_write(struct rt_device *dev,
ret = size;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
rt_free_align(align_buf);
}
#endif
return ret;
}

View File

@@ -38,7 +38,7 @@ static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
rt_uint8_t *align_buf;
align_buf = (rt_uint8_t *)buffer;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = rt_malloc_align(size * msc_class->blocksize, CONFIG_USB_ALIGN_SIZE);
if (!align_buf) {
@@ -47,18 +47,18 @@ static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
}
} else {
}
#endif
ret = usbh_msc_scsi_read10(msc_class, pos, (uint8_t *)align_buf, size);
if (ret < 0) {
rt_kprintf("usb mass_storage read failed\n");
return 0;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
usb_memcpy(buffer, align_buf, size * msc_class->blocksize);
rt_free_align(align_buf);
}
#endif
return size;
}
@@ -70,7 +70,7 @@ static rt_ssize_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buff
rt_uint8_t *align_buf;
align_buf = (rt_uint8_t *)buffer;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = rt_malloc_align(size * msc_class->blocksize, CONFIG_USB_ALIGN_SIZE);
if (!align_buf) {
@@ -80,17 +80,16 @@ static rt_ssize_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buff
usb_memcpy(align_buf, buffer, size * msc_class->blocksize);
}
#endif
ret = usbh_msc_scsi_write10(msc_class, pos, (uint8_t *)align_buf, size);
if (ret < 0) {
rt_kprintf("usb mass_storage write failed\n");
return 0;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
rt_free_align(align_buf);
}
#endif
return size;
}

View File

@@ -25,7 +25,7 @@
#endif
#ifndef LWIP_NO_RX_THREAD
#error must enable LWIP_NO_RX_THREAD, we do not use rtthread eth rx thread
#warning suggest you to enable LWIP_NO_RX_THREAD, we do not use rtthread eth rx thread
#endif
#ifndef LWIP_NO_TX_THREAD
@@ -33,7 +33,7 @@
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT != 1
#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1 for better performance, usb handles eth input with own thread
#endif
#if LWIP_TCPIP_CORE_LOCKING != 1

View File

@@ -193,9 +193,9 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
serial = (struct usbh_serial *)dev;
align_buf = (rt_uint8_t *)buffer;
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = rt_malloc_align(size, CONFIG_USB_ALIGN_SIZE);
align_buf = rt_malloc_align(USB_ALIGN_UP(size, CONFIG_USB_ALIGN_SIZE), CONFIG_USB_ALIGN_SIZE);
if (!align_buf) {
USB_LOG_ERR("serial get align buf failed\n");
return 0;
@@ -203,7 +203,6 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
usb_memcpy(align_buf, buffer, size);
}
#endif
switch (serial->type) {
#if defined(PKG_CHERRYUSB_HOST_CDC_ACM) || defined(RT_CHERRYUSB_HOST_CDC_ACM)
@@ -211,10 +210,7 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
ret = usbh_cdc_acm_bulk_out_transfer((struct usbh_cdc_acm *)dev->user_data, (uint8_t *)align_buf, size, RT_WAITING_FOREVER);
if (ret < 0) {
USB_LOG_ERR("usbh_cdc_acm_bulk_out_transfer failed: %d\n", ret);
#ifdef CONFIG_USB_DCACHE_ENABLE
rt_free_align(align_buf);
#endif
return 0;
ret = 0;
}
break;
#endif
@@ -223,10 +219,7 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
ret = usbh_ftdi_bulk_out_transfer((struct usbh_ftdi *)dev->user_data, (uint8_t *)align_buf, size, RT_WAITING_FOREVER);
if (ret < 0) {
USB_LOG_ERR("usbh_ftdi_bulk_out_transfer failed: %d\n", ret);
#ifdef CONFIG_USB_DCACHE_ENABLE
rt_free_align(align_buf);
#endif
return 0;
ret = 0;
}
break;
#endif
@@ -235,10 +228,7 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
ret = usbh_ch34x_bulk_out_transfer((struct usbh_ch34x *)dev->user_data, (uint8_t *)align_buf, size, RT_WAITING_FOREVER);
if (ret < 0) {
USB_LOG_ERR("usbh_ch34x_bulk_out_transfer failed: %d\n", ret);
#ifdef CONFIG_USB_DCACHE_ENABLE
rt_free_align(align_buf);
#endif
return 0;
ret = 0;
}
break;
#endif
@@ -247,10 +237,7 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
ret = usbh_pl2303_bulk_out_transfer((struct usbh_pl2303 *)dev->user_data, (uint8_t *)align_buf, size, RT_WAITING_FOREVER);
if (ret < 0) {
USB_LOG_ERR("usbh_pl2303_bulk_out_transfer failed: %d\n", ret);
#ifdef CONFIG_USB_DCACHE_ENABLE
rt_free_align(align_buf);
#endif
return 0;
ret = 0;
}
break;
#endif
@@ -258,11 +245,9 @@ static rt_ssize_t usbh_serial_write(struct rt_device *dev,
break;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
if ((uint32_t)buffer & (CONFIG_USB_ALIGN_SIZE - 1)) {
rt_free_align(align_buf);
}
#endif
return ret;
}

View File

@@ -202,7 +202,6 @@ VOID _fx_usbh_msc_driver(FX_MEDIA *media_ptr)
media_ptr->fx_media_driver_status = FX_IO_ERROR;
return;
}
printf("read success\r\n");
/* Successful driver request. */
media_ptr->fx_media_driver_status = FX_SUCCESS;
break;

View File

@@ -594,10 +594,15 @@ int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, ui
return -2;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
USB_ASSERT_MSG(!((uintptr_t)data % CONFIG_USB_ALIGN_SIZE), "data is not aligned %d", CONFIG_USB_ALIGN_SIZE);
#endif
g_chipidea_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_chipidea_udc[busid].in_ep[ep_idx].xfer_len = data_len;
g_chipidea_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
usb_dcache_clean((uintptr_t)data, USB_ALIGN_UP(data_len, CONFIG_USB_ALIGN_SIZE));
chipidea_start_xfer(busid, ep, (uint8_t *)data, data_len);
return 0;
@@ -614,10 +619,15 @@ int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t
return -2;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
USB_ASSERT_MSG(!((uintptr_t)data % CONFIG_USB_ALIGN_SIZE), "data is not aligned %d", CONFIG_USB_ALIGN_SIZE);
#endif
g_chipidea_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_chipidea_udc[busid].out_ep[ep_idx].xfer_len = data_len;
g_chipidea_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
usb_dcache_invalidate((uintptr_t)data, USB_ALIGN_UP(data_len, CONFIG_USB_ALIGN_SIZE));
chipidea_start_xfer(busid, ep, data, data_len);
return 0;
@@ -649,7 +659,7 @@ void USBD_IRQHandler(uint8_t busid)
memset(g_chipidea_udc[busid].in_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
memset(g_chipidea_udc[busid].out_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
usbd_event_reset_handler(busid);
chipidea_bus_reset(busid, 64);
chipidea_bus_reset(busid, g_chipidea_udc[busid].in_ep[0].ep_mps);
}
if (int_status & intr_suspend) {
@@ -712,6 +722,7 @@ void USBD_IRQHandler(uint8_t busid)
if (ep_addr & 0x80) {
usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
} else {
usb_dcache_invalidate((uintptr_t)g_chipidea_udc[busid].out_ep[ep_idx].xfer_buf, USB_ALIGN_UP(transfer_len, CONFIG_USB_ALIGN_SIZE));
usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
}
}

View File

@@ -15,6 +15,13 @@
#ifndef __UNALIGNED_UINT32_READ
#define __UNALIGNED_UINT32_READ(addr) (*((const __packed uint32_t *)(addr)))
#endif
#elif defined (__ICCARM__)
#ifndef __UNALIGNED_UINT32_WRITE
#define __UNALIGNED_UINT32_WRITE(addr, val) ((*((__packed uint32_t *)(addr))) = (val))
#endif
#ifndef __UNALIGNED_UINT32_READ
#define __UNALIGNED_UINT32_READ(addr) (*((const __packed uint32_t *)(addr)))
#endif
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#ifndef __UNALIGNED_UINT32_WRITE
#pragma clang diagnostic push
@@ -334,6 +341,8 @@ static void dwc2_ep0_start_read_setup(uint8_t busid, uint8_t *psetup)
USB_OTG_OUTEP(0U)->DOEPTSIZ |= USB_OTG_DOEPTSIZ_STUPCNT;
if (g_dwc2_udc[busid].user_params.device_dma_enable) {
usb_dcache_invalidate((uintptr_t)&g_dwc2_udc[busid].setup, USB_ALIGN_UP(8, CONFIG_USB_ALIGN_SIZE));
USB_OTG_OUTEP(0U)->DOEPDMA = (uint32_t)psetup;
/* EP enable */
USB_OTG_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_USBAEP;
@@ -675,6 +684,7 @@ uint8_t usbd_get_port_speed(uint8_t busid)
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
uint16_t ep_mps;
USB_ASSERT_MSG(ep_idx < (g_dwc2_udc[busid].hw_params.num_dev_ep + 1), "Ep addr %02x overflow", ep->bEndpointAddress);
@@ -682,14 +692,34 @@ int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
g_dwc2_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_dwc2_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
if (ep_idx == 0) {
switch (ep_mps) {
case 64:
ep_mps = EP_MPS_64;
break;
case 32:
ep_mps = EP_MPS_32;
break;
case 16:
ep_mps = EP_MPS_16;
break;
case 8:
ep_mps = EP_MPS_8;
break;
default:
ep_mps = EP_MPS_64;
break;
}
}
USB_OTG_DEV->DAINTMSK |= USB_OTG_DAINTMSK_OEPM & (uint32_t)(1UL << (16 + ep_idx));
if ((USB_OTG_OUTEP(ep_idx)->DOEPCTL & USB_OTG_DOEPCTL_USBAEP) == 0) {
USB_OTG_OUTEP(ep_idx)->DOEPCTL |= (USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize) & USB_OTG_DOEPCTL_MPSIZ) |
((uint32_t)USB_GET_ENDPOINT_TYPE(ep->bmAttributes) << 18) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DOEPCTL_USBAEP;
}
USB_OTG_OUTEP(ep_idx)->DOEPCTL |= (ep_mps & USB_OTG_DOEPCTL_MPSIZ) |
((uint32_t)USB_GET_ENDPOINT_TYPE(ep->bmAttributes) << 18) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DOEPCTL_USBAEP;
} else {
uint16_t fifo_size;
if (ep_idx == 0) {
@@ -703,14 +733,34 @@ int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
g_dwc2_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_dwc2_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
if (ep_idx == 0) {
switch (ep_mps) {
case 64:
ep_mps = EP_MPS_64;
break;
case 32:
ep_mps = EP_MPS_32;
break;
case 16:
ep_mps = EP_MPS_16;
break;
case 8:
ep_mps = EP_MPS_8;
break;
default:
ep_mps = EP_MPS_64;
break;
}
}
USB_OTG_DEV->DAINTMSK |= USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << ep_idx);
if ((USB_OTG_INEP(ep_idx)->DIEPCTL & USB_OTG_DIEPCTL_USBAEP) == 0) {
USB_OTG_INEP(ep_idx)->DIEPCTL |= (USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize) & USB_OTG_DIEPCTL_MPSIZ) |
((uint32_t)USB_GET_ENDPOINT_TYPE(ep->bmAttributes) << 18) | (ep_idx << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DIEPCTL_USBAEP;
}
USB_OTG_INEP(ep_idx)->DIEPCTL |= (ep_mps & USB_OTG_DIEPCTL_MPSIZ) |
((uint32_t)USB_GET_ENDPOINT_TYPE(ep->bmAttributes) << 18) | (ep_idx << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM |
USB_OTG_DIEPCTL_USBAEP;
dwc2_flush_txfifo(busid, ep_idx);
}
return 0;
@@ -782,7 +832,6 @@ int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
}
if ((ep_idx == 0) && g_dwc2_udc[busid].user_params.device_dma_enable) {
usb_dcache_invalidate((uintptr_t)&g_dwc2_udc[busid].setup, USB_ALIGN_UP(8, CONFIG_USB_ALIGN_SIZE));
dwc2_ep0_start_read_setup(busid, (uint8_t *)&g_dwc2_udc[busid].setup);
}
@@ -1046,7 +1095,7 @@ void USBD_IRQHandler(uint8_t busid)
usbd_event_ep_out_complete_handler(busid, ep_idx, g_dwc2_udc[busid].out_ep[ep_idx].actual_xfer_len);
}
}
// clang-format off
// clang-format off
process_setup:
// clang-format on
if ((epint & USB_OTG_DOEPINT_STUP) == USB_OTG_DOEPINT_STUP) {

View File

@@ -1,29 +1,296 @@
/*
* Copyright (c) 2024, sakumisu
* Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-08-08 CDT first version
*/
#include "usb_config.h"
#include "usb_dwc2_reg.h"
/* When using [GPIO_SetFunc(USBF_VBUS_PORT, USBF_VBUS_PIN, USBF_VBUS_FUNC);], there is no need to configure GOTGCTL */
#include "usbd_core.h"
#include "usbh_core.h"
#include "usb_dwc2_param.h"
#define USB_OTG_GLB ((DWC2_GlobalTypeDef *)(reg_base))
#include "board_config.h"
uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
#if defined(RT_CHERRYUSB_HOST) && defined(RT_CHERRYUSB_DEVICE)
#if defined(HC32F460) || defined(HC32F472)
#error "Only one USB role can be selected!"
#endif
#endif
const struct dwc2_user_params param_fs_core =
{
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
.device_dma_enable = true,
#else
.device_dma_enable = false,
#endif
.device_dma_desc_enable = false,
.device_rx_fifo_size = CONFIG_USB_FS_CORE_DEVICE_RX_FIFO_SIZE,
.device_tx_fifo_size = {
[0] = CONFIG_USB_FS_CORE_DEVICE_TX0_FIFO_SIZE,
[1] = CONFIG_USB_FS_CORE_DEVICE_TX1_FIFO_SIZE,
[2] = CONFIG_USB_FS_CORE_DEVICE_TX2_FIFO_SIZE,
[3] = CONFIG_USB_FS_CORE_DEVICE_TX3_FIFO_SIZE,
[4] = CONFIG_USB_FS_CORE_DEVICE_TX4_FIFO_SIZE,
[5] = CONFIG_USB_FS_CORE_DEVICE_TX5_FIFO_SIZE,
#if defined(HC32F4A0) || defined(HC32F4A8)
[6] = CONFIG_USB_FS_CORE_DEVICE_TX6_FIFO_SIZE,
[7] = CONFIG_USB_FS_CORE_DEVICE_TX7_FIFO_SIZE,
[8] = CONFIG_USB_FS_CORE_DEVICE_TX8_FIFO_SIZE,
[9] = CONFIG_USB_FS_CORE_DEVICE_TX9_FIFO_SIZE,
[10] = CONFIG_USB_FS_CORE_DEVICE_TX10_FIFO_SIZE,
[11] = CONFIG_USB_FS_CORE_DEVICE_TX11_FIFO_SIZE,
[12] = CONFIG_USB_FS_CORE_DEVICE_TX12_FIFO_SIZE,
[13] = CONFIG_USB_FS_CORE_DEVICE_TX13_FIFO_SIZE,
[14] = CONFIG_USB_FS_CORE_DEVICE_TX14_FIFO_SIZE,
[15] = CONFIG_USB_FS_CORE_DEVICE_TX15_FIFO_SIZE
#elif defined(HC32F460) || defined(HC32F472)
[6] = 0,
[7] = 0,
[8] = 0,
[9] = 0,
[10] = 0,
[11] = 0,
[12] = 0,
[13] = 0,
[14] = 0,
[15] = 0
#endif
},
.total_fifo_size = CONFIG_USB_FS_CORE_TOTAL_FIFO_SIZE,
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
USB_OTG_GLB->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
return 0;
.host_dma_desc_enable = false,
.host_rx_fifo_size = CONFIG_USB_FS_CORE_HOST_RX_FIFO_SIZE,
.host_nperio_tx_fifo_size = CONFIG_USB_FS_CORE_HOST_NP_FIFO_SIZE,
.host_perio_tx_fifo_size = CONFIG_USB_FS_CORE_HOST_PE_FIFO_SIZE,
.device_gccfg = 0,
.host_gccfg = 0,
#if defined(HC32F4A0) || defined(HC32F4A8) || defined(HC32F460)
.b_session_valid_override = false,
#elif defined(HC32F472)
.b_session_valid_override = true,
#endif
};
#if defined(HC32F4A0) || defined(HC32F4A8)
const struct dwc2_user_params param_hs_core =
{
#ifdef CONFIG_USB_HS
.phy_type = DWC2_PHY_TYPE_PARAM_UTMI,
#else
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
#endif
#ifdef CONFIG_USB_DWC2_DMA_ENABLE
.device_dma_enable = true,
#else
.device_dma_enable = false,
#endif
.device_dma_desc_enable = false,
.device_rx_fifo_size = CONFIG_USB_HS_CORE_DEVICE_RX_FIFO_SIZE,
.device_tx_fifo_size = {
[0] = CONFIG_USB_HS_CORE_DEVICE_TX0_FIFO_SIZE,
[1] = CONFIG_USB_HS_CORE_DEVICE_TX1_FIFO_SIZE,
[2] = CONFIG_USB_HS_CORE_DEVICE_TX2_FIFO_SIZE,
[3] = CONFIG_USB_HS_CORE_DEVICE_TX3_FIFO_SIZE,
[4] = CONFIG_USB_HS_CORE_DEVICE_TX4_FIFO_SIZE,
[5] = CONFIG_USB_HS_CORE_DEVICE_TX5_FIFO_SIZE,
[6] = CONFIG_USB_HS_CORE_DEVICE_TX6_FIFO_SIZE,
[7] = CONFIG_USB_HS_CORE_DEVICE_TX7_FIFO_SIZE,
[8] = CONFIG_USB_HS_CORE_DEVICE_TX8_FIFO_SIZE,
[9] = CONFIG_USB_HS_CORE_DEVICE_TX9_FIFO_SIZE,
[10] = CONFIG_USB_HS_CORE_DEVICE_TX10_FIFO_SIZE,
[11] = CONFIG_USB_HS_CORE_DEVICE_TX11_FIFO_SIZE,
[12] = CONFIG_USB_HS_CORE_DEVICE_TX12_FIFO_SIZE,
[13] = CONFIG_USB_HS_CORE_DEVICE_TX13_FIFO_SIZE,
[14] = CONFIG_USB_HS_CORE_DEVICE_TX14_FIFO_SIZE,
[15] = CONFIG_USB_HS_CORE_DEVICE_TX15_FIFO_SIZE
},
.total_fifo_size = CONFIG_USB_HS_CORE_TOTAL_FIFO_SIZE,
.host_dma_desc_enable = false,
.host_rx_fifo_size = CONFIG_USB_HS_CORE_HOST_RX_FIFO_SIZE,
.host_nperio_tx_fifo_size = CONFIG_USB_HS_CORE_HOST_NP_FIFO_SIZE,
.host_perio_tx_fifo_size = CONFIG_USB_HS_CORE_HOST_PE_FIFO_SIZE,
.device_gccfg = 0,
.host_gccfg = 0,
.b_session_valid_override = false,
};
#endif
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
{
#if defined(HC32F4A0) || defined(HC32F4A8)
if (reg_base == CM_USBHS_BASE)
{
memcpy(params, &param_hs_core, sizeof(struct dwc2_user_params));
}
else
#endif
{
memcpy(params, &param_fs_core, sizeof(struct dwc2_user_params));
}
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++)
{
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
}
#endif
}
#endif
#define BOARD_INIT_USB_HOST_MODE (0U)
#define BOARD_INIT_USB_DEVICE_MODE (1U)
extern rt_err_t rt_hw_usbfs_board_init(uint8_t devmode);
static uint8_t g_usb_fs_busid = 0U;
#if defined(HC32F4A0) || defined(HC32F4A8)
extern rt_err_t rt_hw_usbhs_board_init(uint8_t devmode);
static uint8_t g_usb_hs_busid = 0U;
#endif
#if defined(RT_CHERRYUSB_HOST)
static void usbh_fs_irq_handler(void)
{
USBH_IRQHandler(g_usb_fs_busid);
}
uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
#if defined(HC32F4A0) || defined(HC32F4A8)
static void usbh_hs_irq_handler(void)
{
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOEN;
USB_OTG_GLB->GOTGCTL &= ~USB_OTG_GOTGCTL_BVALOVAL;
return 0;
USBH_IRQHandler(g_usb_hs_busid);
}
#endif
#if defined(HC32F472)
void USBFS_Handler(void)
{
usbh_fs_irq_handler();
}
#endif
void usb_hc_low_level_init(struct usbh_bus *bus)
{
struct hc32_irq_config irq_config;
#if defined(HC32F4A0) || defined(HC32F4A8)
if (bus->hcd.reg_base == CM_USBHS_BASE)
{
g_usb_hs_busid = bus->hcd.hcd_id;
rt_hw_usbhs_board_init(BOARD_INIT_USB_HOST_MODE);
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBHS, ENABLE);
#ifndef CONFIG_USB_HS
/* enable the embedded PHY in USBHS mode */
CM_PERIC->USB_SYCTLREG |= PERIC_USB_SYCTLREG_USBHS_FSPHYE;
#endif
irq_config.irq_num = BSP_USBHS_GLB_IRQ_NUM;
irq_config.int_src = INT_SRC_USBHS_GLB;
irq_config.irq_prio = BSP_USBHS_GLB_IRQ_PRIO;
/* register interrupt */
hc32_install_irq_handler(&irq_config,
usbh_hs_irq_handler,
RT_TRUE);
}
else
#endif
{
g_usb_fs_busid = bus->hcd.hcd_id;
rt_hw_usbfs_board_init(BOARD_INIT_USB_HOST_MODE);
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBFS, ENABLE);
irq_config.irq_num = BSP_USBFS_GLB_IRQ_NUM;
irq_config.int_src = INT_SRC_USBFS_GLB;
irq_config.irq_prio = BSP_USBFS_GLB_IRQ_PRIO;
/* register interrupt */
hc32_install_irq_handler(&irq_config,
usbh_fs_irq_handler,
RT_TRUE);
}
}
#endif
#if defined(RT_CHERRYUSB_DEVICE)
static void usbd_fs_irq_handler(void)
{
USBD_IRQHandler(g_usb_fs_busid);
}
#if defined(HC32F4A0) || defined(HC32F4A8)
static void usbd_hs_irq_handler(void)
{
USBD_IRQHandler(g_usb_hs_busid);
}
#endif
#if defined(HC32F472)
void USBFS_Handler(void)
{
usbd_fs_irq_handler();
}
#endif
void usb_dc_low_level_init(uint8_t busid)
{
struct hc32_irq_config irq_config;
#if defined(HC32F4A0) || defined(HC32F4A8)
if (g_usbdev_bus[busid].reg_base == CM_USBHS_BASE)
{
g_usb_hs_busid = busid;
rt_hw_usbhs_board_init(BOARD_INIT_USB_DEVICE_MODE);
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBHS, ENABLE);
#ifndef CONFIG_USB_HS
/* enable the embedded PHY in USBHS mode */
CM_PERIC->USB_SYCTLREG |= PERIC_USB_SYCTLREG_USBHS_FSPHYE;
#endif
irq_config.irq_num = BSP_USBHS_GLB_IRQ_NUM;
irq_config.int_src = INT_SRC_USBHS_GLB;
irq_config.irq_prio = BSP_USBHS_GLB_IRQ_PRIO;
/* register interrupt */
hc32_install_irq_handler(&irq_config,
usbd_hs_irq_handler,
RT_TRUE);
}
else
#endif
{
g_usb_fs_busid = busid;
rt_hw_usbfs_board_init(BOARD_INIT_USB_DEVICE_MODE);
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBFS, ENABLE);
irq_config.irq_num = BSP_USBFS_GLB_IRQ_NUM;
irq_config.int_src = INT_SRC_USBFS_GLB;
irq_config.irq_prio = BSP_USBFS_GLB_IRQ_PRIO;
/* register interrupt */
hc32_install_irq_handler(&irq_config,
usbd_fs_irq_handler,
RT_TRUE);
}
}
void usb_dc_low_level_deinit(uint8_t busid)
{
(void)busid;
/* reserved */
}
#endif
extern uint32_t SystemCoreClock;

View File

@@ -16,10 +16,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -50,10 +50,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -124,10 +124,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -212,10 +212,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -380,10 +380,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -446,10 +446,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,
@@ -481,10 +481,10 @@ const struct dwc2_user_params param_pa11_pa12 = {
.phy_type = DWC2_PHY_TYPE_PARAM_FS,
.device_dma_enable = false,
.device_dma_desc_enable = false,
.device_rx_fifo_size = (320 - 16 - 16 - 16 - 16),
.device_rx_fifo_size = (320 - 16 - 64 - 16 - 16),
.device_tx_fifo_size = {
[0] = 16, // 64 byte
[1] = 16, // 64 byte
[1] = 64, // 256 byte
[2] = 16, // 64 byte
[3] = 16, // 64 byte
[4] = 0,

View File

@@ -1337,6 +1337,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
EHCI_HCOR->usbcmd |= (EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
qh = (struct ehci_qh_hw *)urb->hcpriv;
qh->remove_in_iaad = 0;
urb->errorcode = -USB_ERR_SHUTDOWN;
if (urb->timeout) {
@@ -1347,6 +1348,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
if (remove_in_iaad) {
volatile uint32_t timeout = 0;
EHCI_HCOR->usbsts = EHCI_USBSTS_IAA;
EHCI_HCOR->usbcmd |= EHCI_USBCMD_IAAD;
while (!(EHCI_HCOR->usbsts & EHCI_USBSTS_IAA)) {
timeout++;

View File

@@ -102,7 +102,9 @@ int usb_dc_init(uint8_t busid)
#endif
usb_device_init(g_hpm_udc[busid].handle, int_mask);
#ifdef CONFIG_USB_OTG_ENABLE
usb_otgsc_enable_id_chg_int(g_hpm_udc[busid].handle->regs);
#endif
usb_dc_isr_connect(busid);
return 0;
@@ -240,10 +242,15 @@ int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, ui
return -2;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
USB_ASSERT_MSG(!((uintptr_t)data % CONFIG_USB_ALIGN_SIZE), "data is not aligned %d", CONFIG_USB_ALIGN_SIZE);
#endif
g_hpm_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_hpm_udc[busid].in_ep[ep_idx].xfer_len = data_len;
g_hpm_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
usb_dcache_clean((uintptr_t)data, USB_ALIGN_UP(data_len, CONFIG_USB_ALIGN_SIZE));
usb_device_edpt_xfer(handle, ep, (uint8_t *)data, data_len);
return 0;
@@ -261,10 +268,15 @@ int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t
return -2;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
USB_ASSERT_MSG(!((uintptr_t)data % CONFIG_USB_ALIGN_SIZE), "data is not aligned %d", CONFIG_USB_ALIGN_SIZE);
#endif
g_hpm_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_hpm_udc[busid].out_ep[ep_idx].xfer_len = data_len;
g_hpm_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
usb_dcache_invalidate((uintptr_t)data, USB_ALIGN_UP(data_len, CONFIG_USB_ALIGN_SIZE));
usb_device_edpt_xfer(handle, ep, data, data_len);
return 0;
@@ -297,7 +309,7 @@ void USBD_IRQHandler(uint8_t busid)
memset(g_hpm_udc[busid].in_ep, 0, sizeof(struct hpm_ep_state) * USB_NUM_BIDIR_ENDPOINTS);
memset(g_hpm_udc[busid].out_ep, 0, sizeof(struct hpm_ep_state) * USB_NUM_BIDIR_ENDPOINTS);
usbd_event_reset_handler(busid);
usb_device_bus_reset(handle, 64);
usb_device_bus_reset(handle, g_hpm_udc[busid].in_ep[0].ep_mps);
}
if (int_status & intr_suspend) {
@@ -362,6 +374,7 @@ void USBD_IRQHandler(uint8_t busid)
if (ep_addr & 0x80) {
usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
} else {
usb_dcache_invalidate((uintptr_t)g_hpm_udc[busid].out_ep[ep_idx].xfer_buf, USB_ALIGN_UP(transfer_len, CONFIG_USB_ALIGN_SIZE));
usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
}
}

View File

@@ -7,11 +7,73 @@
#include "hpm_common.h"
#include "hpm_soc.h"
#include "hpm_l1c_drv.h"
#include "hpm_usb_drv.h"
#include "usb_config.h"
void (*g_usb_hpm_irq[2])(uint8_t busid);
uint8_t g_usb_hpm_busid[2];
#ifndef CONFIG_CHERRYUSB_CUSTOM_IRQ_HANDLER
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, hpm_isr_usb0)
#ifdef HPM_USB1_BASE
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, hpm_isr_usb1)
#endif
#endif
#ifdef CONFIG_USB_OTG_ENABLE
#include "usbotg_core.h"
int usb_otg_init(uint8_t busid)
{
(void)busid;
return 0;
}
int usb_otg_deinit(uint8_t busid)
{
(void)busid;
return 0;
}
void hpm_isr_usb0(void)
{
if (usb_otgsc_get_id_chg_flag(HPM_USB0)) {
usb_otgsc_clear_id_chg_flag(HPM_USB0);
usbotg_trigger_role_change(g_usb_hpm_busid[0], usb_otgsc_get_id_status(HPM_USB0) ? USBOTG_MODE_DEVICE : USBOTG_MODE_HOST);
}
USBOTG_IRQHandler(g_usb_hpm_busid[0]);
}
#ifdef HPM_USB1_BASE
void hpm_isr_usb1(void)
{
if (usb_otgsc_get_id_chg_flag(HPM_USB1)) {
usb_otgsc_clear_id_chg_flag(HPM_USB1);
usbotg_trigger_role_change(g_usb_hpm_busid[1], usb_otgsc_get_id_status(HPM_USB1) ? USBOTG_MODE_DEVICE : USBOTG_MODE_HOST);
}
USBOTG_IRQHandler(g_usb_hpm_busid[1]);
}
#endif
#else
void hpm_isr_usb0(void)
{
g_usb_hpm_irq[0](g_usb_hpm_busid[0]);
}
#ifdef HPM_USB1_BASE
void hpm_isr_usb1(void)
{
g_usb_hpm_irq[1](g_usb_hpm_busid[1]);
}
#endif
#endif
ATTR_WEAK void hpm_usb_isr_enable(uint32_t base)
{
if (base == HPM_USB0_BASE) {
@@ -34,24 +96,6 @@ ATTR_WEAK void hpm_usb_isr_disable(uint32_t base)
}
}
#ifndef CONFIG_CHERRYUSB_CUSTOM_IRQ_HANDLER
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, hpm_isr_usb0)
#endif
void hpm_isr_usb0(void)
{
g_usb_hpm_irq[0](g_usb_hpm_busid[0]);
}
#ifdef HPM_USB1_BASE
#ifndef CONFIG_CHERRYUSB_CUSTOM_IRQ_HANDLER
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, hpm_isr_usb1)
#endif
void hpm_isr_usb1(void)
{
g_usb_hpm_irq[1](g_usb_hpm_busid[1]);
}
#endif
#ifdef CONFIG_USB_DCACHE_ENABLE
void usb_dcache_clean(uintptr_t addr, size_t size)
{
@@ -67,4 +111,4 @@ void usb_dcache_flush(uintptr_t addr, size_t size)
{
l1c_dc_flush(addr, size);
}
#endif
#endif

View File

@@ -57,31 +57,29 @@ void usb_hc_low_level2_init(struct usbh_bus *bus)
if (bus->hcd.reg_base == HPM_USB0_BASE) {
g_usb_hpm_busid[0] = bus->hcd.hcd_id;
g_usb_hpm_irq[0] = USBH_IRQHandler;
hpm_usb_isr_enable(HPM_USB0_BASE);
} else {
#ifdef HPM_USB1_BASE
g_usb_hpm_busid[1] = bus->hcd.hcd_id;
g_usb_hpm_irq[1] = USBH_IRQHandler;
hpm_usb_isr_enable(HPM_USB1_BASE);
#endif
}
#ifdef CONFIG_USB_OTG_ENABLE
usb_otgsc_enable_id_chg_int((USB_Type *)(bus->hcd.reg_base));
#endif
hpm_usb_isr_enable(bus->hcd.reg_base);
}
void usb_hc_low_level_deinit(struct usbh_bus *bus)
{
usb_phy_deinit((USB_Type *)(bus->hcd.reg_base));
hpm_usb_isr_disable(bus->hcd.reg_base);
if (bus->hcd.reg_base == HPM_USB0_BASE) {
hpm_usb_isr_disable(HPM_USB0_BASE);
g_usb_hpm_busid[0] = 0;
g_usb_hpm_irq[0] = NULL;
} else {
#ifdef HPM_USB1_BASE
hpm_usb_isr_disable(HPM_USB1_BASE);
g_usb_hpm_busid[1] = 0;
g_usb_hpm_irq[1] = NULL;
#endif

View File

@@ -82,4 +82,12 @@ void usb_dc_low_level_deinit(uint8_t busid)
void usbd_kinetis_delay_ms(uint8_t ms)
{
#ifdef __RTTHREAD__
rt_thread_mdelay(ms);
#else
for (uint32_t i = 0; i < ms; i++)
{
for (volatile uint32_t j = 0; j < 10000; j++);
}
#endif
}

View File

@@ -328,10 +328,16 @@ void musb_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb
speed = USB_TYPE0_SPEED_LOW;
}
#ifdef CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
/* Without multipoint, use FADDR for host target addressing and do not access Hub/FuncAddr regs */
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = (urb->hport->dev_addr & 0x7F);
HWREGB(USB_TXTYPE_BASE(chidx)) = speed;
#else
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_TXTYPE_BASE(chidx)) = speed;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
#endif
musb_write_packet(bus, chidx, (uint8_t *)setup, 8);
HWREGB(USB_TXCSRL_BASE(chidx)) = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
@@ -360,12 +366,19 @@ int musb_bulk_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb
return -USB_ERR_RANGE;
}
#ifdef CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = (urb->hport->dev_addr & 0x7F);
HWREGB(USB_RXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_BULK;
HWREGH(USB_RXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_RXINTERVAL_BASE(chidx)) = 0;
#else
HWREGB(USB_RXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_RXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_BULK;
HWREGH(USB_RXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_RXINTERVAL_BASE(chidx)) = 0;
HWREGB(USB_RXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(chidx)) = 0;
#endif
HWREGB(USB_TXCSRH_BASE(chidx)) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_RXCSRL_BASE(chidx)) = USB_RXCSRL1_REQPKT;
@@ -376,12 +389,19 @@ int musb_bulk_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb
return -USB_ERR_RANGE;
}
#ifdef CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = (urb->hport->dev_addr & 0x7F);
HWREGB(USB_TXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_BULK;
HWREGH(USB_TXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_TXINTERVAL_BASE(chidx)) = 0;
#else
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_TXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_BULK;
HWREGH(USB_TXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_TXINTERVAL_BASE(chidx)) = 0;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
#endif
if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
buflen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
@@ -419,12 +439,19 @@ int musb_intr_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb
return -USB_ERR_RANGE;
}
#ifdef CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = (urb->hport->dev_addr & 0x7F);
HWREGB(USB_RXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_INT;
HWREGH(USB_RXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_RXINTERVAL_BASE(chidx)) = urb->ep->bInterval;
#else
HWREGB(USB_RXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_RXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_INT;
HWREGH(USB_RXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_RXINTERVAL_BASE(chidx)) = urb->ep->bInterval;
HWREGB(USB_RXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_RXHUBPORT_BASE(chidx)) = 0;
#endif
HWREGB(USB_TXCSRH_BASE(chidx)) &= ~USB_TXCSRH1_MODE;
HWREGB(USB_RXCSRL_BASE(chidx)) = USB_RXCSRL1_REQPKT;
@@ -435,12 +462,19 @@ int musb_intr_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb
return -USB_ERR_RANGE;
}
#ifdef CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = (urb->hport->dev_addr & 0x7F);
HWREGB(USB_TXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_INT;
HWREGH(USB_TXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_TXINTERVAL_BASE(chidx)) = urb->ep->bInterval;
#else
HWREGB(USB_TXADDR_BASE(chidx)) = urb->hport->dev_addr;
HWREGB(USB_TXTYPE_BASE(chidx)) = (urb->ep->bEndpointAddress & 0x0f) | speed | USB_TXTYPE1_PROTO_INT;
HWREGH(USB_TXMAP_BASE(chidx)) = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
HWREGB(USB_TXINTERVAL_BASE(chidx)) = urb->ep->bInterval;
HWREGB(USB_TXHUBADDR_BASE(chidx)) = 0;
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
#endif
if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
buflen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);

View File

@@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.15)
include(proj.conf)
find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE})
sdk_add_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_ECM)
sdk_add_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_NCM)
sdk_add_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_RNDIS)
sdk_add_compile_definitions(-DCONFIG_USBHOST_PLATFORM_ASIX)
sdk_add_compile_definitions(-DCONFIG_USBHOST_PLATFORM_RTL8152)
sdk_add_include_directories(inc)
target_sources(app PRIVATE ../../demo/usb_host.c)
set(CONFIG_CHERRYMP 1)
set(CONFIG_CHERRYUSB 1)
set(CONFIG_CHERRYUSB_DEVICE 1)
set(CONFIG_CHERRYUSB_HOST 1)
set(CONFIG_CHERRYUSB_DEVICE_CDC_RNDIS 1)
set(CONFIG_CHERRYUSB_DEVICE_CDC_ECM 1)
# add_subdirectory(src/cherryusb_hostuvcuac)
add_subdirectory(../.. cherryusb)
# sdk_add_link_options(-uusbd_cdc_acm_init_intf)
# sdk_add_link_options(-uusbd_hid_init_intf)
# sdk_add_link_options(-uusbd_msc_init_intf)
# sdk_add_link_options(-uusbd_video_init_intf)
# sdk_add_link_options(-uusbd_audio_init_intf)
# sdk_add_link_options(-uusbd_cdc_ecm_init_intf)
# sdk_add_link_options(-uusbd_rndis_init_intf)
# sdk_add_link_options(-uusbd_initialize)
# sdk_add_link_options(-uusbd_desc_register)
# sdk_add_link_options(-uusbd_add_interface)
# sdk_add_link_options(-uusbd_add_endpoint)
# sdk_add_link_options(-uusbd_rndis_start_write)
# sdk_add_link_options(-uusbd_rndis_start_read)
# sdk_add_link_options(-uusbd_cdc_ecm_start_write)
# sdk_add_link_options(-uusbd_cdc_ecm_start_read)
# sdk_add_link_options(-uusbd_video_stream_start_write)
# sdk_add_link_options(-uusbd_video_stream_split_transfer)
sdk_set_main_file(src/main.c)
project(cherryusb)

View File

@@ -0,0 +1,13 @@
SDK_DEMO_PATH ?= .
BL_SDK_BASE ?= /home/sakumisu/repo/bouffalolab/bouffalo_sdk_github
export BL_SDK_BASE
CHIP ?= bl616
BOARD ?= bl616dk
CROSS_COMPILE = riscv64-unknown-elf-
# add custom cmake definition
#cmake_definition+=-Dxxx=sss
include $(BL_SDK_BASE)/project.build

View File

@@ -0,0 +1,14 @@
[cfg]
# 0: no erase, 1:programmed section erase, 2: chip erase
erase = 1
# skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
skip_mode = 0x0, 0x0
# 0: not use isp mode, #1: isp mode
boot2_isp_mode = 0
pre_program =
pre_program_args =
[FW]
filedir = ./build/build_out/cherryusb*_$(CHIPNAME).bin
address = 0x000000

View File

@@ -0,0 +1,128 @@
/*
* FreeRTOS Kernel V10.2.1
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
#if defined(BL602) || defined(BL702) || defined(BL702L)
#define configMTIME_BASE_ADDRESS (0x02000000UL + 0xBFF8UL)
#define configMTIMECMP_BASE_ADDRESS (0x02000000UL + 0x4000UL)
#else
#if __riscv_xlen == 64
#define configMTIME_BASE_ADDRESS (0)
#define configMTIMECMP_BASE_ADDRESS ((0xE4000000UL) + 0x4000UL)
#else
#define configMTIME_BASE_ADDRESS ((0xE0000000UL) + 0xBFF8UL)
#define configMTIMECMP_BASE_ADDRESS ((0xE0000000UL) + 0x4000UL)
#endif
#endif
#define configSUPPORT_STATIC_ALLOCATION 1
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ((uint32_t)(1 * 1000 * 1000))
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES (32)
#define configMINIMAL_STACK_SIZE ((unsigned short)128) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */
#define configTOTAL_HEAP_SIZE ((size_t)24 * 1024)
#define configMAX_TASK_NAME_LEN (16)
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_POSIX_ERRNO 1
#define configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS 0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES (2)
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 4
#define configTIMER_TASK_STACK_DEPTH (512)
/* Task priorities. Allow these to be overridden. */
#ifndef uartPRIMARY_PRIORITY
#define uartPRIMARY_PRIORITY (configMAX_PRIORITIES - 3)
#endif
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
void vApplicationMallocFailedHook(void);
void vAssertCalled(void);
#include <stdio.h>
#define configASSERT(x) \
if ((x) == 0) { \
printf("file [%s]\r\n", __FILE__); \
printf("func [%s]\r\n", __FUNCTION__); \
printf("line [%d]\r\n", __LINE__); \
printf("%s\r\n", (const char *)(#x)); \
vAssertCalled(); \
}
#if (configUSE_TICKLESS_IDLE != 0)
void vApplicationSleep(uint32_t xExpectedIdleTime);
#define portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime) vApplicationSleep(xExpectedIdleTime)
#endif
// #define portUSING_MPU_WRAPPERS
#endif /* FREERTOS_CONFIG_H */

View File

@@ -0,0 +1,270 @@
/*---------------------------------------------------------------------------/
/ Configurations of FatFs Module
/---------------------------------------------------------------------------*/
/* User external configuration, User need to use this file as a template.
All configuration items must be included in the file */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_CONTINUOUS 1
/* Read and write as much data as possible at one time, regardless of the cluster size */
#define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_USE_FASTSEEK 1
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
#define FF_USE_STRFUNC 0
#define FF_PRINT_LLI 1
#define FF_PRINT_FLOAT 1
#define FF_STRF_ENCODE 3
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion.
/
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
/ makes f_printf() support floating point argument. These features want C99 or later.
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect code page setting can cause a file open failure.
/
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/
#define FF_USE_LFN 2
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
#define FF_LFN_UNICODE 0
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_FS_RPATH 0
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 5
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 2
#define FF_VOLUME_STRS "ram", "flash", "sd", "sd2", "usb"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table is needed as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 0
/* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ function will be available. */
#define FF_MIN_SS 512
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk, but a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
#define FF_LBA64 0
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
#define FF_MIN_GPT 0x10000000
/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2022
/* The option FF_FS_NORTC switches timestamp feature. If the system does not have
/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
/ timestamp feature. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at the first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
#define FF_FS_LOCK 0
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1.
/
/ 0: Disable file lock function. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock function. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this featuer.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
/ function, must be added to the project. Samples are available in ffsystem.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
*/
/*--- End of configuration options ---*/

View File

@@ -0,0 +1,442 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef LWIPOPTS_H
#define LWIPOPTS_H
#ifdef USE_LWIPOPTS_APP_H
#include "lwipopts_app.h"
#endif
/**
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
* critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#define SYS_LIGHTWEIGHT_PROT 1
#define IP_REASSEMBLY 0
#define IP_FRAG 0
#define ARP_QUEUEING 0
#define NO_SYS 0
#define LWIP_RAND rand
#define LWIP_NETIF_HOSTNAME 0
#define LWIP_TIMEVAL_PRIVATE 0
#define LWIP_TIMERS 1
#define LWIP_RAW 1
#define LWIP_IPV4 1
#define LWIP_IGMP 1
#define LWIP_ICMP 1
#define ICMP_TTL 64
#define LWIP_TCP 1
#define TCP_TTL 255
#define LWIP_UDP 1
#define UDP_TTL 255
#define LWIP_DNS 1
/**
* LWIP_NETIF_API==1: Support netif api (in netifapi.c)
*/
#define LWIP_NETIF_API 1
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN 1
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#define LWIP_SOCKET 1
/* ---------- Memory options ---------- */
#define MEMP_MEM_MALLOC 0
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#ifndef MEM_ALIGNMENT
#define MEM_ALIGNMENT 64
#endif
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#ifndef MEM_SIZE
#define MEM_SIZE (32 * 1024)
#endif
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#ifndef MEMP_NUM_PBUF
#define MEMP_NUM_PBUF 100
#endif
/**
* MEMP_NUM_RAW_PCB: Number of raw connection PCBs
* (requires the LWIP_RAW option)
*/
#ifndef MEMP_NUM_RAW_PCB
#define MEMP_NUM_RAW_PCB 4
#endif
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#ifndef MEMP_NUM_UDP_PCB
#define MEMP_NUM_UDP_PCB 4
#endif
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB
#define MEMP_NUM_TCP_PCB 4
#endif
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB_LISTEN
#define MEMP_NUM_TCP_PCB_LISTEN 5
#endif
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#ifndef MEMP_NUM_TCP_SEG
#define MEMP_NUM_TCP_SEG 40
#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL)
#endif
/**
* MEMP_NUM_NETCONN: the number of struct netconns.
* (only needed if you use the sequential API, like api_lib.c)
*/
#ifndef MEMP_NUM_NETCONN
#define MEMP_NUM_NETCONN 4
#endif
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#ifndef PBUF_POOL_SIZE
#define PBUF_POOL_SIZE 20
#endif
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#ifndef PBUF_POOL_BUFSIZE
#define PBUF_POOL_BUFSIZE 1600
#endif
/* ---------- TCP options ---------- */
/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#ifndef TCP_QUEUE_OOSEQ
#define TCP_QUEUE_OOSEQ 0
#endif
/* TCP Maximum segment size. */
#ifndef TCP_MSS
#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
#endif
/* TCP sender buffer space (bytes). */
#ifndef TCP_SND_BUF
#define TCP_SND_BUF (8 * TCP_MSS)
#endif
/* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF / TCP_MSS)
#endif
/* TCP receive window. */
#ifndef TCP_WND
#define TCP_WND (16 * TCP_MSS)
#endif
/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
#ifndef LWIP_DHCP
#define LWIP_DHCP 1
#endif
/* ---------- Statistics options ---------- */
#ifndef LWIP_STATS
#define LWIP_STATS 0
#endif
#ifndef LWIP_PROVIDE_ERRNO
#define LWIP_PROVIDE_ERRNO 1
#endif
/*
------------------------------------------------
---------- Network Interfaces options ----------
------------------------------------------------
*/
/**
* LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for
* small real-life targets. Some code like routing etc. can be left out.
*/
#ifndef LWIP_SINGLE_NETIF
#define LWIP_SINGLE_NETIF 1
#endif
/* ---------- link callback options ---------- */
/* LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
* whenever the link changes (i.e., link down)
*/
#ifndef LWIP_NETIF_LINK_CALLBACK
#define LWIP_NETIF_LINK_CALLBACK 1
#endif
/**
* LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP *tries* to put all data
* to be sent into one single pbuf. This is for compatibility with DMA-enabled
* MACs that do not support scatter-gather.
* Beware that this might involve CPU-memcpy before transmitting that would not
* be needed without this flag! Use this only if you need to!
*
* ATTENTION: a driver should *NOT* rely on getting single pbufs but check TX
* pbufs for being in one piece. If not, @ref pbuf_clone can be used to get
* a single pbuf:
* if (p->next != NULL) {
* struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
* if (q == NULL) {
* return ERR_MEM;
* }
* p = q; ATTENTION: do NOT free the old 'p' as the ref belongs to the caller!
* }
*/
#ifndef LWIP_NETIF_TX_SINGLE_PBUF
#define LWIP_NETIF_TX_SINGLE_PBUF 0
#endif
/*
--------------------------------------
---------- Checksum options ----------
--------------------------------------
*/
/*
* Some MCUs allow computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
* To use this feature let the following define uncommented.
* To disable it and process by CPU comment the the checksum.
*/
#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 0
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 0
/* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP 0
#else
/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 1
/* CHECKSUM_CHECK_ICMP==1: Check checksums by software for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP 1
#endif
/*
-----------------------------------
---------- DEBUG options ----------
-----------------------------------
*/
#ifdef LWIP_DEBUG
#ifndef LWIP_DBG_MIN_LEVEL
#define LWIP_DBG_MIN_LEVEL 0
#endif
#ifndef PPP_DEBUG
#define PPP_DEBUG LWIP_DBG_OFF
#endif
#ifndef MEM_DEBUG
#define MEM_DEBUG LWIP_DBG_OFF
#endif
#ifndef MEMP_DEBUG
#define MEMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef PBUF_DEBUG
#define PBUF_DEBUG LWIP_DBG_OFF
#endif
#ifndef API_LIB_DEBUG
#define API_LIB_DEBUG LWIP_DBG_OFF
#endif
#ifndef API_MSG_DEBUG
#define API_MSG_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCPIP_DEBUG
#define TCPIP_DEBUG LWIP_DBG_OFF
#endif
#ifndef NETIF_DEBUG
#define NETIF_DEBUG LWIP_DBG_OFF
#endif
#ifndef SOCKETS_DEBUG
#define SOCKETS_DEBUG LWIP_DBG_OFF
#endif
#ifndef DNS_DEBUG
#define DNS_DEBUG LWIP_DBG_OFF
#endif
#ifndef AUTOIP_DEBUG
#define AUTOIP_DEBUG LWIP_DBG_OFF
#endif
#ifndef DHCP_DEBUG
#define DHCP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IP_DEBUG
#define IP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IP_REASS_DEBUG
#define IP_REASS_DEBUG LWIP_DBG_OFF
#endif
#ifndef ICMP_DEBUG
#define ICMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IGMP_DEBUG
#define IGMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef UDP_DEBUG
#define UDP_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_DEBUG
#define TCP_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_INPUT_DEBUG
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_OUTPUT_DEBUG
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_RTO_DEBUG
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_CWND_DEBUG
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_WND_DEBUG
#define TCP_WND_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_FR_DEBUG
#define TCP_FR_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_QLEN_DEBUG
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_RST_DEBUG
#define TCP_RST_DEBUG LWIP_DBG_OFF
#endif
#ifndef ETHARP_DEBUG
#define ETHARP_DEBUG LWIP_DBG_OFF
#endif
#endif
/*
---------------------------------
---------- OS options ----------
---------------------------------
*/
#ifndef TCPIP_THREAD_NAME
#define TCPIP_THREAD_NAME "tcpip"
#endif
#ifndef TCPIP_THREAD_STACKSIZE
#define TCPIP_THREAD_STACKSIZE 2048
#endif
#ifndef TCPIP_MBOX_SIZE
#define TCPIP_MBOX_SIZE 8
#endif
#ifndef DEFAULT_RAW_RECVMBOX_SIZE
#define DEFAULT_RAW_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_UDP_RECVMBOX_SIZE
#define DEFAULT_UDP_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_TCP_RECVMBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_ACCEPTMBOX_SIZE
#define DEFAULT_ACCEPTMBOX_SIZE 50
#endif
#ifndef DEFAULT_THREAD_STACKSIZE
#define DEFAULT_THREAD_STACKSIZE 500
#endif
#ifndef TCPIP_THREAD_PRIO
#define TCPIP_THREAD_PRIO 10
#endif
#define LWIP_COMPAT_MUTEX 0
#define LWIP_TCPIP_CORE_LOCKING 1
#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#endif
#ifndef LWIP_MEM_SECTION
#define LWIP_MEM_SECTION ".bss"
#endif
// bouffalo patch
#define LWIP_DNS_SERVER 0
#define LWIP_SUPPORT_CUSTOM_PBUF 1
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(LWIP_MEM_SECTION)))
#endif /* __LWIPOPTS_H__ */

View File

@@ -0,0 +1,325 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
/* ================ USB common Configuration ================ */
#include "bflb_core.h"
#ifdef __RTTHREAD__
#include <rtthread.h>
#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
#else
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#endif
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#endif
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
// #define CONFIG_USB_DCACHE_ENABLE
/* data align size when use dma or use dcache */
#ifdef CONFIG_USB_DCACHE_ENABLE
#define CONFIG_USB_ALIGN_SIZE 32 // 32 or 64
#else
#define CONFIG_USB_ALIGN_SIZE 4
#endif
/* attribute data into no cache ram */
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
/* use usb_memcpy default for high performance but cost more flash memory.
* And, arm libc has a bug that memcpy() may cause data misalignment when the size is not a multiple of 4.
*/
// #define CONFIG_USB_MEMCPY_DISABLE
/* ================= USB Device Stack Configuration ================ */
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
*/
// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
/* Check if the input descriptor is correct */
// #define CONFIG_USBDEV_DESC_CHECK
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
/* enable advance desc register api */
#define CONFIG_USBDEV_ADVANCE_DESC
/* move ep0 setup handler from isr to thread */
// #define CONFIG_USBDEV_EP0_THREAD
#ifndef CONFIG_USBDEV_EP0_PRIO
#define CONFIG_USBDEV_EP0_PRIO 4
#endif
#ifndef CONFIG_USBDEV_EP0_STACKSIZE
#define CONFIG_USBDEV_EP0_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
/* move msc read & write from isr to while(1), you should call usbd_msc_polling in while(1) */
// #define CONFIG_USBDEV_MSC_POLLING
/* move msc read & write from isr to thread */
// #define CONFIG_USBDEV_MSC_THREAD
#ifndef CONFIG_USBDEV_MSC_PRIO
#define CONFIG_USBDEV_MSC_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_BUFSIZE
#define CONFIG_USBDEV_MTP_MAX_BUFSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_OBJECTS
#define CONFIG_USBDEV_MTP_MAX_OBJECTS 256
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_PATHNAME
#define CONFIG_USBDEV_MTP_MAX_PATHNAME 256
#endif
#define CONFIG_USBDEV_MTP_THREAD
#ifndef CONFIG_USBDEV_MTP_PRIO
#define CONFIG_USBDEV_MTP_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MTP_STACKSIZE
#define CONFIG_USBDEV_MTP_STACKSIZE 4096
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
#define CONFIG_USBHOST_DEV_NAMELEN 16
#ifndef CONFIG_USBHOST_PSC_PRIO
#define CONFIG_USBHOST_PSC_PRIO 0
#endif
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
#define CONFIG_USBHOST_PSC_STACKSIZE 2048
#endif
//#define CONFIG_USBHOST_GET_STRING_DESC
// #define CONFIG_USBHOST_MSOS_ENABLE
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
/* Ep0 max transfer buffer */
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 4096
#endif
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
#endif
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
#endif
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
#endif
/* ================ USB Device Port Configuration ================*/
#ifndef CONFIG_USBDEV_MAX_BUS
#define CONFIG_USBDEV_MAX_BUS 1
#endif
// #define CONFIG_USBDEV_SOF_ENABLE
/* ---------------- FSDEV Configuration ---------------- */
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
/* ---------------- DWC2 Configuration ---------------- */
/* enable dwc2 buffer dma mode for device
* in xxx32 chips, only pb14/pb15 can support dma mode, pa11/pa12 is not supported(only a few supports, but we ignore them)
*/
// #define CONFIG_USB_DWC2_DMA_ENABLE
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_EP_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Host Port Configuration ==================*/
#ifndef CONFIG_USBHOST_MAX_BUS
#define CONFIG_USBHOST_MAX_BUS 1
#endif
/* ---------------- EHCI Configuration ---------------- */
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
#define CONFIG_USB_EHCI_QH_NUM 10
#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3)
#define CONFIG_USB_EHCI_ITD_NUM 4
#define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
// #define CONFIG_USB_EHCI_CONFIGFLAG
// #define CONFIG_USB_EHCI_ISO
// #define CONFIG_USB_EHCI_WITH_OHCI
// #define CONFIG_USB_EHCI_DESC_DCACHE_ENABLE
/* ---------------- OHCI Configuration ---------------- */
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
#define CONFIG_USB_OHCI_ED_NUM 10
#define CONFIG_USB_OHCI_TD_NUM 3
// #define CONFIG_USB_OHCI_DESC_DCACHE_ENABLE
/* ---------------- XHCI Configuration ---------------- */
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- DWC2 Configuration ---------------- */
// nothing to define
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_PIPE_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
// #define CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode,
* the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS.
*
* in xxx32 chips, only pb14/pb15 can support hs mode, pa11/pa12 is not supported(only a few supports, but we ignore them).
*/
// #define CONFIG_USB_HS
#ifndef usb_phyaddr2ramaddr
#define usb_phyaddr2ramaddr(addr) (addr)
#endif
#ifndef usb_ramaddr2phyaddr
#define usb_ramaddr2phyaddr(addr) (addr)
#endif
#define ATTR_FAST_RAM_SECTION ATTR_TCM_SECTION
#define CONFIG_USB_HS
#endif

View File

@@ -0,0 +1,16 @@
set(CONFIG_FREERTOS 1)
# do not use sdk cherryusb because its version is lower than master.
#set(CONFIG_CHERRYUSB 1)
#set(CONFIG_CHERRYUSB_HOST 1)
#set(CONFIG_CHERRYUSB_HOST_ECM 1)
set(CONFIG_PSRAM 1)
set(CONFIG_FATFS 1)
set(CONFIG_FATFS_USBH 1)
set(CONFIG_LWIP 1)
set(CONFIG_PING 1)
set(CONFIG_IPERF 1)
set(CONFIG_SHELL 1)

View File

@@ -0,0 +1,158 @@
#include <FreeRTOS.h>
#include "semphr.h"
#include "usbh_core.h"
#include "bflb_uart.h"
#include "board.h"
#include "shell.h"
#ifdef CONFIG_USB_EHCI_ISO
#include "usbh_uvc_stream.h"
#include "usbh_uac_stream.h"
#endif
#include "lwip/tcpip.h"
static struct bflb_device_s *uart0;
extern void shell_init_with_task(struct bflb_device_s *shell);
#ifdef CONFIG_USB_EHCI_ISO
static ATTR_NOINIT_PSRAM_SECTION USB_MEM_ALIGNX uint8_t frame_buffer1[640 * 480 * 2];
static ATTR_NOINIT_PSRAM_SECTION USB_MEM_ALIGNX uint8_t frame_buffer2[640 * 480 * 2];
static struct usbh_videoframe frame_pool[2];
static ATTR_NOINIT_PSRAM_SECTION USB_MEM_ALIGNX uint8_t frame_buffer[AUDIO_MIC_EP_MPS * 8];
static struct usbh_audioframe frame_pool2[8];
void usbh_video_run(struct usbh_video *video_class)
{
usbh_video_stream_start(640, 480, USBH_VIDEO_FORMAT_MJPEG);
}
void usbh_video_stop(struct usbh_video *video_class)
{
usbh_video_stream_stop();
}
void usbh_video_frame_callback(struct usbh_videoframe *frame)
{
USB_LOG_RAW("frame buf:%p,frame len:%d\r\n", frame->frame_buf, frame->frame_size);
}
#endif
int main(void)
{
board_init();
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
/* Initialize the LwIP stack */
tcpip_init(NULL, NULL);
printf("Starting usb host task...\r\n");
#ifdef CONFIG_USB_EHCI_ISO
extern void usbh_video_fps_init(void);
usbh_video_fps_init();
frame_pool[0].frame_buf = frame_buffer1;
frame_pool[0].frame_bufsize = 640 * 480 * 2;
frame_pool[1].frame_buf = frame_buffer2;
frame_pool[1].frame_bufsize = 640 * 480 * 2;
usbh_video_stream_init(5, frame_pool, 2);
for (uint8_t i = 0; i < 8; i++) {
frame_pool2[i].frame_buf = frame_buffer + i * AUDIO_MIC_EP_MPS;
frame_pool2[i].frame_bufsize = AUDIO_MIC_EP_MPS;
}
usbh_audio_mic_stream_init(5, frame_pool2, 8);
#endif
vTaskStartScheduler();
while (1) {
}
}
int usbh_deinit(int argc, char **argv)
{
printf("usbh_deinit\r\n");
usbh_deinitialize(0);
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_deinit, usbh_deinit, usbh deinit);
int usbh_init(int argc, char **argv)
{
printf("usbh_init\r\n");
usbh_initialize(0, 0x20072000);
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_init, usbh_init, usbh init);
SHELL_CMD_EXPORT_ALIAS(lsusb, lsusb, ls usb);
// int uvcinit(int argc, char **argv)
// {
// video_init(0, 0x20072000);
// return 0;
// }
// SHELL_CMD_EXPORT_ALIAS(uvcinit, uvcinit, usbh init);
// int uvcsend(int argc, char **argv)
// {
// extern void video_test(uint8_t busid);
// video_test(0);
// return 0;
// }
// SHELL_CMD_EXPORT_ALIAS(uvcsend, uvcsend, usbh init);
#ifdef CONFIG_USB_EHCI_ISO
int usbh_uvc_start(int argc, char **argv)
{
uint8_t type;
if (argc < 2) {
USB_LOG_ERR("please input correct command: usbh_uvc_start type\r\n");
USB_LOG_ERR("type 0:yuyv, type 1:mjpeg\r\n");
return -1;
}
type = atoi(argv[1]);
usbh_video_stream_start(640, 480, type);
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_uvc_start, usbh_uvc_start, usbh_uvc_start);
int usbh_uvc_stop(int argc, char **argv)
{
usbh_video_stream_stop();
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_uvc_stop, usbh_uvc_stop, usbh_uvc_stop);
int usbh_uac_start(int argc, char **argv)
{
uint32_t freq;
if (argc < 2) {
USB_LOG_ERR("please input correct command: usbh_uac_start freq\r\n");
return -1;
}
freq = atoi(argv[1]);
usbh_audio_mic_stream_start(freq);
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_uac_start, usbh_uac_start, usbh_uac_start);
int usbh_uac_stop(int argc, char **argv)
{
usbh_audio_mic_stream_stop();
return 0;
}
SHELL_CMD_EXPORT_ALIAS(usbh_uac_stop, usbh_uac_stop, usbh_uac_stop);
#endif

View File

@@ -0,0 +1,9 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND EXTRA_COMPONENT_DIRS "../../../../CherryUSB")
project(cherryusb)

View File

@@ -0,0 +1,4 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "usbd_core.h"
#include "usbh_core.h"
#include "demo/cdc_acm_msc_template.c"
extern void cdc_acm_msc_init(uint8_t busid, uintptr_t reg_base);
void app_main(void)
{
USB_LOG_INFO("Hello CherryUSB!\n");
cdc_acm_msc_init(0, 0x60080000);
while(1)
{
vTaskDelay(10);
}
}

View File

@@ -0,0 +1,7 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
#
CONFIG_CHERRYUSB=y
CONFIG_CHERRYUSB_DEVICE=y
CONFIG_CHERRYUSB_DEVICE_CDC_ACM=y
CONFIG_CHERRYUSB_DEVICE_HID=y
CONFIG_CHERRYUSB_DEVICE_MSC=y

View File

@@ -0,0 +1,9 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
list(APPEND EXTRA_COMPONENT_DIRS "../../../../CherryUSB")
project(cherryusb)

View File

@@ -0,0 +1,4 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_log.h"
#include "usbd_core.h"
#include "usbh_core.h"
#include "demo/usb_host.c"
void app_main(void)
{
USB_LOG_INFO("Hello CherryUSB!\n");
// Initialize TCP/IP network interface aka the esp-netif (should be called only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
usbh_initialize(0, 0x60080000);
while(1)
{
vTaskDelay(10);
}
}

View File

@@ -0,0 +1,19 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
#
CONFIG_CHERRYUSB=y
CONFIG_CHERRYUSB_HOST=y
CONFIG_CHERRYUSB_HOST_CUSTOM=y
CONFIG_CHERRYUSB_HOST_CDC_ACM=y
CONFIG_CHERRYUSB_HOST_HID=y
CONFIG_CHERRYUSB_HOST_MSC=y
CONFIG_CHERRYUSB_HOST_CDC_ECM=y
CONFIG_CHERRYUSB_HOST_CDC_NCM=y
CONFIG_CHERRYUSB_HOST_CDC_RNDIS=y
CONFIG_CHERRYUSB_HOST_ASIX=y
CONFIG_CHERRYUSB_HOST_RTL8152=y
CONFIG_CHERRYUSB_HOST_CH34X=y
CONFIG_CHERRYUSB_HOST_CP210X=y
CONFIG_CHERRYUSB_HOST_FTDI=y
CONFIG_CHERRYUSB_HOST_PL2303=y
CONFIG_CHERRYUSB_HOST_VIDEO=y
CONFIG_CHERRYUSB_HOST_AUDIO=y

View File

@@ -0,0 +1,57 @@
# Copyright (c) 2021 HPMicro
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.13)
set(CONFIG_CHERRYSH 1)
set(CONFIG_CHERRYSH_INTERFACE "uart")
set(CONFIG_USB_DEVICE 1)
set(CONFIG_FREERTOS 1)
set(CONFIG_LWIP 1)
set(CONFIG_LWIP_IPERF 1)
set(CONFIG_LWIP_STRERR 1)
set(CONFIG_LWIP_NETDB 1)
set(CONFIG_LWIP_SOCKET_API 1)
set(CONFIG_HPM_PANEL 1)
find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})
project(cherryusb)
sdk_compile_definitions(-D__freertos_irq_stack_top=_stack)
sdk_compile_definitions(-DCONFIG_FREERTOS=1)
sdk_compile_definitions(-DUSE_NONVECTOR_MODE=1)
sdk_compile_definitions(-DDISABLE_IRQ_PREEMPTIVE=1)
sdk_compile_definitions(-DLWIP_TIMEVAL_PRIVATE=0)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_ECM)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_NCM)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_RNDIS)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_ASIX)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_RTL8152)
# sdk_compile_definitions(-DCONFIG_USB_OTG_ENABLE)
sdk_compile_options("-O2")
sdk_inc(inc)
sdk_app_src(inc/arch/sys_arch.c)
sdk_app_src(src/main.c)
sdk_app_src(../../demo/usb_host.c)
sdk_inc(src/iperf)
sdk_app_src(src/iperf/iperf.c src/iperf/iperf_cli.c src/iperf/utils_getopt.c src/ping.c)
sdk_app_src(src/cdc_acm_otg_template.c)
set(CONFIG_CHERRYMP 1)
set(CONFIG_CHERRYUSB 1)
set(CONFIG_CHERRYUSB_DEVICE 1)
set(CONFIG_CHERRYUSB_HOST 1)
# sdk_app_src(src/uvc2lcd.c)
# sdk_app_src(src/font24x48.c)
# add_subdirectory(src/cherryusb_hostuvcuac)
add_subdirectory(../.. cherryusb)
generate_ses_project()

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2022 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*/
#include "board.h"
#if (portasmHAS_MTIME == 0)
#define configMTIME_BASE_ADDRESS (0)
#define configMTIMECMP_BASE_ADDRESS (0)
#else
#define configMTIME_BASE_ADDRESS (HPM_MCHTMR_BASE)
#define configMTIMECMP_BASE_ADDRESS (HPM_MCHTMR_BASE + 8UL)
#endif
/* When USE_SYSCALL_INTERRUPT_PRIORITY is set, interrupts whose priority is higher than configMAX_SYSCALL_INTERRUPT_PRIORITY
will not be delayed by anything FreeRTOS do. */
#if defined (USE_SYSCALL_INTERRUPT_PRIORITY) && USE_SYSCALL_INTERRUPT_PRIORITY
#ifndef configMAX_SYSCALL_INTERRUPT_PRIORITY
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
#endif
#endif
#define configUSE_PREEMPTION 1
#define configCPU_CLOCK_HZ ((uint32_t) 24000000)
#define configTICK_RATE_HZ ((TickType_t) 1000)
#define configMAX_PRIORITIES (32)
#define configMINIMAL_STACK_SIZE (256)
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_MUTEXES 1
/* Memory allocation definitions. */
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#ifndef configTOTAL_HEAP_SIZE
#define configTOTAL_HEAP_SIZE ((size_t) (64 * 1024))
#endif
/* Hook function definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 2
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 4
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE)
/* Task priorities.*/
#ifndef uartPRIMARY_PRIORITY
#define uartPRIMARY_PRIORITY (configMAX_PRIORITIES - 3)
#endif
/* Normal assert() semantics without relying on the provision of an assert.h header file. */
#define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); __asm volatile("ebreak"); for (;;); }
/*
* The size of the global output buffer that is available for use when there
* are multiple command interpreters running at once (for example, one on a UART
* and one on TCP/IP). This is done to prevent an output buffer being defined by
* each implementation - which would waste RAM. In this case, there is only one
* command interpreter running.
*/
/*
* The buffer into which output generated by FreeRTOS+CLI is placed. This must
* be at least big enough to contain the output of the task-stats command, as the
* example implementation does not include buffer overlow checking.
*/
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096
#define configINCLUDE_QUERY_HEAP_COMMAND 1
/* This file is included from assembler files - make sure C code is not included in assembler files. */
#ifndef __ASSEMBLER__
void vAssertCalled(const char *pcFile, unsigned long ulLine);
void vConfigureTickInterrupt(void);
void vClearTickInterrupt(void);
void vPreSleepProcessing(unsigned long uxExpectedIdleTime);
void vPostSleepProcessing(unsigned long uxExpectedIdleTime);
#endif /* __ASSEMBLER__ */
/****** Hardware/compiler specific settings. *******/
/*
* The application must provide a function that configures a peripheral to
* create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT()
* in FreeRTOSConfig.h to call the function.
*/
#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt()
#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt()
/*
* The configPRE_SLEEP_PROCESSING() and configPOST_SLEEP_PROCESSING() macros
* allow the application writer to add additional code before and after the MCU is
* placed into the low power state respectively. The empty implementations
* provided in this demo can be extended to save even more power.
*/
#define configPRE_SLEEP_PROCESSING(uxExpectedIdleTime) vPreSleepProcessing(uxExpectedIdleTime);
#define configPOST_SLEEP_PROCESSING(uxExpectedIdleTime) vPostSleepProcessing(uxExpectedIdleTime);
/* Compiler specifics. */
#define fabs(x) __builtin_fabs(x)
/* Enable Hardware Stack Protection and Recording mechanism. */
#define configHSP_ENABLE 0
/* Record the highest address of stack. */
#if (configHSP_ENABLE == 1 && configRECORD_STACK_HIGH_ADDRESS != 1)
#define configRECORD_STACK_HIGH_ADDRESS 1
#endif
#endif /* FREERTOS_CONFIG_H */

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* Copyright (c) 2021-2024 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __CC_H__
#define __CC_H__
#include <stdio.h>
#define U16_F "hu"
#define S16_F "d"
#define X16_F "hx"
#define U32_F "u"
#define S32_F "d"
#define X32_F "x"
#define SZT_F "uz"
/* define compiler specific symbols */
#if defined (__ICCARM__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined (__CC_ARM)
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__GNUC__)
#include <sys/time.h>
#include <time.h>
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined(__ICCRISCV__)
#include <time.h>
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
typedef unsigned long clockid_t;
#elif defined (__TASKING__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif
#define LWIP_PLATFORM_ASSERT(x) printf(x)
#endif /* __CC_H__ */

View File

@@ -0,0 +1,618 @@
/*
* Copyright (c) 2017 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt <goldsimon@gmx.de>
*
*/
/*
* Copyright (c) 2021-2022 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "lwip/tcpip.h"
#if !NO_SYS
#include "FreeRTOS.h"
#include "semphr.h"
#endif
#if !NO_SYS
#include "sys_arch.h"
#endif
int errno;
#if !NO_SYS
/** Set this to 1 if you want the stack size passed to sys_thread_new() to be
* interpreted as number of stack words (FreeRTOS-like).
* Default is that they are interpreted as byte count (lwIP-like).
*/
#ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
#define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 0
#endif
/** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions.
* Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT().
*/
#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
#define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0
#endif
/** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and
* SYS_ARCH_UNPROTECT() are called matching.
*/
#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
#define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0
#endif
/** Set this to 1 to let sys_mbox_free check that queues are empty when freed */
#ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
#define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0
#endif
/** Set this to 1 to enable core locking check functions in this port.
* For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED()
* and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */
#ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING
#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1
#endif
/** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer.
* Default is 1, where FreeRTOS ticks are used to calculate back to ms.
*/
#ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
#define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1
#endif
#if !configSUPPORT_DYNAMIC_ALLOCATION
# error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION"
#endif
#if !INCLUDE_vTaskDelay
# error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay"
#endif
#if !INCLUDE_vTaskSuspend
# error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend"
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX
#if !configUSE_MUTEXES
# error "lwIP FreeRTOS port requires configUSE_MUTEXES"
#endif
#endif
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
static SemaphoreHandle_t sys_arch_protect_mutex;
#endif
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
static sys_prot_t sys_arch_protect_nesting;
#endif
/* Initialize this module (see description in sys.h) */
void
sys_init(void)
{
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
/* initialize sys_arch_protect global mutex */
sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex();
LWIP_ASSERT("failed to create sys_arch_protect mutex",
sys_arch_protect_mutex != NULL);
#endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
}
#if configUSE_16_BIT_TICKS == 1
#error This port requires 32 bit ticks or timer overflow will fail
#endif
#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
u32_t sys_now(void)
{
return xTaskGetTickCount() * portTICK_PERIOD_MS;
}
#else
u32_t sys_now(void)
{
return 0;
}
#endif
u32_t sys_jiffies(void)
{
return xTaskGetTickCount();
}
#if SYS_LIGHTWEIGHT_PROT
sys_prot_t sys_arch_protect(void)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
BaseType_t ret;
LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY);
LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE);
#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
taskENTER_CRITICAL();
#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
{
/* every nested call to sys_arch_protect() returns an increased number */
sys_prot_t ret = sys_arch_protect_nesting;
sys_arch_protect_nesting++;
LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret);
return ret;
}
#else
return 1;
#endif
}
void sys_arch_unprotect(sys_prot_t pval)
{
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
BaseType_t ret;
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK
LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0);
sys_arch_protect_nesting--;
LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval);
#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex);
LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);
#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
taskEXIT_CRITICAL();
#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
LWIP_UNUSED_ARG(pval);
}
#endif /* SYS_LIGHTWEIGHT_PROT */
void sys_arch_msleep(u32_t delay_ms)
{
TickType_t delay_ticks = delay_ms / portTICK_RATE_MS;
vTaskDelay(delay_ticks);
}
#if !LWIP_COMPAT_MUTEX
/* Create a new mutex*/
err_t sys_mutex_new(sys_mutex_t *mutex)
{
LWIP_ASSERT("mutex != NULL", mutex != NULL);
mutex->mut = xSemaphoreCreateRecursiveMutex();
if (mutex->mut == NULL) {
SYS_STATS_INC(mutex.err);
return ERR_MEM;
}
SYS_STATS_INC_USED(mutex);
return ERR_OK;
}
void sys_mutex_lock(sys_mutex_t *mutex)
{
BaseType_t ret;
LWIP_ASSERT("mutex != NULL", mutex != NULL);
LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); /* NOLINT */
ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);
LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
}
void sys_mutex_unlock(sys_mutex_t *mutex)
{
BaseType_t ret;
LWIP_ASSERT("mutex != NULL", mutex != NULL);
LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); /* NOLINT */
ret = xSemaphoreGiveRecursive(mutex->mut);
LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
}
void sys_mutex_free(sys_mutex_t *mutex)
{
LWIP_ASSERT("mutex != NULL", mutex != NULL);
LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL); /* NOLINT */
SYS_STATS_DEC(mutex.used);
vSemaphoreDelete(mutex->mut);
mutex->mut = NULL;
}
#endif /* !LWIP_COMPAT_MUTEX */
err_t sys_sem_new(sys_sem_t *sem, u8_t initial_count)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("initial_count invalid (not 0 or 1)",
(initial_count == 0) || (initial_count == 1));
sem->sem = xSemaphoreCreateBinary();
if (sem->sem == NULL) {
SYS_STATS_INC(sem.err);
return ERR_MEM;
}
SYS_STATS_INC_USED(sem);
if (initial_count == 1) {
BaseType_t ret = xSemaphoreGive(sem->sem);
LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
}
return ERR_OK;
}
void sys_sem_signal(sys_sem_t *sem)
{
BaseType_t ret;
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); /* NOLINT */
ret = xSemaphoreGive(sem->sem);
/* queue full is OK, this is a signal only... */
LWIP_ASSERT("sys_sem_signal: sane return value",
(ret == pdTRUE) || (ret == errQUEUE_FULL));
}
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms)
{
BaseType_t ret;
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); /* NOLINT */
if (!timeout_ms) {
/* wait infinite */
ret = xSemaphoreTake(sem->sem, portMAX_DELAY);
LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
} else {
TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
ret = xSemaphoreTake(sem->sem, timeout_ticks);
if (ret == errQUEUE_EMPTY) {
/* timed out */
return SYS_ARCH_TIMEOUT;
}
LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
}
/* Old versions of lwIP required us to return the time waited.
This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
here is enough. */
return 1;
}
void sys_sem_free(sys_sem_t *sem)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); /* NOLINT */
SYS_STATS_DEC(sem.used);
vSemaphoreDelete(sem->sem);
sem->sem = NULL;
}
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{
LWIP_ASSERT("mbox != NULL", mbox != NULL); /* NOLINT */
LWIP_ASSERT("size > 0", size > 0);
mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *));
if (mbox->mbx == NULL) {
SYS_STATS_INC(mbox.err);
return ERR_MEM;
}
SYS_STATS_INC_USED(mbox);
return ERR_OK;
}
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY);
LWIP_ASSERT("mbox post failed", ret == pdTRUE);
}
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
ret = xQueueSendToBack(mbox->mbx, &msg, 0);
if (ret == pdTRUE) {
return ERR_OK;
} else {
LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
SYS_STATS_INC(mbox.err);
return ERR_MEM;
}
}
err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
{
BaseType_t ret;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken);
if (ret == pdTRUE) {
if (xHigherPriorityTaskWoken == pdTRUE) {
return ERR_NEED_SCHED;
}
return ERR_OK;
} else {
LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL);
SYS_STATS_INC(mbox.err);
return ERR_MEM;
}
}
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms)
{
BaseType_t ret;
void *msg_dummy;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
if (!msg) {
msg = &msg_dummy;
}
if (!timeout_ms) {
/* wait infinite */
ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY);
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
} else {
TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS;
ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks);
if (ret == errQUEUE_EMPTY) {
/* timed out */
*msg = NULL;
return SYS_ARCH_TIMEOUT;
}
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
}
/* Old versions of lwIP required us to return the time waited.
This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
here is enough. */
return 1;
}
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
BaseType_t ret;
void *msg_dummy;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
if (!msg) {
msg = &msg_dummy;
}
ret = xQueueReceive(mbox->mbx, &(*msg), 0);
if (ret == errQUEUE_EMPTY) {
*msg = NULL;
return SYS_MBOX_EMPTY;
}
LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
/* Old versions of lwIP required us to return the time waited.
This is not the case any more. Just returning != SYS_ARCH_TIMEOUT
here is enough. */
return 1;
}
void sys_mbox_free(sys_mbox_t *mbox)
{
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL); /* NOLINT */
#if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE
{
UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx);
LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
if (msgs_waiting != 0) {
SYS_STATS_INC(mbox.err);
}
}
#endif
vQueueDelete(mbox->mbx);
SYS_STATS_DEC(mbox.used);
}
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
TaskHandle_t rtos_task;
BaseType_t ret;
sys_thread_t lwip_thread;
size_t rtos_stacksize;
LWIP_ASSERT("invalid stacksize", stacksize > 0);
#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
rtos_stacksize = (size_t)stacksize;
#else
rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);
#endif
/* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the
thread function without adaption here. */
ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task);
LWIP_ASSERT("task creation failed", ret == pdTRUE);
lwip_thread.thread_handle = rtos_task;
return lwip_thread;
}
#if LWIP_NETCONN_SEM_PER_THREAD
#if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0
sys_sem_t *sys_arch_netconn_sem_get(void)
{
void *ret;
TaskHandle_t task = xTaskGetCurrentTaskHandle();
LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0);
return ret;
}
void sys_arch_netconn_sem_alloc(void)
{
void *ret;
TaskHandle_t task = xTaskGetCurrentTaskHandle();
LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0);
if (ret == NULL) {
sys_sem_t *sem;
err_t err;
/* need to allocate the memory for this semaphore */
sem = mem_malloc(sizeof(sys_sem_t));
LWIP_ASSERT("sem != NULL", sem != NULL);
err = sys_sem_new(sem, 0);
LWIP_ASSERT("err == ERR_OK", err == ERR_OK);
LWIP_ASSERT("sem invalid", sys_sem_valid(sem));
vTaskSetThreadLocalStoragePointer(task, 0, sem);
}
}
void sys_arch_netconn_sem_free(void)
{
void *ret;
TaskHandle_t task = xTaskGetCurrentTaskHandle();
LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0);
if (ret != NULL) {
sys_sem_t *sem = ret;
sys_sem_free(sem);
mem_free(sem);
vTaskSetThreadLocalStoragePointer(task, 0, NULL);
}
}
#else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
#error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS
#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#if LWIP_FREERTOS_CHECK_CORE_LOCKING
#if LWIP_TCPIP_CORE_LOCKING
/** Flag the core lock held. A counter for recursive locks. */
static u8_t lwip_core_lock_count;
static TaskHandle_t lwip_core_lock_holder_thread;
void sys_lock_tcpip_core(void)
{
sys_mutex_lock(&lock_tcpip_core);
if (lwip_core_lock_count == 0) {
lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle();
}
lwip_core_lock_count++;
}
void sys_unlock_tcpip_core(void)
{
lwip_core_lock_count--;
if (lwip_core_lock_count == 0) {
lwip_core_lock_holder_thread = 0;
}
sys_mutex_unlock(&lock_tcpip_core);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if !NO_SYS
static TaskHandle_t lwip_tcpip_thread;
#endif
void sys_mark_tcpip_thread(void)
{
#if !NO_SYS
lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
#endif
}
void sys_check_core_locking(void)
{
/* Embedded systems should check we are NOT in an interrupt context here */
/* E.g. core Cortex-M3/M4 ports:
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */
taskENTER_CRITICAL();
taskEXIT_CRITICAL();
#if !NO_SYS
if (lwip_tcpip_thread != 0) {
TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();
#if LWIP_TCPIP_CORE_LOCKING
LWIP_ASSERT("Function called without core lock",
current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);
#else /* LWIP_TCPIP_CORE_LOCKING */
LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);
#endif /* LWIP_TCPIP_CORE_LOCKING */
}
#endif /* !NO_SYS */
}
#endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/
#else
static uint32_t sys_tick = 0;
void sys_timer_callback(void)
{
sys_tick++;
}
u32_t sys_now(void)
{
return (u32_t)sys_tick;
}
#endif

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2017 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmdit <goldsimon@gmx.de>
*
*/
/*
* Copyright (c) 2021-2023 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#include "lwip/opt.h"
#include "lwip/arch.h"
#if !NO_SYS
/** This is returned by _fromisr() sys functions to tell the outermost function
* that a higher priority task was woken and the scheduler needs to be invoked.
*/
#define ERR_NEED_SCHED 123
/* This port includes FreeRTOS headers in sys_arch.c only.
* FreeRTOS uses pointers as object types. We use wrapper structs instead of
* void pointers directly to get a tiny bit of type safety.
*/
void sys_arch_msleep(u32_t delay_ms);
#define sys_msleep(ms) sys_arch_msleep(ms)
#if SYS_LIGHTWEIGHT_PROT
typedef u32_t sys_prot_t;
#endif /* SYS_LIGHTWEIGHT_PROT */
#if !LWIP_COMPAT_MUTEX
struct _sys_mut {
void *mut;
};
typedef struct _sys_mut sys_mutex_t;
#define sys_mutex_valid_val(mutex) ((mutex).mut != NULL)
#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))
#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)
#endif /* !LWIP_COMPAT_MUTEX */
struct _sys_sem {
void *sem;
};
typedef struct _sys_sem sys_sem_t;
#define sys_sem_valid_val(sema) ((sema).sem != NULL)
#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema)))
#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)
struct _sys_mbox {
void *mbx;
};
typedef struct _sys_mbox sys_mbox_t;
#define sys_mbox_valid_val(mbox) ((mbox).mbx != NULL)
#define sys_mbox_valid(mbox) (((mbox) != NULL) && sys_mbox_valid_val(*(mbox)))
#define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL)
struct _sys_thread {
void *thread_handle;
};
typedef struct _sys_thread sys_thread_t;
#if LWIP_NETCONN_SEM_PER_THREAD
sys_sem_t *sys_arch_netconn_sem_get(void);
void sys_arch_netconn_sem_alloc(void);
void sys_arch_netconn_sem_free(void);
#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get()
#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc()
#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free()
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#else
void sys_timer_callback(void);
#endif /* !NO_SYS */
#endif /* LWIP_ARCH_SYS_ARCH_H */

View File

@@ -0,0 +1,436 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef LWIPOPTS_H
#define LWIPOPTS_H
#ifdef USE_LWIPOPTS_APP_H
#include "lwipopts_app.h"
#endif
/**
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
* critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#define SYS_LIGHTWEIGHT_PROT 1
#define IP_REASSEMBLY 0
#define IP_FRAG 0
#define ARP_QUEUEING 0
#define NO_SYS 0
#define LWIP_RAND rand
#define LWIP_NETIF_HOSTNAME 0
#define LWIP_TIMEVAL_PRIVATE 0
#define LWIP_TIMERS 1
#define LWIP_RAW 1
#define LWIP_IPV4 1
#define LWIP_IGMP 1
#define LWIP_ICMP 1
#define ICMP_TTL 64
#define LWIP_TCP 1
#define TCP_TTL 255
#define LWIP_UDP 1
#define UDP_TTL 255
#define LWIP_DNS 1
/**
* LWIP_NETIF_API==1: Support netif api (in netifapi.c)
*/
#define LWIP_NETIF_API 1
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN 1
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#define LWIP_SOCKET 1
/* ---------- Memory options ---------- */
#define MEMP_MEM_MALLOC 0
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#ifndef MEM_ALIGNMENT
#define MEM_ALIGNMENT 64
#endif
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#ifndef MEM_SIZE
#define MEM_SIZE (32 * 1024)
#endif
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#ifndef MEMP_NUM_PBUF
#define MEMP_NUM_PBUF 100
#endif
/**
* MEMP_NUM_RAW_PCB: Number of raw connection PCBs
* (requires the LWIP_RAW option)
*/
#ifndef MEMP_NUM_RAW_PCB
#define MEMP_NUM_RAW_PCB 4
#endif
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#ifndef MEMP_NUM_UDP_PCB
#define MEMP_NUM_UDP_PCB 4
#endif
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB
#define MEMP_NUM_TCP_PCB 4
#endif
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#ifndef MEMP_NUM_TCP_PCB_LISTEN
#define MEMP_NUM_TCP_PCB_LISTEN 5
#endif
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#ifndef MEMP_NUM_TCP_SEG
#define MEMP_NUM_TCP_SEG 40
#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL)
#endif
/**
* MEMP_NUM_NETCONN: the number of struct netconns.
* (only needed if you use the sequential API, like api_lib.c)
*/
#ifndef MEMP_NUM_NETCONN
#define MEMP_NUM_NETCONN 4
#endif
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#ifndef PBUF_POOL_SIZE
#define PBUF_POOL_SIZE 20
#endif
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#ifndef PBUF_POOL_BUFSIZE
#define PBUF_POOL_BUFSIZE 1600
#endif
/* ---------- TCP options ---------- */
/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#ifndef TCP_QUEUE_OOSEQ
#define TCP_QUEUE_OOSEQ 0
#endif
/* TCP Maximum segment size. */
#ifndef TCP_MSS
#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
#endif
/* TCP sender buffer space (bytes). */
#ifndef TCP_SND_BUF
#define TCP_SND_BUF (8 * TCP_MSS)
#endif
/* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF / TCP_MSS)
#endif
/* TCP receive window. */
#ifndef TCP_WND
#define TCP_WND (16 * TCP_MSS)
#endif
/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
#ifndef LWIP_DHCP
#define LWIP_DHCP 1
#endif
/* ---------- Statistics options ---------- */
#ifndef LWIP_STATS
#define LWIP_STATS 0
#endif
#ifndef LWIP_PROVIDE_ERRNO
#define LWIP_PROVIDE_ERRNO 1
#endif
/*
------------------------------------------------
---------- Network Interfaces options ----------
------------------------------------------------
*/
/**
* LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for
* small real-life targets. Some code like routing etc. can be left out.
*/
#ifndef LWIP_SINGLE_NETIF
#define LWIP_SINGLE_NETIF 1
#endif
/* ---------- link callback options ---------- */
/* LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
* whenever the link changes (i.e., link down)
*/
#ifndef LWIP_NETIF_LINK_CALLBACK
#define LWIP_NETIF_LINK_CALLBACK 1
#endif
/**
* LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP *tries* to put all data
* to be sent into one single pbuf. This is for compatibility with DMA-enabled
* MACs that do not support scatter-gather.
* Beware that this might involve CPU-memcpy before transmitting that would not
* be needed without this flag! Use this only if you need to!
*
* ATTENTION: a driver should *NOT* rely on getting single pbufs but check TX
* pbufs for being in one piece. If not, @ref pbuf_clone can be used to get
* a single pbuf:
* if (p->next != NULL) {
* struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
* if (q == NULL) {
* return ERR_MEM;
* }
* p = q; ATTENTION: do NOT free the old 'p' as the ref belongs to the caller!
* }
*/
#ifndef LWIP_NETIF_TX_SINGLE_PBUF
#define LWIP_NETIF_TX_SINGLE_PBUF 0
#endif
/*
--------------------------------------
---------- Checksum options ----------
--------------------------------------
*/
/*
* Some MCUs allow computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
* To use this feature let the following define uncommented.
* To disable it and process by CPU comment the the checksum.
*/
#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 0
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 0
/* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP 0
#else
/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 1
/* CHECKSUM_CHECK_ICMP==1: Check checksums by software for incoming ICMP packets.*/
#define CHECKSUM_GEN_ICMP 1
#endif
/*
-----------------------------------
---------- DEBUG options ----------
-----------------------------------
*/
#ifdef LWIP_DEBUG
#ifndef LWIP_DBG_MIN_LEVEL
#define LWIP_DBG_MIN_LEVEL 0
#endif
#ifndef PPP_DEBUG
#define PPP_DEBUG LWIP_DBG_OFF
#endif
#ifndef MEM_DEBUG
#define MEM_DEBUG LWIP_DBG_OFF
#endif
#ifndef MEMP_DEBUG
#define MEMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef PBUF_DEBUG
#define PBUF_DEBUG LWIP_DBG_OFF
#endif
#ifndef API_LIB_DEBUG
#define API_LIB_DEBUG LWIP_DBG_OFF
#endif
#ifndef API_MSG_DEBUG
#define API_MSG_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCPIP_DEBUG
#define TCPIP_DEBUG LWIP_DBG_OFF
#endif
#ifndef NETIF_DEBUG
#define NETIF_DEBUG LWIP_DBG_OFF
#endif
#ifndef SOCKETS_DEBUG
#define SOCKETS_DEBUG LWIP_DBG_OFF
#endif
#ifndef DNS_DEBUG
#define DNS_DEBUG LWIP_DBG_OFF
#endif
#ifndef AUTOIP_DEBUG
#define AUTOIP_DEBUG LWIP_DBG_OFF
#endif
#ifndef DHCP_DEBUG
#define DHCP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IP_DEBUG
#define IP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IP_REASS_DEBUG
#define IP_REASS_DEBUG LWIP_DBG_OFF
#endif
#ifndef ICMP_DEBUG
#define ICMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef IGMP_DEBUG
#define IGMP_DEBUG LWIP_DBG_OFF
#endif
#ifndef UDP_DEBUG
#define UDP_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_DEBUG
#define TCP_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_INPUT_DEBUG
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_OUTPUT_DEBUG
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_RTO_DEBUG
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_CWND_DEBUG
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_WND_DEBUG
#define TCP_WND_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_FR_DEBUG
#define TCP_FR_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_QLEN_DEBUG
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#endif
#ifndef TCP_RST_DEBUG
#define TCP_RST_DEBUG LWIP_DBG_OFF
#endif
#ifndef ETHARP_DEBUG
#define ETHARP_DEBUG LWIP_DBG_OFF
#endif
#endif
/*
---------------------------------
---------- OS options ----------
---------------------------------
*/
#ifndef TCPIP_THREAD_NAME
#define TCPIP_THREAD_NAME "tcpip"
#endif
#ifndef TCPIP_THREAD_STACKSIZE
#define TCPIP_THREAD_STACKSIZE 2048
#endif
#ifndef TCPIP_MBOX_SIZE
#define TCPIP_MBOX_SIZE 8
#endif
#ifndef DEFAULT_RAW_RECVMBOX_SIZE
#define DEFAULT_RAW_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_UDP_RECVMBOX_SIZE
#define DEFAULT_UDP_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_TCP_RECVMBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE 50
#endif
#ifndef DEFAULT_ACCEPTMBOX_SIZE
#define DEFAULT_ACCEPTMBOX_SIZE 50
#endif
#ifndef DEFAULT_THREAD_STACKSIZE
#define DEFAULT_THREAD_STACKSIZE 500
#endif
#ifndef TCPIP_THREAD_PRIO
#define TCPIP_THREAD_PRIO 10
#endif
#define LWIP_COMPAT_MUTEX 0
#define LWIP_TCPIP_CORE_LOCKING 1
#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#endif
#ifndef LWIP_MEM_SECTION
#define LWIP_MEM_SECTION ".bss"
#endif
#endif /* __LWIPOPTS_H__ */

View File

@@ -0,0 +1,308 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2022-2025, HPMicro
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
#include "board.h"
/* ================ USB common Configuration ================ */
#ifdef __RTTHREAD__
#include <rtthread.h>
#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
#else
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#endif
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#endif
#if defined(CONFIG_USB_DEVICE_FS) || defined(CONFIG_USB_DEVICE_FORCE_FULL_SPEED)
#undef CONFIG_USB_HS
#else
#define CONFIG_USB_HS
#endif
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
/* #define CONFIG_USB_DCACHE_ENABLE */
/* data align size when use dma or use dcache */
#ifdef CONFIG_USB_DCACHE_ENABLE
#define CONFIG_USB_ALIGN_SIZE HPM_L1C_CACHELINE_SIZE
#else
#define CONFIG_USB_ALIGN_SIZE 4
#endif
/* descriptor common define */
#define USBD_VID 0x34B7 /* HPMicro VID */
#define USBD_PID 0xFFFF
#define USBD_MAX_POWER 200
/* attribute data into no cache ram */
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".fast_ram.non_init")))
/* use usb_memcpy default for high performance but cost more flash memory.
* And, arm libc has a bug that memcpy() may cause data misalignment when the size is not a multiple of 4.
*/
/* #define CONFIG_USB_MEMCPY_DISABLE */
/* ================= USB Device Stack Configuration ================ */
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* Setup packet log for debug */
/* #define CONFIG_USBDEV_SETUP_LOG_PRINT */
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
*/
/* #define CONFIG_USBDEV_EP0_INDATA_NO_COPY */
/* Check if the input descriptor is correct */
/* #define CONFIG_USBDEV_DESC_CHECK */
/* Enable test mode */
#define CONFIG_USBDEV_TEST_MODE
/* enable advance desc register api */
#define CONFIG_USBDEV_ADVANCE_DESC
/* move ep0 setup handler from isr to thread */
/* #define CONFIG_USBDEV_EP0_THREAD */
#ifndef CONFIG_USBDEV_EP0_PRIO
#define CONFIG_USBDEV_EP0_PRIO 4
#endif
#ifndef CONFIG_USBDEV_EP0_STACKSIZE
#define CONFIG_USBDEV_EP0_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
/* move msc read & write from isr to while(1), you should call usbd_msc_polling in while(1) */
/* #define CONFIG_USBDEV_MSC_POLLING */
/* move msc read & write from isr to thread */
/* #define CONFIG_USBDEV_MSC_THREAD */
#ifndef CONFIG_USBDEV_MSC_PRIO
#define CONFIG_USBDEV_MSC_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_BUFSIZE
#define CONFIG_USBDEV_MTP_MAX_BUFSIZE 2048
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_OBJECTS
#define CONFIG_USBDEV_MTP_MAX_OBJECTS 256
#endif
#ifndef CONFIG_USBDEV_MTP_MAX_PATHNAME
#define CONFIG_USBDEV_MTP_MAX_PATHNAME 256
#endif
#define CONFIG_USBDEV_MTP_THREAD
#ifndef CONFIG_USBDEV_MTP_PRIO
#define CONFIG_USBDEV_MTP_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MTP_STACKSIZE
#define CONFIG_USBDEV_MTP_STACKSIZE 4096
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "HPMicro"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
#define CONFIG_USBHOST_DEV_NAMELEN 16
#ifndef CONFIG_USBHOST_PSC_PRIO
#define CONFIG_USBHOST_PSC_PRIO 0
#endif
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
#define CONFIG_USBHOST_PSC_STACKSIZE 2048
#endif
/* #define CONFIG_USBHOST_GET_STRING_DESC */
/* #define CONFIG_USBHOST_MSOS_ENABLE */
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
/* Ep0 max transfer buffer */
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 4096
#endif
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
#endif
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (16 * 1024)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
#endif
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
/* #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG */
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
#endif
/* ================ USB Device Port Configuration ================*/
#define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT
#ifndef CONFIG_HPM_USBD_BASE
#define CONFIG_HPM_USBD_BASE HPM_USB0_BASE
#endif
#ifndef CONFIG_HPM_USBD_IRQn
#define CONFIG_HPM_USBD_IRQn IRQn_USB0
#endif
/* ================ USB Host Port Configuration ==================*/
#define CONFIG_USBHOST_MAX_BUS USB_SOC_MAX_COUNT
#ifndef CONFIG_HPM_USBH_BASE
#define CONFIG_HPM_USBH_BASE HPM_USB0_BASE
#endif
#ifndef CONFIG_HPM_USBH_IRQn
#define CONFIG_HPM_USBH_IRQn IRQn_USB0
#endif
/* ================ EHCI Configuration ================ */
#define CONFIG_USB_EHCI_HPMICRO (1)
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x100u)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
#define CONFIG_USB_EHCI_QH_NUM 10
#define CONFIG_USB_EHCI_QTD_NUM 64
/* ================ Addr Convert Configuration ==================*/
#ifndef usb_phyaddr2ramaddr
#define usb_phyaddr2ramaddr(addr) core_local_mem_to_sys_address(BOARD_RUNNING_CORE, addr)
#endif
#ifndef usb_ramaddr2phyaddr
#define usb_ramaddr2phyaddr(addr) sys_address_to_core_local_mem(BOARD_RUNNING_CORE, addr)
#endif
#define ATTR_FAST_RAM_SECTION __attribute__((section(".fast")))
// #define CONFIG_USB_EHCI_ISO
#endif

View File

@@ -0,0 +1,277 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbotg_core.h"
#include "usbd_cdc_acm.h"
/*!< endpoint address */
#define CDC_IN_EP 0x81
#define CDC_OUT_EP 0x02
#define CDC_INT_EP 0x83
#define USBD_LANGID_STRING 1033
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
#ifdef CONFIG_USB_HS
#define CDC_MAX_MPS 512
#else
#define CDC_MAX_MPS 64
#endif
#ifdef CONFIG_USBDEV_ADVANCE_DESC
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
static const uint8_t config_descriptor[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
///////////////////////////////////////
/// device qualifier descriptor
///////////////////////////////////////
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x00,
0x00,
};
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"CherryUSB", /* Manufacturer */
"CherryUSB CDC DEMO", /* Product */
"2022123456", /* Serial Number */
};
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
return config_descriptor;
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
return device_quality_descriptor;
}
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index > 3) {
return NULL;
}
return string_descriptors[index];
}
const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
#else
/*!< global descriptor */
static const uint8_t cdc_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
///////////////////////////////////////
/// string0 descriptor
///////////////////////////////////////
USB_LANGID_INIT(USBD_LANGID_STRING),
///////////////////////////////////////
/// string1 descriptor
///////////////////////////////////////
0x14, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
///////////////////////////////////////
/// string2 descriptor
///////////////////////////////////////
0x26, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
' ', 0x00, /* wcChar9 */
'C', 0x00, /* wcChar10 */
'D', 0x00, /* wcChar11 */
'C', 0x00, /* wcChar12 */
' ', 0x00, /* wcChar13 */
'D', 0x00, /* wcChar14 */
'E', 0x00, /* wcChar15 */
'M', 0x00, /* wcChar16 */
'O', 0x00, /* wcChar17 */
///////////////////////////////////////
/// string3 descriptor
///////////////////////////////////////
0x16, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'2', 0x00, /* wcChar0 */
'0', 0x00, /* wcChar1 */
'2', 0x00, /* wcChar2 */
'2', 0x00, /* wcChar3 */
'1', 0x00, /* wcChar4 */
'2', 0x00, /* wcChar5 */
'3', 0x00, /* wcChar6 */
'4', 0x00, /* wcChar7 */
'5', 0x00, /* wcChar8 */
'6', 0x00, /* wcChar9 */
#ifdef CONFIG_USB_HS
///////////////////////////////////////
/// device qualifier descriptor
///////////////////////////////////////
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x00,
0x00,
#endif
0x00
};
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
volatile bool ep_tx_busy_flag = false;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
ep_tx_busy_flag = false;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
// for (int i = 0; i < 100; i++) {
// printf("%02x ", read_buffer[i]);
// }
// printf("\r\n");
/* setup next out ep read transfer */
usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
}
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
} else {
ep_tx_busy_flag = false;
}
}
/*!< endpoint call back */
struct usbd_endpoint cdc_out_ep = {
.ep_addr = CDC_OUT_EP,
.ep_cb = usbd_cdc_acm_bulk_out
};
struct usbd_endpoint cdc_in_ep = {
.ep_addr = CDC_IN_EP,
.ep_cb = usbd_cdc_acm_bulk_in
};
static struct usbd_interface intf0;
static struct usbd_interface intf1;
void cdc_acm_otg_init(uint8_t busid, uintptr_t reg_base)
{
const uint8_t data[10] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 };
memcpy(&write_buffer[0], data, 10);
memset(&write_buffer[10], 'a', 2038);
#ifdef CONFIG_USBDEV_ADVANCE_DESC
usbd_desc_register(busid, &cdc_descriptor);
#else
usbd_desc_register(busid, cdc_descriptor);
#endif
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
usbd_add_endpoint(busid, &cdc_out_ep);
usbd_add_endpoint(busid, &cdc_in_ep);
usbotg_initialize(busid, reg_base, usbd_event_handler, NULL, USBOTG_MODE_DEVICE);
}
volatile uint8_t dtr_enable = 0;
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
{
if (dtr) {
dtr_enable = 1;
} else {
dtr_enable = 0;
}
}
void cdc_acm_data_send_with_dtr_test(uint8_t busid)
{
if (dtr_enable) {
ep_tx_busy_flag = true;
usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
while (ep_tx_busy_flag) {
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,763 @@
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <lwip/sockets.h>
#include <FreeRTOS.h>
#include <task.h>
#include "iperf.h"
#include "hpm_clock_drv.h"
#include "hpm_csr_drv.h"
#include "board.h"
// TODO move to common
#define xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, \
pvParameters, uxPriority, \
pvCreatedTask, xCoreID_) \
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, \
uxPriority, pvCreatedTask)
int64_t iperf_timer_get_time()
{
return (hpm_csr_get_core_mcycle() / (clock_get_frequency(clock_cpu0) / 1000000));
}
#define iperf_delay_us board_delay_us
#define IRAM_ATTR __attribute__((section(".fast"))) // on tcm run
#define IPERF_V6 0 // TODO sync with lwip config
#define iperf_err_t int
#define IPERF_OK 0 /*!< iperf_err_t value indicating success (no error) */
#define IPERF_FAIL -1 /*!< Generic iperf_err_t code indicating failure */
#define IPERF_LOGE(tag, format, ...) \
do { \
(void)tag; \
printf("[%s] " format "\r\n", tag, ##__VA_ARGS__); \
} while (0)
#define IPERF_LOGW(tag, format, ...) \
do { \
(void)tag; \
printf("[%s] " format "\r\n", tag, ##__VA_ARGS__); \
} while (0)
#define IPERF_LOGI(tag, format, ...) \
do { \
(void)tag; \
printf("[%s] " format "\r\n", tag, ##__VA_ARGS__); \
} while (0)
#define IPERF_LOGD(tag, format, ...) \
do { \
(void)tag; \
printf("[%s] " format "\r\n", tag, ##__VA_ARGS__); \
} while (0)
#define IPERF_LOGV(tag, format, ...) \
do { \
(void)tag; \
printf("[%s] " format "\r\n", tag, ##__VA_ARGS__); \
} while (0)
#define IPERF_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) \
do { \
(void)log_tag; \
if ((!(a))) { \
ret = err_code; \
goto goto_tag; \
} \
} while (0)
#define NL "\r\n"
typedef struct {
iperf_cfg_t cfg;
bool finish;
uint32_t actual_len;
uint32_t tot_len;
uint32_t buffer_len;
uint8_t *buffer;
uint32_t sockfd;
} iperf_ctrl_t;
static bool s_iperf_is_running = false;
static iperf_ctrl_t s_iperf_ctrl;
static const char *TAG = "iperf";
inline static bool iperf_is_udp_client(void)
{
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
}
inline static bool iperf_is_udp_server(void)
{
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
}
inline static bool iperf_is_tcp_client(void)
{
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
}
inline static bool iperf_is_tcp_dual_client(void)
{
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_DUAL));
}
inline static bool iperf_is_tcp_server(void)
{
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
}
static int iperf_get_socket_error_code(int sockfd)
{
return errno;
}
static int iperf_show_socket_error_reason(const char *str, int sockfd)
{
int err = errno;
if (err != 0) {
IPERF_LOGW(TAG, "%s error, error code: %d, reason: %s", str, err, strerror(err));
}
return err;
}
static void iperf_report_task(void *arg)
{
uint32_t interval = s_iperf_ctrl.cfg.interval;
uint32_t time = s_iperf_ctrl.cfg.time;
TickType_t delay_interval = (interval * 1000) / portTICK_PERIOD_MS;
uint32_t cur = 0;
double average = 0;
double actual_bandwidth = 0;
double actual_transfer = 0;
int k = 1;
printf("[ ID] Interval Transfer Bandwidth\r\n");
while (!s_iperf_ctrl.finish) {
vTaskDelay(delay_interval);
actual_bandwidth = (s_iperf_ctrl.actual_len / 1e6 * 8) / interval;
actual_transfer = s_iperf_ctrl.actual_len / 1e6;
printf("[%3d] %2d.0-%2d.0 sec %.2f MByte %.2f Mbits/sec\r\n",
s_iperf_ctrl.sockfd, cur, cur + interval, actual_transfer, actual_bandwidth);
cur += interval;
average = ((average * (k - 1) / k) + (actual_bandwidth / k));
k++;
s_iperf_ctrl.actual_len = 0;
if (cur >= time) {
actual_transfer = s_iperf_ctrl.tot_len / 1e6;
printf("[%3d] %2d.0-%2d.0 sec %.2f MByte %.2f Mbits/sec\r\n",
s_iperf_ctrl.sockfd, 0, time, actual_transfer, average);
break;
}
}
s_iperf_ctrl.finish = true;
vTaskDelete(NULL);
}
static iperf_err_t iperf_start_report(void)
{
int ret;
ret = xTaskCreatePinnedToCore(iperf_report_task, IPERF_REPORT_TASK_NAME, IPERF_REPORT_TASK_STACK, NULL, s_iperf_ctrl.cfg.traffic_task_priority, NULL, portNUM_PROCESSORS - 1);
if (ret != pdPASS) {
IPERF_LOGE(TAG, "create task %s failed", IPERF_REPORT_TASK_NAME);
return IPERF_FAIL;
}
return IPERF_OK;
}
static void socket_recv(int recv_socket, struct sockaddr_storage listen_addr, uint8_t type)
{
bool iperf_recv_start = true;
uint8_t *buffer;
int want_recv = 0;
int actual_recv = 0;
#if IPERF_V6
socklen_t socklen = (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
#else
socklen_t socklen = sizeof(struct sockaddr_in);
#endif
const char *error_log = (type == IPERF_TRANS_TYPE_TCP) ? "tcp server recv" : "udp server recv";
buffer = s_iperf_ctrl.buffer;
want_recv = s_iperf_ctrl.buffer_len;
while (!s_iperf_ctrl.finish) {
actual_recv = recvfrom(recv_socket, buffer, want_recv, 0, (struct sockaddr *)&listen_addr, &socklen);
if (actual_recv < 0) {
iperf_show_socket_error_reason(error_log, recv_socket);
s_iperf_ctrl.finish = true;
break;
} else {
if (iperf_recv_start) {
iperf_start_report();
iperf_recv_start = false;
}
s_iperf_ctrl.actual_len += actual_recv;
s_iperf_ctrl.tot_len += actual_recv;
if (s_iperf_ctrl.cfg.num_bytes > 0 && s_iperf_ctrl.tot_len > s_iperf_ctrl.cfg.num_bytes) {
break;
}
}
}
}
static void socket_recv_dual(int recv_socket, struct sockaddr_storage listen_addr, uint8_t type)
{
uint8_t *buffer;
int want_recv = 0;
int actual_recv = 0;
socklen_t socklen = sizeof(struct sockaddr_in);
#define RECV_DUAL_BUF_LEN (16 * 1024)
buffer = pvPortMalloc(RECV_DUAL_BUF_LEN);
want_recv = RECV_DUAL_BUF_LEN;
if (!buffer) {
return;
}
while (1) {
actual_recv = recvfrom(recv_socket, buffer, want_recv, 0, (struct sockaddr *)&listen_addr, &socklen);
if (actual_recv <= 0) {
break;
}
}
vPortFree(buffer);
}
typedef struct {
int32_t flags;
int32_t numThreads;
int32_t mPort;
int32_t bufferlen;
int32_t mWindowSize;
int32_t mAmount;
int32_t mRate;
int32_t mUDPRateUnits;
int32_t mRealtime;
} iperf_client_hdr_t;
#define HEADER_VERSION1 0x80000000
#define RUN_NOW 0x00000001
#define UNITS_PPS 0x00000002
static void send_dual_header(int sock, struct sockaddr *addr, socklen_t socklen)
{
iperf_client_hdr_t hdr = {};
iperf_cfg_t *cfg = &s_iperf_ctrl.cfg;
hdr.flags = htonl(HEADER_VERSION1 | RUN_NOW);
hdr.numThreads = htonl(1);
hdr.mPort = htonl(cfg->sport);
hdr.mAmount = htonl(-(cfg->time * 100));
sendto(sock, &hdr, sizeof(hdr), 0, addr, socklen);
}
static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint8_t type, int bw_lim)
{
uint8_t *buffer;
int32_t *pkt_id_p;
int32_t pkt_cnt = 0;
int actual_send = 0;
int want_send = 0;
int period_us = -1;
int delay_us = 0;
int64_t prev_time = 0;
int64_t send_time = 0;
int err = 0;
#if IPERF_V6
const socklen_t socklen = (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
#else
const socklen_t socklen = sizeof(struct sockaddr_in);
#endif
const char *error_log = (type == IPERF_TRANS_TYPE_TCP) ? "tcp client send" : "udp client send";
buffer = s_iperf_ctrl.buffer;
pkt_id_p = (int32_t *)s_iperf_ctrl.buffer;
want_send = s_iperf_ctrl.buffer_len;
iperf_start_report();
if (bw_lim > 0) {
period_us = want_send * 8 / bw_lim;
}
if (iperf_is_tcp_dual_client()) {
send_dual_header(send_socket, (struct sockaddr *)&dest_addr, socklen);
}
while (!s_iperf_ctrl.finish) {
if (period_us > 0) {
send_time = iperf_timer_get_time();
if (actual_send > 0) {
// Last packet "send" was successful, check how much off the previous loop duration was to the ideal send period. Result will adjust the
// next send delay.
delay_us += period_us + (int32_t)(prev_time - send_time);
} else {
// Last packet "send" was not successful. Ideally we should try to catch up the whole previous loop duration (e.g. prev_time - send_time).
// However, that's not possible since the most probable reason why the send was unsuccessful is the HW was not able to process the packet.
// Hence, we cannot queue more packets with shorter (or no) delay to catch up since we are already at the performance edge. The best we
// can do is to reset the send delay (which is probably big negative number) and start all over again.
delay_us = 0;
}
prev_time = send_time;
}
*pkt_id_p = htonl(pkt_cnt); // datagrams need to be sequentially numbered
if (pkt_cnt >= INT32_MAX) {
pkt_cnt = 0;
} else {
pkt_cnt++;
}
actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, socklen);
if (actual_send != want_send) {
if (type == IPERF_TRANS_TYPE_UDP) {
err = iperf_get_socket_error_code(send_socket);
// ENOMEM is expected under heavy load => do not print it
if (err != ENOMEM) {
iperf_show_socket_error_reason(error_log, send_socket);
}
} else if (type == IPERF_TRANS_TYPE_TCP) {
iperf_show_socket_error_reason(error_log, send_socket);
break;
}
} else {
s_iperf_ctrl.actual_len += actual_send;
s_iperf_ctrl.tot_len += actual_send;
if (s_iperf_ctrl.cfg.num_bytes > 0 && s_iperf_ctrl.tot_len >= s_iperf_ctrl.cfg.num_bytes) {
break;
}
}
// The send delay may be negative, it indicates we are trying to catch up and hence to not delay the loop at all.
if (delay_us > 0) {
iperf_delay_us(delay_us);
}
}
}
static iperf_err_t IRAM_ATTR iperf_run_tcp_server(void)
{
int listen_socket = -1;
int client_socket = -1;
int opt = 1;
int err = 0;
iperf_err_t ret = IPERF_OK;
struct sockaddr_in remote_addr;
struct timeval timeout = { 0 };
socklen_t addr_len = sizeof(struct sockaddr);
struct sockaddr_storage listen_addr = { 0 };
#if IPERF_V6
struct sockaddr_in6 listen_addr6 = { 0 };
#endif
struct sockaddr_in listen_addr4 = { 0 };
IPERF_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), IPERF_FAIL, exit, TAG, "Ivalid AF types");
#if IPERF_V6
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
// The TCP server listen at the address "::", which means all addresses can be listened to.
inet6_aton("::", &listen_addr6.sin6_addr);
listen_addr6.sin6_family = AF_INET6;
listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
listen_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
IPERF_GOTO_ON_FALSE((listen_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(listen_socket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
IPERF_LOGI(TAG, "Socket created");
err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(listen_addr6));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET6);
err = listen(listen_socket, 1);
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
} else
#endif
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
listen_addr4.sin_family = AF_INET;
listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
IPERF_GOTO_ON_FALSE((listen_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
IPERF_LOGI(TAG, "Socket created");
err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(listen_addr4));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET);
err = listen(listen_socket, 5);
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
}
client_socket = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
IPERF_LOGI(TAG, "accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
socket_recv(client_socket, listen_addr, IPERF_TRANS_TYPE_TCP);
exit:
if (client_socket != -1) {
close(client_socket);
}
if (listen_socket != -1) {
shutdown(listen_socket, 0);
close(listen_socket);
IPERF_LOGI(TAG, "TCP Socket server is closed.");
}
s_iperf_ctrl.finish = true;
return ret;
}
static void IRAM_ATTR iperf_tcp_dual_server_task(void *pvParameters)
{
int listen_socket = -1;
int client_socket = -1;
int opt = 1;
int err = 0;
iperf_err_t ret = IPERF_OK;
struct sockaddr_in remote_addr;
struct timeval timeout = { 0 };
socklen_t addr_len = sizeof(struct sockaddr);
struct sockaddr_storage listen_addr = { 0 };
struct sockaddr_in listen_addr4 = { 0 };
(void)ret;
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
listen_addr4.sin_family = AF_INET;
listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
IPERF_GOTO_ON_FALSE((listen_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
IPERF_LOGI(TAG, "Socket created");
err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(listen_addr4));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET);
err = listen(listen_socket, 5);
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
}
client_socket = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
IPERF_LOGI(TAG, "accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
socket_recv_dual(client_socket, listen_addr, IPERF_TRANS_TYPE_TCP);
exit:
if (client_socket != -1) {
close(client_socket);
}
if (listen_socket != -1) {
shutdown(listen_socket, 0);
close(listen_socket);
IPERF_LOGI(TAG, "TCP Socket server is closed.");
}
vTaskDelete(NULL);
}
static iperf_err_t iperf_run_tcp_client(void)
{
int client_socket = -1;
int err = 0;
iperf_err_t ret = IPERF_OK;
struct sockaddr_storage dest_addr = { 0 };
#if IPERF_V6
struct sockaddr_in6 dest_addr6 = { 0 };
#endif
struct sockaddr_in dest_addr4 = { 0 };
int opt = s_iperf_ctrl.cfg.tos;
IPERF_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), IPERF_FAIL, exit, TAG, "Ivalid AF types");
if (iperf_is_tcp_dual_client()) {
xTaskCreate(iperf_tcp_dual_server_task, "dual_rx", IPERF_TRAFFIC_TASK_STACK, NULL, s_iperf_ctrl.cfg.traffic_task_priority, NULL);
vTaskDelay(pdMS_TO_TICKS(100));
}
#if IPERF_V6
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
client_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
setsockopt(client_socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
dest_addr6.sin6_family = AF_INET6;
dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
err = connect(client_socket, (struct sockaddr *)&dest_addr6, sizeof(struct sockaddr_in6));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
IPERF_LOGI(TAG, "Successfully connected");
memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
} else
#endif
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
setsockopt(client_socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
dest_addr4.sin_family = AF_INET;
dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
err = connect(client_socket, (struct sockaddr *)&dest_addr4, sizeof(struct sockaddr_in));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
IPERF_LOGI(TAG, "Successfully connected");
memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
}
socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_TCP, s_iperf_ctrl.cfg.bw_lim);
exit:
if (client_socket != -1) {
shutdown(client_socket, 0);
close(client_socket);
IPERF_LOGI(TAG, "TCP Socket client is closed.");
}
s_iperf_ctrl.finish = true;
return ret;
}
static iperf_err_t IRAM_ATTR iperf_run_udp_server(void)
{
int listen_socket = -1;
int opt = 1;
int err = 0;
iperf_err_t ret = IPERF_OK;
struct timeval timeout = { 0 };
struct sockaddr_storage listen_addr = { 0 };
#if IPERF_V6
struct sockaddr_in6 listen_addr6 = { 0 };
#endif
struct sockaddr_in listen_addr4 = { 0 };
IPERF_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), IPERF_FAIL, exit, TAG, "Ivalid AF types");
#if IPERF_V6
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
// The UDP server listen at the address "::", which means all addresses can be listened to.
inet6_aton("::", &listen_addr6.sin6_addr);
listen_addr6.sin6_family = AF_INET6;
listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
listen_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
IPERF_GOTO_ON_FALSE((listen_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
IPERF_LOGI(TAG, "Socket created");
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(struct sockaddr_in6));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
IPERF_LOGI(TAG, "Socket bound, port %d", listen_addr6.sin6_port);
memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
} else
#endif
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
listen_addr4.sin_family = AF_INET;
listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
listen_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
IPERF_GOTO_ON_FALSE((listen_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
IPERF_LOGI(TAG, "Socket created");
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(struct sockaddr_in));
IPERF_GOTO_ON_FALSE((err == 0), IPERF_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
IPERF_LOGI(TAG, "Socket bound, port %d", listen_addr4.sin_port);
memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
}
timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
socket_recv(listen_socket, listen_addr, IPERF_TRANS_TYPE_UDP);
exit:
if (listen_socket != -1) {
shutdown(listen_socket, 0);
close(listen_socket);
}
IPERF_LOGI(TAG, "Udp socket server is closed.");
s_iperf_ctrl.finish = true;
return ret;
}
static iperf_err_t iperf_run_udp_client(void)
{
int client_socket = -1;
int opt = 1;
iperf_err_t ret = IPERF_OK;
struct sockaddr_storage dest_addr = { 0 };
#if IPERF_V6
struct sockaddr_in6 dest_addr6 = { 0 };
#endif
struct sockaddr_in dest_addr4 = { 0 };
IPERF_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), IPERF_FAIL, exit, TAG, "Ivalid AF types");
#if IPERF_V6
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
dest_addr6.sin6_family = AF_INET6;
dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
client_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
IPERF_LOGI(TAG, "Socket created, sending to %s:%d", s_iperf_ctrl.cfg.destination_ip6, s_iperf_ctrl.cfg.dport);
setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
opt = s_iperf_ctrl.cfg.tos;
setsockopt(client_socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
} else
#endif
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
dest_addr4.sin_family = AF_INET;
dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
IPERF_GOTO_ON_FALSE((client_socket >= 0), IPERF_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
IPERF_LOGI(TAG, "Socket created, sending to %d:%d", s_iperf_ctrl.cfg.destination_ip4, s_iperf_ctrl.cfg.dport);
setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
opt = s_iperf_ctrl.cfg.tos;
setsockopt(client_socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
}
socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_UDP, s_iperf_ctrl.cfg.bw_lim);
exit:
if (client_socket != -1) {
shutdown(client_socket, 0);
close(client_socket);
}
s_iperf_ctrl.finish = true;
IPERF_LOGI(TAG, "UDP Socket client is closed");
return ret;
}
static void iperf_task_traffic(void *arg)
{
if (iperf_is_udp_client()) {
iperf_run_udp_client();
} else if (iperf_is_udp_server()) {
iperf_run_udp_server();
} else if (iperf_is_tcp_client()) {
iperf_run_tcp_client();
} else {
iperf_run_tcp_server();
}
if (s_iperf_ctrl.buffer) {
vPortFree(s_iperf_ctrl.buffer);
s_iperf_ctrl.buffer = NULL;
}
printf("iperf exit\r\n");
s_iperf_is_running = false;
vTaskDelete(NULL);
}
static uint32_t iperf_get_buffer_len(void)
{
if (iperf_is_udp_client()) {
return (s_iperf_ctrl.cfg.len_buf == 0 ? IPERF_UDP_TX_LEN : s_iperf_ctrl.cfg.len_buf);
} else if (iperf_is_udp_server()) {
return IPERF_UDP_RX_LEN;
} else if (iperf_is_tcp_client()) {
return (s_iperf_ctrl.cfg.len_buf == 0 ? IPERF_TCP_TX_LEN : s_iperf_ctrl.cfg.len_buf);
} else {
return (s_iperf_ctrl.cfg.len_buf == 0 ? IPERF_TCP_RX_LEN : s_iperf_ctrl.cfg.len_buf);
}
return 0;
}
static void net_iperf_print_header(iperf_cfg_t *cfg)
{
printf("------------------------------------------------------------\r\n");
if (iperf_is_udp_server()) {
printf("Server listening on UDP port %d\r\n",
cfg->sport);
} else if (iperf_is_tcp_server()) {
printf("Server listening on TCP port %d\r\n",
cfg->sport);
} else if (iperf_is_udp_client()) {
printf("Client connecting to %s, UDP port %d\r\n"
"Sending %d byte datagrams\r\n",
inet_ntoa(cfg->destination_ip4),
cfg->dport, cfg->num_bytes);
} else if (iperf_is_tcp_client()) {
printf("Client connecting to %s, TCP port %d\r\n",
inet_ntoa(cfg->destination_ip4), cfg->dport);
}
printf("------------------------------------------------------------\r\n");
}
iperf_err_t iperf_start(iperf_cfg_t *cfg)
{
BaseType_t ret;
if (!cfg) {
return IPERF_FAIL;
}
if (s_iperf_is_running) {
IPERF_LOGW(TAG, "iperf is running");
printf("iperf is running\r\n");
return IPERF_FAIL;
}
memset(&s_iperf_ctrl, 0, sizeof(s_iperf_ctrl));
memcpy(&s_iperf_ctrl.cfg, cfg, sizeof(*cfg));
s_iperf_is_running = true;
s_iperf_ctrl.finish = false;
s_iperf_ctrl.buffer_len = iperf_get_buffer_len();
s_iperf_ctrl.buffer = (uint8_t *)pvPortMalloc(s_iperf_ctrl.buffer_len);
if (!s_iperf_ctrl.buffer) {
IPERF_LOGE(TAG, "create buffer: not enough memory");
return IPERF_FAIL;
}
memset(s_iperf_ctrl.buffer, 0, s_iperf_ctrl.buffer_len);
ret = xTaskCreatePinnedToCore(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, s_iperf_ctrl.cfg.traffic_task_priority, NULL, portNUM_PROCESSORS - 1);
if (ret != pdPASS) {
IPERF_LOGE(TAG, "create task %s failed", IPERF_TRAFFIC_TASK_NAME);
vPortFree(s_iperf_ctrl.buffer);
s_iperf_ctrl.buffer = NULL;
return IPERF_FAIL;
}
net_iperf_print_header(cfg);
return IPERF_OK;
}
iperf_err_t iperf_stop(void)
{
if (s_iperf_is_running) {
s_iperf_ctrl.finish = true;
}
return IPERF_OK;
}

View File

@@ -0,0 +1,82 @@
/* Iperf Example - iperf declaration
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef __IPERF_H_
#define __IPERF_H_
#ifdef __cplusplus
extern "C" {
#endif
#define IPERF_IP_TYPE_IPV4 0
#define IPERF_IP_TYPE_IPV6 1
#define IPERF_TRANS_TYPE_TCP 0
#define IPERF_TRANS_TYPE_UDP 1
#define IPERF_FLAG_SET(cfg, flag) ((cfg) |= (flag))
#define IPERF_FLAG_CLR(cfg, flag) ((cfg) &= (~(flag)))
#define IPERF_FLAG_CLIENT (1)
#define IPERF_FLAG_SERVER (1 << 1)
#define IPERF_FLAG_TCP (1 << 2)
#define IPERF_FLAG_UDP (1 << 3)
#define IPERF_FLAG_DUAL (1 << 4)
#define IPERF_DEFAULT_PORT 5001
#define IPERF_DEFAULT_INTERVAL 1
#define IPERF_DEFAULT_TIME 10
#define IPERF_DEFAULT_NO_BW_LIMIT -1
#define IPERF_TRAFFIC_TASK_NAME "iperf_traffic"
#define IPERF_TRAFFIC_TASK_PRIORITY 10
#define IPERF_TRAFFIC_TASK_STACK 2048
#define IPERF_REPORT_TASK_NAME "iperf_report"
#define IPERF_REPORT_TASK_STACK 2048
#define IPERF_UDP_TX_LEN (1470)
#define IPERF_UDP_RX_LEN (1470)
#define IPERF_TCP_TX_LEN (8 << 10)
#define IPERF_TCP_RX_LEN (8 << 10)
#define IPERF_MAX_DELAY 64
#define IPERF_SOCKET_RX_TIMEOUT 10
#define IPERF_SOCKET_ACCEPT_TIMEOUT 5
typedef struct {
uint32_t flag;
union {
uint32_t destination_ip4;
char *destination_ip6;
};
union {
uint32_t source_ip4;
char *source_ip6;
};
uint8_t type;
uint16_t dport;
uint16_t sport;
uint32_t interval;
uint32_t time;
uint16_t len_buf;
int32_t bw_lim;
uint8_t tos;
uint8_t traffic_task_priority;
uint32_t num_bytes;
} iperf_cfg_t;
int iperf_start(iperf_cfg_t *cfg);
int iperf_stop(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,115 @@
#include <string.h>
#include <stdint.h>
#include <utils_getopt.h>
#include <iperf.h>
#include <lwip/ip_addr.h>
#define NL "\r\n"
static void iperf_cmd(int argc, char **argv)
{
int opt;
getopt_env_t opt_env;
int o_c = 0, o_s = 0, o_u = 0, o_a = 0;
int o_p = IPERF_DEFAULT_PORT, o_l = 0, o_i = IPERF_DEFAULT_INTERVAL, o_t = IPERF_DEFAULT_TIME, o_b = IPERF_DEFAULT_NO_BW_LIMIT, o_S = 0, o_n = 0;
int o_d = 0;
int o_P = IPERF_TRAFFIC_TASK_PRIORITY;
uint32_t dst_addr = 0;
iperf_cfg_t cfg;
utils_getopt_init(&opt_env, 0);
while ((opt = utils_getopt(&opt_env, argc, argv, ":c:sup:l:i:t:b:S:n:P:ad")) != -1) {
#define ARG_READ(v) v = atoi(opt_env.optarg)
switch (opt) {
case 'c':
++o_c;
dst_addr = ipaddr_addr(opt_env.optarg);
break;
case 's': ++o_s; break;
case 'u': ++o_u; break;
case 'p': ARG_READ(o_p); break;
case 'l': ARG_READ(o_l); break;
case 'i': ARG_READ(o_i); break;
case 't': ARG_READ(o_t); break;
case 'b': ARG_READ(o_b); break;
case 'S': ARG_READ(o_S); break;
case 'n': ARG_READ(o_n); break;
case 'P': ARG_READ(o_P); break;
case 'd': ++o_d; break;
case 'a': ++o_a; break;
}
#undef ARG_READ
}
memset(&cfg, 0, sizeof(cfg));
cfg.type = IPERF_IP_TYPE_IPV4;
if (o_a) {
iperf_stop();
return;
}
if (!((o_c && !o_s) || (!o_c && o_s))) {
printf("client/server required" NL);
return;
}
if (o_c) {
cfg.destination_ip4 = dst_addr;
cfg.flag |= IPERF_FLAG_CLIENT;
} else {
cfg.flag |= IPERF_FLAG_SERVER;
}
if (o_u) {
cfg.flag |= IPERF_FLAG_UDP;
} else {
cfg.flag |= IPERF_FLAG_TCP;
}
if (o_c && !o_u && o_d) {
cfg.flag |= IPERF_FLAG_DUAL;
}
cfg.len_buf = o_l;
cfg.sport = o_p;
cfg.dport = o_p;
cfg.interval = o_i;
cfg.time = o_t;
if (cfg.time < cfg.interval) {
cfg.time = cfg.interval;
}
cfg.bw_lim = o_b;
cfg.tos = o_S;
cfg.num_bytes = o_n * 1000 * 1000;
if (cfg.bw_lim <= 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
}
cfg.traffic_task_priority = o_P;
iperf_start(&cfg);
}
#include <shell.h>
#define ML(s) s NL
#define IPERF_USAGE \
ML("iperf") \
ML(" -c server_addr: run in client mode") \
ML(" -s: run in server mode") \
ML(" -u: UDP") \
ML(" -p port: specify port") \
ML(" -l length: set read/write buffer size") \
ML(" -i interval: seconds between bandwidth reports") \
ML(" -t time: time in seconds to run") \
ML(" -b bandwith: bandwidth to send in Mbps") \
ML(" -S tos: TOS") \
ML(" -n MB: number of MB to send/recv") \
ML(" -P priority: traffic task priority") \
ML(" -d: dual mode") \
ML(" -a: abort running iperf") \
#if 0
const static struct cli_command iperf_cmds[] STATIC_CLI_CMD_ATTRIBUTE = {
{"iperf", IPERF_USAGE, iperf_cmd},
};
#endif
CSH_CMD_EXPORT_ALIAS(iperf_cmd, iperf, iperf command);

View File

@@ -0,0 +1,377 @@
/*
* This file is derived from musl v1.2.0.
* Modifications are applied.
* Copyright (C) Bouffalo Lab 2016-2020
*/
/*
* Copyright © 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <utils_getopt.h>
int utils_getopt_init(getopt_env_t *env, int opterr)
{
if (!env) {
return -1;
}
env->optarg = NULL;
env->optind = 1;
env->opterr = opterr;
env->optopt = 0;
env->__optpos = 0;
return 0;
}
#define NEWLINE "\r\n"
int utils_getopt(getopt_env_t *env, int argc, char *const argv[], const char *optstring)
{
int i;
char c, d;
char *optchar;
if (!env) {
return -1;
}
if (env->optind >= argc || !argv[env->optind])
return -1;
if (argv[env->optind][0] != '-') {
if (optstring[0] == '-') {
env->optarg = argv[env->optind++];
return 1;
}
return -1;
}
if (!argv[env->optind][1])
return -1;
if (argv[env->optind][1] == '-' && !argv[env->optind][2])
return env->optind++, -1;
if (!env->__optpos)
env->__optpos++;
c = argv[env->optind][env->__optpos];
optchar = argv[env->optind] + env->__optpos;
env->__optpos += !!c;
if (!argv[env->optind][env->__optpos]) {
env->optind++;
env->__optpos = 0;
}
if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
i = 0;
do
d = optstring[i++];
while (d && d != c);
if (d != c || c == ':') {
env->optopt = c;
if (optstring[0] != ':' && env->opterr)
printf("%s: unrecognized option: %c" NEWLINE, argv[0], *optchar);
return '?';
}
if (optstring[i] == ':') {
env->optarg = 0;
if (optstring[i + 1] != ':' || env->__optpos) {
env->optarg = argv[env->optind++] + env->__optpos;
env->__optpos = 0;
}
if (env->optind > argc) {
env->optopt = c;
if (optstring[0] == ':')
return ':';
if (env->opterr) {
printf("%s: option requires an argument: %c" NEWLINE, argv[0], *optchar);
}
return '?';
}
}
return c;
}
static int params_filter(char **params, uint32_t *r)
{
char *p;
uint32_t result = 0;
uint8_t base = 0;
p = *params;
if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X'))) {
p = p + 2;
base = 16;
} else {
base = 10;
}
while (*p) {
result *= base;
if (*p >= '0' && *p <= '9')
result += *p - '0';
else if (base == 10)
return -1;
if (base == 16) {
if (*p >= 'a' && *p <= 'f')
result += *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
result += *p - 'A' + 10;
}
p++;
}
*r = result;
return 0;
}
void get_bytearray_from_string(char **params, uint8_t *result, int array_size)
{
int i = 0;
char rand[3];
for (i = 0; i < array_size; i++) {
memcpy(rand, *params, 2);
rand[2] = '\0';
result[i] = strtol(rand, NULL, 16);
*params = *params + 2;
}
}
void get_uint8_from_string(char **params, uint8_t *result)
{
uint32_t p = 0;
int state = 0;
state = params_filter(params, &p);
if (!state) {
*result = p & 0xff;
} else
*result = 0;
}
void get_uint16_from_string(char **params, uint16_t *result)
{
uint32_t p = 0;
int state = 0;
state = params_filter(params, &p);
if (!state) {
*result = p & 0xffff;
} else
*result = 0;
}
void get_uint32_from_string(char **params, uint32_t *result)
{
uint32_t p = 0;
int state = 0;
state = params_filter(params, &p);
if (!state) {
*result = p;
} else
*result = 0;
}
void utils_parse_number(const char *str, char sep, uint8_t *buf, int buflen, int base)
{
int i;
for (i = 0; i < buflen; i++) {
buf[i] = (uint8_t)strtol(str, NULL, base);
str = strchr(str, sep);
if (str == NULL || *str == '\0') {
break;
}
str++;
}
}
void utils_parse_number_adv(const char *str, char sep, uint8_t *buf, int buflen, int base, int *count)
{
int i;
for (i = 0; i < buflen; i++) {
buf[i] = (uint8_t)strtol(str, NULL, base);
str = strchr(str, sep);
if (str == NULL || *str == '\0') {
break;
}
str++;
}
*count = (i + 1);
}
unsigned long long convert_arrayToU64(uint8_t *inputArray)
{
unsigned long long result = 0;
for (uint8_t i = 0; i < 8; i++) {
result <<= 8;
result |= (unsigned long long)inputArray[7 - i];
}
return result;
}
void convert_u64ToArray(unsigned long long inputU64, uint8_t result[8])
{
for (int i = 0; i < 8; i++) {
result[i] = inputU64 >> (i * 8);
}
}
void utils_memdrain8(void *src, size_t len)
{
volatile uint8_t *s = (uint8_t *)src;
uint8_t tmp;
while (len--) {
tmp = *s++;
}
(void)tmp;
}
void utils_memdrain16(void *src, size_t len)
{
volatile uint16_t *s = (uint16_t *)src;
uint16_t tmp;
len >>= 1; //convert to half words
while (len--) {
tmp = *s++;
}
(void)tmp;
}
void utils_memdrain32(void *src, size_t len)
{
volatile uint32_t *s = (uint32_t *)src;
uint32_t tmp;
len >>= 2; //convert to words
while (len--) {
tmp = *s++;
}
(void)tmp;
}
void utils_memdrain64(void *src, size_t len)
{
volatile uint64_t *s = (uint64_t *)src;
uint64_t tmp;
len >>= 3; //convert to two words
while (len--) {
tmp = *s++;
}
(void)tmp;
}
void *utils_memdrain8_with_check(void *src, size_t len, uint8_t seq)
{
volatile uint8_t *s = (uint8_t *)src;
uint8_t tmp;
(void)tmp;
while (len--) {
tmp = *s++;
if ((seq++) != tmp) {
return (uint8_t *)s - 1;
}
}
return NULL;
}
void *utils_memdrain16_with_check(void *src, size_t len, uint16_t seq)
{
volatile uint16_t *s = (uint16_t *)src;
uint16_t tmp;
(void)tmp;
len >>= 1; //convert to half words
while (len--) {
tmp = *s++;
if ((seq++) != tmp) {
return (uint16_t *)s - 1;
}
}
return NULL;
}
void *utils_memdrain32_with_check(void *src, size_t len, uint32_t seq)
{
volatile uint32_t *s = (uint32_t *)src;
uint32_t tmp;
(void)tmp;
len >>= 2; //convert to words
while (len--) {
tmp = *s++;
if ((seq++) != tmp) {
return (uint32_t *)s - 1;
}
}
return NULL;
}
void *utils_memdrain64_with_check(void *src, size_t len, uint64_t seq)
{
volatile uint64_t *s = (uint64_t *)src;
uint64_t tmp;
(void)tmp;
len >>= 3; //convert to two words
while (len--) {
tmp = *s++;
if ((seq++) != tmp) {
return (uint64_t *)s - 1;
}
}
return NULL;
}

View File

@@ -0,0 +1,107 @@
#ifndef __GETOPT_H__
#define __GETOPT_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Parameters needed to parse the command line
*
*/
typedef struct getopt_env {
char *optarg; /*!< if the option accepts parameters, then optarg point to the option parameter*/
int optind; /*!< current index of argv*/
int opterr; /*!< non-zero enable error message output, while 0,no error message output*/
int optopt; /*!< contain unrecognized option character*/
int __optpos;
} getopt_env_t;
/**
* @brief Initialize struct getopt_env
*
* @param env pointer to struct getopt_env
* @param opterr set error message output method
*
* @return
* - 0: success
* - -1: fail
*/
int utils_getopt_init(getopt_env_t *env, int opterr);
/**
* @brief Parses the command-line arguments
*
* @param env pointer to struct getopt_env
* @param argc the argument count
* @param argv the argument array
*
* @return
* - option character : an option was successfully found
* - -1 : all command-line options have been parsed
* - '?' : option character was not in optstring
* - ':' or '?' : If utils_getopt() encounters an option with a missing argument, then the return value depends on the first character in optstring: if it is ':', then ':' is returned; otherwise '?' is returned
*
* @note Example
* @code
*
* #include <utils_getopt.h>
* #include <stdio.h>
*
* void cmd(char *buf, int len, int argc, char **argv)
* {
* int opt;
getopt_env_t getopt_env;
utils_getopt_init(&getopt_env, 0);
* //put ':' in the starting of the string so that program can distinguish between '?' and ':'
* while ((opt = utils_getopt(&getopt_env, argc, argv, ":if:lr")) != -1) {
* switch(opt)
* {
* case 'i':
* case 'l':
* case 'r':
* printf("option: %c\r\n", opt);
* break;
* case 'f':
* printf("filename: %s\r\n", getopt_env.optarg);
* break;
* case ':':
printf("%s: %c requires an argument\r\n", *argv, getopt_env.optopt);
* break;
* case '?':
* printf("unknow option: %c\r\n", getopt_env.optopt);
* break;
* }
* }
* //optind is for the extra arguments which are not parsed
* for(; getopt_env.optind < argc; getopt_env.optind++){
* printf("extra arguments: %s\r\n", argv[getopt_env.optind]);
* }
*
* }
* @endcode
*/
int utils_getopt(getopt_env_t *env, int argc, char *const argv[], const char *optstring);
void get_bytearray_from_string(char **params, uint8_t *result, int array_size);
void get_uint8_from_string(char **params, uint8_t *result);
void get_uint16_from_string(char **params, uint16_t *result);
void get_uint32_from_string(char **params, uint32_t *result);
void utils_parse_number(const char *str, char sep, uint8_t *buf, int buflen, int base);
void utils_parse_number_adv(const char *str, char sep, uint8_t *buf, int buflen, int base, int *count);
unsigned long long convert_arrayToU64(uint8_t *inputArray);
void convert_u64ToArray(unsigned long long inputU64, uint8_t result[8]);
void utils_memdrain8(void *src, size_t len);
void utils_memdrain16(void *src, size_t len);
void utils_memdrain32(void *src, size_t len);
void utils_memdrain64(void *src, size_t len);
void *utils_memdrain8_with_check(void *src, size_t len, uint8_t seq);
void *utils_memdrain16_with_check(void *src, size_t len, uint16_t seq);
void *utils_memdrain32_with_check(void *src, size_t len, uint32_t seq);
void *utils_memdrain64_with_check(void *src, size_t len, uint64_t seq);
#ifdef __cplusplus
}
#endif
#endif /* __GETOPT_H__ */

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