Преглед изворни кода

chore: add build ci

Signed-off-by: sakumisu <1203593632@qq.com>
sakumisu пре 2 месеци
родитељ
комит
0c220ea127

+ 57 - 0
.github/workflows/build_tests.yml

@@ -0,0 +1,57 @@
+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=hpm6750evk2 -DCMAKE_BUILD_TYPE=flash_sdram_xip -DEXTRA_C_FLAGS="-Werror";cmake --build build
+
+  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 - 0
.gitignore

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

+ 1 - 1
README.md

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

+ 1 - 1
README_zh.md

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

+ 9 - 0
tests/espressif/device/CMakeLists.txt

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

+ 4 - 0
tests/espressif/device/main/CMakeLists.txt

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

+ 27 - 0
tests/espressif/device/main/main.c

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

+ 7 - 0
tests/espressif/device/sdkconfig.defaults

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

+ 9 - 0
tests/espressif/host/CMakeLists.txt

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

+ 4 - 0
tests/espressif/host/main/CMakeLists.txt

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

+ 33 - 0
tests/espressif/host/main/main.c

@@ -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, NULL);
+    while(1)
+    {
+        vTaskDelay(10);
+    }
+}

+ 8 - 0
tests/espressif/host/sdkconfig.defaults

@@ -0,0 +1,8 @@
+# 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_CDC_RNDIS=y

+ 53 - 0
tests/hpmicro/CMakeLists.txt

@@ -0,0 +1,53 @@
+# 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(-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_inc(inc)
+sdk_app_src(inc/arch/sys_arch.c)
+sdk_app_src(src/main.c)
+sdk_app_src(../../demo/usb_host.c)
+# sdk_app_src(src/uvc2lcd.c)
+# sdk_app_src(src/font24x48.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/usbh_uvc_port.c)
+
+set(CONFIG_CHERRYMP 1)
+set(CONFIG_CHERRYUSB 1)
+set(CONFIG_CHERRYUSB_DEVICE 1)
+set(CONFIG_CHERRYUSB_HOST 1)
+
+# add_subdirectory(src/cherryusb_hostuvcuac)
+add_subdirectory(../.. cherryusb)
+
+generate_ses_project()

+ 154 - 0
tests/hpmicro/inc/FreeRTOSConfig.h

@@ -0,0 +1,154 @@
+/*
+ * 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
+
+#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) (120 * 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 */

+ 91 - 0
tests/hpmicro/inc/arch/cc.h

@@ -0,0 +1,91 @@
+/*
+ * 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-2022 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__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#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)
+
+#ifndef LWIP_MEM_SECTION
+#define LWIP_MEM_SECTION ".framebuffer"
+#endif
+
+#endif /* __CC_H__ */

+ 646 - 0
tests/hpmicro/inc/arch/sys_arch.c

