diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index c5e5894cd..cfc834c73 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -72,6 +72,24 @@ menu "test app" endif endif + menuconfig USER_TEST_SOCKET + select BSP_USING_LWIP + 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 6016dcb7a..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 @@ -113,6 +117,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..81c4543cc --- /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_SERVER) { + 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_SERVER) { + 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_CLIENT) { + 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_CLIENT) { + 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 TestSocket(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/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 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