Add app test and command line tool from Tu_Yuyang

it is OK
This commit is contained in:
IACU 2023-08-11 11:06:42 +08:00
commit dd383ef424
14 changed files with 1139 additions and 56 deletions

View File

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

View File

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

View File

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

View File

@ -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 <argparse.h>
#include <stdbool.h>
#include <transform.h>
#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));

View File

@ -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 <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <transform.h>
#include <argparse.h>
#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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,27 +19,67 @@
*/
#include "board.h"
#include "sys_arch.h"
#include "lwip/udp.h"
#include <shell.h>
#include <sys.h>
#include <xizi.h>
#include "lwip/sockets.h"
#include <stdbool.h>
#include <unistd.h>
#include "lwip/sockets.h"
#include "lwip/udp.h"
#include <argparse.h>
#include <shell.h>
#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)
{

View File

@ -1,3 +1,4 @@
SRC_DIR := letter-shell
SRC_FILES += argparse.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,389 @@
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* 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 <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <xizi.h>
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("=<int>");
}
if (options->type == ARGPARSE_OPT_FLOAT) {
len += strlen("=<flt>");
} else if (options->type == ARGPARSE_OPT_STRING) {
len += strlen("=<str>");
}
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, "=<int>");
} else if (options->type == ARGPARSE_OPT_FLOAT) {
pos += fprintf(stdout, "=<flt>");
} else if (options->type == ARGPARSE_OPT_STRING) {
pos += fprintf(stdout, "=<str>");
}
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;
}

View File

@ -0,0 +1,157 @@
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* 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 <stdint.h>
#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