@@ -0,0 +1,646 @@
+/*
+ * 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);
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+  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);
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+
+#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

+ 108 - 0
tests/hpmicro/inc/arch/sys_arch.h

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

+ 202 - 0
tests/hpmicro/inc/lwipopts.h

@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * Copyright (c) 2023 HPMicro
+ * 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
+ *
+ */
+#ifndef __LWIPOPTS_H__
+#define __LWIPOPTS_H__
+
+#include <stdint.h>
+
+#define SYS_LIGHTWEIGHT_PROT            0
+#define LWIP_PROVIDE_ERRNO              1
+
+#if defined(__SEGGER_RTL_VERSION)
+#define LWIP_TIMEVAL_PRIVATE            1
+#else
+#define LWIP_TIMEVAL_PRIVATE            0
+#endif
+
+#define LWIP_RAND                       rand
+
+#define NO_SYS                          0
+#define MEM_ALIGNMENT                   4
+#define LWIP_DNS                        1
+#define LWIP_DNS_SERVER                 0
+#define LWIP_RAW                        1
+#define LWIP_NETCONN                    1
+#define LWIP_SOCKET                     1
+#define LWIP_DHCP                       1
+#define LWIP_ICMP                       1
+#define ICMP_TTL                        64
+#define LWIP_UDP                        1
+#define LWIP_TCP                        1
+#define TCP_TTL                         255
+#define LWIP_IPV4                       1
+#define LWIP_IPV6                       0
+#define ETH_PAD_SIZE                    0
+#define LWIP_IP_ACCEPT_UDP_PORT(p)      ((p) == PP_NTOHS(67))
+#define LWIP_WND_SCALE                  1
+#define TCP_RCV_SCALE                   0
+
+#define MEM_SIZE                        (150 * 1024)
+#define TCP_MSS                         (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
+#define TCP_SND_BUF                     (50 * TCP_MSS)
+#define ETHARP_SUPPORT_STATIC_ENTRIES   1
+
+#define LWIP_HTTPD_CGI                  0
+#define LWIP_HTTPD_SSI                  0
+#define LWIP_HTTPD_SSI_INCLUDE_TAG      0
+
+/**
+ * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
+ */
+#define MEMP_MEM_MALLOC         1
+
+/* 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.
+ */
+#define MEMP_NUM_PBUF           100
+
+/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
+ * per active UDP "connection".
+ */
+#define MEMP_NUM_UDP_PCB        6
+
+/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
+ *   connections.
+ */
+#define MEMP_NUM_TCP_PCB        10
+
+/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
+ *  connections.
+ */
+#define MEMP_NUM_TCP_PCB_LISTEN 5
+
+/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
+ *  segments.
+ */
+#define MEMP_NUM_TCP_SEG        20
+
+/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
+ *  timeouts.
+ */
+#define MEMP_NUM_SYS_TIMEOUT    10
+
+
+/* ---------- Pbuf options ---------- */
+/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
+#define PBUF_POOL_SIZE          20
+
+/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool.*/
+#define PBUF_POOL_BUFSIZE       1600
+
+/* Controls if TCP should queue segments that arrive out of
+   order. Define to 0 if your device is low on memory
+*/
+#define TCP_QUEUE_OOSEQ         1
+
+/*  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.
+*/
+#define TCP_SND_QUEUELEN        (4* TCP_SND_BUF/TCP_MSS)
+
+/* TCP receive window. */
+#define TCP_WND                 (16*TCP_MSS)
+
+/*
+ *  -----------------------------------
+ *  ---------- DEBUG options ----------
+ *  -----------------------------------
+ */
+
+#define LWIP_DEBUG                      1
+
+#ifdef LWIP_DEBUG
+
+#define LWIP_DBG_MIN_LEVEL         1
+
+#define PPP_DEBUG                  LWIP_DBG_OFF
+#define MEM_DEBUG                  LWIP_DBG_OFF
+#define MEMP_DEBUG                 LWIP_DBG_OFF
+#define PBUF_DEBUG                 LWIP_DBG_OFF
+#define API_LIB_DEBUG              LWIP_DBG_OFF
+#define API_MSG_DEBUG              LWIP_DBG_OFF
+#define TCPIP_DEBUG                LWIP_DBG_OFF
+#define NETIF_DEBUG                LWIP_DBG_OFF
+#define SOCKETS_DEBUG              LWIP_DBG_OFF
+#define DNS_DEBUG                  LWIP_DBG_OFF
+#define AUTOIP_DEBUG               LWIP_DBG_OFF
+#define DHCP_DEBUG                 LWIP_DBG_OFF
+#define IP_DEBUG                   LWIP_DBG_OFF
+#define IP_REASS_DEBUG             LWIP_DBG_OFF
+#define ICMP_DEBUG                 LWIP_DBG_OFF
+#define IGMP_DEBUG                 LWIP_DBG_OFF
+#define UDP_DEBUG                  LWIP_DBG_OFF
+#define TCP_DEBUG                  LWIP_DBG_OFF
+#define TCP_INPUT_DEBUG            LWIP_DBG_OFF
+#define TCP_OUTPUT_DEBUG           LWIP_DBG_OFF
+#define TCP_RTO_DEBUG              LWIP_DBG_OFF
+#define TCP_CWND_DEBUG             LWIP_DBG_OFF
+#define TCP_WND_DEBUG              LWIP_DBG_OFF
+#define TCP_FR_DEBUG               LWIP_DBG_OFF
+#define TCP_QLEN_DEBUG             LWIP_DBG_OFF
+#define TCP_RST_DEBUG              LWIP_DBG_OFF
+#define ETHARP_DEBUG               LWIP_DBG_OFF
+
+#endif
+
+#define DHCP_DOES_ARP_CHECK             0
+
+/*
+ *  ---------------------------------
+ *  ---------- OS options ----------
+ *  ---------------------------------
+ */
+
+#define TCPIP_THREAD_NAME              "tcpip"
+#define TCPIP_THREAD_STACKSIZE          1500
+#define TCPIP_MBOX_SIZE                 64
+#define DEFAULT_RAW_RECVMBOX_SIZE       1000
+#define DEFAULT_UDP_RECVMBOX_SIZE       100
+#define DEFAULT_TCP_RECVMBOX_SIZE       100
+#define DEFAULT_ACCEPTMBOX_SIZE         1500
+#define DEFAULT_THREAD_STACKSIZE        500
+#define TCPIP_THREAD_PRIO               31
+#define LWIP_SINGLE_NETIF               1
+#define LWIP_COMPAT_MUTEX               0
+
+#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
+#define LWIP_TCPIP_CORE_LOCKING       1
+
+#include <FreeRTOS.h>
+#include <task.h>
+#endif /* __LWIPOPTS_H__ */

