28
.github/workflows/build_tests.yml
vendored
28
.github/workflows/build_tests.yml
vendored
@@ -37,7 +37,33 @@ jobs:
|
||||
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
|
||||
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:
|
||||
|
||||
46
tests/bouffalolab/CMakeLists.txt
Normal file
46
tests/bouffalolab/CMakeLists.txt
Normal 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)
|
||||
13
tests/bouffalolab/Makefile
Normal file
13
tests/bouffalolab/Makefile
Normal 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
|
||||
14
tests/bouffalolab/flash_prog_cfg.ini
Normal file
14
tests/bouffalolab/flash_prog_cfg.ini
Normal 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
|
||||
|
||||
128
tests/bouffalolab/inc/FreeRTOSConfig.h
Normal file
128
tests/bouffalolab/inc/FreeRTOSConfig.h
Normal 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 */
|
||||
270
tests/bouffalolab/inc/fatfs_conf_user.h
Normal file
270
tests/bouffalolab/inc/fatfs_conf_user.h
Normal 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 ---*/
|
||||
442
tests/bouffalolab/inc/lwipopts_user.h
Normal file
442
tests/bouffalolab/inc/lwipopts_user.h
Normal 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__ */
|
||||
325
tests/bouffalolab/inc/usb_config.h
Normal file
325
tests/bouffalolab/inc/usb_config.h
Normal 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
|
||||
16
tests/bouffalolab/proj.conf
Normal file
16
tests/bouffalolab/proj.conf
Normal 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)
|
||||
158
tests/bouffalolab/src/main.c
Normal file
158
tests/bouffalolab/src/main.c
Normal 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
|
||||
@@ -23,6 +23,7 @@ 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)
|
||||
@@ -30,23 +31,23 @@ sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_RNDIS)
|
||||
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_ASIX)
|
||||
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_RTL8152)
|
||||
|
||||
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_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)
|
||||
sdk_inc(src/iperf)
|
||||
sdk_app_src(src/iperf/iperf.c src/iperf/iperf_cli.c src/iperf/utils_getopt.c src/ping.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)
|
||||
|
||||
|
||||
@@ -29,6 +29,14 @@
|
||||
#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)
|
||||
@@ -47,7 +55,7 @@
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#ifndef configTOTAL_HEAP_SIZE
|
||||
#define configTOTAL_HEAP_SIZE ((size_t) (120 * 1024))
|
||||
#define configTOTAL_HEAP_SIZE ((size_t) (64 * 1024))
|
||||
#endif
|
||||
|
||||
/* Hook function definitions. */
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021-2022 HPMicro
|
||||
* Copyright (c) 2021-2024 HPMicro
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
@@ -68,11 +68,23 @@
|
||||
|
||||
#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
|
||||
@@ -84,8 +96,4 @@
|
||||
|
||||
#define LWIP_PLATFORM_ASSERT(x) printf(x)
|
||||
|
||||
#ifndef LWIP_MEM_SECTION
|
||||
#define LWIP_MEM_SECTION ".framebuffer"
|
||||
#endif
|
||||
|
||||
#endif /* __CC_H__ */
|
||||
|
||||
@@ -124,9 +124,9 @@ 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",
|
||||
/* 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 */
|
||||
}
|
||||
@@ -136,424 +136,400 @@ sys_init(void)
|
||||
#endif
|
||||
|
||||
#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS
|
||||
u32_t
|
||||
sys_now(void)
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
||||
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
||||
}
|
||||
#else
|
||||
u32_t
|
||||
sys_now(void)
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32_t
|
||||
sys_jiffies(void)
|
||||
u32_t sys_jiffies(void)
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
|
||||
#if SYS_LIGHTWEIGHT_PROT
|
||||
|
||||
sys_prot_t
|
||||
sys_arch_protect(void)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sys_arch_unprotect(sys_prot_t pval)
|
||||
void sys_arch_unprotect(sys_prot_t pval)
|
||||
{
|
||||
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX
|
||||
BaseType_t ret;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
taskEXIT_CRITICAL();
|
||||
#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */
|
||||
LWIP_UNUSED_ARG(pval);
|
||||
LWIP_UNUSED_ARG(pval);
|
||||
}
|
||||
|
||||
#endif /* SYS_LIGHTWEIGHT_PROT */
|
||||
|
||||
void
|
||||
sys_arch_msleep(u32_t delay_ms)
|
||||
void sys_arch_msleep(u32_t delay_ms)
|
||||
{
|
||||
TickType_t delay_ticks = delay_ms / portTICK_RATE_MS;
|
||||
vTaskDelay(delay_ticks);
|
||||
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)
|
||||
err_t sys_mutex_new(sys_mutex_t *mutex)
|
||||
{
|
||||
LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
||||
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;
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);
|
||||
LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
|
||||
}
|
||||
|
||||
void
|
||||
sys_mutex_unlock(sys_mutex_t *mutex)
|
||||
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);
|
||||
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);
|
||||
ret = xSemaphoreGiveRecursive(mutex->mut);
|
||||
LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);
|
||||
}
|
||||
|
||||
void
|
||||
sys_mutex_free(sys_mutex_t *mutex)
|
||||
void sys_mutex_free(sys_mutex_t *mutex)
|
||||
{
|
||||
LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
||||
LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
|
||||
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;
|
||||
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)
|
||||
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));
|
||||
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;
|
||||
sem->sem = xSemaphoreCreateBinary();
|
||||
if (sem->sem == NULL) {
|
||||
SYS_STATS_INC(sem.err);
|
||||
return ERR_MEM;
|
||||
}
|
||||
LWIP_ASSERT("taking semaphore failed", ret == pdTRUE);
|
||||
}
|
||||
SYS_STATS_INC_USED(sem);
|
||||
|
||||
/* 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;
|
||||
if (initial_count == 1) {
|
||||
BaseType_t ret = xSemaphoreGive(sem->sem);
|
||||
LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);
|
||||
}
|
||||
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)
|
||||
void sys_sem_signal(sys_sem_t *sem)
|
||||
{
|
||||
BaseType_t ret;
|
||||
void *msg_dummy;
|
||||
LWIP_ASSERT("mbox != NULL", mbox != NULL);
|
||||
LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
|
||||
BaseType_t ret;
|
||||
LWIP_ASSERT("sem != NULL", sem != NULL);
|
||||
LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); /* NOLINT */
|
||||
|
||||
if (!msg) {
|
||||
msg = &msg_dummy;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
/* timed out */
|
||||
*msg = NULL;
|
||||
return SYS_ARCH_TIMEOUT;
|
||||
*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;
|
||||
/* 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)
|
||||
void sys_mbox_free(sys_mbox_t *mbox)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
{
|
||||
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);
|
||||
if (msgs_waiting != 0) {
|
||||
SYS_STATS_INC(mbox.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vQueueDelete(mbox->mbx);
|
||||
vQueueDelete(mbox->mbx);
|
||||
|
||||
SYS_STATS_DEC(mbox.used);
|
||||
SYS_STATS_DEC(mbox.used);
|
||||
}
|
||||
|
||||
sys_thread_t
|
||||
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
|
||||
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;
|
||||
TaskHandle_t rtos_task;
|
||||
BaseType_t ret;
|
||||
sys_thread_t lwip_thread;
|
||||
size_t rtos_stacksize;
|
||||
|
||||
LWIP_ASSERT("invalid stacksize", stacksize > 0);
|
||||
LWIP_ASSERT("invalid stacksize", stacksize > 0);
|
||||
#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS
|
||||
rtos_stacksize = (size_t)stacksize;
|
||||
rtos_stacksize = (size_t)stacksize;
|
||||
#else
|
||||
rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);
|
||||
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'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;
|
||||
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)
|
||||
sys_sem_t *sys_arch_netconn_sem_get(void)
|
||||
{
|
||||
void *ret;
|
||||
TaskHandle_t task = xTaskGetCurrentTaskHandle();
|
||||
LWIP_ASSERT("task != NULL", task != NULL);
|
||||
void *ret;
|
||||
TaskHandle_t task = xTaskGetCurrentTaskHandle();
|
||||
LWIP_ASSERT("task != NULL", task != NULL);
|
||||
|
||||
ret = pvTaskGetThreadLocalStoragePointer(task, 0);
|
||||
return ret;
|
||||
ret = pvTaskGetThreadLocalStoragePointer(task, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
sys_arch_netconn_sem_alloc(void)
|
||||
void sys_arch_netconn_sem_alloc(void)
|
||||
{
|
||||
void *ret;
|
||||
TaskHandle_t task = xTaskGetCurrentTaskHandle();
|
||||
LWIP_ASSERT("task != NULL", task != NULL);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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 */
|
||||
@@ -569,24 +545,22 @@ void sys_arch_netconn_sem_free(void)
|
||||
static u8_t lwip_core_lock_count;
|
||||
static TaskHandle_t lwip_core_lock_holder_thread;
|
||||
|
||||
void
|
||||
sys_lock_tcpip_core(void)
|
||||
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++;
|
||||
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)
|
||||
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);
|
||||
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 */
|
||||
@@ -595,36 +569,34 @@ sys_unlock_tcpip_core(void)
|
||||
static TaskHandle_t lwip_tcpip_thread;
|
||||
#endif
|
||||
|
||||
void
|
||||
sys_mark_tcpip_thread(void)
|
||||
void sys_mark_tcpip_thread(void)
|
||||
{
|
||||
#if !NO_SYS
|
||||
lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
|
||||
lwip_tcpip_thread = xTaskGetCurrentTaskHandle();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sys_check_core_locking(void)
|
||||
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 );
|
||||
/* 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();
|
||||
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_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);
|
||||
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);
|
||||
LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
}
|
||||
}
|
||||
#endif /* !NO_SYS */
|
||||
}
|
||||
|
||||
|
||||
@@ -1,202 +1,436 @@
|
||||
/*
|
||||
* 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
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_H__
|
||||
#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
|
||||
#ifdef USE_LWIPOPTS_APP_H
|
||||
#include "lwipopts_app.h"
|
||||
#endif
|
||||
|
||||
#define LWIP_RAND rand
|
||||
/**
|
||||
* 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 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
|
||||
#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
|
||||
|
||||
/**
|
||||
* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
|
||||
* LWIP_NETIF_API==1: Support netif api (in netifapi.c)
|
||||
*/
|
||||
#define MEMP_MEM_MALLOC 1
|
||||
#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.
|
||||
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)
|
||||
*/
|
||||
#define MEMP_NUM_PBUF 100
|
||||
#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".
|
||||
*/
|
||||
#define MEMP_NUM_UDP_PCB 6
|
||||
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.
|
||||
*/
|
||||
#define MEMP_NUM_TCP_PCB 10
|
||||
connections. */
|
||||
#ifndef MEMP_NUM_TCP_PCB
|
||||
#define MEMP_NUM_TCP_PCB 4
|
||||
#endif
|
||||
|
||||
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
|
||||
* connections.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
#define MEMP_NUM_TCP_SEG 20
|
||||
segments. */
|
||||
#ifndef MEMP_NUM_TCP_SEG
|
||||
#define MEMP_NUM_TCP_SEG 40
|
||||
#endif
|
||||
|
||||
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
|
||||
* timeouts.
|
||||
*/
|
||||
#define MEMP_NUM_SYS_TIMEOUT 10
|
||||
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. */
|
||||
#define PBUF_POOL_SIZE 20
|
||||
#ifndef PBUF_POOL_SIZE
|
||||
#define PBUF_POOL_SIZE 20
|
||||
#endif
|
||||
|
||||
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool.*/
|
||||
#define PBUF_POOL_BUFSIZE 1600
|
||||
/* 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
|
||||
*/
|
||||
#define TCP_QUEUE_OOSEQ 1
|
||||
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.
|
||||
*/
|
||||
#define TCP_SND_QUEUELEN (4* TCP_SND_BUF/TCP_MSS)
|
||||
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. */
|
||||
#define TCP_WND (16*TCP_MSS)
|
||||
#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
|
||||
|
||||
/*
|
||||
* -----------------------------------
|
||||
* ---------- DEBUG options ----------
|
||||
* -----------------------------------
|
||||
------------------------------------------------
|
||||
---------- 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
|
||||
|
||||
#define LWIP_DEBUG 1
|
||||
/* ---------- 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
|
||||
|
||||
#define LWIP_DBG_MIN_LEVEL 1
|
||||
#ifndef LWIP_DBG_MIN_LEVEL
|
||||
#define LWIP_DBG_MIN_LEVEL 0
|
||||
#endif
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
#define DHCP_DOES_ARP_CHECK 0
|
||||
|
||||
/*
|
||||
* ---------------------------------
|
||||
* ---------- OS options ----------
|
||||
* ---------------------------------
|
||||
*/
|
||||
---------------------------------
|
||||
---------- OS options ----------
|
||||
---------------------------------
|
||||
*/
|
||||
#ifndef TCPIP_THREAD_NAME
|
||||
#define TCPIP_THREAD_NAME "tcpip"
|
||||
#endif
|
||||
|
||||
#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
|
||||
#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
|
||||
#define LWIP_TCPIP_CORE_LOCKING 1
|
||||
#endif
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
#ifndef LWIP_MEM_SECTION
|
||||
#define LWIP_MEM_SECTION ".bss"
|
||||
#endif
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#define USBD_MAX_POWER 200
|
||||
|
||||
/* attribute data into no cache ram */
|
||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable.non_init")))
|
||||
#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.
|
||||
@@ -172,7 +172,7 @@
|
||||
#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_ENDPOINTS 4
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
/* Ep0 max transfer buffer */
|
||||
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
|
||||
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 4096
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
@@ -213,7 +213,7 @@
|
||||
* 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)
|
||||
#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 */
|
||||
@@ -306,4 +306,7 @@
|
||||
#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
|
||||
|
||||
1066
tests/hpmicro/src/font24x48.c
Normal file
1066
tests/hpmicro/src/font24x48.c
Normal file
File diff suppressed because it is too large
Load Diff
763
tests/hpmicro/src/iperf/iperf.c
Normal file
763
tests/hpmicro/src/iperf/iperf.c
Normal 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;
|
||||
}
|
||||
82
tests/hpmicro/src/iperf/iperf.h
Normal file
82
tests/hpmicro/src/iperf/iperf.h
Normal 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
|
||||
115
tests/hpmicro/src/iperf/iperf_cli.c
Normal file
115
tests/hpmicro/src/iperf/iperf_cli.c
Normal 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);
|
||||
|
||||
377
tests/hpmicro/src/iperf/utils_getopt.c
Normal file
377
tests/hpmicro/src/iperf/utils_getopt.c
Normal 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;
|
||||
}
|
||||
107
tests/hpmicro/src/iperf/utils_getopt.h
Normal file
107
tests/hpmicro/src/iperf/utils_getopt.h
Normal 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__ */
|
||||
@@ -13,9 +13,14 @@
|
||||
#include <stdio.h>
|
||||
#include "board.h"
|
||||
#include "hpm_clock_drv.h"
|
||||
#include "hpm_l1c_drv.h"
|
||||
#include "shell.h"
|
||||
#include "usbh_core.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#ifdef CONFIG_USB_EHCI_ISO
|
||||
#include "usbh_uvc_stream.h"
|
||||
#include "usbh_uac_stream.h"
|
||||
#endif
|
||||
|
||||
SDK_DECLARE_EXT_ISR_M(BOARD_CONSOLE_UART_IRQ, shell_uart_isr)
|
||||
|
||||
@@ -36,7 +41,11 @@ int main(void)
|
||||
tcpip_init(NULL, NULL);
|
||||
|
||||
printf("Start usb host task...\r\n");
|
||||
#ifdef CONFIG_USB_EHCI_ISO
|
||||
extern void uvc2lcd_init(void);
|
||||
|
||||
uvc2lcd_init();
|
||||
#endif
|
||||
usbh_initialize(0, CONFIG_HPM_USBH_BASE);
|
||||
|
||||
if (pdPASS != xTaskCreate(task_start, "task_start", 1024U, NULL, task_start_PRIORITY, NULL)) {
|
||||
@@ -100,5 +109,96 @@ static void task_start(void *param)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
extern int lsusb(int argc, char **argv);
|
||||
CSH_CMD_EXPORT(lsusb, );
|
||||
CSH_CMD_EXPORT(lsusb, );
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_ISO
|
||||
// clang-format off
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t src_buffer[1024 * 10];
|
||||
ATTR_PLACE_AT_WITH_ALIGNMENT(".framebuffer", 64) uint8_t dst_buffer[1024 * 10];
|
||||
// clang-format on
|
||||
|
||||
void usb_dma_test()
|
||||
{
|
||||
usbh_video_dma_init();
|
||||
for (size_t i = 0; i < 10 * 1024; i++) {
|
||||
src_buffer[i] = i & 0xff;
|
||||
}
|
||||
memset(dst_buffer, 0, 10 * 1024);
|
||||
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
usbh_video_dma_lli_fill(i, (uint32_t)src_buffer + i * 1024, (uint32_t)dst_buffer + i * 1024, 1024);
|
||||
}
|
||||
volatile uint64_t start_tick = hpm_csr_get_core_mcycle();
|
||||
usbh_video_dma_start();
|
||||
|
||||
while (usbh_video_dma_isbusy()) {
|
||||
}
|
||||
volatile uint64_t end_tick = hpm_csr_get_core_mcycle();
|
||||
|
||||
double consumed_seconds = (end_tick - start_tick) * 1.0l / (clock_get_frequency(clock_cpu0) / 1000000);
|
||||
printf("dma done:%.2f us\n", consumed_seconds);
|
||||
l1c_dc_invalidate((uint32_t)dst_buffer, 10 * 1024);
|
||||
for (size_t i = 0; i < 10 * 1024; i++) {
|
||||
if (dst_buffer[i] != src_buffer[i]) {
|
||||
printf("error:%d\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dma_test(int argc, char **argv)
|
||||
{
|
||||
usb_dma_test();
|
||||
return 0;
|
||||
}
|
||||
CSH_CMD_EXPORT(dma_test, );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
CSH_CMD_EXPORT(usbh_uvc_start, usbh_uvc_start);
|
||||
|
||||
int usbh_uvc_stop(int argc, char **argv)
|
||||
{
|
||||
usbh_video_stream_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CSH_CMD_EXPORT(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;
|
||||
}
|
||||
|
||||
CSH_CMD_EXPORT(usbh_uac_start, usbh_uac_start);
|
||||
|
||||
int usbh_uac_stop(int argc, char **argv)
|
||||
{
|
||||
usbh_audio_mic_stream_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CSH_CMD_EXPORT(usbh_uac_stop, usbh_uac_stop);
|
||||
#endif
|
||||
257
tests/hpmicro/src/ping.c
Normal file
257
tests/hpmicro/src/ping.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* netutils: ping implementation
|
||||
*/
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#include <lwip/opt.h>
|
||||
#include <lwip/init.h>
|
||||
#include <lwip/mem.h>
|
||||
#include <lwip/icmp.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <lwip/sys.h>
|
||||
#include <lwip/inet.h>
|
||||
#include <lwip/inet_chksum.h>
|
||||
#include <lwip/ip.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
/**
|
||||
* PING_DEBUG: Enable debugging for PING.
|
||||
*/
|
||||
#ifndef PING_DEBUG
|
||||
#define PING_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/** ping receive timeout - in milliseconds */
|
||||
#define PING_RCV_TIMEO (2000 * portTICK_PERIOD_MS)
|
||||
/** ping delay - in milliseconds */
|
||||
#define PING_DELAY (1000 * portTICK_PERIOD_MS)
|
||||
|
||||
/** ping identifier - must fit on a u16_t */
|
||||
#ifndef PING_ID
|
||||
#define PING_ID 0xAFAF
|
||||
#endif
|
||||
|
||||
/** ping additional data size to include in the packet */
|
||||
#ifndef PING_DATA_SIZE
|
||||
#define PING_DATA_SIZE 32
|
||||
#endif
|
||||
|
||||
/* ping variables */
|
||||
static u16_t ping_seq_num;
|
||||
struct _ip_addr {
|
||||
uint8_t addr0, addr1, addr2, addr3;
|
||||
};
|
||||
|
||||
/** Prepare a echo ICMP request */
|
||||
static void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len)
|
||||
{
|
||||
size_t i;
|
||||
size_t data_len = len - sizeof(struct icmp_echo_hdr);
|
||||
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
|
||||
ICMPH_CODE_SET(iecho, 0);
|
||||
iecho->chksum = 0;
|
||||
iecho->id = PING_ID;
|
||||
iecho->seqno = htons(++ping_seq_num);
|
||||
|
||||
/* fill the additional data buffer with some data */
|
||||
for (i = 0; i < data_len; i++) {
|
||||
((char *)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
|
||||
}
|
||||
|
||||
iecho->chksum = inet_chksum(iecho, len);
|
||||
}
|
||||
|
||||
/* Ping using the socket ip */
|
||||
err_t lwip_ping_send(int s, ip_addr_t *addr, int size)
|
||||
{
|
||||
int err;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct sockaddr_in to;
|
||||
int ping_size = sizeof(struct icmp_echo_hdr) + size;
|
||||
LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
|
||||
|
||||
iecho = mem_malloc(ping_size);
|
||||
if (iecho == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
ping_prepare_echo(iecho, (u16_t)ping_size);
|
||||
|
||||
to.sin_len = sizeof(to);
|
||||
to.sin_family = AF_INET;
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
to.sin_addr.s_addr = addr->u_addr.ip4.addr;
|
||||
#elif LWIP_IPV4
|
||||
to.sin_addr.s_addr = addr->addr;
|
||||
#elif LWIP_IPV6
|
||||
#error Not supported IPv6.
|
||||
#endif
|
||||
|
||||
err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr *)&to, sizeof(to));
|
||||
mem_free(iecho);
|
||||
|
||||
return (err == ping_size ? ERR_OK : ERR_VAL);
|
||||
}
|
||||
|
||||
int lwip_ping_recv(int s, int *ttl)
|
||||
{
|
||||
char buf[64];
|
||||
int fromlen = sizeof(struct sockaddr_in), len;
|
||||
struct sockaddr_in from;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
|
||||
while ((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) {
|
||||
if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) {
|
||||
iphdr = (struct ip_hdr *)buf;
|
||||
iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
|
||||
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
|
||||
*ttl = iphdr->_ttl;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* using the lwIP custom ping */
|
||||
uint32_t cmd_ping(char *target_name, uint16_t interval, uint16_t size, uint32_t count)
|
||||
{
|
||||
#if LWIP_VERSION_MAJOR >= 2U
|
||||
struct timeval timeout = { PING_RCV_TIMEO / (1000 * portTICK_PERIOD_MS), PING_RCV_TIMEO % (1000 * portTICK_PERIOD_MS) };
|
||||
#else
|
||||
int timeout = PING_RCV_TIMEO * 1000UL / (1000 * portTICK_PERIOD_MS);
|
||||
#endif
|
||||
|
||||
int s, ttl = 0, recv_len;
|
||||
ip_addr_t target_addr;
|
||||
uint32_t send_times;
|
||||
uint32_t recv_start_tick;
|
||||
struct addrinfo hint, *res = NULL;
|
||||
struct sockaddr_in *h = NULL;
|
||||
struct in_addr ina;
|
||||
|
||||
send_times = 0;
|
||||
ping_seq_num = 0;
|
||||
|
||||
if (size == 0) {
|
||||
size = PING_DATA_SIZE;
|
||||
}
|
||||
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
/* convert URL to IP */
|
||||
if (lwip_getaddrinfo(target_name, NULL, &hint, &res) != 0) {
|
||||
printf("ping: unknown host %s\n\r", target_name);
|
||||
return -1;
|
||||
}
|
||||
memcpy(&h, &res->ai_addr, sizeof(struct sockaddr_in *));
|
||||
memcpy(&ina, &h->sin_addr, sizeof(ina));
|
||||
lwip_freeaddrinfo(res);
|
||||
if (inet_aton(inet_ntoa(ina), &target_addr) == 0) {
|
||||
printf("ping: unknown host %s\n\r", target_name);
|
||||
return -1;
|
||||
}
|
||||
/* new a socket */
|
||||
if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) {
|
||||
printf("ping: create socket failed\n\r");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
while (1) {
|
||||
int elapsed_time;
|
||||
|
||||
if (lwip_ping_send(s, &target_addr, size) == ERR_OK) {
|
||||
recv_start_tick = sys_now();
|
||||
if ((recv_len = lwip_ping_recv(s, &ttl)) >= 0) {
|
||||
elapsed_time = (sys_now() - recv_start_tick) * 1000UL / (1000 * portTICK_PERIOD_MS);
|
||||
printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n\r", recv_len, inet_ntoa(ina), send_times,
|
||||
ttl, elapsed_time);
|
||||
} else {
|
||||
printf("From %s icmp_seq=%d timeout\n\r", inet_ntoa(ina), send_times);
|
||||
}
|
||||
} else {
|
||||
printf("Send %s - error\n\r", inet_ntoa(ina));
|
||||
}
|
||||
|
||||
send_times++;
|
||||
if (send_times >= count) {
|
||||
/* send ping times reached, stop */
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(interval); /* take a delay */
|
||||
}
|
||||
|
||||
lwip_close(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <shell.h>
|
||||
#include "utils_getopt.h"
|
||||
|
||||
#define PING_USAGE \
|
||||
"ping [-c count] [-i interval] [-s size] [-h help] destination\r\n" \
|
||||
"\t\t-c count of ping requests. default is 4\r\n" \
|
||||
"\t\t-i interval in ms. default is 1000\r\n" \
|
||||
"\t\t-s ICMP payload size in bytes. default is 32\r\n" \
|
||||
"\t\t-h print this help\r\n"
|
||||
|
||||
int ping(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
getopt_env_t getopt_env;
|
||||
u16_t interval = PING_DELAY;
|
||||
u16_t data_size = PING_DATA_SIZE;
|
||||
u32_t total_count = 4;
|
||||
|
||||
if (argc == 1) {
|
||||
goto usage;
|
||||
} else {
|
||||
utils_getopt_init(&getopt_env, 0);
|
||||
|
||||
while ((opt = utils_getopt(&getopt_env, argc, argv, ":i:s:c:W:h")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
interval = atoi(getopt_env.optarg);
|
||||
break;
|
||||
case 's':
|
||||
data_size = atoi(getopt_env.optarg);
|
||||
break;
|
||||
case 'c':
|
||||
total_count = atoi(getopt_env.optarg);
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
case ':':
|
||||
printf("%s: %c requires an argument\r\n", *argv, getopt_env.optopt);
|
||||
goto usage;
|
||||
case '?':
|
||||
printf("%s: unknown option %c\r\n", *argv, getopt_env.optopt);
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (getopt_env.optind + 1 == argc) {
|
||||
cmd_ping(argv[getopt_env.optind], interval, data_size, total_count);
|
||||
} else {
|
||||
printf("Need target address\r\n");
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
printf("%s", PING_USAGE);
|
||||
return 0;
|
||||
}
|
||||
CSH_CMD_EXPORT(ping, ping network host);
|
||||
|
||||
157
tests/hpmicro/src/uvc2lcd.c
Normal file
157
tests/hpmicro/src/uvc2lcd.c
Normal file
@@ -0,0 +1,157 @@
|
||||
#include "board.h"
|
||||
#include "hpm_lcdc_drv.h"
|
||||
#include "hpm_l1c_drv.h"
|
||||
#include "usbh_uvc_stream.h"
|
||||
|
||||
#define LCD BOARD_LCD_BASE
|
||||
#define PIXEL_FORMAT display_pixel_format_ycbcr422
|
||||
|
||||
#define IMAGE_WIDTH 640
|
||||
#define IMAGE_HEIGHT 480
|
||||
|
||||
static ATTR_PLACE_AT_WITH_ALIGNMENT(".framebuffer", 64) uint8_t frame_buffer1[IMAGE_WIDTH * IMAGE_HEIGHT * 2];
|
||||
static ATTR_PLACE_AT_WITH_ALIGNMENT(".framebuffer", 64) uint8_t frame_buffer2[IMAGE_WIDTH * IMAGE_HEIGHT * 2];
|
||||
static struct usbh_videoframe frame_pool[2];
|
||||
|
||||
void writefont2screen(uint16_t or_x, uint16_t or_y, uint16_t x_end, uint16_t y_end, uint8_t assic_id, uint16_t colour,
|
||||
uint8_t clearflag, uint8_t *str_font, uint32_t screen_addr, uint16_t font_size)
|
||||
{
|
||||
uint8_t *strdisp;
|
||||
uint16_t x, y;
|
||||
uint8_t bit;
|
||||
uint8_t temp1;
|
||||
strdisp = (uint8_t *)screen_addr;
|
||||
str_font += font_size * (assic_id - 0x20); /*get end encode*/
|
||||
bit = 0;
|
||||
for (y = or_y; y <= y_end; y++) {
|
||||
for (x = or_x; x <= x_end; x++) {
|
||||
if (clearflag == true) {
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x) = colour & 0x00ff;
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x + 1) = colour >> 8;
|
||||
} else {
|
||||
temp1 = (*str_font) >> bit;
|
||||
if ((temp1 & 0x01) == 0x01) {
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x) = colour & 0x00ff;
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x + 1) = colour >> 8;
|
||||
} else {
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x) = 0;
|
||||
*(strdisp + y * (IMAGE_WIDTH * 2) + 2 * x + 1) = 0;
|
||||
}
|
||||
bit++;
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
str_font += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char string2font(uint16_t line, uint16_t column, uint8_t *string, uint8_t string_num, uint16_t colour,
|
||||
uint8_t *str_font, uint32_t screen_addr, uint8_t font_width, uint8_t font_height)
|
||||
{
|
||||
uint8_t i = 0, j = 0, numtemp = 0;
|
||||
uint16_t or_x, or_y, x_end, y_end;
|
||||
uint16_t font_stroage_size;
|
||||
or_x = column * font_width;
|
||||
or_y = line * font_height;
|
||||
x_end = or_x + font_width - 1;
|
||||
y_end = or_y + font_height - 1;
|
||||
font_stroage_size = font_width * font_height / 8;
|
||||
for (numtemp = 0; numtemp < string_num; numtemp++) {
|
||||
if ((*(string + numtemp) != 10) && (*(string + numtemp) != 0)) { /*enter or end*/
|
||||
if (*(string + numtemp) != 8) { /*delete*/
|
||||
writefont2screen(or_x + font_width * i, or_y + font_height * j, x_end + font_width * i, y_end + font_height * j,
|
||||
*(string + numtemp), colour, false, str_font, screen_addr, font_stroage_size);
|
||||
} else {
|
||||
writefont2screen(or_x + font_width * i, or_y + font_height * j, x_end + font_width * i, y_end + font_height * j,
|
||||
*(string + numtemp), colour, true, str_font, screen_addr, font_stroage_size);
|
||||
}
|
||||
} else if (*(string + numtemp) == 10) {
|
||||
i = 19; /* jump next line */
|
||||
} else if (*(string + numtemp) == 0) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
if (i * font_width == IMAGE_WIDTH) {
|
||||
j++;
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern const unsigned char nAsciiDot24x48[];
|
||||
extern volatile uint32_t g_uvc_fps;
|
||||
|
||||
void usbh_video_run(struct usbh_video *video_class)
|
||||
{
|
||||
usbh_video_stream_start(640, 480, USBH_VIDEO_FORMAT_UNCOMPRESSED);
|
||||
lcdc_turn_on_display(LCD);
|
||||
}
|
||||
|
||||
void usbh_video_stop(struct usbh_video *video_class)
|
||||
{
|
||||
usbh_video_stream_stop();
|
||||
lcdc_turn_off_display(LCD);
|
||||
}
|
||||
|
||||
void usbh_video_frame_callback(struct usbh_videoframe *frame)
|
||||
{
|
||||
char font_display_buf[50];
|
||||
|
||||
//USB_LOG_RAW("frame buf:%p,frame len:%d\r\n", frame->frame_buf, frame->frame_size);
|
||||
l1c_dc_invalidate((uint32_t)frame->frame_buf, IMAGE_WIDTH * IMAGE_HEIGHT * 2);
|
||||
sprintf(font_display_buf, "fps:%d", g_uvc_fps);
|
||||
string2font(1, 1, (uint8_t *)font_display_buf, sizeof(font_display_buf), 0x001f, (uint8_t *)nAsciiDot24x48, (uint32_t)frame->frame_buf, 24, 48);
|
||||
l1c_dc_writeback((uint32_t)frame->frame_buf, IMAGE_WIDTH * IMAGE_HEIGHT * 2);
|
||||
lcdc_layer_set_next_buffer(LCD, 0, (uint32_t)frame->frame_buf);
|
||||
}
|
||||
|
||||
void init_lcd(void)
|
||||
{
|
||||
uint8_t layer_index = 0;
|
||||
lcdc_config_t config = { 0 };
|
||||
lcdc_layer_config_t layer = { 0 };
|
||||
|
||||
lcdc_get_default_config(LCD, &config);
|
||||
board_panel_para_to_lcdc(&config);
|
||||
lcdc_init(LCD, &config);
|
||||
|
||||
lcdc_get_default_layer_config(LCD, &layer, PIXEL_FORMAT, layer_index);
|
||||
|
||||
layer.position_x = (BOARD_LCD_WIDTH - IMAGE_WIDTH) / 2;
|
||||
layer.position_y = (BOARD_LCD_HEIGHT - IMAGE_HEIGHT) / 2;
|
||||
layer.width = IMAGE_WIDTH;
|
||||
layer.height = IMAGE_HEIGHT;
|
||||
|
||||
layer.buffer = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)frame_buffer1);
|
||||
layer.alphablend.src_alpha = 0xF4; /* src */
|
||||
layer.alphablend.dst_alpha = 0xF0; /* dst */
|
||||
layer.alphablend.src_alpha_op = display_alpha_op_override;
|
||||
layer.alphablend.dst_alpha_op = display_alpha_op_override;
|
||||
layer.background.u = 0xffff0000;
|
||||
layer.alphablend.mode = display_alphablend_mode_xor;
|
||||
|
||||
if (status_success != lcdc_config_layer(LCD, layer_index, &layer, true)) {
|
||||
printf("failed to configure layer\n");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void uvc2lcd_init(void)
|
||||
{
|
||||
board_init_lcd();
|
||||
init_lcd();
|
||||
|
||||
frame_pool[0].frame_buf = frame_buffer1;
|
||||
frame_pool[0].frame_bufsize = IMAGE_WIDTH * IMAGE_HEIGHT * 2;
|
||||
frame_pool[1].frame_buf = frame_buffer2;
|
||||
frame_pool[1].frame_bufsize = IMAGE_WIDTH * IMAGE_HEIGHT * 2;
|
||||
|
||||
usbh_video_stream_init(5, frame_pool, 2);
|
||||
|
||||
extern void usbh_video_fps_init(void);
|
||||
usbh_video_fps_init();
|
||||
}
|
||||
Reference in New Issue
Block a user