From 3463c8515f921b09e6523627980e77b17ec31097 Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Mon, 29 May 2023 16:58:22 +0800 Subject: [PATCH 1/9] feat add abstruction_mmu for XiZi_AIoT(support MmuInit\MmuSectionMap\MmuSectionUnmap\MmuTtbSwitch\MmuTransform) --- .../XiZi_AIoT/hardkernel/abstraction/Makefile | 2 +- .../hardkernel/abstraction/abstraction_mmu.c | 206 ++++++++++++++++++ .../hardkernel/abstraction/abstraction_mmu.h | 114 ++++++++++ .../XiZi_AIoT/hardkernel/abstraction/cache.c | 19 ++ .../XiZi_AIoT/hardkernel/abstraction/mmu.c | 0 .../memory/multiple-address-spaces/memory.c | 20 ++ 6 files changed, 360 insertions(+), 1 deletion(-) create mode 100755 Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.c create mode 100644 Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.h delete mode 100755 Ubiquitous/XiZi_AIoT/hardkernel/abstraction/mmu.c diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/Makefile b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/Makefile index 262587f99..c794367b8 100644 --- a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/Makefile +++ b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := cache.c isr.c mmu.c +SRC_FILES := cache.c isr.c abstraction_mmu.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.c b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.c new file mode 100755 index 000000000..6f37b7d6f --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.c @@ -0,0 +1,206 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: abstraction_mmu.c +* @brief: the general management of system mmu +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2023/4/27 +* +*/ + +#include + +AbstractionMmu abstraction_mmu; + +volatile uint32_t global_L1_pte_table[4096]; + +/** + * @description: write cmd to CP15 register + * @param reg_type - CP15 register type + * @param val - ops val pointer + * @return + */ +static void MmuCp15Write(uint8_t reg_type, uint32_t *val) +{ + uint32_t write_val = *val; + switch (reg_type) { + case AM_MMU_CP15_TTBCR: + TTBCR_W(write_val); + AM_ISB; + case AM_MMU_CP15_TTBR0: + TTBR0_W(write_val); + AM_ISB; + default: + break; + } +} + +/** + * @description: read CP15 register from mmu + * @param reg_type - CP15 register type + * @param val - ops val pointer + * @return + */ +static void MmuCp15Read(uint8_t reg_type, uint32_t *val) +{ + uint32_t read_val = 0; + switch (reg_type) { + case AM_MMU_CP15_TTBCR: + TTBCR_R(read_val); + case AM_MMU_CP15_TTBR0: + TTBR0_R(read_val); + default: + break; + } + + *val = read_val; +} + +/** + * @description: write or read CP15 register to set mmu + * @param ops_type - CP15 write or read + * @param reg_type - CP15 register type + * @param val - ops val pointer + * @return + */ +static void MmuRegOps(uint8_t ops_type, uint8_t reg_type, uint32_t *val) +{ + switch (ops_type) { + case AM_MMU_CP15_WRITE: + MmuCp15Write(reg_type, val); + case AM_MMU_CP15_READ: + MmuCp15Read(reg_type, val); + default: + break; + } +} + +/** + * @description: Init abstraction_mmu function + * @param mmu - abstraction mmu pointer + * @param ttb_base - ttb base pointer + * @return success : 0 error : -1 + */ +static int _AbstractionMmuInit(AbstractionMmu *mmu, uint32_t *ttb_base) +{ + mmu_init(); + + return 0; +} + +/** + * @description: map L1 or L2 page table section + * @param mmu - abstraction mmu pointer + * @param section_size - section size + * @return success : 0 error : -1 + */ +static int _AbstractionMmuSectionMap(AbstractionMmu *mmu, uint32_t section_size) +{ + uint32_t vaddr_length = mmu->vaddr_end - mmu->vaddr_start + 1; + + mmu_map_l1_range(mmu->paddr_start, mmu->vaddr_start, vaddr_length, + mmu->mmu_memory_type, mmu->mmu_shareability, mmu->mmu_access); + + mmu->mmu_status = 1; + + return 0; +} + +/** + * @description: unmap L1 or L2 page table section + * @param mmu - abstraction mmu pointer + * @param vaddr_start - virtual address start + * @param vaddr_size - virtual address size + * @return success : 0 error : -1 + */ +static int _AbstractionMmuSectionUnmap(AbstractionMmu *mmu, uint32_t vaddr_start, uint32_t vaddr_size) +{ + uint32_t *l1_umap_ventry = mmu->ttb_vbase + (vaddr_start >> AM_MMU_L1_SECTION_SHIFT); + uint32_t vaddr_end = vaddr_start + vaddr_size - 1; + uint32_t umap_count = (vaddr_end >> AM_MMU_L1_SECTION_SHIFT) - (vaddr_start >> AM_MMU_L1_SECTION_SHIFT) + 1; + + while (umap_count) { + AM_DMB; + *l1_umap_ventry = 0; + AM_DSB; + + umap_count--; + l1_umap_ventry += (1 << AM_MMU_L1_SECTION_SHIFT);//1MB section + } + + AM_DSB; + CLEARTLB(0);//clear TLB data and configure + AM_DSB; + AM_ISB; + mmu->mmu_status = 0; + + return 0; +} + +/** + * @description: switch ttb base by re-write ttbr register + * @param mmu - abstraction mmu pointer + * @return success : 0 error : -1 + */ +static int _AbstractionMmuTtbSwitch(AbstractionMmu *mmu) +{ + uint32_t ttbr, ttbcr; + MmuRegOps(AM_MMU_CP15_READ, AM_MMU_CP15_TTBCR, &ttbcr); + + /* Set TTBR0 with inner/outer write back write allocate and not shareable, [4:3]=01, [1]=0, [6,0]=01 */ + ttbr = ((mmu->ttb_pbase & 0xFFFFC000UL) | 0x9UL); + /* enable TTBR0 */ + ttbcr = 0; + + AM_DSB; + MmuRegOps(AM_MMU_CP15_WRITE, AM_MMU_CP15_TTBR0, &ttbr); + MmuRegOps(AM_MMU_CP15_WRITE, AM_MMU_CP15_TTBCR, &ttbcr); + + return 0; +} + +/** + * @description: get physical address transformed from virtual address + * @param mmu - abstraction mmu pointer + * @param vaddr - virtual address pointer + * @param paddr - physical address pointer + * @return success : 0 error : -1 + */ +static int _AbstracktonMmuTransform(AbstractionMmu *mmu, uint32_t *vaddr, uint32_t *paddr) +{ + uint32_t virtualAddress = *vaddr; + + if (mmu->mmu_status) { + mmu_virtual_to_physical(virtualAddress, paddr); + } + + return 0; +} + +static struct AbstractionMmuDone mmu_done = { + .AbstractionMmuInit = _AbstractionMmuInit, + .AbstractionMmuSectionMap = _AbstractionMmuSectionMap, + .AbstractionMmuSectionUnmap = _AbstractionMmuSectionUnmap, + .AbstractionMmuTtbSwitch = _AbstractionMmuTtbSwitch, + .AbstracktonMmuTransform = _AbstracktonMmuTransform, +}; + +/** + * @description: init abstraciton mmu info when system start + * @return success : 0 error : -1 + */ +int SysInitAbstractionMmu(void) +{ + abstraction_mmu.mmu_done = &mmu_done; +} diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.h b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.h new file mode 100644 index 000000000..ce3c35d06 --- /dev/null +++ b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/abstraction_mmu.h @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: mmu.h +* @brief: the general management of system mmu +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2023/5/24 +* +*/ +#include +#include + +#define ARCH_ARM +#ifdef ARCH_ARM +/* ARM System Registers */ +#define AM_DSB __asm__ volatile("dsb" ::: "memory") +#define AM_DMB __asm__ volatile("dmb" ::: "memory") +#define AM_ISB __asm__ volatile("isb" ::: "memory") +#define AM_WFI __asm__ volatile("wfi" ::: "memory") +#define AM_BARRIER __asm__ volatile("":::"memory") +#define AM_WFE __asm__ volatile("wfe" ::: "memory") +#define AM_SEV __asm__ volatile("sev" ::: "memory") + +#define TTBR0_R(val) __asm__ volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(val)) +#define TTBR0_W(val) __asm__ volatile("mcr p15, 0, %0, c2, c0, 0" ::"r"(val)) + +#define TTBCR_R(val) __asm__ volatile("mrc p15, 0, %0, c2, c0, 2" : "=r"(val)) +#define TTBCR_W(val) __asm__ volatile("mcr p15, 0, %0, c2, c0, 2" ::"r"(val)) + +#define CLEARTLB(val) __asm__ volatile("mcr p15, 0, %0, c8, c7, 0" ::"r"(val)) +#endif + +#define AM_MMU_L1_PAGE_TABLE_SIZE (4 * 4096) +#define AM_MMU_L1_SECTION_SHIFT 20 + +typedef enum +{ + AM_MMU_CP15_WRITE = 0, + AM_MMU_CP15_READ, +}MmuCP15OpsType; + +typedef enum +{ + AM_MMU_CP15_TTBCR = 0, + AM_MMU_CP15_TTBR0, + AM_MMU_CP15_CLEARTLB, +}MmuCP15RegType; + +typedef enum +{ + AM_StronglyOrdered = 0, + AM_Device, + AM_OuterInner_WB_WA, + AM_OuterInner_WT, + AM_Noncacheable, +}MmuMemoryType; + +typedef enum +{ + AM_Noaccess = 0, + AM_Read_Write, + AM_Read, +}MmuAccess; + +typedef enum +{ + AM_Shareable = 1, + AM_Nonshareable = 0 +}MmuShareability; + +struct AbstractionMmuDone +{ + int (*AbstractionMmuInit)(AbstractionMmu *mmu, uint32_t *ttb_base); + int (*AbstractionMmuSectionMap)(AbstractionMmu *mmu, uint32_t section_size); + int (*AbstractionMmuSectionUnmap)(AbstractionMmu *mmu, uint32_t vaddr_start, uint32_t vaddr_size); + int (*AbstractionMmuTtbSwitch)(AbstractionMmu *mmu); + int (*AbstracktonMmuTransform)(AbstractionMmu *mmu, uint32_t *vaddr, uint32_t *paddr); +}; + +typedef struct +{ + uint32_t ttb_vbase; + uint32_t ttb_pbase; + + uint32_t vaddr_start; + uint32_t vaddr_end; + uint32_t paddr_start; + uint32_t paddr_end; + + uint32_t vpaddr_offset; + + uint32_t pte_attr; + uint32_t mmu_status; + + MmuMemoryType mmu_memory_type; + MmuAccess mmu_access; + MmuShareability mmu_shareability; + + struct AbstractionMmuDone *mmu_done; + + int lock; + int link_list; +}AbstractionMmu; \ No newline at end of file diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/cache.c b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/cache.c index 5af33edcf..4a71e6c30 100755 --- a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/cache.c +++ b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/cache.c @@ -1,4 +1,23 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +/** +* @file: cache.c +* @brief: the general management of system cache +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2023/4/27 +* +*/ void InvalidInsCache() { diff --git a/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/mmu.c b/Ubiquitous/XiZi_AIoT/hardkernel/abstraction/mmu.c deleted file mode 100755 index e69de29bb..000000000 diff --git a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/memory.c b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/memory.c index e69de29bb..eb735195b 100644 --- a/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/memory.c +++ b/Ubiquitous/XiZi_AIoT/softkernel/memory/multiple-address-spaces/memory.c @@ -0,0 +1,20 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: memory.c +* @brief: the general management of system memory +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2023/4/27 +* +*/ \ No newline at end of file From 5f642507b4dc8e76a6d38b5a572d25ece1bc1ed1 Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Wed, 9 Aug 2023 15:10:11 +0800 Subject: [PATCH 2/9] fix adc/dac funciton error on edu-arm32 baord --- .../Applications/app_test/test_adc.c | 17 +- .../Applications/app_test/test_dac.c | 31 +- .../Applications/app_test/test_hwtimer.c | 23 +- .../edu-arm32/third_party_driver/adc/Kconfig | 83 +--- .../third_party_driver/adc/connect_adc.c | 377 +++++++++++------- .../common/hc32_ll_driver/src/Makefile | 2 +- .../third_party_driver/dac/connect_dac.c | 299 ++++++++++++-- .../third_party_driver/include/connect_dac.h | 7 - 8 files changed, 546 insertions(+), 293 deletions(-) diff --git a/APP_Framework/Applications/app_test/test_adc.c b/APP_Framework/Applications/app_test/test_adc.c index ceceec161..c1b8f66d3 100644 --- a/APP_Framework/Applications/app_test/test_adc.c +++ b/APP_Framework/Applications/app_test/test_adc.c @@ -26,9 +26,8 @@ void TestAdc(void) { int adc_fd; - uint8 adc_channel = 0x0; - uint16 adc_sample, adc_value_decimal = 0; - float adc_value; + uint8 adc_channel = 0x1; + uint16 adc_sample = 0; adc_fd = PrivOpen(ADC_DEV_DRIVER, O_RDWR); if (adc_fd < 0) { @@ -45,13 +44,11 @@ void TestAdc(void) return; } - PrivRead(adc_fd, &adc_sample, 2); - - adc_value = (float)adc_sample * (3.3 / 4096); - - adc_value_decimal = (adc_value - (uint16)adc_value) * 1000; - - printf("adc sample %u value integer %u decimal %u\n", adc_sample, (uint16)adc_value, adc_value_decimal); + for (int i = 0; i < 10; i ++) { + PrivRead(adc_fd, &adc_sample, 2); + printf("adc sample %u mv\n", adc_sample); + PrivTaskDelay(500); + } PrivClose(adc_fd); diff --git a/APP_Framework/Applications/app_test/test_dac.c b/APP_Framework/Applications/app_test/test_dac.c index 37ac2bf1c..8628d1a00 100644 --- a/APP_Framework/Applications/app_test/test_dac.c +++ b/APP_Framework/Applications/app_test/test_dac.c @@ -22,17 +22,16 @@ #include #ifdef ADD_XIZI_FEATURES -void TestDac(void) +static pthread_t test_dac_task; + +static void *TestDacTask(void *parameter) { int dac_fd; - uint16 dac_set_value = 800; - uint16 dac_sample, dac_value_decimal = 0; - float dac_value; + uint16 dac_set_value = 4096 * 10;//sin length dac_fd = PrivOpen(DAC_DEV_DRIVER, O_RDWR); if (dac_fd < 0) { KPrintf("open dac fd error %d\n", dac_fd); - return; } struct PrivIoctlCfg ioctl_cfg; @@ -41,20 +40,24 @@ void TestDac(void) if (0 != PrivIoctl(dac_fd, OPE_CFG, &ioctl_cfg)) { KPrintf("ioctl dac fd error %d\n", dac_fd); PrivClose(dac_fd); - return; } - PrivRead(dac_fd, &dac_sample, 2); - - dac_value = (float)dac_sample * (3.3 / 4096);//Vref+ need to be 3.3V - - dac_value_decimal = (dac_value - (uint16)dac_value) * 1000; - - printf("dac sample %u value integer %u decimal %u\n", dac_sample, (uint16)dac_value, dac_value_decimal); + while (1) { + //start dac output sin + PrivWrite(dac_fd, NULL, 0); + } PrivClose(dac_fd); +} - return; +void TestDac(void) +{ + pthread_attr_t tid; + tid.schedparam.sched_priority = 20; + tid.stacksize = 4096; + + PrivTaskCreate(&test_dac_task, &tid, &TestDacTask, NULL); + PrivTaskStartup(&test_dac_task); } PRIV_SHELL_CMD_FUNCTION(TestDac, a dac test sample, PRIV_SHELL_CMD_MAIN_ATTR); #endif \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_hwtimer.c b/APP_Framework/Applications/app_test/test_hwtimer.c index 9e6f7f981..9438683f8 100644 --- a/APP_Framework/Applications/app_test/test_hwtimer.c +++ b/APP_Framework/Applications/app_test/test_hwtimer.c @@ -28,11 +28,11 @@ static uint16_t pin_fd=0; static struct PinStat pin_led; -void ledflip(void *parameter) +void LedFlip(void *parameter) { pin_led.pin = BSP_LED_PIN; pin_led.val = !pin_led.val; - PrivWrite(pin_fd,&pin_led,NULL_PARAMETER); + PrivWrite(pin_fd, &pin_led, NULL_PARAMETER); } void TestHwTimer(void) @@ -40,22 +40,22 @@ void TestHwTimer(void) x_ticks_t period = 100000; pin_fd = PrivOpen(HWTIMER_PIN_DEV_DRIVER, O_RDWR); - if(pin_fd<0){ + if(pin_fd<0) { printf("open pin fd error:%d\n",pin_fd); return; } int timer_fd = PrivOpen(HWTIMER_TIMER_DEV_DRIVER, O_RDWR); - if(timer_fd<0){ + if(timer_fd<0) { printf("open timer fd error:%d\n",timer_fd); return; } //config led pin in board - struct PinParam parameter; - parameter.cmd = GPIO_CONFIG_MODE; - parameter.pin = BSP_LED_PIN; - parameter.mode = GPIO_CFG_OUTPUT; + struct PinParam parameter; + parameter.cmd = GPIO_CONFIG_MODE; + parameter.pin = BSP_LED_PIN; + parameter.mode = GPIO_CFG_OUTPUT; struct PrivIoctlCfg ioctl_cfg; ioctl_cfg.ioctl_driver_type = PIN_TYPE; @@ -68,7 +68,7 @@ void TestHwTimer(void) } ioctl_cfg.ioctl_driver_type = TIME_TYPE; - ioctl_cfg.args = (void *)&ledflip; + ioctl_cfg.args = (void *)&LedFlip; if (0 != PrivIoctl(timer_fd, OPE_INT, &ioctl_cfg)) { printf("timer pin fd error %d\n", pin_fd); PrivClose(pin_fd); @@ -82,13 +82,10 @@ void TestHwTimer(void) return; } - while(1){ + while(1) { } - // int32 timer_handle = KCreateTimer("LED on and off by 1s",&ledflip,&pin_fd,period,TIMER_TRIGGER_PERIODIC); - - // KTimerStartRun(timer_handle); PrivClose(pin_fd); PrivClose(timer_fd); } diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/Kconfig index f721032c6..fdc0b1c91 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/Kconfig @@ -1,74 +1,13 @@ -menuconfig BSP_USING_ADC1 - bool "Enable ADC1" - default y - if BSP_USING_ADC1 - config ADC1_BUS_NAME - string "adc 1 bus name" - default "adc1" +if BSP_USING_ADC + config ADC1_BUS_NAME + string "adc 1 bus name" + default "adc1" - config ADC1_DRIVER_NAME - string "adc 1 driver name" - default "adc1_drv" + config ADC1_DRIVER_NAME + string "adc 1 driver name" + default "adc1_drv" - config ADC1_DEVICE_NAME - string "adc 1 bus device name" - default "adc1_dev" - - config ADC1_GPIO_NUM - int "adc 1 gpio pin num" - default "0" - - config ADC1_GPIO_DEF - string "adc 1 gpio define type" - default "A" - endif - -menuconfig BSP_USING_ADC2 - bool "Enable ADC2" - default y - if BSP_USING_ADC2 - config ADC2_BUS_NAME - string "adc 2 bus name" - default "adc2" - - config ADC2_DRIVER_NAME - string "adc 2 driver name" - default "adc2_drv" - - config ADC2_DEVICE_NAME - string "adc 2 bus device name" - default "adc2_dev" - - config ADC2_GPIO_NUM - int "adc 2 gpio pin num" - default "6" - - config ADC2_GPIO_DEF - string "adc 2 gpio define type" - default "A" - endif - -menuconfig BSP_USING_ADC3 - bool "Enable ADC3" - default y - if BSP_USING_ADC3 - config ADC3_BUS_NAME - string "adc 3 bus name" - default "adc3" - - config ADC3_DRIVER_NAME - string "adc 3 driver name" - default "adc3_drv" - - config ADC3_DEVICE_NAME - string "adc 3 bus device name" - default "adc3_dev" - - config ADC3_GPIO_NUM - int "adc 3 gpio pin num" - default "0" - - config ADC3_GPIO_DEF - string "adc 3 gpio define type" - default "A" - endif + config ADC1_DEVICE_NAME + string "adc 1 bus device name" + default "adc1_dev" +endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/connect_adc.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/connect_adc.c index 620b21d8f..4e8b09475 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/connect_adc.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/adc/connect_adc.c @@ -20,79 +20,251 @@ #include -#define _ADC_CONS(string1, string2) string1##string2 -#define ADC_CONS(string1, string2) _ADC_CONS(string1, string2) +/******************************************************************************* + * Local pre-processor symbols/macros ('#define') + ******************************************************************************/ -#ifdef BSP_USING_ADC1 -#define ADC1_GPIO ADC_CONS(GPIO_Pin_, ADC1_GPIO_NUM) +/* The clock source of ADC. */ +#define ADC_CLK_SYS_CLK (1U) +#define ADC_CLK_PLLH (2U) +#define ADC_CLK_PLLA (3U) + +/* + * Selects a clock source according to the application requirements. + * PCLK4 is the clock for digital interface. + * PCLK2 is the clock for analog circuit. + * PCLK4 and PCLK2 are synchronous when the clock source is PLL. + * PCLK4 : PCLK2 = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4. + * PCLK2 is in range [1MHz, 60MHz]. + * If the system clock is selected as the ADC clock, macro 'ADC_ADC_CLK' can only be defined as 'CLK_PERIPHCLK_PCLK'. + * If PLLH is selected as the ADC clock, macro 'ADC_ADC_CLK' can be defined as 'CLK_PERIPHCLK_PLLx'(x=Q, R). + * If PLLA is selected as the ADC clock, macro 'ADC_ADC_CLK' can be defined as 'CLK_PERIPHCLK_PLLXx'(x=P, Q, R). + */ +#define ADC_CLK_SEL (ADC_CLK_SYS_CLK) + +#if (ADC_CLK_SEL == ADC_CLK_SYS_CLK) +#define ADC_CLK (CLK_PERIPHCLK_PCLK) + +#elif (ADC_CLK_SEL == ADC_CLK_PLLH) +#define ADC_CLK (CLK_PERIPHCLK_PLLQ) + +#elif (ADC_CLK_SEL == ADC_CLK_PLLA) +#define ADC_CLK (CLK_PERIPHCLK_PLLXP) + +#else +#error "The clock source your selected does not exist!!!" #endif -#ifdef BSP_USING_ADC2 -#define ADC2_GPIO ADC_CONS(GPIO_Pin_, ADC2_GPIO_NUM) -#endif +/* ADC unit instance for this example. */ +#define ADC_UNIT (CM_ADC1) +#define ADC_PERIPH_CLK (FCG3_PERIPH_ADC1) -#ifdef BSP_USING_ADC3 -#define ADC3_GPIO ADC_CONS(GPIO_Pin_, ADC3_GPIO_NUM) -#endif +/* Selects ADC channels that needed. */ +#define ADC_CH_POTENTIOMETER (ADC_CH3) +#define ADC_CH (ADC_CH_POTENTIOMETER) +#define ADC_CH_PORT (GPIO_PORT_A) +#define ADC_CH_PIN (GPIO_PIN_03) -static int AdcUdelay(uint32 us) +/* ADC sequence to be used. */ +#define ADC_SEQ (ADC_SEQ_A) +/* Flag of conversion end. */ +#define ADC_EOC_FLAG (ADC_FLAG_EOCA) + +/* ADC reference voltage. The voltage of pin VREFH. */ +#define ADC_VREF (3.3F) + +/* ADC accuracy(according to the resolution of ADC). */ +#define ADC_ACCURACY (1UL << 12U) + +/* Calculate the voltage(mV). */ +#define ADC_CAL_VOL(adcVal) (uint16_t)((((float32_t)(adcVal) * ADC_VREF) / ((float32_t)ADC_ACCURACY)) * 1000.F) + +/* Timeout value. */ +#define ADC_TIMEOUT_VAL (1000U) + +/** + * @brief Set specified ADC pin to analog mode. + * @param None + * @retval None + */ +static void AdcSetPinAnalogMode(void) { - uint32 ticks; - uint32 told, tnow, tcnt = 0; - uint32 reload = SysTick->LOAD; + stc_gpio_init_t stcGpioInit; - ticks = us * reload / (1000000 / TICK_PER_SECOND); - told = SysTick->VAL; - while (1) { - tnow = SysTick->VAL; - if (tnow != told) { - if (tnow < told) { - tcnt += told - tnow; - } else { - tcnt += reload - tnow + told; - } - told = tnow; - if (tcnt >= ticks) { - return 0; - break; - } - } - } + (void)GPIO_StructInit(&stcGpioInit); + stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG; + (void)GPIO_Init(ADC_CH_PORT, ADC_CH_PIN, &stcGpioInit); } -static uint16 GetAdcAverageValue(CM_ADC_TypeDef *ADCx, uint8 channel, uint8 times) +/** + * @brief Configures ADC clock. + * @param None + * @retval None + */ +static void AdcClockConfig(void) { - uint32 temp_val = 0; - int i; +#if (ADC_CLK_SEL == ADC_CLK_SYS_CLK) + /* + * 1. Configures the clock divider of PCLK2 and PCLK4 here or in the function of configuring the system clock. + * In this example, the system clock is MRC@8MHz. + * PCLK4 is the digital interface clock, and PCLK2 is the analog circuit clock. + * Make sure that PCLK2 and PCLK4 meet the following conditions: + * PCLK4 : PCLK2 = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4. + * PCLK2 is in range [1MHz, 60MHz]. + */ + CLK_SetClockDiv((CLK_BUS_PCLK2 | CLK_BUS_PCLK4), (CLK_PCLK2_DIV8 | CLK_PCLK4_DIV2)); - for(i = 0;i < times;i ++) { - temp_val += ADC_GetValue(ADCx, channel) & 0x0FFF; - KPrintf("GetAdcAverageValue val %u\n", ADC_GetValue(ADCx, channel)); - AdcUdelay(5000); - } - return temp_val / times; -} +#elif (ADC_CLK_SEL == ADC_CLK_PLLH) + /* + * 1. Configures PLLH and the divider of PLLHx(x=Q, R). + * PLLHx(x=Q, R) is used as both the digital interface clock and the analog circuit clock. + * PLLHx(x=Q, R) must be in range [1MHz, 60MHz] for ADC use. + * The input source of PLLH is XTAL(8MHz). + */ + stc_clock_pll_init_t stcPLLHInit; + stc_clock_xtal_init_t stcXtalInit; + /* Configures XTAL. PLLH input source is XTAL. */ + (void)CLK_XtalStructInit(&stcXtalInit); + stcXtalInit.u8State = CLK_XTAL_ON; + stcXtalInit.u8Drv = CLK_XTAL_DRV_ULOW; + stcXtalInit.u8Mode = CLK_XTAL_MD_OSC; + stcXtalInit.u8StableTime = CLK_XTAL_STB_499US; + (void)CLK_XtalInit(&stcXtalInit); + + (void)CLK_PLLStructInit(&stcPLLHInit); + /* + * PLLHx(x=Q, R) = ((PLL_source / PLLM) * PLLN) / PLLx + * PLLHQ = (8 / 1) * 80 /16 = 40MHz + * PLLHR = (8 / 1) * 80 /16 = 40MHz + */ + stcPLLHInit.u8PLLState = CLK_PLL_ON; + stcPLLHInit.PLLCFGR = 0UL; + stcPLLHInit.PLLCFGR_f.PLLM = (1UL - 1UL); + stcPLLHInit.PLLCFGR_f.PLLN = (80UL - 1UL); + stcPLLHInit.PLLCFGR_f.PLLP = (4UL - 1UL); + stcPLLHInit.PLLCFGR_f.PLLQ = (16UL - 1UL); + stcPLLHInit.PLLCFGR_f.PLLR = (16UL - 1UL); + /* stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL; */ + (void)CLK_PLLInit(&stcPLLHInit); + +#elif (ADC_CLK_SEL == ADC_CLK_PLLA) + /* + * 1. Configures PLLA and the divider of PLLAx(x=P, Q, R). + * PLLAx(x=P, Q, R) is used as both the digital interface clock and the analog circuit clock. + * PLLAx(x=P, Q, R) must be in range [1MHz, 60MHz] for ADC use. + * The input source of PLLA is HRC(16MHz). + */ + stc_clock_pllx_init_t stcPLLAInit; + + /* Enable HRC(16MHz) for PLLA. */ + CLK_HrcCmd(ENABLE); + + /* Specify the input source of PLLA. NOTE!!! PLLA and PLLH use the same input source. */ + CLK_SetPLLSrc(CLK_PLL_SRC_HRC); + /* PLLA configuration */ + (void)CLK_PLLxStructInit(&stcPLLAInit); + /* + * PLLAx(x=P, Q, R) = ((PLL_source / PLLM) * PLLN) / PLLx + * PLLAP = (16 / 2) * 40 / 8 = 40MHz + * PLLAQ = (16 / 2) * 40 / 10 = 32MHz + * PLLAR = (16 / 2) * 40 / 16 = 20MHz + */ + stcPLLAInit.u8PLLState = CLK_PLLX_ON; + stcPLLAInit.PLLCFGR = 0UL; + stcPLLAInit.PLLCFGR_f.PLLM = (2UL - 1UL); + stcPLLAInit.PLLCFGR_f.PLLN = (40UL - 1UL); + stcPLLAInit.PLLCFGR_f.PLLR = (8UL - 1UL); + stcPLLAInit.PLLCFGR_f.PLLQ = (10UL - 1UL); + stcPLLAInit.PLLCFGR_f.PLLP = (16UL - 1UL); + (void)CLK_PLLxInit(&stcPLLAInit); +#endif + /* 2. Specifies the clock source of ADC. */ + CLK_SetPeriClockSrc(ADC_CLK); +} + +/** + * @brief Initializes ADC. + * @param None + * @retval None + */ +static void AdcInitConfig(void) +{ + stc_adc_init_t stcAdcInit; + + /* 1. Enable ADC peripheral clock. */ + FCG_Fcg3PeriphClockCmd(ADC_PERIPH_CLK, ENABLE); + + /* 2. Modify the default value depends on the application. Not needed here. */ + (void)ADC_StructInit(&stcAdcInit); + + /* 3. Initializes ADC. */ + (void)ADC_Init(ADC_UNIT, &stcAdcInit); + + /* 4. ADC channel configuration. */ + /* 4.1 Set the ADC pin to analog input mode. */ + AdcSetPinAnalogMode(); + /* 4.2 Enable ADC channels. Call ADC_ChCmd() again to enable more channels if needed. */ + ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CH, ENABLE); + + /* 5. Conversion data average calculation function, if needed. + Call ADC_ConvDataAverageChCmd() again to enable more average channels if needed. */ + ADC_ConvDataAverageConfig(ADC_UNIT, ADC_AVG_CNT8); + ADC_ConvDataAverageChCmd(ADC_UNIT, ADC_CH, ENABLE); +} + +/** + * @brief Use ADC in polling mode. + * @param None + * @retval uint16_t u16AdcValue + */ +static uint16_t AdcPolling(void) +{ + uint16_t u16AdcValue = 0; + int32_t iRet = LL_ERR; + __IO uint32_t u32TimeCount = 0UL; + + /* Can ONLY start sequence A conversion. + Sequence B needs hardware trigger to start conversion. */ + ADC_Start(ADC_UNIT); + do { + if (ADC_GetStatus(ADC_UNIT, ADC_EOC_FLAG) == SET) { + ADC_ClearStatus(ADC_UNIT, ADC_EOC_FLAG); + iRet = LL_OK; + break; + } + } while (u32TimeCount++ < ADC_TIMEOUT_VAL); + + if (iRet == LL_OK) { + /* Get any ADC value of sequence A channel that needed. */ + u16AdcValue = ADC_GetValue(ADC_UNIT, ADC_CH); + KPrintf("The ADC value of potentiometer is %u, voltage is %u mV\r\n", + u16AdcValue, ADC_CAL_VOL(u16AdcValue)); + } else { + ADC_Stop(ADC_UNIT); + KPrintf("ADC exception.\r\n"); + } + + return ADC_CAL_VOL(u16AdcValue); +} static uint32 AdcOpen(void *dev) { x_err_t ret = EOK; - stc_adc_init_t stcAdcInit; - ADC_StructInit(&stcAdcInit); struct AdcHardwareDevice* adc_dev = (struct AdcHardwareDevice*)dev; - CM_ADC_TypeDef *ADCx= (CM_ADC_TypeDef *)adc_dev->private_data; - ADC_Init((ADCx),&stcAdcInit); + + AdcClockConfig(); + AdcInitConfig(); + return ret; } - static uint32 AdcClose(void *dev) { - // CM_ADC_TypeDef *adc_dev = (CM_ADC_TypeDef*)dev; struct AdcHardwareDevice* adc_dev = (struct AdcHardwareDevice*)dev; - CM_ADC_TypeDef *ADCx= (CM_ADC_TypeDef *)adc_dev->private_data; - + + ADC_Stop(ADC_UNIT); ADC_DeInit(ADCx); return EOK; @@ -100,19 +272,10 @@ static uint32 AdcClose(void *dev) static uint32 AdcRead(void *dev, struct BusBlockReadParam *read_param) { - struct AdcHardwareDevice *adc_dev = (struct AdcHardwareDevice *)dev; + *(uint16 *)read_param->buffer = AdcPolling(); + read_param->read_length = 2; - struct HwAdc *adc_cfg = (struct HwAdc *)adc_dev->haldev.private_data; - - uint16 adc_average_value = 0; - uint8 times = 20; - - adc_average_value = GetAdcAverageValue(adc_cfg->ADCx, adc_cfg->adc_channel, times); - - *(uint16 *)read_param->buffer = adc_average_value; - read_param->read_length = 2; - - return read_param->read_length; + return EOK; } static uint32 AdcDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) @@ -131,9 +294,9 @@ static uint32 AdcDrvConfigure(void *drv, struct BusConfigureInfo *configure_info { case OPE_CFG: adc_cfg->adc_channel = *(uint8 *)configure_info->private_data; - if (adc_cfg->adc_channel > 18) { - KPrintf("AdcDrvConfigure set adc channel(0-18) %u error!", adc_cfg->adc_channel); - adc_cfg->adc_channel = 0; + if (adc_cfg->adc_channel != 1) { + KPrintf("AdcDrvConfigure set adc channel(1) %u error!", adc_cfg->adc_channel); + adc_cfg->adc_channel = 1; ret = ERROR; } break; @@ -156,7 +319,7 @@ int HwAdcInit(void) { x_err_t ret = EOK; -#ifdef BSP_USING_ADC1 +#ifdef BSP_USING_ADC static struct AdcBus adc1_bus; static struct AdcDriver adc1_drv; static struct AdcHardwareDevice adc1_dev; @@ -183,7 +346,7 @@ int HwAdcInit(void) adc1_dev.adc_dev_done = &dev_done; adc1_cfg.ADCx = CM_ADC1; - adc1_cfg.adc_channel = 0; + adc1_cfg.adc_channel = 1; ret = AdcDeviceRegister(&adc1_dev, (void *)&adc1_cfg, ADC1_DEVICE_NAME); if (ret != EOK) { @@ -197,88 +360,6 @@ int HwAdcInit(void) } #endif -#ifdef BSP_USING_ADC2 - static struct AdcBus adc2_bus; - static struct AdcDriver adc2_drv; - static struct AdcHardwareDevice adc2_dev; - static struct HwAdc adc2_cfg; - - adc2_drv.configure = AdcDrvConfigure; - - ret = AdcBusInit(&adc2_bus, ADC2_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC2 bus init error %d\n", ret); - return ERROR; - } - - ret = AdcDriverInit(&adc2_drv, ADC2_DRIVER_NAME); - if (ret != EOK) { - KPrintf("ADC2 driver init error %d\n", ret); - return ERROR; - } - ret = AdcDriverAttachToBus(ADC2_DRIVER_NAME, ADC2_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC2 driver attach error %d\n", ret); - return ERROR; - } - - adc2_dev.adc_dev_done = &dev_done; - adc2_cfg.ADCx = CM_ADC2; - adc2_cfg.adc_channel = 0; - - ret = AdcDeviceRegister(&adc2_dev, (void *)&adc2_cfg, ADC2_DEVICE_NAME); - if (ret != EOK) { - KPrintf("ADC2 device register error %d\n", ret); - return ERROR; - } - ret = AdcDeviceAttachToBus(ADC2_DEVICE_NAME, ADC2_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC2 device register error %d\n", ret); - return ERROR; - } -#endif - -#ifdef BSP_USING_ADC3 - static struct AdcBus adc3_bus; - static struct AdcDriver adc3_drv; - static struct AdcHardwareDevice adc3_dev; - static struct HwAdc adc3_cfg; - - adc3_drv.configure = AdcDrvConfigure; - - ret = AdcBusInit(&adc3_bus, ADC3_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC3 bus init error %d\n", ret); - return ERROR; - } - - ret = AdcDriverInit(&adc3_drv, ADC3_DRIVER_NAME); - if (ret != EOK) { - KPrintf("ADC3 driver init error %d\n", ret); - return ERROR; - } - ret = AdcDriverAttachToBus(ADC3_DRIVER_NAME, ADC3_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC3 driver attach error %d\n", ret); - return ERROR; - } - - adc3_dev.adc_dev_done = &dev_done; - adc3_cfg.ADCx = CM_ADC3; - adc3_cfg.adc_channel = 0; - - ret = AdcDeviceRegister(&adc3_dev, (void *)&adc3_cfg, ADC3_DEVICE_NAME); - if (ret != EOK) { - KPrintf("ADC3 device register error %d\n", ret); - return ERROR; - } - ret = AdcDeviceAttachToBus(ADC3_DEVICE_NAME, ADC3_BUS_NAME); - if (ret != EOK) { - KPrintf("ADC3 device register error %d\n", ret); - return ERROR; - } -#endif - return ret; } diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/common/hc32_ll_driver/src/Makefile b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/common/hc32_ll_driver/src/Makefile index 501d182d5..7254a2cb6 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/common/hc32_ll_driver/src/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/common/hc32_ll_driver/src/Makefile @@ -9,7 +9,7 @@ ifeq ($(CONFIG_BSP_USING_ADC),y) endif ifeq ($(CONFIG_BSP_USING_DAC),y) - SRC_FILES += hc32_ll_dac.c + SRC_FILES += hc32_ll_dac.c hc32_ll_mau.c endif ifeq ($(CONFIG_BSP_USING_SDIO),y) diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/dac/connect_dac.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/dac/connect_dac.c index 3cbd220c3..efcc80743 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/dac/connect_dac.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/dac/connect_dac.c @@ -20,56 +20,301 @@ #include -#define _DAC_CONS(string1, string2) string1##string2 -#define DAC_CONS(string1, string2) _DAC_CONS(string1, string2) +/******************************************************************************* + * Local pre-processor symbols/macros ('#define') + ******************************************************************************/ +#define DAC_UNIT1_PORT (GPIO_PORT_A) +#define DAC_UNIT1_CHN1_PIN (GPIO_PIN_04) -#ifdef BSP_USING_DAC -#define DAC_GPIO DAC_CONS(GPIO_Pin_, DAC_GPIO_NUM) +#define VREFH (3.3F) +#define DAC_CHN1 (0U) +#define DAC_CHN2 (1U) +#define DAC_DATA_ALIGN_12b_R (0U) +#define DAC_DATA_ALIGN_12b_L (1U) + +#define SUPPORT_AMP +#define SUPPORT_ADP +#define SINGLE_WAVE_DAC_CHN (DAC_CHN1) +#define DAC_DATA_ALIGN (DAC_DATA_ALIGN_12b_L) + +#define SINE_DOT_NUMBER (4096U) +#define SINE_NEGATIVE_TO_POSITVE (1.0F) + +/******************************************************************************* + * Local type definitions ('typedef') + ******************************************************************************/ +typedef enum { + DAC_Unit1, + DAC_Unit2, + DAC_Unit_Max, +}en_dac_unit_t; + +typedef enum { + E_Dac_Single, + E_Dac_Dual, +}en_dac_cvt_t; + +typedef struct { + CM_DAC_TypeDef *pUnit; + en_dac_cvt_t enCvtType; + uint16_t u16Ch; +} stc_dac_handle_t; + +/******************************************************************************* + * Local variable definitions ('static') + ******************************************************************************/ +static stc_dac_handle_t m_stcDACHandle[DAC_Unit_Max] = {0}; +static uint32_t gu32SinTable[SINE_DOT_NUMBER]; +static stc_dac_handle_t *pSingleDac; + +/******************************************************************************* + * Function implementation - global ('extern') and local ('static') + ******************************************************************************/ +/** + * @brief MAU Initialization + * @param None + * @retval None + */ +static void MauInit(void) +{ + /* Enable MAU peripheral clock. */ + FCG_Fcg0PeriphClockCmd(PWC_FCG0_MAU, ENABLE); +} + +/** + * @brief MAU De-Initialization + * @param None + * @retval None + */ +static void MauDeinit(void) +{ + /* Enable MAU peripheral clock. */ + FCG_Fcg0PeriphClockCmd(PWC_FCG0_MAU, DISABLE); +} + +/** + * @brief Sin table Initialization + * @param [in] pSinTable sin table + * @param [in] u32count number of pSinTable items + * @retval None + */ +static void SinTableInit(uint32_t pSinTable[], uint32_t u32count) +{ + uint32_t i; + uint32_t u32AngAvg = (uint32_t)(float32_t)((float32_t)((float32_t)MAU_SIN_ANGIDX_TOTAL / (float32_t)u32count) + 0.5); + float32_t fSin; + for (i = 0U; i < u32count; i++) { + fSin = (((float32_t)MAU_Sin(CM_MAU, (uint16_t)(u32AngAvg * i)) + / (float32_t)MAU_SIN_Q15_SCALAR + SINE_NEGATIVE_TO_POSITVE) / VREFH) * + (float32_t)DAC_DATAREG_VALUE_MAX + 0.5F; + +#if (DAC_DATA_ALIGN == DAC_DATA_ALIGN_12b_L) + { + pSinTable[i] = (uint32_t)fSin << 4; + } +#else + { + pSinTable[i] = (uint32_t)fSin; + } #endif - + } +} + +/** + * @brief Enable DAC peripheral clock + * @param [in] enUnit The selected DAC unit + * @retval None + */ +static void DacPClkEnable(en_dac_unit_t enUnit) +{ + uint32_t u32PClk; + switch (enUnit) { + case DAC_Unit1: + u32PClk = PWC_FCG3_DAC1; + break; + case DAC_Unit2: + u32PClk = PWC_FCG3_DAC2; + break; + default: + u32PClk = PWC_FCG3_DAC1 | PWC_FCG3_DAC2; + break; + } + /* Enable DAC peripheral clock. */ + FCG_Fcg3PeriphClockCmd(u32PClk, ENABLE); +} + +/** + * @brief Init DAC single channel + * @param [in] enUnit The selected DAC unit + * @retval A pointer of DAC handler + */ +static stc_dac_handle_t *DacSingleConversionInit(en_dac_unit_t enUnit) +{ + uint8_t u8Port; + uint16_t u16Pin; + stc_dac_handle_t *pDac; + + if (enUnit == DAC_Unit1) { + pDac = &m_stcDACHandle[DAC_Unit1]; + pDac->pUnit = CM_DAC1; + } else { + pDac = &m_stcDACHandle[DAC_Unit2]; + pDac->pUnit = CM_DAC2; + } + DacPClkEnable(enUnit); + + pDac->enCvtType = E_Dac_Single; +#if (SINGLE_WAVE_DAC_CHN == DAC_CHN1) + pDac->u16Ch = DAC_CH1; +#else + pDac->u16Ch = DAC_CH2; +#endif + + /* Init DAC by default value: source from data register and output enabled*/ + DAC_DeInit(pDac->pUnit); + stc_dac_init_t stInit; + (void)DAC_StructInit(&stInit); + (void)DAC_Init(pDac->pUnit, pDac->u16Ch, &stInit); +#if (DAC_DATA_ALIGN == DAC_DATA_ALIGN_12b_L) + DAC_DataRegAlignConfig(pDac->pUnit, DAC_DATA_ALIGN_L); +#else + DAC_DataRegAlignConfig(pDac->pUnit, DAC_DATA_ALIGN_R); +#endif + + /* Set DAC pin attribute to analog */ + if (enUnit == DAC_Unit1) { + u8Port = DAC_UNIT1_PORT; +#if (SINGLE_WAVE_DAC_CHN == DAC_CHN1) + u16Pin = DAC_UNIT1_CHN1_PIN; +#endif + } + stc_gpio_init_t stcGpioInit; + (void)GPIO_StructInit(&stcGpioInit); + stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG; + (void)GPIO_Init(u8Port, u16Pin, &stcGpioInit); + +#ifdef SUPPORT_ADP + /* Set ADC first */ + /* Enable ADC peripheral clock. */ + FCG_Fcg3PeriphClockCmd(PWC_FCG3_ADC1 | PWC_FCG3_ADC2 | PWC_FCG3_ADC3, ENABLE); + if (CM_ADC1->STR == 0U) { + if (CM_ADC2->STR == 0U) { + if (CM_ADC3->STR == 0U) { + DAC_ADCPrioConfig(pDac->pUnit, DAC_ADP_SELECT_ALL, ENABLE); + DAC_ADCPrioCmd(pDac->pUnit, ENABLE); + } + } + } +#endif + return pDac; +} + +/** + * @brief Start single DAC conversions + * @param [in] pDac A pointer of DAC handler + * @retval None + */ +static void DacStartSingleConversion(const stc_dac_handle_t *pDac) +{ + /* Enalbe AMP */ +#ifdef SUPPORT_AMP + (void)DAC_AMPCmd(pDac->pUnit, pDac->u16Ch, ENABLE); +#endif + + (void)DAC_Start(pDac->pUnit, pDac->u16Ch); + +#ifdef SUPPORT_AMP + /* delay 3us before setting data*/ + DDL_DelayMS(1U); +#endif +} + +/** + * @brief Convert data by single DAC channel + * @param [in] pDac A pointer of DAC handler + * @param [in] pDataTable The data table to be converted + * @param [in] u32count Number of data table items + * @retval None + */ +__STATIC_INLINE void DacSetSingleConversionData(const stc_dac_handle_t *pDac, uint32_t const pDataTable[], uint32_t u32count) +{ + uint32_t i = 0U; + + for (i = 0U; i < u32count; i++) { +#ifdef SUPPORT_ADP + uint32_t u32TryCount = 100U; + while (u32TryCount != 0U) { + u32TryCount--; + if (SET != DAC_GetChConvertState(pDac->pUnit, pDac->u16Ch)) { + break; + } + } +#endif + DAC_SetChData(pDac->pUnit, pDac->u16Ch, (uint16_t)pDataTable[i]); + } +} + +/** + * @brief stop DAC conversion + * @param [in] pDac A pointer of DAC handler + * @retval None + */ +static void DAC_StopConversion(const stc_dac_handle_t *pDac) +{ + if (NULL == pDac) { + DAC_DeInit(CM_DAC1); + DAC_DeInit(CM_DAC2); + } else if (pDac->enCvtType != E_Dac_Dual) { + (void)DAC_Stop(pDac->pUnit, pDac->u16Ch); + } else { + DAC_StopDualCh(pDac->pUnit); + } +} static uint32 DacOpen(void *dev) { struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev; - CM_DAC_TypeDef *DACx = (CM_DAC_TypeDef *)dac_dev->private_data; + /* Init MAU for generating sine data*/ + MauInit(); + /* Init sine data table */ + SinTableInit(gu32SinTable, SINE_DOT_NUMBER); - stc_dac_init_t pstcDacInit; - - DAC_StructInit(&pstcDacInit); - - DAC_Init(DACx,DAC_CH1,&pstcDacInit); + /* Init single DAC */ + pSingleDac = DacSingleConversionInit(DAC_Unit1); return EOK; } static uint32 DacClose(void *dev) { - struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev; - CM_DAC_TypeDef *DACx = (CM_DAC_TypeDef *)dac_dev->private_data; - + + DAC_StopConversion(pSingleDac); + DAC_DeInit(DACx); + MauDeinit(); + + memset(gu32SinTable, 0 , sizeof(gu32SinTable)); + return EOK; } - -static uint32 DacRead(void *dev, struct BusBlockReadParam *read_param) +static uint32 DacWrite(void *dev, struct BusBlockWriteParam *write_param) { struct DacHardwareDevice *dac_dev = (struct DacHardwareDevice *)dev; + struct HwDac *dac_cfg = (struct HwDac *)dac_dev->haldev.private_data; - CM_DAC_TypeDef *DACx = (CM_DAC_TypeDef *)dac_dev->private_data; + for (int i = 0; i < dac_cfg->digital_data; i ++) { + DacStartSingleConversion(pSingleDac); + DacSetSingleConversionData(pSingleDac, &gu32SinTable[i], 1U); + if (i > SINE_DOT_NUMBER) { + i = 0; + } + } - uint16 dac_set_value = 0; - - dac_set_value = DAC_GetChConvertState(DACx,DAC_CH1); - - *(uint16 *)read_param->buffer = dac_set_value; - read_param->read_length = 2; - - return read_param->read_length; return EOK; } @@ -88,8 +333,6 @@ static uint32 DacDrvConfigure(void *drv, struct BusConfigureInfo *configure_info { case OPE_CFG: dac_cfg->digital_data = *(uint16 *)configure_info->private_data; - // DAC_SetChannel1Data(DAC_Align_12b_R, dac_cfg->digital_data);//12 bits、R-Align data format, digital data - DAC_SetChData(dac_cfg->DACx,DAC_CH1,dac_cfg->digital_data); break; default: break; @@ -102,8 +345,8 @@ static const struct DacDevDone dev_done = { DacOpen, DacClose, + DacWrite, NONE, - DacRead, }; int HwDacInit(void) diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/include/connect_dac.h b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/include/connect_dac.h index 1108fcfdb..c99f28010 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/include/connect_dac.h +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/include/connect_dac.h @@ -34,13 +34,6 @@ struct HwDac uint16 digital_data; }; -typedef struct { - CM_DAC_TypeDef *pUnit; - // en_dac_cvt_t enCvtType; - uint16_t u16Ch; -} stc_dac_handle_t; - - int HwDacInit(void); #ifdef __cplusplus From 379cd567a21115ed633e805a8de27396586c1ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Wed, 9 Aug 2023 16:33:17 +0800 Subject: [PATCH 3/9] Fix edu-arm32 i2c. --- .../Applications/app_test/test_i2c.c | 67 +++++++++++++------ .../third_party_driver/i2c/connect_i2c.c | 10 ++- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/APP_Framework/Applications/app_test/test_i2c.c b/APP_Framework/Applications/app_test/test_i2c.c index 76881b92e..e2be2ce47 100644 --- a/APP_Framework/Applications/app_test/test_i2c.c +++ b/APP_Framework/Applications/app_test/test_i2c.c @@ -24,18 +24,16 @@ #define I2C_SLAVE_ADDRESS 0x0012U -void TestI2C(void) +int open_iic(void) { - // config IIC pin(SCL:34.SDA:35) in menuconfig int iic_fd = PrivOpen(I2C_DEV_DRIVER, O_RDWR); if (iic_fd < 0) { - printf("open iic_fd fd error:%d\n", iic_fd); - return; + printf("[TestI2C] Open iic_fd fd error: %d\n", iic_fd); + return -ERROR; } - printf("IIC open successful!\n"); + printf("[TestI2C] IIC open successful!\n"); - // init iic uint16 iic_address = I2C_SLAVE_ADDRESS; struct PrivIoctlCfg ioctl_cfg; @@ -44,28 +42,55 @@ void TestI2C(void) if (0 != PrivIoctl(iic_fd, OPE_INT, &ioctl_cfg)) { - printf("ioctl iic fd error %d\n", iic_fd); + printf("[TestI2C] Ioctl iic fd error %d\n", iic_fd); PrivClose(iic_fd); - return; + return -ERROR; } printf("IIC configure successful!\n"); - // I2C read and write - char tmp_buff[100]; - while (1) - { - PrivTaskDelay(1000); - PrivWrite(iic_fd, "Hello World!\n", sizeof("Hello World!\n")); - printf("msg send:%s\n", "Hello World!\n"); - PrivTaskDelay(1000); - memset(tmp_buff, 0, sizeof(tmp_buff)); - PrivRead(iic_fd, tmp_buff, sizeof(tmp_buff)); - printf("msg recv:%s\n", tmp_buff); + return iic_fd; +} + +static const int nr_transmit = 15; + +void TestMasterI2c(void) +{ + char recv_buff[13] = { 0 }; + + int iic_fd = open_iic(); + if (iic_fd < 0) { + printf("[%s] Error open iic\n", __func__); + return; + } + + for (int transmit_cnt = 0; transmit_cnt < nr_transmit; transmit_cnt++) { + // wait if you like. + PrivTaskDelay(500); + memset(recv_buff, 0, sizeof(recv_buff)); + PrivRead(iic_fd, recv_buff, sizeof(recv_buff)); + printf("[%s] Msg recv: %s\n", __func__, recv_buff); } PrivClose(iic_fd); - return; } -PRIV_SHELL_CMD_FUNCTION(TestI2C, a iic test sample, PRIV_SHELL_CMD_MAIN_ATTR); +void TestSlaveI2c(void) +{ + char send_buff[] = "Hello, World"; + + int iic_fd = open_iic(); + + for (int transmit_cnt = 0; transmit_cnt < nr_transmit; transmit_cnt++) { + // wait if you like. + PrivTaskDelay(500); + PrivWrite(iic_fd, send_buff, sizeof(send_buff)); + printf("[%s] Msg send: %s\n", __func__, send_buff); + } + + PrivClose(iic_fd); +} + +PRIV_SHELL_CMD_FUNCTION(TestMasterI2c, a iic test sample, PRIV_SHELL_CMD_MAIN_ATTR); +PRIV_SHELL_CMD_FUNCTION(TestSlaveI2c, a iic test sample, PRIV_SHELL_CMD_MAIN_ATTR); + #endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/i2c/connect_i2c.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/i2c/connect_i2c.c index d59f7b98b..20149f915 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/i2c/connect_i2c.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/i2c/connect_i2c.c @@ -117,6 +117,9 @@ static uint32 I2cDrvConfigure(void *drv, struct BusConfigureInfo *configure_info static uint32 I2cMasterWriteData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) { + if (msg->len == 0) { + return EOK; + } uint32 i32Ret; I2C_Cmd(I2C_UNIT, ENABLE); @@ -171,6 +174,9 @@ static uint32 I2cMasterReadData(struct I2cHardwareDevice *i2c_dev, struct I2cDat } static uint32 I2cSlaveWriteData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) { + if (msg->len == 0) { + return EOK; + } uint32 i32Ret; I2C_Cmd(I2C_UNIT, ENABLE); @@ -222,7 +228,7 @@ static uint32 I2cSlaveReadData(struct I2cHardwareDevice *i2c_dev, struct I2cData if (RESET == I2C_GetStatus(I2C_UNIT, I2C_FLAG_TRA)) { /* Slave receive data*/ i32Ret = I2C_ReceiveData(I2C_UNIT, msg->buf, msg->len, I2C_TIMEOUT); - KPrintf("Slave receive success!\r\n"); + KPrintf("Slave receive success!\r\n"); if ((LL_OK == i32Ret) || (LL_ERR_TIMEOUT == i32Ret)) { /* Wait stop condition */ @@ -336,7 +342,7 @@ int HwI2cInit(void) return ret; } -//#define I2C_TEST +// #define I2C_TEST #ifdef I2C_TEST #define USER_KEY_PORT (GPIO_PORT_I) From 0e82fac640c1b31ef62ba5a85df041ef28daa7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Wed, 9 Aug 2023 17:31:06 +0800 Subject: [PATCH 4/9] Fix edu-arm32 i2c. --- APP_Framework/Applications/app_test/test_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APP_Framework/Applications/app_test/test_i2c.c b/APP_Framework/Applications/app_test/test_i2c.c index e2be2ce47..a5a9475bd 100644 --- a/APP_Framework/Applications/app_test/test_i2c.c +++ b/APP_Framework/Applications/app_test/test_i2c.c @@ -24,7 +24,7 @@ #define I2C_SLAVE_ADDRESS 0x0012U -int open_iic(void) +int OpenIic(void) { int iic_fd = PrivOpen(I2C_DEV_DRIVER, O_RDWR); if (iic_fd < 0) From a9ebe1e96d741c9428198356029cdfbd21afb336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Fri, 11 Aug 2023 10:01:08 +0800 Subject: [PATCH 5/9] 23/08/11 Add app test socket; Fix app test i2c; Add command line argument parse tool argparse; Increase lwip related threads' priority. --- APP_Framework/Applications/app_test/Kconfig | 5 + APP_Framework/Applications/app_test/Makefile | 4 + .../Applications/app_test/test_i2c.c | 4 +- .../Applications/app_test/test_socket.c | 347 ++++++++++++++++ .../third_party_driver/ethernet/eth_driver.c | 2 +- .../third_party_driver/ethernet/ethernetif.c | 2 +- Ubiquitous/XiZi_IIoT/path_kernel.mk | 3 +- .../resources/ethernet/LwIP/arch/lwipopts.h | 2 +- .../resources/ethernet/LwIP/arch/sys_arch.c | 9 +- .../ethernet/cmd_lwip/lwip_udp_demo.c | 158 ++++--- Ubiquitous/XiZi_IIoT/tool/shell/Makefile | 1 + Ubiquitous/XiZi_IIoT/tool/shell/argparse.c | 389 ++++++++++++++++++ Ubiquitous/XiZi_IIoT/tool/shell/argparse.h | 157 +++++++ 13 files changed, 1027 insertions(+), 56 deletions(-) create mode 100644 APP_Framework/Applications/app_test/test_socket.c create mode 100644 Ubiquitous/XiZi_IIoT/tool/shell/argparse.c create mode 100644 Ubiquitous/XiZi_IIoT/tool/shell/argparse.h diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index c5e5894cd..136492b05 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -72,6 +72,11 @@ menu "test app" endif endif + menuconfig USER_TEST_SOCKET + select BSP_USING_LWIP + bool "Config test socket(lwip)" + default n + menuconfig USER_TEST_RS485 select BSP_USING_UART select BSP_USING_GPIO diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 6016dcb7a..21e3dd8f5 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -113,6 +113,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y) SRC_FILES += test_rbtree/test_rbtree.c endif + ifeq ($(CONFIG_USER_TEST_SOCKET),y) + SRC_FILES += test_socket.c + endif + ifeq ($(CONFIG_USER_TEST_WEBSERVER),y) SRC_FILES += endif diff --git a/APP_Framework/Applications/app_test/test_i2c.c b/APP_Framework/Applications/app_test/test_i2c.c index a5a9475bd..a7fb3a060 100644 --- a/APP_Framework/Applications/app_test/test_i2c.c +++ b/APP_Framework/Applications/app_test/test_i2c.c @@ -57,7 +57,7 @@ void TestMasterI2c(void) { char recv_buff[13] = { 0 }; - int iic_fd = open_iic(); + int iic_fd = OpenIic(); if (iic_fd < 0) { printf("[%s] Error open iic\n", __func__); return; @@ -78,7 +78,7 @@ void TestSlaveI2c(void) { char send_buff[] = "Hello, World"; - int iic_fd = open_iic(); + int iic_fd = OpenIic(); for (int transmit_cnt = 0; transmit_cnt < nr_transmit; transmit_cnt++) { // wait if you like. diff --git a/APP_Framework/Applications/app_test/test_socket.c b/APP_Framework/Applications/app_test/test_socket.c new file mode 100644 index 000000000..1df10349e --- /dev/null +++ b/APP_Framework/Applications/app_test/test_socket.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include +#include +#include + +#include "lwip/sockets.h" +#include "sys_arch.h" + +#define IPERF_PORT 5001 +#define IPERF_BUFSZ (4 * 1024) + +enum IperfMode { + IPERF_MODE_STOP = (1 << 0), + IPERF_MODE_SERVER = (1 << 1), + IPERF_MODE_CLIENT = (1 << 2), +}; + +struct AtomicIperfMode { + /* pthread_mutex_t here is a int */ + pthread_mutex_t mtx; + enum IperfMode mode; +}; + +static struct AtomicIperfMode* GetGlobalIperfMode() +{ + /* init when used */ + static struct AtomicIperfMode g_iperf_mode = { + -1, + IPERF_MODE_STOP, + }; + if (g_iperf_mode.mtx < 0) { + /* mtx is a static obj, so there is only creation but not destruction */ + PrivMutexCreate(&g_iperf_mode.mtx, NULL); + /* init lwip if necessary */ + lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); + } + return &g_iperf_mode; +} + +static enum IperfMode GetGlobalMode() +{ + enum IperfMode mode = IPERF_MODE_STOP; + struct AtomicIperfMode* g_mode = GetGlobalIperfMode(); + + PrivMutexObtain(&g_mode->mtx); + mode = g_mode->mode; + PrivMutexAbandon(&g_mode->mtx); + + return mode; +} + +static void SetGlobalMode(enum IperfMode mode) +{ + struct AtomicIperfMode* g_mode = GetGlobalIperfMode(); + PrivMutexObtain(&g_mode->mtx); + g_mode->mode = mode; + PrivMutexAbandon(&g_mode->mtx); +} + +struct IperfParam { + char host[16]; + int port; +}; + +static void* TestIperfServer(void* param) +{ + struct IperfParam* iperf_param = (struct IperfParam*)param; + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + printf("[%s] Err: Can't create socker.\n", __func__); + return NULL; + } + + uint8_t* recv_data = (uint8_t*)malloc(IPERF_BUFSZ); + if (recv_data == NULL) { + KPrintf("[%s] No memory to alloc buffer!\n", __func__); + goto __exit; + } + + struct sockaddr_in server_addr, client_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(iperf_param->port); + server_addr.sin_addr.s_addr = INADDR_ANY; + memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero)); + + if (bind(sock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1) { + KPrintf("[%s] Err: Unable to bind socket: %d!\n", __func__, sock); + goto __exit; + } + + if (listen(sock, 5) == -1) { + KPrintf("[%s] Err: Listen error!\n", __func__); + goto __exit; + } + + struct timeval timeout = { + .tv_sec = 3, + .tv_usec = 0, + }; + + fd_set readset; + while (GetGlobalMode() != IPERF_MODE_STOP) { + FD_ZERO(&readset); + FD_SET(sock, &readset); + + if (select(sock + 1, &readset, NULL, NULL, &timeout) == 0) { + continue; + } + + socklen_t sin_size = sizeof(struct sockaddr_in); + struct sockaddr_in client_addr; + int connection = accept(sock, (struct sockaddr*)&client_addr, &sin_size); + printf("[%s] Info: New client connected from (%s, %d)\n", __func__, + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + + int flag = 1; + setsockopt(connection, + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (void*)&flag, /* the cast is historical cruft */ + sizeof(int)); /* length of option value */ + + int recvlen = 0; + int tick_beg = PrivGetTickTime(); + int tick_end = tick_beg; + while (GetGlobalMode() != IPERF_MODE_STOP) { + int bytes_received = recv(connection, recv_data, IPERF_BUFSZ, 0); + if (bytes_received == 0) { + KPrintf("client disconnected (%s, %d)\n", + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + break; + } else if (bytes_received < 0) { + KPrintf("recv error, client: (%s, %d)\n", + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + break; + } + + recvlen += bytes_received; + + tick_end = PrivGetTickTime(); + if (tick_end - tick_beg >= 5000) { + double speed; + // int integer, decimal; + + speed = (double)(recvlen / (tick_end - tick_beg)); + speed = speed / 1000.0f; + printf("[%s]: %2.4f MBps!\n", __func__, speed); + tick_beg = tick_end; + recvlen = 0; + } + } + if (connection >= 0) + closesocket(connection); + connection = -1; + } + +__exit: + if (sock >= 0) + closesocket(sock); + if (recv_data) + free(recv_data); + return NULL; +} + +static void* TestIperfClient(void* param) +{ + struct IperfParam* iperf_param = (struct IperfParam*)param; + + uint8_t* send_buf + = (uint8_t*)malloc(IPERF_BUFSZ); + if (NONE == send_buf) { + printf("[%s] Err: Unable to alloc buffer\n", __func__); + return NULL; + } + for (int i = 0; i < IPERF_BUFSZ; i++) { + send_buf[i] = i & 0xff; + } + + struct sockaddr_in addr; + while (GetGlobalMode() != IPERF_MODE_STOP) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + printf("[%s] Warning: Can't create socker.\n", __func__); + PrivTaskDelay(1000); + continue; + } + + addr.sin_family = PF_INET; + addr.sin_port = htons(iperf_param->port); + addr.sin_addr.s_addr = inet_addr((char*)iperf_param->host); + + int ret = connect(sock, (const struct sockaddr*)&addr, sizeof(addr)); + if (ret == -1) { + printf("[%s] Warning: Connect to iperf server faile, Waiting for the server to open!\n", __func__); + closesocket(sock); + DelayKTask(TICK_PER_SECOND); + continue; + } + printf("[%s] Connect to iperf server successful!\n", __func__); + + int flag = 1; + setsockopt(sock, + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (void*)&flag, /* the cast is historical cruft */ + sizeof(int)); /* length of option value */ + + int tick_beg = PrivGetTickTime(); + int tick_end = tick_beg; + int sentlen = 0; + while (GetGlobalMode() != IPERF_MODE_STOP) { + tick_end = PrivGetTickTime(); + /* Print every 5 second */ + if (tick_end - tick_beg >= 5000) { + double speed; + + speed = (double)(sentlen / (tick_end - tick_beg)); + speed = speed / 1000.0f; + printf("[%s]: %2.4f MBps!\n", __func__, speed); + tick_beg = tick_end; + sentlen = 0; + } + + ret = send(sock, send_buf, IPERF_BUFSZ, 0); + if (ret > 0) { + sentlen += ret; + } + + if (ret < 0) + break; + } + + closesocket(sock); + printf("[%s] Info: Disconnected, iperf server shut down!\n", __func__); + } + free(send_buf); + return NULL; +} + +enum IperfParamEnum { + IPERF_PARAM_SERVER = 's', + IPERF_PARAM_CLIENT = 'c', + IPERF_PARAM_STOP = 0, + IPERF_PARAM_IPADDR = 0, + IPERF_PARAM_PORT = 'p', +}; + +void TestIperf(int argc, char* argv[]) +{ + lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); + + static char usage_info[] = "Run either a iperf server or iperf client."; + static char program_info[] = "Lwip socket test task, a simple iperf."; + static const char* const usages[] = { + "TestIperf -c [--ip arg] [-p arg]", + "TestIperf -s [-p arg]", + NULL, + }; + + static struct IperfParam iperf_param = { + .host = "255.255.255.255", + .port = 5001, + }; + + enum IperfMode mode = 0; + char* ip_ptr = NULL; + bool is_help = false; + struct argparse_option options[] = { + OPT_HELP(&is_help), + OPT_GROUP("Bit Options"), + OPT_BIT(IPERF_PARAM_SERVER, "server", &mode, "start a iperf server", NULL, IPERF_MODE_SERVER, 0), + OPT_BIT(IPERF_PARAM_CLIENT, "client", &mode, "start a iperf client", NULL, IPERF_MODE_CLIENT, 0), + OPT_BIT(IPERF_PARAM_STOP, "stop", &mode, "stop iperf", NULL, IPERF_MODE_STOP, OPT_NONEG), + OPT_GROUP("Param Options"), + OPT_STRING(IPERF_PARAM_IPADDR, "ip", &ip_ptr, "server IP if iperf is a client", NULL, 0, 0), + OPT_INTEGER(IPERF_PARAM_PORT, "port", &iperf_param.port, "server PORT needed for iperf", NULL, 0, 0), + OPT_END(), + }; + + struct argparse argparse; + argparse_init(&argparse, options, usages, 0); + argparse_describe(&argparse, usage_info, program_info); + argc = argparse_parse(&argparse, argc, (const char**)argv); + /* help task */ + if (is_help) { + return; + } + + /* stop iperf task */ + if (mode & IPERF_MODE_STOP) { + SetGlobalMode(IPERF_MODE_STOP); + return; + } + if (mode & IPERF_MODE_SERVER && mode & IPERF_MODE_CLIENT) { + printf("[%s] Err: Can't run iperf server and client at one time.\n", __func__); + } + + /* iperf server or iperf client*/ + struct AtomicIperfMode* iperf_mode = GetGlobalIperfMode(); + PrivMutexObtain(&iperf_mode->mtx); + if (iperf_mode->mode != IPERF_MODE_STOP) { + PrivMutexAbandon(&iperf_mode->mtx); + printf("[%s] Err: There is already a iperf running, please stop it before running a new one\n", __func__); + return; + } + + if (mode & IPERF_MODE_SERVER) { + iperf_mode->mode = IPERF_MODE_SERVER; + } else if (mode & IPERF_MODE_CLIENT) { + if (ip_ptr == NONE) { + PrivMutexAbandon(&iperf_mode->mtx); + printf("[%s] Err: Iperf client must assign a server ip.\n", __func__); + return; + } else { + memset(iperf_param.host, 0, sizeof(iperf_param.host)); + strncpy(iperf_param.host, ip_ptr, strlen(ip_ptr)); + } + iperf_mode->mode = IPERF_MODE_CLIENT; + } + PrivMutexAbandon(&iperf_mode->mtx); + + pthread_t thd; + mode = GetGlobalMode(); + if (mode == IPERF_MODE_SERVER) { + printf("[%s] Running iperf server at port %d.\n", __func__, iperf_param.port); + + PrivTaskCreate(&thd, NULL, TestIperfServer, (void*)&iperf_param); + } else if (mode == IPERF_MODE_CLIENT) { + printf("[%s] Running iperf client to server at %s:%d.\n", __func__, iperf_param.host, iperf_param.port); + PrivTaskCreate(&thd, NULL, TestIperfClient, (void*)&iperf_param); + } + + PrivTaskStartup(&thd); +} + +PRIV_SHELL_CMD_FUNCTION(TestSocket, Test socket using iperf, PRIV_SHELL_CMD_MAIN_ATTR | SHELL_CMD_PARAM_NUM(8)); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/eth_driver.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/eth_driver.c index 800c08697..25d106209 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/eth_driver.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/eth_driver.c @@ -281,7 +281,7 @@ struct pbuf* low_level_input(struct netif* netif) extern void LwipSetIPTest(int argc, char* argv[]); int HwEthInit(void) { - // lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); + // lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); LwipSetIPTest(1, NULL); return EOK; } diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/ethernetif.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/ethernetif.c index 738359b59..ec463faab 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/ethernetif.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/ethernet/ethernetif.c @@ -263,7 +263,7 @@ err_t ethernetif_init(struct netif* netif) if (EOK != lwip_netdev_add(netif)) { SYS_KDEBUG_LOG(NETDEV_DEBUG, ("[%s] LWIP add netdev failed.\n", __func__)); } else { - printf("[%s] Add Netdev successful\n", __func__); + // printf("[%s] Add Netdev successful\n", __func__); } return LL_OK; } diff --git a/Ubiquitous/XiZi_IIoT/path_kernel.mk b/Ubiquitous/XiZi_IIoT/path_kernel.mk index 1603864c8..c32ee1572 100755 --- a/Ubiquitous/XiZi_IIoT/path_kernel.mk +++ b/Ubiquitous/XiZi_IIoT/path_kernel.mk @@ -572,7 +572,8 @@ endif ifeq ($(CONFIG_TOOL_SHELL), y) KERNELPATHS +=-I$(KERNEL_ROOT)/tool/shell/letter-shell \ - -I$(KERNEL_ROOT)/tool/shell/letter-shell/file_ext # + -I$(KERNEL_ROOT)/tool/shell/letter-shell/file_ext \ + -I$(KERNEL_ROOT)/tool/shell/ endif ifeq ($(CONFIG_TOOL_USING_OTA), y) diff --git a/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/lwipopts.h b/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/lwipopts.h index cdf5a61d9..8d76990a2 100644 --- a/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/lwipopts.h +++ b/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/lwipopts.h @@ -540,7 +540,7 @@ The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums #define TCPIP_THREAD_NAME "tcp" #define TCPIP_THREAD_STACKSIZE 2048 #define TCPIP_MBOX_SIZE 16 -#define TCPIP_THREAD_PRIO 20 +#define TCPIP_THREAD_PRIO 30 /* ---------------------------------------- diff --git a/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/sys_arch.c b/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/sys_arch.c index 7ec40271d..e6f405af0 100644 --- a/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/sys_arch.c +++ b/Ubiquitous/XiZi_IIoT/resources/ethernet/LwIP/arch/sys_arch.c @@ -336,7 +336,7 @@ void lwip_config_input(struct netif* net) { sys_thread_t th_id = 0; - th_id = sys_thread_new("eth_input", ethernetif_input, net, LWIP_TASK_STACK_SIZE, 20); + th_id = sys_thread_new("eth_input", ethernetif_input, net, LWIP_TASK_STACK_SIZE, 30); if (th_id >= 0) { lw_print("%s %d successfully!\n", __func__, th_id); @@ -347,6 +347,12 @@ void lwip_config_input(struct netif* net) void lwip_config_tcp(uint8_t enet_port, char* ip, char* mask, char* gw) { + static char is_init = 0; + if (is_init != 0) { + return; + } + is_init = 1; + sys_sem_new(get_eth_recv_sem(), 0); ip4_addr_t net_ipaddr, net_netmask, net_gw; @@ -371,7 +377,6 @@ void lwip_config_tcp(uint8_t enet_port, char* ip, char* mask, char* gw) if (0 == enet_port) { #ifdef NETIF_ENET0_INIT_FUNC - printf("[%s:%d] call netif_add\n", __func__, __LINE__); netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, eth_cfg, NETIF_ENET0_INIT_FUNC, tcpip_input); #endif diff --git a/Ubiquitous/XiZi_IIoT/resources/ethernet/cmd_lwip/lwip_udp_demo.c b/Ubiquitous/XiZi_IIoT/resources/ethernet/cmd_lwip/lwip_udp_demo.c index 71c6bc703..a978e773d 100755 --- a/Ubiquitous/XiZi_IIoT/resources/ethernet/cmd_lwip/lwip_udp_demo.c +++ b/Ubiquitous/XiZi_IIoT/resources/ethernet/cmd_lwip/lwip_udp_demo.c @@ -19,27 +19,67 @@ */ #include "board.h" #include "sys_arch.h" -#include "lwip/udp.h" -#include #include #include -#include "lwip/sockets.h" +#include +#include + +#include "lwip/sockets.h" +#include "lwip/udp.h" + +#include +#include #define PBUF_SIZE 27 static struct udp_pcb *udpecho_raw_pcb; -char udp_server_ip[] = {192, 168, 130, 2}; u16_t udp_server_port = LWIP_TARGET_PORT; -int32 udp_send_num = 0; -int8 udp_send_task_on = 0; -uint32 udp_interval = 50; - +#define UDP_BUFFER_SIZE 50 char hello_str[] = {"hello world\r\n"}; -char udp_demo_msg[] = "\nThis one is UDP package!!!\n"; +char udp_demo_buffer[UDP_BUFFER_SIZE] = { '\0' }; /******************************************************************************/ +enum LwipUdpSendParamEnum { + TARGET_IP = 0, + TARGET_PORT = 'p', + SEND_MESSAGE = 'm', + SEND_NUM = 'n', + SEND_INTERVAL = 'i', +}; + +struct LwipUdpSendParam { + uint32_t num; + uint32_t interval; + uint16_t port; + uint8_t ip[4]; + bool task_on; + bool given_ip; + bool given_port; + bool given_msg; +}; + +struct LwipUdpSendParam* get_udp_test_info() +{ + /* init once and init when used. */ + static struct LwipUdpSendParam g_udp_send_param = { + .interval = 100, + .num = 10, + .port = LWIP_TARGET_PORT, + .ip = { 127, 0, 0, 1 }, + .task_on = false, + .given_ip = false, + .given_port = false, + .given_msg = false, + }; + return &g_udp_send_param; +} + +static const char* const usages[] = { + "UDPSend [--options arg] [-option arg]", + NULL, +}; static void LwipUDPSendTask(void *arg) { @@ -56,8 +96,8 @@ static void LwipUDPSendTask(void *arg) struct sockaddr_in udp_sock; udp_sock.sin_family = AF_INET; - udp_sock.sin_port = htons(udp_server_port); - udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(udp_server_ip[0], udp_server_ip[1], udp_server_ip[2], udp_server_ip[3])); + udp_sock.sin_port = htons(get_udp_test_info()->port); + udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(get_udp_test_info()->ip[0], get_udp_test_info()->ip[1], get_udp_test_info()->ip[2], get_udp_test_info()->ip[3])); memset(&(udp_sock.sin_zero), 0, sizeof(udp_sock.sin_zero)); if (connect(socket_fd, (struct sockaddr *)&udp_sock, sizeof(struct sockaddr))) { @@ -68,59 +108,81 @@ static void LwipUDPSendTask(void *arg) KPrintf("UDP connect success, start to send.\n"); KPrintf("\n\nTarget Port:%d\n\n", udp_sock.sin_port); - udp_send_task_on = 1; + get_udp_test_info()->task_on = true; - while(udp_send_num > 0 || udp_send_num == -1) { - sendto(socket_fd, udp_demo_msg, strlen(udp_demo_msg), 0, (struct sockaddr*)&udp_sock, sizeof(struct sockaddr)); - KPrintf("Send UDP msg: %s \n", udp_demo_msg); - MdelayKTask(udp_interval); - udp_send_num--; + while (get_udp_test_info()->num > 0 || get_udp_test_info()->num == -1) { + sendto(socket_fd, udp_demo_buffer, strlen(udp_demo_buffer), 0, (struct sockaddr*)&udp_sock, sizeof(struct sockaddr)); + KPrintf("Send UDP msg: %s \n", udp_demo_buffer); + MdelayKTask(get_udp_test_info()->interval); + get_udp_test_info()->num--; } closesocket(socket_fd); - udp_send_task_on = 0; + get_udp_test_info()->task_on = false; return; } -void *LwipUdpSendTest(int argc, char *argv[]) +static int LwipUdpSend(int argc, char* argv[]) { - if(udp_send_task_on) { - udp_send_num = 0; - printf("waitting send task exit...\n"); - while(udp_send_task_on){ - MdelayKTask(1000); - } - udp_send_num = 1; + static char usage_info[] = "Send udp NUM message to IP:PORT with time INTERVAL between each message send."; + static char program_info[] = "UDP SEND TEST DEMO."; + + /* Wait if there are former udp task */ + if (get_udp_test_info()->task_on) { + KPrintf("[%s] Waiting former udp send task to exit.\n"); + } + while (get_udp_test_info()->task_on) { + MdelayKTask(1000); } - uint8_t enet_port = 0; ///< test enet port 0 - memset(udp_demo_msg, 0, sizeof(udp_demo_msg)); + get_udp_test_info()->given_ip = false; + get_udp_test_info()->given_port = false; + get_udp_test_info()->given_msg = false; - if(argc == 1) { - KPrintf("lw: [%s] gw %d.%d.%d.%d:%d\n", __func__, udp_server_ip[0], udp_server_ip[1], udp_server_ip[2], udp_server_ip[3], udp_server_port); - strncpy(udp_demo_msg, hello_str, strlen(hello_str)); - udp_send_num = 10; - udp_interval = 100; - } else { - strncpy(udp_demo_msg, argv[1], strlen(argv[1])); - strncat(udp_demo_msg, "\r\n", 3); - if(argc >= 3) { - sscanf(argv[2], "%d.%d.%d.%d:%d", &udp_server_ip[0], &udp_server_ip[1], &udp_server_ip[2], &udp_server_ip[3], &udp_server_port); - } - if(argc > 3) { - sscanf(argv[3], "%d", &udp_send_num); - sscanf(argv[4], "%d", &udp_interval); - } + /* Parse options */ + char* msg_ptr = NULL; + char* ip_ptr = NULL; + bool is_help = false; + struct argparse_option options[] = { + OPT_HELP(&is_help), + OPT_STRING(SEND_MESSAGE, "message", &msg_ptr, "MESSAGE to send", NULL, 0, 0), + OPT_STRING(TARGET_IP, "ip", &ip_ptr, "target IP to send upd messages", NULL, 0, 0), + OPT_INTEGER(TARGET_PORT, "port", &get_udp_test_info()->port, "target PORT to send udp messages", NULL, 0, 0), + OPT_INTEGER(SEND_NUM, "num", &get_udp_test_info()->num, "send NUM udp messages", NULL, 0, 0), + OPT_INTEGER(SEND_INTERVAL, "interval", &get_udp_test_info()->interval, "time INTERVAL between messages", NULL, 0, 0), + OPT_END(), + }; + + struct argparse argparse; + argparse_init(&argparse, options, usages, 0); + argparse_describe(&argparse, usage_info, program_info); + argc = argparse_parse(&argparse, argc, (const char**)argv); + if (argc < 0) { + KPrintf("Error options.\n"); + return -ERROR; + } + if (is_help) { + return EOK; } - KPrintf("lw: [%s] gw %d.%d.%d.%d:%d send time %d udp_interval %d\n", __func__, udp_server_ip[0], udp_server_ip[1], udp_server_ip[2], udp_server_ip[3], udp_server_port, udp_send_num, udp_interval); + // translate string to array + sscanf(ip_ptr, "%d.%d.%d.%d", &get_udp_test_info()->ip[0], &get_udp_test_info()->ip[1], &get_udp_test_info()->ip[2], &get_udp_test_info()->ip[3]); + int msg_len = strlen(msg_ptr); + strncpy(udp_demo_buffer, msg_ptr, msg_len < UDP_BUFFER_SIZE ? msg_len : UDP_BUFFER_SIZE); - //init lwip and net dirver - lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); + /* start task */ + KPrintf("[%s] gw %d.%d.%d.%d:%d send time %d udp_interval %d\n", __func__, + get_udp_test_info()->ip[0], get_udp_test_info()->ip[1], get_udp_test_info()->ip[2], get_udp_test_info()->ip[3], + get_udp_test_info()->port, + get_udp_test_info()->num, + get_udp_test_info()->interval); + + lwip_config_net(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); sys_thread_new("udp send", LwipUDPSendTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); + return EOK; } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(5), - UDPSend, LwipUdpSendTest, UDPSend msg [ip:port [num [interval]]]); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(16), + UDPSend, LwipUdpSend, UDPSend Demo); void LwipUdpRecvTest(void) { diff --git a/Ubiquitous/XiZi_IIoT/tool/shell/Makefile b/Ubiquitous/XiZi_IIoT/tool/shell/Makefile index f45467e4a..d2a8f1357 100644 --- a/Ubiquitous/XiZi_IIoT/tool/shell/Makefile +++ b/Ubiquitous/XiZi_IIoT/tool/shell/Makefile @@ -1,3 +1,4 @@ SRC_DIR := letter-shell +SRC_FILES += argparse.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/tool/shell/argparse.c b/Ubiquitous/XiZi_IIoT/tool/shell/argparse.c new file mode 100644 index 000000000..ed453547a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/shell/argparse.c @@ -0,0 +1,389 @@ +/** + * Copyright (C) 2012-2015 Yecheng Fu + * All rights reserved. + * + * Use of this source code is governed by a MIT-style license that can be found + * in the LICENSE file. + */ +#include "argparse.h" +#include +#include +#include +#include +#include +#include + +#define OPT_UNSET 1 +#define OPT_LONG (1 << 1) + +static const char* +prefix_skip(const char* str, const char* prefix) +{ + size_t len = strlen(prefix); + return strncmp(str, prefix, len) ? NULL : str + len; +} + +static int +prefix_cmp(const char* str, const char* prefix) +{ + for (;; str++, prefix++) + if (!*prefix) { + return 0; + } else if (*str != *prefix) { + return (unsigned char)*prefix - (unsigned char)*str; + } +} + +static void +argparse_error(struct argparse* self, const struct argparse_option* opt, + const char* reason, int flags) +{ + (void)self; + if (flags & OPT_LONG) { + fprintf(stderr, "error: option `--%s` %s\n", opt->long_name, reason); + } else { + fprintf(stderr, "error: option `-%c` %s\n", opt->short_name, reason); + } +} + +#include + +static int +argparse_getvalue(struct argparse* self, const struct argparse_option* opt, + int flags) +{ + const char* s = NULL; + if (!opt->value) + goto skipped; + switch (opt->type) { + case ARGPARSE_OPT_BOOLEAN: + if (flags & OPT_UNSET) { + *(int*)opt->value = *(int*)opt->value - 1; + } else { + *(int*)opt->value = *(int*)opt->value + 1; + } + if (*(int*)opt->value < 0) { + *(int*)opt->value = 0; + } + break; + case ARGPARSE_OPT_BIT: + if (flags & OPT_UNSET) { + *(int*)opt->value &= ~opt->data; + } else { + *(int*)opt->value |= opt->data; + } + break; + case ARGPARSE_OPT_STRING: + if (self->optvalue) { + *(const char**)opt->value = self->optvalue; + self->optvalue = NULL; + } else if (self->argc > 1) { + self->argc--; + *(const char**)opt->value = *++self->argv; + } else { + argparse_error(self, opt, "requires a value", flags); + } + break; + case ARGPARSE_OPT_INTEGER: + errno = 0; + if (self->optvalue) { + *(int*)opt->value = strtol(self->optvalue, (char**)&s, 0); + self->optvalue = NULL; + } else if (self->argc > 1) { + self->argc--; + *(int*)opt->value = strtol(*++self->argv, (char**)&s, 0); + } else { + argparse_error(self, opt, "requires a value", flags); + } + if (errno == ERANGE) + argparse_error(self, opt, "numerical result out of range", flags); + if (s[0] != '\0') // no digits or contains invalid characters + argparse_error(self, opt, "expects an integer value", flags); + break; + case ARGPARSE_OPT_FLOAT: + errno = 0; + if (self->optvalue) { + *(float*)opt->value = strtof(self->optvalue, (char**)&s); + self->optvalue = NULL; + } else if (self->argc > 1) { + self->argc--; + *(float*)opt->value = strtof(*++self->argv, (char**)&s); + } else { + argparse_error(self, opt, "requires a value", flags); + } + if (errno == ERANGE) + argparse_error(self, opt, "numerical result out of range", flags); + if (s[0] != '\0') // no digits or contains invalid characters + argparse_error(self, opt, "expects a numerical value", flags); + break; + default: + assert(0); + } + +skipped: + if (opt->callback) { + return opt->callback(self, opt); + } + return 0; +} + +static void +argparse_options_check(const struct argparse_option* options) +{ + for (; options->type != ARGPARSE_OPT_END; options++) { + switch (options->type) { + case ARGPARSE_OPT_END: + case ARGPARSE_OPT_BOOLEAN: + case ARGPARSE_OPT_BIT: + case ARGPARSE_OPT_INTEGER: + case ARGPARSE_OPT_FLOAT: + case ARGPARSE_OPT_STRING: + case ARGPARSE_OPT_GROUP: + continue; + default: + fprintf(stderr, "wrong option type: %d", options->type); + break; + } + } +} + +static int +argparse_short_opt(struct argparse* self, const struct argparse_option* options) +{ + for (; options->type != ARGPARSE_OPT_END; options++) { + if (options->short_name == *self->optvalue) { + self->optvalue = self->optvalue[1] ? self->optvalue + 1 : NULL; + return argparse_getvalue(self, options, 0); + } + } + return -2; +} + +static int +argparse_long_opt(struct argparse* self, const struct argparse_option* options) +{ + for (; options->type != ARGPARSE_OPT_END; options++) { + const char* rest; + int opt_flags = 0; + if (!options->long_name) + continue; + + rest = prefix_skip(self->argv[0] + 2, options->long_name); + if (!rest) { + // negation disabled? + if (options->flags & OPT_NONEG) { + continue; + } + // only OPT_BOOLEAN/OPT_BIT supports negation + if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) { + continue; + } + + if (prefix_cmp(self->argv[0] + 2, "no-")) { + continue; + } + rest = prefix_skip(self->argv[0] + 2 + 3, options->long_name); + if (!rest) + continue; + opt_flags |= OPT_UNSET; + } + if (*rest) { + if (*rest != '=') + continue; + self->optvalue = rest + 1; + } + return argparse_getvalue(self, options, opt_flags | OPT_LONG); + } + return -2; +} + +int argparse_init(struct argparse* self, struct argparse_option* options, + const char* const* usages, int flags) +{ + memset(self, 0, sizeof(*self)); + self->options = options; + self->usages = usages; + self->flags = flags; + self->description = NULL; + self->epilog = NULL; + return 0; +} + +void argparse_describe(struct argparse* self, const char* description, + const char* epilog) +{ + self->description = description; + self->epilog = epilog; +} + +int argparse_parse(struct argparse* self, int argc, const char** argv) +{ + self->argc = argc - 1; + self->argv = argv + 1; + self->out = argv; + + argparse_options_check(self->options); + + for (; self->argc; self->argc--, self->argv++) { + const char* arg = self->argv[0]; + if (arg[0] != '-' || !arg[1]) { + if (self->flags & ARGPARSE_STOP_AT_NON_OPTION) { + goto end; + } + // if it's not option or is a single char '-', copy verbatim + self->out[self->cpidx++] = self->argv[0]; + continue; + } + // short option + if (arg[1] != '-') { + self->optvalue = arg + 1; + switch (argparse_short_opt(self, self->options)) { + case -1: + break; + case -2: + goto unknown; + } + while (self->optvalue) { + switch (argparse_short_opt(self, self->options)) { + case -1: + break; + case -2: + goto unknown; + } + } + continue; + } + // if '--' presents + if (!arg[2]) { + self->argc--; + self->argv++; + break; + } + // long option + switch (argparse_long_opt(self, self->options)) { + case -1: + break; + case -2: + goto unknown; + } + continue; + + unknown: + fprintf(stderr, "error: unknown option `%s`\n", self->argv[0]); + argparse_usage(self); + if (!(self->flags & ARGPARSE_IGNORE_UNKNOWN_ARGS)) { + return ARGPARSE_ERROR; + } + } + +end: + memmove(self->out + self->cpidx, self->argv, + self->argc * sizeof(*self->out)); + self->out[self->cpidx + self->argc] = NULL; + + return self->cpidx + self->argc; +} + +void argparse_usage(struct argparse* self) +{ + if (self->usages) { + fprintf(stdout, "Usage: %s\n", *self->usages++); + while (*self->usages && **self->usages) + fprintf(stdout, " or: %s\n", *self->usages++); + } else { + fprintf(stdout, "Usage:\n"); + } + + // print description + if (self->description) + fprintf(stdout, "%s\n", self->description); + + fputc('\n', stdout); + + const struct argparse_option* options; + + // figure out best width + size_t usage_opts_width = 0; + size_t len; + options = self->options; + for (; options->type != ARGPARSE_OPT_END; options++) { + len = 0; + if ((options)->short_name) { + len += 2; + } + if ((options)->short_name && (options)->long_name) { + len += 2; // separator ", " + } + if ((options)->long_name) { + len += strlen((options)->long_name) + 2; + } + if (options->type == ARGPARSE_OPT_INTEGER) { + len += strlen("="); + } + if (options->type == ARGPARSE_OPT_FLOAT) { + len += strlen("="); + } else if (options->type == ARGPARSE_OPT_STRING) { + len += strlen("="); + } + len = (len + 3) - ((len + 3) & 3); + if (usage_opts_width < len) { + usage_opts_width = len; + } + } + usage_opts_width += 4; // 4 spaces prefix + + options = self->options; + for (; options->type != ARGPARSE_OPT_END; options++) { + size_t pos = 0; + size_t pad = 0; + if (options->type == ARGPARSE_OPT_GROUP) { + fputc('\n', stdout); + fprintf(stdout, "%s", options->help); + fputc('\n', stdout); + continue; + } + pos = fprintf(stdout, " "); + if (options->short_name) { + pos += fprintf(stdout, "-%c", options->short_name); + } + if (options->long_name && options->short_name) { + pos += fprintf(stdout, ", "); + } + if (options->long_name) { + pos += fprintf(stdout, "--%s", options->long_name); + } + if (options->type == ARGPARSE_OPT_INTEGER) { + pos += fprintf(stdout, "="); + } else if (options->type == ARGPARSE_OPT_FLOAT) { + pos += fprintf(stdout, "="); + } else if (options->type == ARGPARSE_OPT_STRING) { + pos += fprintf(stdout, "="); + } + if (pos <= usage_opts_width) { + pad = usage_opts_width - pos; + } else { + fputc('\n', stdout); + pad = usage_opts_width; + } + fprintf(stdout, "%*s%s\n", (int)pad + 2, "", options->help); + } + + // print epilog + if (self->epilog) + fprintf(stdout, "%s\n", self->epilog); +} + +int argparse_help_cb_no_exit(struct argparse* self, + const struct argparse_option* option) +{ + (void)option; + argparse_usage(self); + return 0; +} + +int argparse_help_cb(struct argparse* self, const struct argparse_option* option) +{ + argparse_help_cb_no_exit(self, option); + *(bool*)option->value = true; + return 0; +} diff --git a/Ubiquitous/XiZi_IIoT/tool/shell/argparse.h b/Ubiquitous/XiZi_IIoT/tool/shell/argparse.h new file mode 100644 index 000000000..2ccf51b04 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/shell/argparse.h @@ -0,0 +1,157 @@ +/** + * Copyright (C) 2012-2015 Yecheng Fu + * All rights reserved. + * + * Use of this source code is governed by a MIT-style license that can be found + * in the LICENSE file. + */ +#ifndef ARGPARSE_H +#define ARGPARSE_H + +/* For c++ compatibility */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ARGPARSE_HELP_DONE -1 +#define ARGPARSE_ERROR -2 + +struct argparse; +struct argparse_option; + +typedef int argparse_callback(struct argparse* self, + const struct argparse_option* option); + +enum argparse_flag { + ARGPARSE_STOP_AT_NON_OPTION = 1 << 0, + ARGPARSE_IGNORE_UNKNOWN_ARGS = 1 << 1, +}; + +enum argparse_option_type { + /* special */ + ARGPARSE_OPT_END, + ARGPARSE_OPT_GROUP, + /* options with no arguments */ + ARGPARSE_OPT_BOOLEAN, + ARGPARSE_OPT_BIT, + /* options with arguments (optional or required) */ + ARGPARSE_OPT_INTEGER, + ARGPARSE_OPT_FLOAT, + ARGPARSE_OPT_STRING, +}; + +enum argparse_option_flags { + OPT_NONEG = 1, /* disable negation */ +}; + +/** + * argparse option + * + * `type`: + * holds the type of the option, you must have an ARGPARSE_OPT_END last in your + * array. + * + * `short_name`: + * the character to use as a short option name, '\0' if none. + * + * `long_name`: + * the long option name, without the leading dash, NULL if none. + * + * `value`: + * stores pointer to the value to be filled. + * + * `help`: + * the short help message associated to what the option does. + * Must never be NULL (except for ARGPARSE_OPT_END). + * + * `callback`: + * function is called when corresponding argument is parsed. + * + * `data`: + * associated data. Callbacks can use it like they want. + * + * `flags`: + * option flags. + */ +struct argparse_option { + enum argparse_option_type type; + const char short_name; + const char* long_name; + void* value; + const char* help; + argparse_callback* callback; + intptr_t data; + int flags; +}; + +/** + * argpparse + */ +struct argparse { + // user supplied + const struct argparse_option* options; + const char* const* usages; + int flags; + const char* description; // a description after usage + const char* epilog; // a description at the end + // internal context + int argc; + const char** argv; + const char** out; + int cpidx; + const char* optvalue; // current option value +}; + +// built-in callbacks +int argparse_help_cb(struct argparse* self, + const struct argparse_option* option); +int argparse_help_cb_no_exit(struct argparse* self, + const struct argparse_option* option); + +// built-in option macros +#define OPT_END() \ + { \ + ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 \ + } +#define OPT_BOOLEAN(...) \ + { \ + ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ \ + } +#define OPT_BIT(...) \ + { \ + ARGPARSE_OPT_BIT, __VA_ARGS__ \ + } +#define OPT_INTEGER(...) \ + { \ + ARGPARSE_OPT_INTEGER, __VA_ARGS__ \ + } +#define OPT_FLOAT(...) \ + { \ + ARGPARSE_OPT_FLOAT, __VA_ARGS__ \ + } +#define OPT_STRING(...) \ + { \ + ARGPARSE_OPT_STRING, __VA_ARGS__ \ + } +#define OPT_GROUP(h) \ + { \ + ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 \ + } +#define OPT_HELP(flag) OPT_BOOLEAN('h', "help", flag, \ + "show this help message and exit", \ + argparse_help_cb, 0, OPT_NONEG) + +int argparse_init(struct argparse* self, struct argparse_option* options, + const char* const* usages, int flags); +void argparse_describe(struct argparse* self, const char* description, + const char* epilog); +int argparse_parse(struct argparse* self, int argc, const char** argv); +void argparse_usage(struct argparse* self); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file From 586ceba08e67cc34df4bf74428791423664e9994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Fri, 11 Aug 2023 10:02:51 +0800 Subject: [PATCH 6/9] 23/08/11 Fix app test socket --- APP_Framework/Applications/app_test/test_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APP_Framework/Applications/app_test/test_socket.c b/APP_Framework/Applications/app_test/test_socket.c index 1df10349e..ac9b87b34 100644 --- a/APP_Framework/Applications/app_test/test_socket.c +++ b/APP_Framework/Applications/app_test/test_socket.c @@ -256,7 +256,7 @@ enum IperfParamEnum { IPERF_PARAM_PORT = 'p', }; -void TestIperf(int argc, char* argv[]) +void TestSocket(int argc, char* argv[]) { lwip_config_tcp(0, lwip_ipaddr, lwip_netmask, lwip_gwaddr); From dd35692866f7826c3e248678d58959e9acdaf51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Fri, 11 Aug 2023 10:07:31 +0800 Subject: [PATCH 7/9] 23/08/11 Fix app test socket --- APP_Framework/Applications/app_test/test_socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/APP_Framework/Applications/app_test/test_socket.c b/APP_Framework/Applications/app_test/test_socket.c index ac9b87b34..81c4543cc 100644 --- a/APP_Framework/Applications/app_test/test_socket.c +++ b/APP_Framework/Applications/app_test/test_socket.c @@ -110,7 +110,7 @@ static void* TestIperfServer(void* param) }; fd_set readset; - while (GetGlobalMode() != IPERF_MODE_STOP) { + while (GetGlobalMode() == IPERF_MODE_SERVER) { FD_ZERO(&readset); FD_SET(sock, &readset); @@ -134,7 +134,7 @@ static void* TestIperfServer(void* param) int recvlen = 0; int tick_beg = PrivGetTickTime(); int tick_end = tick_beg; - while (GetGlobalMode() != IPERF_MODE_STOP) { + while (GetGlobalMode() == IPERF_MODE_SERVER) { int bytes_received = recv(connection, recv_data, IPERF_BUFSZ, 0); if (bytes_received == 0) { KPrintf("client disconnected (%s, %d)\n", @@ -188,7 +188,7 @@ static void* TestIperfClient(void* param) } struct sockaddr_in addr; - while (GetGlobalMode() != IPERF_MODE_STOP) { + while (GetGlobalMode() == IPERF_MODE_CLIENT) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { printf("[%s] Warning: Can't create socker.\n", __func__); @@ -219,7 +219,7 @@ static void* TestIperfClient(void* param) int tick_beg = PrivGetTickTime(); int tick_end = tick_beg; int sentlen = 0; - while (GetGlobalMode() != IPERF_MODE_STOP) { + while (GetGlobalMode() == IPERF_MODE_CLIENT) { tick_end = PrivGetTickTime(); /* Print every 5 second */ if (tick_end - tick_beg >= 5000) { From 38962426229def714279d535bfa4762d1c7288de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=82=E7=85=9C=E6=B4=8B?= <1163589503@qq.com> Date: Fri, 11 Aug 2023 11:03:10 +0800 Subject: [PATCH 8/9] 23/08/11 Add app test_uart. --- APP_Framework/Applications/app_test/Kconfig | 13 +++ APP_Framework/Applications/app_test/Makefile | 4 + .../Applications/app_test/test_uart.c | 95 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 APP_Framework/Applications/app_test/test_uart.c diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index 136492b05..cfc834c73 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -77,6 +77,19 @@ menu "test app" bool "Config test socket(lwip)" default n + menuconfig USER_TEST_UART + select BSP_USING_UART + select BSP_USING_UART6 + bool "Config test uart" + default n + if USER_TEST_UART + if ADD_XIZI_FEATURES + config UART_DEV_DRIVER + string "Set uart dev path" + default "/dev/usart6_dev6" + endif + endif + menuconfig USER_TEST_RS485 select BSP_USING_UART select BSP_USING_GPIO diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index 21e3dd8f5..36a913ca6 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -49,6 +49,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y) SRC_FILES += test_i2c.c endif + ifeq ($(CONFIG_USER_TEST_UART),y) + SRC_FILES += test_uart.c + endif + ifeq ($(CONFIG_USER_TEST_GPIO),y) SRC_FILES += test_gpio.c endif diff --git a/APP_Framework/Applications/app_test/test_uart.c b/APP_Framework/Applications/app_test/test_uart.c new file mode 100644 index 000000000..c714269ab --- /dev/null +++ b/APP_Framework/Applications/app_test/test_uart.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file: test_uart.c + * @brief: a application of uart function, uart6 for edu-arm32 + * @version: 3.0 + * @author: AIIT XUOS Lab + * @date: 2023/8/11 + */ +#include +#include +#include + +#include + +#include +#ifdef ADD_XIZI_FEATURES + +void TestUart(int argc, char* argv[]) +{ + static char program_info[] = "App Test uart, sending a message through uart and receive messages from uart."; + static const char* const usages[] = { + "TestUart -m arg", + NULL, + }; + + bool is_help = false; + char* msg = NULL; + struct argparse_option options[] = { + OPT_HELP(&is_help), + OPT_STRING('m', "message", &msg, "MESSAGE to send through uart.", NULL, 0, 0), + OPT_END(), + }; + struct argparse argparse; + argparse_init(&argparse, options, usages, 0); + argparse_describe(&argparse, NULL, program_info); + argc = argparse_parse(&argparse, argc, (const char**)argv); + if (is_help) { + return; + } + + int uart_fd = PrivOpen(UART_DEV_DRIVER, O_RDWR); + if (uart_fd < 0) { + printf("open pin fd error:%d\n", uart_fd); + return; + } + printf("[%s] Info: Uart and pin fopen success\n", __func__); + + struct SerialDataCfg uart_cfg; + memset(&uart_cfg, 0, sizeof(struct SerialDataCfg)); + + uart_cfg.serial_baud_rate = BAUD_RATE_115200; + uart_cfg.serial_data_bits = DATA_BITS_8; + uart_cfg.serial_stop_bits = STOP_BITS_1; + uart_cfg.serial_parity_mode = PARITY_NONE; + uart_cfg.serial_bit_order = BIT_ORDER_LSB; + uart_cfg.serial_invert_mode = NRZ_NORMAL; + uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ; + uart_cfg.serial_timeout = -1; + uart_cfg.is_ext_uart = 0; + + struct PrivIoctlCfg ioctl_cfg; + ioctl_cfg.ioctl_driver_type = SERIAL_TYPE; + ioctl_cfg.args = (void*)&uart_cfg; + + if (0 != PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg)) { + printf("[%s] Err: ioctl uart fd error %d\n", __func__, uart_fd); + PrivClose(uart_fd); + return; + } + PrivWrite(uart_fd, msg, strlen(msg)); + + char recv_buf[100]; + while (1) { + memset(recv_buf, 0, sizeof(recv_buf)); + PrivRead(uart_fd, recv_buf, sizeof(recv_buf)); + printf("[%s] Info: Recv from uart: %s\n", __func__, recv_buf); + } + + PrivClose(uart_fd); + return; +} + +PRIV_SHELL_CMD_FUNCTION(TestUart, a uart test sample, PRIV_SHELL_CMD_MAIN_ATTR); +#endif \ No newline at end of file From 7077cf74c23900521f6867068b88d2aa326d69d7 Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Thu, 17 Aug 2023 15:04:48 +0800 Subject: [PATCH 9/9] feat add RS485 using usart4 for edu_arm32 board and fix test_rs485 error --- .../Applications/app_test/test_rs485.c | 118 ++++++++++++++---- .../Framework/control/shared/control_io.c | 2 +- .../third_party_driver/usart/Kconfig | 15 +++ .../third_party_driver/usart/connect_usart.c | 91 ++++++++++++++ .../XiZi_IIoT/resources/serial/dev_serial.c | 14 ++- 5 files changed, 211 insertions(+), 29 deletions(-) diff --git a/APP_Framework/Applications/app_test/test_rs485.c b/APP_Framework/Applications/app_test/test_rs485.c index bbe6f1c4d..0b562359c 100644 --- a/APP_Framework/Applications/app_test/test_rs485.c +++ b/APP_Framework/Applications/app_test/test_rs485.c @@ -22,26 +22,94 @@ #include #ifdef ADD_XIZI_FEATURES -#define BSP_485_DIR_PIN 24 +//edu-arm board dir pin PG01----no.67 in XiZi_IIoT/board/edu_arm32/third_party_driver/gpio/connect_gpio.c +#define BSP_485_DIR_PIN 67 + +static int pin_fd; +static int uart_fd; +static char write_485_data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; +static char read_485_data[8] = {0}; + +/** + * @description: Set Uart 485 Input + * @return + */ +static void Set485Input(void) +{ + struct PinStat pin_stat; + pin_stat.pin = BSP_485_DIR_PIN; + pin_stat.val = GPIO_LOW; + PrivWrite(pin_fd, &pin_stat, 1); +} + +/** + * @description: Set Uart 485 Output + * @return + */ +static void Set485Output(void) +{ + struct PinStat pin_stat; + pin_stat.pin = BSP_485_DIR_PIN; + pin_stat.val = GPIO_HIGH; + PrivWrite(pin_fd, &pin_stat, 1); +} + +/** + * @description: Control Framework Serial Write + * @param write_data - write data + * @param length - length + * @return + */ +void Rs485Write(uint8_t *write_data, int length) +{ + Set485Output(); + PrivTaskDelay(20); + + PrivWrite(uart_fd, write_data, length); + + PrivTaskDelay(15); + Set485Input(); +} + +/** + * @description: Control Framework Serial Read + * @param read_data - read data + * @param length - length + * @return read data size + */ +int Rs485Read(uint8_t *read_data, int length) +{ + int data_size = 0; + int data_recv_size = 0; + + while (data_size < length) { + data_recv_size = PrivRead(uart_fd, read_data + data_size, length - data_size); + data_size += data_recv_size; + } + + //need to wait 30ms , make sure write cmd again and receive data successfully + PrivTaskDelay(30); + + return data_size; +} void Test485(void) { - int pin_fd = PrivOpen(RS485_PIN_DEV_DRIVER, O_RDWR); - if (pin_fd < 0) - { + int read_data_length = 0; + pin_fd = PrivOpen(RS485_PIN_DEV_DRIVER, O_RDWR); + if (pin_fd < 0) { printf("open pin fd error:%d\n", pin_fd); return; } - int uart_fd = PrivOpen(RS485_UART_DEV_DRIVER, O_RDWR); - if (uart_fd < 0) - { + uart_fd = PrivOpen(RS485_UART_DEV_DRIVER, O_RDWR); + if (uart_fd < 0) { printf("open pin fd error:%d\n", uart_fd); return; } printf("uart and pin fopen success\n"); - //config led pin in board + //config dir pin in board struct PinParam pin_parameter; memset(&pin_parameter, 0, sizeof(struct PinParam)); pin_parameter.cmd = GPIO_CONFIG_MODE; @@ -68,36 +136,34 @@ void Test485(void) uart_cfg.serial_bit_order = BIT_ORDER_LSB; uart_cfg.serial_invert_mode = NRZ_NORMAL; uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ; - uart_cfg.serial_timeout = 1000; + uart_cfg.serial_timeout = -1; uart_cfg.is_ext_uart = 0; ioctl_cfg.ioctl_driver_type = SERIAL_TYPE; ioctl_cfg.args = (void *)&uart_cfg; - if (0 != PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg)) - { + if (0 != PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg)) { printf("ioctl uart fd error %d\n", uart_fd); PrivClose(uart_fd); return; } - struct PinStat pin_dir; - pin_dir.pin = BSP_485_DIR_PIN; - while (1) - { - pin_dir.val = GPIO_HIGH; - PrivWrite(pin_fd,&pin_dir,0); - PrivWrite(uart_fd,"Hello world!\n",sizeof("Hello world!\n")); - PrivTaskDelay(100); + Rs485Write(write_485_data, sizeof(write_485_data)); - pin_dir.val = GPIO_LOW; - PrivWrite(pin_fd,&pin_dir,0); - char recv_buff[100]; - memset(recv_buff,0,sizeof(recv_buff)); - PrivRead(uart_fd,recv_buff,20); - printf("%s",recv_buff); - PrivTaskDelay(100); + while(1) { + printf("ready to read data\n"); + + read_data_length = Rs485Read(read_485_data, sizeof(read_485_data)); + printf("%s read data length %d\n", __func__, read_data_length); + for (int i = 0; i < read_data_length; i ++) { + printf("i %d read data 0x%x\n", i, read_485_data[i]); + } + Rs485Write(read_485_data, read_data_length); + memset(read_485_data, 0, sizeof(read_485_data)); + + printf("read data done\n"); } + PrivClose(pin_fd); PrivClose(uart_fd); return; diff --git a/APP_Framework/Framework/control/shared/control_io.c b/APP_Framework/Framework/control/shared/control_io.c index fbb01b7ec..5d9e00060 100644 --- a/APP_Framework/Framework/control/shared/control_io.c +++ b/APP_Framework/Framework/control/shared/control_io.c @@ -180,7 +180,7 @@ int SerialRead(uint8_t *read_data, int length) int data_recv_size = 0; while (data_size < length) { - data_recv_size = PrivRead(uart_fd, read_data + data_recv_size, length); + data_recv_size = PrivRead(uart_fd, read_data + data_size, length - data_size); data_size += data_recv_size; } diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/Kconfig index 7f51f8e7b..626811be0 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/Kconfig @@ -13,6 +13,21 @@ menuconfig BSP_USING_UART3 default "usart3_dev3" endif +menuconfig BSP_USING_UART4 + bool "Enable USART4 for RS485" + default y + if BSP_USING_UART4 + config SERIAL_BUS_NAME_4 + string "serial bus 4 name" + default "usart4" + config SERIAL_DRV_NAME_4 + string "serial bus 4 driver name" + default "usart4_drv" + config SERIAL_4_DEVICE_NAME_0 + string "serial bus 4 device 0 name" + default "usart4_dev4" + endif + menuconfig BSP_USING_UART6 bool "Enable USART6" default n diff --git a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/connect_usart.c b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/connect_usart.c index 47a9ca68a..b16c709bd 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/connect_usart.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-arm32/third_party_driver/usart/connect_usart.c @@ -50,6 +50,14 @@ Modification: #define USART3_TX_PIN (GPIO_PIN_10) #endif +#if defined(BSP_USING_UART4) +#define USART4_RX_PORT (GPIO_PORT_E) +#define USART4_RX_PIN (GPIO_PIN_07) + +#define USART4_TX_PORT (GPIO_PORT_G) +#define USART4_TX_PIN (GPIO_PIN_00) +#endif + #if defined(BSP_USING_UART6) #define USART6_RX_PORT (GPIO_PORT_H) #define USART6_RX_PIN (GPIO_PIN_06) @@ -72,6 +80,12 @@ static x_err_t UartGpioInit(CM_USART_TypeDef *USARTx) GPIO_SetFunc(USART3_TX_PORT, USART3_TX_PIN, GPIO_FUNC_32); break; #endif +#ifdef BSP_USING_UART4 + case (uint32)CM_USART4: + GPIO_SetFunc(USART4_RX_PORT, USART4_RX_PIN, GPIO_FUNC_33); + GPIO_SetFunc(USART4_TX_PORT, USART4_TX_PIN, GPIO_FUNC_32); + break; +#endif #ifdef BSP_USING_UART6 case (uint32)CM_USART6: GPIO_SetFunc(USART6_RX_PORT, USART6_RX_PIN, GPIO_FUNC_37); @@ -123,6 +137,32 @@ void Uart3RxErrIrqHandler(void) } #endif +#ifdef BSP_USING_UART4 +struct SerialBus serial_bus_4; +struct SerialDriver serial_driver_4; +struct SerialHardwareDevice serial_device_4; + +void Uart4RxIrqHandler(void) +{ + x_base lock = 0; + lock = DISABLE_INTERRUPT(); + + SerialSetIsr(&serial_device_4, SERIAL_EVENT_RX_IND); + + ENABLE_INTERRUPT(lock); +} + +void Uart4RxErrIrqHandler(void) +{ + x_base lock = 0; + lock = DISABLE_INTERRUPT(); + + UartRxErrIsr(&serial_bus_4, &serial_driver_4, &serial_device_4); + + ENABLE_INTERRUPT(lock); +} +#endif + #ifdef BSP_USING_UART6 struct SerialBus serial_bus_6; struct SerialDriver serial_driver_6; @@ -499,6 +539,57 @@ int HwUsartInit(void) } #endif +#ifdef BSP_USING_UART4 + static struct SerialCfgParam serial_cfg_4; + memset(&serial_cfg_4, 0, sizeof(struct SerialCfgParam)); + + static struct SerialDevParam serial_dev_param_4; + memset(&serial_dev_param_4, 0, sizeof(struct SerialDevParam)); + + static struct UsartHwCfg serial_hw_cfg_4; + memset(&serial_hw_cfg_4, 0, sizeof(struct UsartHwCfg)); + + serial_driver_4.drv_done = &drv_done; + serial_driver_4.configure = SerialDrvConfigure; + serial_device_4.hwdev_done = &hwdev_done; + + serial_cfg_4.data_cfg = data_cfg_init; + + //default irq configure + serial_hw_cfg_4.uart_device = CM_USART4; + serial_hw_cfg_4.usart_clock = FCG3_PERIPH_USART4; + serial_hw_cfg_4.rx_err_irq.irq_config.irq_num = BSP_UART4_RXERR_IRQ_NUM; + serial_hw_cfg_4.rx_err_irq.irq_config.irq_prio = BSP_UART4_RXERR_IRQ_PRIO; + serial_hw_cfg_4.rx_err_irq.irq_config.int_src = INT_SRC_USART4_EI; + + serial_hw_cfg_4.rx_irq.irq_config.irq_num = BSP_UART4_RX_IRQ_NUM; + serial_hw_cfg_4.rx_irq.irq_config.irq_prio = BSP_UART4_RX_IRQ_PRIO; + serial_hw_cfg_4.rx_irq.irq_config.int_src = INT_SRC_USART4_RI; + + serial_hw_cfg_4.rx_err_irq.irq_callback = Uart4RxErrIrqHandler; + serial_hw_cfg_4.rx_irq.irq_callback = Uart4RxIrqHandler; + + hc32_install_irq_handler(&serial_hw_cfg_4.rx_err_irq.irq_config, serial_hw_cfg_4.rx_err_irq.irq_callback, 0); + + serial_cfg_4.hw_cfg.private_data = (void *)&serial_hw_cfg_4; + serial_driver_4.private_data = (void *)&serial_cfg_4; + + serial_dev_param_4.serial_work_mode = SIGN_OPER_INT_RX; + serial_device_4.haldev.private_data = (void *)&serial_dev_param_4; + + ret = BoardSerialBusInit(&serial_bus_4, &serial_driver_4, SERIAL_BUS_NAME_4, SERIAL_DRV_NAME_4); + if (EOK != ret) { + KPrintf("HwUartInit uart4 error ret %u\n", ret); + return ERROR; + } + + ret = BoardSerialDevBend(&serial_device_4, (void *)&serial_cfg_4, SERIAL_BUS_NAME_4, SERIAL_4_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("HwUartInit uart4 error ret %u\n", ret); + return ERROR; + } +#endif + #ifdef BSP_USING_UART6 static struct SerialCfgParam serial_cfg_6; memset(&serial_cfg_6, 0, sizeof(struct SerialCfgParam)); diff --git a/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c b/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c index 37396e6ea..156db4ebb 100644 --- a/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c +++ b/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c @@ -50,6 +50,7 @@ Modification: #include #include +static int serial_isr_cnt = 0; static DoubleLinklistType serialdev_linklist; static int SerialWorkModeCheck(struct SerialDevParam *serial_dev_param) @@ -138,6 +139,9 @@ static inline int SerialDevIntRead(struct SerialHardwareDevice *serial_dev, stru if (serial_dev->serial_fifo.serial_rx->serial_recv_num == serial_dev->serial_fifo.serial_rx->serial_send_num) { if (RET_FALSE == serial_dev->serial_fifo.serial_rx->serial_rx_full) { CriticalAreaUnLock(lock); + if (0 == serial_isr_cnt) { + KSemaphoreSetValue(serial_dev->haldev.dev_sem, 0); + } break; } } @@ -151,11 +155,13 @@ static inline int SerialDevIntRead(struct SerialHardwareDevice *serial_dev, stru if (RET_TRUE == serial_dev->serial_fifo.serial_rx->serial_rx_full) { serial_dev->serial_fifo.serial_rx->serial_rx_full = RET_FALSE; } + + if (serial_isr_cnt > 0) { + serial_isr_cnt--; + } CriticalAreaUnLock(lock); - //MdelayKTask(20); - *read_data = get_char; read_data++; read_length--; @@ -713,6 +719,10 @@ void SerialSetIsr(struct SerialHardwareDevice *serial_dev, int event) if (serial_dev->haldev.dev_recv_callback) { serial_dev->haldev.dev_recv_callback((void *)serial_dev, serial_rx_length); } + + lock = CriticalAreaLock(); + serial_isr_cnt += 1; + CriticalAreaUnLock(lock); KSemaphoreAbandon(serial_dev->haldev.dev_sem); }