+ 309 - 0
tests/hpmicro/inc/usb_config.h

@@ -0,0 +1,309 @@
+/*
+ * 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(".noncacheable.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        8
+
+#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 512
+#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 ================*/
+
+#define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM USB_SOC_DCD_MAX_ENDPOINT_COUNT
+#endif
+
+#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
+#define CONFIG_USBHOST_PIPE_NUM 10
+
+#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_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
+
+#endif

+ 104 - 0
tests/hpmicro/src/main.c

@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2021 HPMicro
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* FreeRTOS kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/*  HPM example includes. */
+#include <stdio.h>
+#include "board.h"
+#include "hpm_clock_drv.h"
+#include "shell.h"
+#include "usbh_core.h"
+#include "lwip/tcpip.h"
+
+SDK_DECLARE_EXT_ISR_M(BOARD_CONSOLE_UART_IRQ, shell_uart_isr)
+
+#define task_start_PRIORITY (configMAX_PRIORITIES - 2U)
+
+static void task_start(void *param);
+
+int main(void)
+{
+    board_init();
+    board_init_led_pins();
+    board_init_usb((USB_Type *)CONFIG_HPM_USBH_BASE);
+
+    /* set irq priority */
+    intc_set_irq_priority(CONFIG_HPM_USBH_IRQn, 1);
+
+    /* Initialize the LwIP stack */
+    tcpip_init(NULL, NULL);
+
+    printf("Start usb host task...\r\n");
+
+    usbh_initialize(0, CONFIG_HPM_USBH_BASE, NULL);
+
+    if (pdPASS != xTaskCreate(task_start, "task_start", 1024U, NULL, task_start_PRIORITY, NULL)) {
+        printf("Task start creation failed!\r\n");
+        for (;;) {
+            ;
+        }
+    }
+
+    vTaskStartScheduler();
+    printf("Unexpected scheduler exit!\r\n");
+    for (;;) {
+        ;
+    }
+
+    return 0;
+}
+
+static void task_start(void *param)
+{
+    (void)param;
+
+    printf("Try to initialize the uart\r\n"
+           "  if you are using the console uart as the shell uart\r\n"
+           "  failure to initialize may result in no log\r\n");
+
+    uart_config_t shell_uart_config = { 0 };
+    uart_default_config(BOARD_CONSOLE_UART_BASE, &shell_uart_config);
+    shell_uart_config.src_freq_in_hz = clock_get_frequency(BOARD_CONSOLE_UART_CLK_NAME);
+    shell_uart_config.baudrate = 115200;
+
+    if (status_success != uart_init(BOARD_CONSOLE_UART_BASE, &shell_uart_config)) {
+        /* uart failed to be initialized */
+        printf("Failed to initialize uart\r\n");
+        for (;;) {
+            ;
+        }
+    }
+
+    printf("Initialize shell uart successfully\r\n");
+
+    /* default password is : 12345678 */
+    /* shell_init() must be called in-task */
+    if (0 != shell_init(BOARD_CONSOLE_UART_BASE, false)) {
+        /* shell failed to be initialized */
+        printf("Failed to initialize shell\r\n");
+        for (;;) {
+            ;
+        }
+    }
+
+    printf("Initialize shell successfully\r\n");
+
+    /* irq must be enabled after shell_init() */
+    uart_enable_irq(BOARD_CONSOLE_UART_BASE, uart_intr_rx_data_avail_or_timeout);
+    intc_m_enable_irq_with_priority(BOARD_CONSOLE_UART_IRQ, 1);
+
+    printf("Enable shell uart interrupt\r\n");
+
+    printf("Exit start task\r\n");
+    vTaskDelete(NULL);
+}
+
+extern int lsusb(int argc, char **argv);
+CSH_CMD_EXPORT(lsusb, );