Merge branch '2023_open_source_contest' of https://gitlink.org.cn/xuos/xiuos into 2023_open_source_contest
@@ -36,5 +36,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
||||
SRC_DIR += control_app
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APP_USING_WEBNET),y)
|
||||
SRC_DIR += webnet
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
@@ -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
|
||||
@@ -252,6 +270,10 @@ menu "test app"
|
||||
bool "Config test red black tree"
|
||||
default n
|
||||
|
||||
menuconfig USER_TEST_MODBUS_TCP
|
||||
bool "Config test modbus_tcp"
|
||||
default n
|
||||
|
||||
menuconfig USER_TEST_WEBSERVER
|
||||
bool "Config test webserver"
|
||||
default n
|
||||
|
||||
@@ -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
|
||||
@@ -111,8 +115,16 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_RBTREE),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_MODBUS_TCP),y)
|
||||
SRC_DIR += test_modbus_tcp
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_WEBSERVER),y)
|
||||
SRC_FILES += test_webserver/test_webserver.c
|
||||
endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -22,17 +22,16 @@
|
||||
#include <transform.h>
|
||||
#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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,18 +24,16 @@
|
||||
|
||||
#define I2C_SLAVE_ADDRESS 0x0012U
|
||||
|
||||
void TestI2C(void)
|
||||
int OpenIic(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 = OpenIic();
|
||||
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 = OpenIic();
|
||||
|
||||
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
|
||||
11
APP_Framework/Applications/app_test/test_modbus_tcp/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
|
||||
SRC_FILES := modbus_tcp.c test_modbus_tcp.c
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/.config
|
||||
ifeq ($(CONFIG_ADD_NUTTX_FEATURES),y)
|
||||
include $(APPDIR)/Make.defs
|
||||
CSRCS += modbus_tcp.c test_modbus_tcp.c
|
||||
include $(APPDIR)/Application.mk
|
||||
endif
|
||||
340
APP_Framework/Applications/app_test/test_modbus_tcp/README.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# ##modbus-tcp##
|
||||
|
||||
## 1. 简介
|
||||
|
||||
在xiuos平台实现modbusTCP协议,包括协议报文组装、解析和数据传输,支持主从通信。
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
|
||||
### 2.1 数据结构定义
|
||||
|
||||
首先,需要定义设备存储区的结构体,包括两种存储类型,16位的寄存器和线圈。
|
||||
|
||||
```c
|
||||
//定义存储区结构体
|
||||
typedef struct MbMemory
|
||||
{
|
||||
coils8_t*rcoil_mem;
|
||||
reg_t*rreg_mem;
|
||||
coils8_t*rwcoil_mem;
|
||||
reg_t*rwreg_mem;
|
||||
}MBmemoryType;
|
||||
```
|
||||
|
||||
然后便是关于ModbusTCP协议相关的结构体定义,包括MBAP和PDU,后续数据区视情况而定,长短不固定。
|
||||
|
||||
```c
|
||||
//协议的固定部分为12个字节,当功能码为写多个数据时,后续还有不定长的数据部分
|
||||
typedef struct mbap
|
||||
{
|
||||
//MbapType
|
||||
u16_t tid;
|
||||
u16_t pid;
|
||||
u16_t len;
|
||||
u8_t uid;
|
||||
|
||||
/* data */
|
||||
}MbapType;
|
||||
|
||||
typedef struct pdu
|
||||
{
|
||||
u8_t func;
|
||||
|
||||
u16_t addr;
|
||||
|
||||
u8_t operand1;
|
||||
u8_t operand2;
|
||||
/* data */
|
||||
}PduType;
|
||||
```
|
||||
|
||||
### 2.1 从设备请求解析和响应部分
|
||||
|
||||
主要定义请求的解析器结构,以及每种功能码对应的解析函数,和发送响应的函数。
|
||||
|
||||
```c
|
||||
//定义解析器结构体
|
||||
typedef struct mbparser
|
||||
{
|
||||
int (*func_set[20])(MBmemoryType*,int,MbapType*,PduType*,u8_t**resp);
|
||||
}MbParserType;
|
||||
|
||||
//功能码解析函数
|
||||
int FuncReadRwCoilX01(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRCoilX02(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRwRegX03(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRRegX04(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwCoilX05(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwRegX06(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwMcoilsX0f(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwMregsX10(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReportSlaveIDX11(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
|
||||
|
||||
/**
|
||||
* @description: 制作响应报文
|
||||
* @param {MbapType*mbap,PduType*pdu,u8_t**resp,u16_t buf_len}
|
||||
* @return {}
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
void MakeResponse(MbapType*,PduType*,u8_t**,u16_t);
|
||||
|
||||
/**
|
||||
* @Description: 发送响应报文
|
||||
* @param {int} fd 套接字对应文件描述符
|
||||
* @param {u16_t} n 报文大小
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:24:55
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int SendResponse(int fd,u8_t**buf,u16_t n);
|
||||
|
||||
|
||||
```
|
||||
|
||||
### 2.2 主设备的请求包装和发送部分
|
||||
|
||||
```c
|
||||
/**
|
||||
* @Description: 读取键盘输入,并生成请求报文
|
||||
* @param {u8_t} flag
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:25:26
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int GenerateModbusRequest(MbapType*,PduType*,u8_t flag,u8_t**request);
|
||||
|
||||
/**
|
||||
* @Description: 发送请求报文
|
||||
* @param {int fd,u8_t**request,int n}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:26:10
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
void SendModbus(int fd,u8_t**request,int n);
|
||||
|
||||
/**
|
||||
* @Description: 读取请求报文
|
||||
* @param {int fd,MbapType*mbap,PduType*pdu}
|
||||
* @return {void}
|
||||
* @Date: 2023-07-25 17:26:49
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
void GetRequest(int fd,MbapType*,PduType*);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 3. 测试程序说明
|
||||
|
||||
modbusTCP协议基于TCP协议,因此其主从通信实际上是基于TCP的S/C通信,因此分为服务端和客户端。
|
||||
|
||||
服务端部分(从设备)程序实际上是一个被动接受请求报文的TCP服务器程序,除了一些基础参数的定义外,主要包括一个无限循环的服务程序,包括报文的接收,以及对存储区的操作,和生成发送响应。
|
||||
|
||||
```c
|
||||
static void *ModbusTcpServer(void *arg)
|
||||
{
|
||||
//设置IP和子网掩码网关
|
||||
u8_t uid=1;//定义从设备id和存储区
|
||||
|
||||
MBmemory mbm;//定义存储区
|
||||
if(mb_memory_init(&mbm)==-1)//初始化存储区,包括对四个存储区进行内存分配
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
MBparser mb_parser;//初始化功能码解析器
|
||||
MBparser_init(&mb_parser,MBTCP);//初始化解析器,将功能码对应函数注册
|
||||
|
||||
int fd=create_socket(PORT);//创建监听套接字
|
||||
if(fd==-1)return 0;
|
||||
|
||||
if (listen(fd, 10) != 0 ) {
|
||||
lw_error("Unable to listen\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
//建立连接,因为每次接受的连接可能不是同一个设备发来的,因此需要把建立连接部分放在循环体内。
|
||||
struct sockaddr_in tcp_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
printf("wait accept\n");
|
||||
int clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len);
|
||||
|
||||
if(clientfd==-1)
|
||||
{
|
||||
lw_error("Unable to listen\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
MBAP mbap;
|
||||
PDU pdu;
|
||||
read_mbtcp_MBAP(clientfd,&mbap);//读取数据前7字节为mbap初始化
|
||||
|
||||
if(mbap.uid!=uid){//检验是否为此从机
|
||||
close(clientfd);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
read_mbtcp_PDU(clientfd,&pdu);//读取pdu和一些定长部分
|
||||
|
||||
printf("OP:%x\n",pdu.func);
|
||||
printf("ADDR:%x\n",pdu.addr);
|
||||
|
||||
u8_t** response_buf;//定义操作返回的指针
|
||||
u8_t buf_len=mb_parser.func_set[pdu.func](&mbm,clientfd,&mbap,&pdu,response_buf);//请求的解析和对存储区的操作
|
||||
|
||||
send_response(clientfd,response_buf,buf_len);//发送响应
|
||||
// return NULL;
|
||||
//执行操作
|
||||
|
||||
}
|
||||
close(clientfd);
|
||||
}
|
||||
close(fd);
|
||||
mb_memory_free(&mbm);//释放存储区
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
客户端部分(主设备)是一个主动发送请求的TCP客户端程序,主要包括一个接受键盘输入的循环体,可以接受用户输入的指令,然后包装成Modbus请求报文,并发送给ModbusTCP服务器,然后接受响应报文。
|
||||
|
||||
```c
|
||||
static void *ModbusTcpClient(void *arg)
|
||||
{
|
||||
u16_t counter=0;
|
||||
int fd = -1;
|
||||
int ret;
|
||||
|
||||
// lw_print("2023-05-27 Peng Guanhua\n");
|
||||
lw_print("%s start\n", __func__);
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);//定义服务器套接字
|
||||
if (fd < 0) {
|
||||
lw_print("Socket error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char tcp_ip_str[128]="192.168.31.148";//服务器ip和端口号
|
||||
u16_t tcp_socket_port=6000;
|
||||
|
||||
/*建立套接字连接*/
|
||||
printf("%s\n",tcp_ip_str);
|
||||
struct sockaddr_in tcp_sock;
|
||||
tcp_sock.sin_family = AF_INET;
|
||||
tcp_sock.sin_port = htons(tcp_socket_port);
|
||||
tcp_sock.sin_addr.s_addr = inet_addr(tcp_ip_str);
|
||||
printf("%s\n",tcp_ip_str);
|
||||
|
||||
memset(&(tcp_sock.sin_zero), 0, sizeof(tcp_sock.sin_zero));
|
||||
|
||||
ret = connect(fd, (struct sockaddr *)&tcp_sock, sizeof(struct sockaddr));
|
||||
|
||||
if (ret < 0) {
|
||||
lw_print("Unable to connect %s:%d = %d\n", tcp_ip_str, tcp_socket_port, ret);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lw_print("TCP connect %s:%d success, start.\n", tcp_ip_str, tcp_socket_port);
|
||||
|
||||
|
||||
|
||||
while (1) {
|
||||
|
||||
MBAP mbap={counter,0,0,0};
|
||||
PDU pdu;
|
||||
u8_t*request;
|
||||
|
||||
int mesg_len=generate_modbus_request(&mbap,&pdu,MBTCP,&request);//此函数中接收键盘输入,并生成请求报文。
|
||||
send_modbus(fd,&request,mesg_len);//发送请求报文。
|
||||
get_response(fd,&mbap,&pdu);//接收响应报文,并显示
|
||||
counter++;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 4. 运行结果
|
||||
|
||||
### 4.1 从设备通信测试
|
||||
|
||||
从设备测试,在终端上将TCP服务端程序打开,如图1,等待主设备的连接。
|
||||
|
||||

|
||||
|
||||
主设备采用Modbus Poll应用程序,建立TCP连接,如图2所示。
|
||||
|
||||

|
||||
|
||||
此时modbus poll程序便会不断的向从设备发送请求,如图3。
|
||||
|
||||

|
||||
|
||||
可以看到解析出的功能码、地址以及对应的响应报文,然后我们在modbus poll上修改一下存储区数据。如图4所示。
|
||||
|
||||

|
||||
|
||||
因为修改的是寄存器存储区的值,因此对应0x10功能码,然后看看从设备的反映。如图5所示。
|
||||
|
||||

|
||||
|
||||
可见成功收到功能码,并返回了响应的报文。
|
||||
|
||||

|
||||
|
||||
modbus poll显示响应成功,存储区已成功修改期望的值。
|
||||
|
||||

|
||||
|
||||
可见存储区已成功修改。
|
||||
|
||||
线圈部分的查询修改同理,不再赘述。
|
||||
|
||||
### 4.2主设备通信测试
|
||||
|
||||
首先打开modbus slave应用程序,用以作为从设备,然后将存储区数据修改,用以测试,并打开TCP端口,等待主设备的连接,如图8所示。
|
||||
|
||||

|
||||
|
||||
同样在终端打开从设备程序,从设备的ip,port在源码中已定义好,所以打开时已经连接上,如图9所示。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
开始输入从设备id,功能码,以及其他信息用以生成请求报文。
|
||||
|
||||

|
||||
|
||||
如图10所示,输入功能码3,对应读取寄存器功能,地址从0开始,数量4,然后便会生成请求报文,然后发送,结果如图11所示。
|
||||
|
||||

|
||||
|
||||
可见,已成功查询到寄存器的值。
|
||||
|
||||
然后测试写入功能,输入功能码15(0xf),对应写入多个线圈功能,如图12,modbus slave对应的响应结果如图13所示。
|
||||
|
||||

|
||||
|
||||
写入线圈的值为5个,分别为1 0 1 0 1。发送成功后,modbus salve中显示如图13所示。
|
||||
|
||||

|
||||
|
||||
可见,已成功修改。
|
||||
|
||||
其他功能码测试过程类似,不再赘述。
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
729
APP_Framework/Applications/app_test/test_modbus_tcp/modbus_tcp.c
Normal file
@@ -0,0 +1,729 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @Description:包含modbusTCP请求报文的包装解析,以及报文收发,和每种功能码对应操作的实现。
|
||||
* @Version: V1.0.0
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @Date: 2023-05-24 04:00:02
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 16:36:53
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include"modbus_tcp.h"
|
||||
|
||||
u16_t Func0x_response_length[20]=
|
||||
{
|
||||
0,9,9,9,9,12,12,0,0,0,0,0,0,0,0,12,12
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @description: 初始化功能码解析器
|
||||
* @param {MbParserType*}mbp {u8_t} type
|
||||
* @return {void}
|
||||
* @Date: 2023-07-25 16:59:23
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
void MbparserInit(MbParserType*mbp,u8_t type)
|
||||
{
|
||||
mbp->func_set[R_RW_COIL]=FuncReadRwCoilX01;
|
||||
mbp->func_set[R_R_COIL]=FuncReadRCoilX02;
|
||||
mbp->func_set[R_RW_REG]=FuncReadRwRegX03;
|
||||
mbp->func_set[R_R_REG]=FuncReadRRegX04;
|
||||
mbp->func_set[W_RW_COIL]=FuncWriteRwCoilX05;
|
||||
mbp->func_set[W_RW_REG]=FuncWriteRwRegX06;
|
||||
mbp->func_set[W_MRW_REG]=FuncWriteRwMregsX10;
|
||||
mbp->func_set[W_MRW_COIL]=FuncWriteRwMcoilsX0f;
|
||||
mbp->func_set[REPORT_SlAVE_ID]=FuncReportSlaveIDX11;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @description:初始化存储区
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:01:47
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
int MbMemoryInit(MBmemoryType*mbm)
|
||||
{
|
||||
mbm->rcoil_mem=(coils8_t*)malloc(sizeof(coils8_t)*RCOILMEM);
|
||||
mbm->rreg_mem=(reg_t*)malloc(sizeof(reg_t)*RREGMEM);
|
||||
mbm->rwcoil_mem=(coils8_t*)malloc(sizeof(coils8_t)*RWCOILMEM);
|
||||
mbm->rwreg_mem=(reg_t*)malloc(sizeof(reg_t)*RWREGMEM);
|
||||
|
||||
memset(mbm->rwreg_mem,0,RWREGMEM);
|
||||
memset(mbm->rreg_mem,0,RREGMEM);
|
||||
memset(mbm->rcoil_mem,0,RCOILMEM);
|
||||
memset(mbm->rwcoil_mem,0,RWCOILMEM);
|
||||
|
||||
// mbm->rwreg_mem[0]=3;
|
||||
// mbm->rwreg_mem[1]=0x30ff;
|
||||
mbm->rwcoil_mem[0]=1;mbm->rwcoil_mem[2]=1;mbm->rwcoil_mem[4]=1;
|
||||
|
||||
if(mbm->rcoil_mem==NULL||mbm->rreg_mem==NULL||mbm->rwcoil_mem==NULL||mbm->rwreg_mem==NULL)
|
||||
{
|
||||
lw_error("memory is not full\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 释放存储区
|
||||
* @return {void}
|
||||
* @Date: 2023-07-25 17:02:22
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
void MbMemoryFree(MBmemoryType*mbm)
|
||||
{
|
||||
free(mbm->rcoil_mem);
|
||||
free(mbm->rreg_mem);
|
||||
free(mbm->rwcoil_mem);
|
||||
free(mbm->rwreg_mem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 创建tcp通信套接字
|
||||
* @param {int} port
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:02:39
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
int CreateSocket(int port)
|
||||
{
|
||||
int fd = -1, clientfd;
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(fd==-1)return -1;
|
||||
int recv_len;
|
||||
char *recv_buf;
|
||||
struct sockaddr_in tcp_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
tcp_addr.sin_family = AF_INET;
|
||||
tcp_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
tcp_addr.sin_port = htons(port);
|
||||
memset(&(tcp_addr.sin_zero), 0, sizeof(tcp_addr.sin_zero));
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&tcp_addr, sizeof(struct sockaddr)) == -1) {
|
||||
lw_error("Unable to bind\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lw_print("tcp bind success, start to receive.\n");
|
||||
lw_notice("\nLocal Port:%d\n", port);
|
||||
|
||||
// setup socket fd as listening mode
|
||||
if (listen(fd,128) != 0 ) {
|
||||
lw_error("Unable to listen\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
lw_print("Tcp start to listen.\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 读取请求报文的MBAP头部分
|
||||
* @param {int} fd {MbapType*}mbap
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:03:04
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
int ReadMbtcpMBAP(int fd,MbapType*mbap)
|
||||
{
|
||||
char buf[MODBUS_MBAP];
|
||||
read(fd,buf,MODBUS_MBAP);
|
||||
mbap->tid=(((u16_t)buf[0])<<8)+(u16_t)buf[1];//高位左移8位再加低位
|
||||
mbap->pid=(((u16_t)buf[2])<<8)+(u16_t)buf[3];
|
||||
mbap->len=(((u16_t)buf[4])<<8)+(u16_t)buf[5];
|
||||
mbap->uid=((u8_t)buf[6]);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @description: 读取请求报文的PDU部分
|
||||
* @param {int} fd {PduType*}pdu
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:03:04
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
int ReadMbtcpPDU(int fd,PduType*pdu)
|
||||
{
|
||||
char buf[MODBUS_PDUHEAD];
|
||||
|
||||
int n=read(fd,buf,MODBUS_PDUHEAD);
|
||||
|
||||
|
||||
pdu->func=(u8_t)buf[0];//高位左移8位再加低位
|
||||
|
||||
if(n>3)
|
||||
{
|
||||
pdu->addr=(((u16_t)buf[1])<<8)+(u16_t)buf[2];
|
||||
pdu->operand1=(u8_t)buf[3];
|
||||
pdu->operand2=(u8_t)buf[4];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description: 制作响应报文
|
||||
* @param {MbapType*mbap,PduType*pdu,u8_t**resp,u16_t buf_len}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:11:23
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
void MakeResponse(MbapType*mbap,PduType*pdu,u8_t**resp,u16_t buf_len)
|
||||
{
|
||||
buf_len-=6;
|
||||
//这个长度实际是从数据长度位置到结束的长度,因此要将响应报文的总长减去事务头、协议、长度三个两字节数共6个
|
||||
(*resp)[0]=(u8_t)(mbap->tid>>8);(*resp)[1]=(u8_t)(0xff&mbap->tid);
|
||||
(*resp)[2]=(u8_t)(mbap->pid>>8);(*resp)[3]=(u8_t)(0xff&mbap->pid);
|
||||
(*resp)[4]=(u8_t)(buf_len>>8);(*resp)[5]=(u8_t)(0xff&buf_len);
|
||||
(*resp)[6]=mbap->uid;
|
||||
(*resp)[7]=pdu->func;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: 功能码0x1,负责读取从设备线圈的状态
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:12:00
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 17:10:31
|
||||
*/
|
||||
int FuncReadRwCoilX01(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x01\n");
|
||||
printf("coils num:%d\n");
|
||||
u16_t coils_num=((u16_t)pdu->operand1<<8)+(u16_t)pdu->operand2;//线圈个数
|
||||
u16_t bytes_num=(coils_num/8+((coils_num%8)!=0));//输出的字节长度
|
||||
u16_t buf_len=Func0x_response_length[R_RW_COIL]+bytes_num;//response报文所占长度
|
||||
|
||||
*resp=(u8_t*)malloc(buf_len); memset(*resp,0,buf_len);
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
(*resp)[8]=(u8_t)bytes_num;
|
||||
u8_t*sub_mem=mem->rwcoil_mem;
|
||||
for(int i=0;i<coils_num;i++)
|
||||
{
|
||||
//按位将线圈值赋给response报文数据区,在内存区中,线圈按u8_t存放,但读取时要将其转换成位
|
||||
(*resp)[9+i/8]|=(sub_mem[i+pdu->addr]==1?((u8_t)1<<(i%8)):0);
|
||||
}
|
||||
|
||||
return buf_len;
|
||||
// u8_t
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0x2功能码,读离散输入状态
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:20:13
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncReadRCoilX02(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x02\n");
|
||||
|
||||
u16_t coils_num=((u16_t)pdu->operand1<<8)+(u16_t)pdu->operand2;//线圈个数
|
||||
u16_t bytes_num=(coils_num/8+((coils_num%8)!=0));//输出的字节长度
|
||||
u16_t buf_len=Func0x_response_length[R_RW_COIL]+bytes_num;//response报文所占长度
|
||||
|
||||
*resp=(u8_t*)malloc(buf_len); memset(*resp,0,buf_len);
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
(*resp)[8]=(u8_t)bytes_num;
|
||||
u8_t*sub_mem=mem->rcoil_mem;
|
||||
for(int i=0;i<coils_num;i++)
|
||||
{
|
||||
//按位将线圈值赋给response报文数据区,在内存区中,线圈按u8_t存放,但读取时要将其转换成位
|
||||
(*resp)[9+i/8]|=(sub_mem[i+pdu->addr]==1?((u8_t)1<<(i%8)):0);
|
||||
}
|
||||
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Description: 读保持寄存器
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:21:01
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncReadRwRegX03(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x03\n");
|
||||
u16_t data_len=((u16_t)pdu->operand1<<8)+(u16_t)pdu->operand2;
|
||||
|
||||
u16_t buf_len=Func0x_response_length[R_RW_REG]+data_len*2;
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)data_len*2;
|
||||
|
||||
u16_t*sub_mem=mem->rwreg_mem;
|
||||
|
||||
u16_t addr_mem=pdu->addr,addr_resp=9;
|
||||
int c=0;
|
||||
while(c<data_len)
|
||||
{
|
||||
(*resp)[addr_resp]=(u8_t)(sub_mem[addr_mem]>>8);
|
||||
(*resp)[addr_resp+1]=(u8_t)(sub_mem[addr_mem]&0xff);
|
||||
addr_resp+=2;addr_mem++;
|
||||
c++;
|
||||
}
|
||||
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0x4功能码,读输入寄存器
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:21:22
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncReadRRegX04(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x04\n");
|
||||
u16_t data_len=((u16_t)pdu->operand1<<8)+(u16_t)pdu->operand2;
|
||||
|
||||
u16_t buf_len=Func0x_response_length[R_R_REG]+data_len*2;
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)data_len*2;
|
||||
|
||||
u16_t*sub_mem=mem->rreg_mem;
|
||||
|
||||
u16_t addr_mem=pdu->addr,addr_resp=9;
|
||||
|
||||
int c=0;
|
||||
while(c<data_len)
|
||||
{
|
||||
(*resp)[addr_resp]=(u8_t)(sub_mem[addr_mem]>>8);
|
||||
(*resp)[addr_resp+1]=(u8_t)(sub_mem[addr_mem]&0xff);
|
||||
addr_resp+=2;addr_mem++;
|
||||
c++;
|
||||
}
|
||||
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0x5功能码,写单个线圈
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:21:51
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncWriteRwCoilX05(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x05\n");
|
||||
u16_t addr_coil=pdu->addr;
|
||||
u16_t operand=(((u16_t)pdu->operand1)<<8)+(u16_t)pdu->operand2;
|
||||
if(operand==0xff00||operand==0x0000)
|
||||
{
|
||||
mem->rwcoil_mem[addr_coil]=(operand==0xff00?1:0);
|
||||
}
|
||||
|
||||
u16_t buf_len=Func0x_response_length[W_RW_COIL];
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)((pdu->addr)>>8);
|
||||
(*resp)[9]=(u8_t)(pdu->addr&0xff);
|
||||
(*resp)[10]=(u8_t)(pdu->operand1);
|
||||
(*resp)[11]=(u8_t)(pdu->operand2);
|
||||
|
||||
printf("write data:%x\n",operand);
|
||||
|
||||
return buf_len;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0x6功能码,写单个保持寄存器
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:22:38
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncWriteRwRegX06(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x06\n");
|
||||
u16_t addr_reg=pdu->addr;
|
||||
u16_t reg_data=(u16_t)((pdu->operand1)<<8)+(u16_t)(pdu->operand2);
|
||||
mem->rwreg_mem[addr_reg]=reg_data;
|
||||
u16_t buf_len=Func0x_response_length[W_RW_REG];
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)((pdu->addr)>>8);
|
||||
(*resp)[9]=(u8_t)(pdu->addr&0xff);
|
||||
(*resp)[10]=(u8_t)(pdu->operand1);
|
||||
(*resp)[11]=(u8_t)(pdu->operand2);
|
||||
|
||||
printf("write data:%x\n",reg_data);
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0xf功能码,写多个线圈
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:23:16
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncWriteRwMcoilsX0f(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x0f\n");
|
||||
u16_t coils_num=(((u16_t)(pdu->operand1))<<8)+(u16_t)(pdu->operand2);
|
||||
|
||||
u16_t res_num=coils_num/8+(coils_num%8!=0)+1;
|
||||
|
||||
u8_t*recv_buf=(u8_t*)malloc(sizeof(u8_t)*res_num);
|
||||
|
||||
int n=read(fd,(char*)recv_buf,res_num);
|
||||
|
||||
|
||||
u8_t*sub_mem=mem->rwcoil_mem;
|
||||
|
||||
for(int i=0;i<coils_num;i++)
|
||||
{
|
||||
sub_mem[pdu->addr+i]=((recv_buf[1+i/8]&(1<<(i%8)))==0?0:1);
|
||||
}
|
||||
|
||||
|
||||
u16_t buf_len=Func0x_response_length[W_MRW_COIL];
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)((pdu->addr)>>8);
|
||||
(*resp)[9]=(u8_t)(pdu->addr&0xff);
|
||||
(*resp)[10]=(u8_t)(pdu->operand1);
|
||||
(*resp)[11]=(u8_t)(pdu->operand2);
|
||||
|
||||
free(recv_buf);
|
||||
|
||||
|
||||
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 0x10功能码,写多个保持寄存器
|
||||
* @param {MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp}
|
||||
* @return {int}
|
||||
* @Date: 2023-07-25 17:23:56
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncWriteRwMregsX10(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x10\n");
|
||||
u16_t data_num=(((u16_t)(pdu->operand1))<<8)+(u16_t)(pdu->operand2);
|
||||
u16_t res_num=data_num*2+1;
|
||||
u8_t*recv_buf=(u8_t*)malloc(sizeof(u8_t)*res_num);
|
||||
|
||||
|
||||
int n=read(fd,(char*)recv_buf,res_num);
|
||||
|
||||
// printf("%x %x %x\n",recv_buf[0],recv_buf[1],recv_buf[2]);
|
||||
|
||||
u16_t*sub_mem=mem->rwreg_mem;
|
||||
|
||||
for(int i=0;i<data_num;i++)
|
||||
{
|
||||
sub_mem[pdu->addr+i]=(((u16_t)(recv_buf[1+i*2]))<<8)+(u16_t)(recv_buf[1+i*2+1]);
|
||||
}
|
||||
|
||||
|
||||
u16_t buf_len=Func0x_response_length[W_MRW_REG];
|
||||
*resp=(u8_t*)malloc(buf_len);
|
||||
|
||||
MakeResponse(mbap,pdu,resp,buf_len);
|
||||
|
||||
(*resp)[8]=(u8_t)((pdu->addr)>>8);
|
||||
(*resp)[9]=(u8_t)(pdu->addr&0xff);
|
||||
(*resp)[10]=(u8_t)(pdu->operand1);
|
||||
(*resp)[11]=(u8_t)(pdu->operand2);
|
||||
|
||||
|
||||
free(recv_buf);
|
||||
|
||||
return buf_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 报告从设备id
|
||||
* @param {int} fd
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:24:43
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int FuncReportSlaveIDX11(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp)
|
||||
{
|
||||
printf("enter x11\n");
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 发送响应报文
|
||||
* @param {int} fd
|
||||
* @param {u16_t} n
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:24:55
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int SendResponse(int fd,u8_t**buf,u16_t n)
|
||||
{
|
||||
printf("Response:");
|
||||
for(int i=0;i<n;i++)printf("%x ",(*buf)[i]);
|
||||
printf("\n\n");
|
||||
int num=write(fd,(char*)*buf,n);
|
||||
free(*buf);
|
||||
return num;
|
||||
};
|
||||
|
||||
/**
|
||||
* @Description: 读取键盘输入,并生成请求报文
|
||||
* @param {u8_t} flag
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:25:26
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
int GenerateModbusRequest(MbapType*mbap,PduType*pdu,u8_t flag,u8_t**request)
|
||||
{
|
||||
int send_buf_length=0;
|
||||
while(1)
|
||||
{
|
||||
printf("\nPlease set the region of command\n");
|
||||
|
||||
printf("The slave id:");
|
||||
scanf("%d",&mbap->uid);printf("%d",mbap->uid);printf("\n");
|
||||
|
||||
printf("Please input function code:");
|
||||
scanf("%x",&pdu->func);printf("%x",pdu->func);printf("\n");
|
||||
|
||||
printf("The address:");
|
||||
scanf("%d",&pdu->addr);printf("%d",pdu->addr);printf("\n");
|
||||
|
||||
switch (pdu->func)
|
||||
{
|
||||
case R_RW_COIL:
|
||||
case R_R_COIL:printf("The number of coils you want read:");break;
|
||||
case R_RW_REG:
|
||||
case R_R_REG:printf("The number of registers you want read:");break;
|
||||
|
||||
case W_RW_COIL:printf("The value of coil you want write(1 or 0):");break;
|
||||
case W_RW_REG:printf("The value of register you want write:");break;
|
||||
|
||||
case W_MRW_COIL:printf("The number of coils you want write:");break;
|
||||
case W_MRW_REG:printf("The number of registers you want write:");break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
u16_t num;
|
||||
scanf("%d",&num);printf("%d\n",num);
|
||||
if(pdu->func==W_RW_COIL)
|
||||
{
|
||||
pdu->operand2=0;
|
||||
pdu->operand1=(num==1?0xff:0);
|
||||
}
|
||||
else {
|
||||
pdu->operand1=(u8_t)(num>>8);
|
||||
pdu->operand2=(u8_t)(num&0x00ff);
|
||||
}
|
||||
|
||||
|
||||
if(pdu->func==W_MRW_REG)
|
||||
{
|
||||
send_buf_length=num*2+1+12;
|
||||
*request=(u8_t*)malloc(send_buf_length);
|
||||
memset(*request,0,send_buf_length);
|
||||
printf("input register data(decimal integer,in total %d):",num);
|
||||
(*request)[12]=(u8_t)(num*2);
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
u16_t tem;
|
||||
scanf("%d",&tem);printf("%d ",tem);
|
||||
(*request)[i*2+13]=(u8_t)(tem>>8);
|
||||
(*request)[i*2+13+1]=(u8_t)(tem&0x00ff);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
else if(pdu->func==W_MRW_COIL)
|
||||
{
|
||||
send_buf_length=num/8+(num%8!=0)+1+12;
|
||||
*request=(u8_t*)malloc(send_buf_length);
|
||||
memset(*request,0,send_buf_length);
|
||||
printf("input coil data(0 or 1,in total %d):",num);
|
||||
(*request)[12]=(u8_t)(num/8+(num%8!=0));
|
||||
for(int i=0;i<num;i++)
|
||||
{
|
||||
u16_t tem;
|
||||
scanf("%d",&tem);printf("%d ",tem);
|
||||
if(tem==1)
|
||||
{
|
||||
(*request)[i/8+13]|=(1<<(i%8));
|
||||
// (*resp)[9+i/8]|=(sub_mem[i+pdu->addr]==1?((u8_t)1<<(i%8)):0);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
send_buf_length=12;
|
||||
*request=(u8_t*)malloc(send_buf_length);
|
||||
if((*request)==NULL)printf("erro\n");
|
||||
|
||||
}
|
||||
|
||||
(*request)[0]=(u8_t)(mbap->tid>>8);(*request)[1]=(u8_t)(0xff&mbap->tid);
|
||||
(*request)[2]=(u8_t)(mbap->pid>>8);(*request)[3]=(u8_t)(0xff&mbap->pid);
|
||||
(*request)[4]=(u8_t)((send_buf_length-6)>>8);(*request)[5]=(u8_t)(0xff&(send_buf_length-6));
|
||||
(*request)[6]=mbap->uid;
|
||||
(*request)[7]=pdu->func;
|
||||
(*request)[8]=(u8_t)(pdu->addr>>8);(*request)[9]=(u8_t)(0xff&pdu->addr);
|
||||
(*request)[10]=pdu->operand1;(*request)[11]=pdu->operand2;
|
||||
|
||||
printf("messege is:");
|
||||
for(int i=0;i<send_buf_length;i++)printf("%x ",(*request)[i]);
|
||||
printf("\n");
|
||||
|
||||
|
||||
printf("Decide to send? input 's' to send,else to reset the command:");
|
||||
char c;
|
||||
scanf("%c",&c);printf("%c\n",c);
|
||||
if(c=='s')break;
|
||||
else {
|
||||
free(*request);
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
return send_buf_length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @Description: 发送请求报文
|
||||
* @param {int fd,u8_t**request,int n}
|
||||
* @return {}
|
||||
* @Date: 2023-07-25 17:26:10
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
void SendModbus(int fd,u8_t**request,int n)
|
||||
{
|
||||
n=write(fd,(char*)*request,n);
|
||||
free(*request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 读取请求报文
|
||||
* @param {(int fd,MbapType*mbap,PduType*pdu}
|
||||
* @return {void}
|
||||
* @Date: 2023-07-25 17:26:49
|
||||
* @Author: pgh_dd 1041315949@qq.com
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
*/
|
||||
void GetRequest(int fd,MbapType*mbap,PduType*pdu)
|
||||
{
|
||||
u16_t data_num;
|
||||
ReadMbtcpMBAP(fd,mbap);//先读取定长的MBAP部分
|
||||
|
||||
|
||||
read(fd,(char*)&pdu->func,1);//读取功能码
|
||||
|
||||
u8_t byte_num=0;
|
||||
u8_t *recv_buf;
|
||||
switch (pdu->func)
|
||||
{
|
||||
case R_R_COIL:
|
||||
case R_R_REG:
|
||||
case R_RW_COIL:
|
||||
case R_RW_REG:
|
||||
data_num=(((u16_t)(pdu->operand1))<<8)+(u16_t)(pdu->operand2);
|
||||
read(fd,&byte_num,1);
|
||||
recv_buf=(u8_t*)malloc(byte_num);
|
||||
read(fd,recv_buf,byte_num);
|
||||
/* code */
|
||||
break;
|
||||
case W_RW_COIL:
|
||||
case W_RW_REG:
|
||||
case W_MRW_REG:
|
||||
case W_MRW_COIL:
|
||||
recv_buf=(u8_t*)malloc(4);
|
||||
read(fd, recv_buf,4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Response: TID:%x func code:%x byte num:%x\n",mbap->tid,pdu->func,byte_num);
|
||||
|
||||
if(pdu->func==R_R_COIL||pdu->func==R_RW_COIL)
|
||||
{
|
||||
printf("coils:");
|
||||
for(int i=0;i<data_num;i++)
|
||||
{
|
||||
printf("%d ",(recv_buf[i/8]&(1<<(i%8)))==0?0:1);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
else if(pdu->func==R_R_REG||pdu->func==R_RW_REG)
|
||||
{
|
||||
printf("registers:");
|
||||
// for(int i=0;i<byte_num;i++)printf("%x ",recv_buf[i]);printf("\n");
|
||||
for(int i=0;i<data_num;i++)
|
||||
{
|
||||
printf("%d ",(((u16_t)(recv_buf[i*2]))<<8)+(u16_t)(recv_buf[i*2+1]));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
free(recv_buf);
|
||||
}
|
||||
141
APP_Framework/Applications/app_test/test_modbus_tcp/modbus_tcp.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @Description: 包含modbusTCP请求报文的包装解析,以及报文收发,和每种功能码对应操作的定义。
|
||||
* @Version: V1.0.0
|
||||
* @Author: 快乐小组
|
||||
* @Date: 2023-05-24 03:59:45
|
||||
* @LastEditors: pgh_dd 1041315949@qq.com
|
||||
* @LastEditTime: 2023-07-25 16:53:39
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MODBUSTCP_H__
|
||||
#define __MODBUSTCP_H__
|
||||
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include<transform.h>
|
||||
#include <sys_arch.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#define PORT 8888
|
||||
#define RCOILMEM 1000
|
||||
#define RREGMEM 1000
|
||||
#define RWCOILMEM 1000
|
||||
#define RWREGMEM 1000
|
||||
|
||||
#define MBTCP 1
|
||||
#define MBRTU 2
|
||||
//功能码
|
||||
#define R_RW_COIL 0x01
|
||||
#define R_R_COIL 0x02
|
||||
#define R_RW_REG 0x03
|
||||
#define R_R_REG 0x04
|
||||
#define W_RW_COIL 0x05
|
||||
#define W_RW_REG 0x06
|
||||
#define DIAGNOSTIC 0x08
|
||||
#define GET_COUNTER 0x0B
|
||||
#define W_MRW_COIL 0x0F
|
||||
#define W_MRW_REG 0x10
|
||||
#define REPORT_SlAVE_ID 0x11
|
||||
|
||||
|
||||
typedef u8_t coils8_t;
|
||||
typedef u16_t reg_t;
|
||||
|
||||
#define MODBUS_MBAP 7
|
||||
#define MODBUS_PDUHEAD 5
|
||||
|
||||
|
||||
//定义存储区结构体
|
||||
typedef struct MbMemory
|
||||
{
|
||||
coils8_t*rcoil_mem;
|
||||
reg_t*rreg_mem;
|
||||
coils8_t*rwcoil_mem;
|
||||
reg_t*rwreg_mem;
|
||||
}MBmemoryType;
|
||||
//初始化存储区的函数
|
||||
int MbMemoryInit(MBmemoryType*mb);
|
||||
//释放存储区
|
||||
void MbMemoryFree(MBmemoryType*mb);
|
||||
|
||||
|
||||
//协议的固定部分为12个字节,当功能码为写多个数据时,后续还有不定长的数据部分
|
||||
typedef struct mbap
|
||||
{
|
||||
//MbapType
|
||||
u16_t tid;
|
||||
u16_t pid;
|
||||
u16_t len;
|
||||
u8_t uid;
|
||||
|
||||
/* data */
|
||||
}MbapType;
|
||||
|
||||
typedef struct pdu
|
||||
{
|
||||
u8_t func;
|
||||
|
||||
u16_t addr;
|
||||
|
||||
u8_t operand1;
|
||||
u8_t operand2;
|
||||
/* data */
|
||||
}PduType;
|
||||
|
||||
int CreateSocket(int port);
|
||||
|
||||
int ReadMbtcpMBAP(int fd,MbapType*mb_s);
|
||||
int ReadMbtcpPDU(int fd,PduType*mb_s);
|
||||
|
||||
|
||||
//操作函数
|
||||
|
||||
int FuncReadRwCoilX01(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRCoilX02(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRwRegX03(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncReadRRegX04(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwCoilX05(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwRegX06(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwMcoilsX0f(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
int FuncWriteRwMregsX10(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
|
||||
int FuncReportSlaveIDX11(MBmemoryType*mem,int fd,MbapType*mbap,PduType*pdu,u8_t**resp);
|
||||
//位地址转换字节地址
|
||||
|
||||
//定义解析器结构体
|
||||
typedef struct mbparser
|
||||
{
|
||||
int (*func_set[20])(MBmemoryType*,int,MbapType*,PduType*,u8_t**resp);
|
||||
}MbParserType;
|
||||
//解析器初始化,实际上就是每个功能码对应的操作函数的注册
|
||||
void MbparserInit(MbParserType*mbp,u8_t flag);
|
||||
|
||||
void MakeResponse(MbapType*,PduType*,u8_t**,u16_t);
|
||||
|
||||
int SendResponse(int fd,u8_t**buf,u16_t n);
|
||||
|
||||
|
||||
// void func(PDU*pdu);
|
||||
|
||||
// void delete_modbus_request();
|
||||
//主机程序
|
||||
int GenerateModbusRequest(MbapType*,PduType*,u8_t flag,u8_t**request);
|
||||
|
||||
void SendModbus(int fd,u8_t**request,int n);
|
||||
|
||||
void GetRequest(int fd,MbapType*,PduType*);
|
||||
#endif
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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 lwip_tcp_socket_demo.c
|
||||
* @brief TCP socket demo based on LwIP
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2022-03-21
|
||||
*/
|
||||
|
||||
#include <transform.h>
|
||||
#include"modbus_tcp.h"
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
#include <sys_arch.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include "lwip/sys.h"
|
||||
#endif
|
||||
|
||||
#ifdef ADD_NUTTX_FEATURES
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "stdio.h"
|
||||
#endif
|
||||
|
||||
#define TCP_DEMO_BUF_SIZE 65535
|
||||
#define TCP_DEMO_SEND_TIMES 20
|
||||
#define LWIP_TCP_DEMO_TASK_STACK_SIZE 4096
|
||||
#define LWIP_TCP_DEMO_TASK_PRIO 20
|
||||
|
||||
static pthread_t tcp_client_task;
|
||||
static pthread_t tcp_server_task;
|
||||
|
||||
static char tcp_demo_ipaddr[] = {192, 168, 31, 77};
|
||||
static char tcp_demo_netmask[] = {255, 255, 255, 0};
|
||||
static char tcp_demo_gwaddr[] = {192, 168, 31, 1};
|
||||
|
||||
#ifdef ADD_NUTTX_FEATURES
|
||||
#define lw_print printf
|
||||
#define lw_notice printf
|
||||
#define lw_error printf
|
||||
|
||||
#define LWIP_DEMO_TIMES 3
|
||||
#define LWIP_TARGET_PORT 4840
|
||||
#endif
|
||||
|
||||
static uint16_t tcp_socket_port = 8888;
|
||||
static char tcp_ip_str[128] = {0};
|
||||
|
||||
/******************************************************************************/
|
||||
static void TcpSocketConfigParam(char *ip_str)
|
||||
{
|
||||
int ip1, ip2, ip3, ip4, port = 0;
|
||||
|
||||
if(ip_str == NULL)
|
||||
return;
|
||||
|
||||
if(sscanf(ip_str, "%d.%d.%d.%d:%d", &ip1, &ip2, &ip3, &ip4, &port)) {
|
||||
printf("config ip %s port %d\n", ip_str, port);
|
||||
strcpy(tcp_ip_str, ip_str);
|
||||
if(port)
|
||||
tcp_socket_port = port;
|
||||
return;
|
||||
}
|
||||
|
||||
if(sscanf(ip_str, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4)) {
|
||||
printf("config ip %s\n", ip_str);
|
||||
strcpy(tcp_ip_str, ip_str);
|
||||
}
|
||||
}
|
||||
|
||||
static void *ModbusTcpServer(void *arg)
|
||||
{
|
||||
|
||||
u8_t uid=1;//定义从设备id和存储区
|
||||
|
||||
MBmemoryType mbm;//定义存储区
|
||||
if(MbMemoryInit(&mbm)==-1)//初始化存储区,包括对四个存储区进行内存分配
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
MbParserType mb_parser;//初始化功能码解析器
|
||||
MbparserInit(&mb_parser,MBTCP);//初始化解析器,将功能码对应函数注册
|
||||
|
||||
int fd=CreateSocket(PORT);//创建监听套接字
|
||||
if(fd==-1)return 0;
|
||||
|
||||
int recv_len;
|
||||
char *recv_buf;
|
||||
struct sockaddr_in tcp_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
while(1)
|
||||
{
|
||||
struct sockaddr_in tcp_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
printf("wait accept\n");
|
||||
int clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len);
|
||||
|
||||
if(clientfd==-1)
|
||||
{
|
||||
lw_error("Unable to listen\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
MbapType mbap;
|
||||
PduType pdu;
|
||||
ReadMbtcpMBAP(clientfd,&mbap);//读取数据前7字节为mbap初始化
|
||||
|
||||
if(mbap.uid!=uid){//检验是否为此从机
|
||||
close(clientfd);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ReadMbtcpPDU(clientfd,&pdu);//读取pdu和一些定长部分
|
||||
|
||||
printf("OP:%x\n",pdu.func);
|
||||
printf("ADDR:%x\n",pdu.addr);
|
||||
|
||||
u8_t* response_buf;//定义操作返回的指针
|
||||
u8_t buf_len=mb_parser.func_set[pdu.func](&mbm,clientfd,&mbap,&pdu,&response_buf);
|
||||
|
||||
SendResponse(clientfd,&response_buf,buf_len);
|
||||
// return NULL;
|
||||
//执行操作
|
||||
|
||||
}
|
||||
close(clientfd);
|
||||
}
|
||||
close(fd);
|
||||
MbMemoryFree(&mbm);//释放存储区
|
||||
}
|
||||
|
||||
void TestModbusTcpServer(int argc, char *argv[])
|
||||
{
|
||||
if(argc >= 2) {
|
||||
lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
TcpSocketConfigParam(argv[1]);
|
||||
}
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
lwip_config_tcp(0, tcp_demo_ipaddr, tcp_demo_netmask, tcp_demo_gwaddr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ADD_NUTTX_FEATURES
|
||||
pthread_attr_t attr = PTHREAD_ATTR_INITIALIZER;
|
||||
attr.priority = LWIP_TCP_DEMO_TASK_PRIO;
|
||||
attr.stacksize = LWIP_TCP_DEMO_TASK_STACK_SIZE;
|
||||
#endif
|
||||
|
||||
ModbusTcpServer(NULL);
|
||||
}
|
||||
|
||||
PRIV_SHELL_CMD_FUNCTION(TestModbusTcpServer, a modbusS test sample, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
|
||||
static void *ModbusTcpClient(void *arg)
|
||||
{
|
||||
u16_t counter=0;
|
||||
int fd = -1;
|
||||
int ret;
|
||||
|
||||
// lw_print("2023-05-27 Peng Guanhua\n");
|
||||
lw_print("%s start\n", __func__);
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
lw_print("Socket error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char tcp_ip_str[128]="192.168.31.148";
|
||||
u16_t tcp_socket_port=6000;
|
||||
|
||||
|
||||
printf("%s\n",tcp_ip_str);
|
||||
struct sockaddr_in tcp_sock;
|
||||
tcp_sock.sin_family = AF_INET;
|
||||
tcp_sock.sin_port = htons(tcp_socket_port);
|
||||
tcp_sock.sin_addr.s_addr = inet_addr(tcp_ip_str);
|
||||
printf("%s\n",tcp_ip_str);
|
||||
|
||||
memset(&(tcp_sock.sin_zero), 0, sizeof(tcp_sock.sin_zero));
|
||||
|
||||
ret = connect(fd, (struct sockaddr *)&tcp_sock, sizeof(struct sockaddr));
|
||||
|
||||
if (ret < 0) {
|
||||
lw_print("Unable to connect %s:%d = %d\n", tcp_ip_str, tcp_socket_port, ret);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lw_print("TCP connect %s:%d success, start.\n", tcp_ip_str, tcp_socket_port);
|
||||
|
||||
|
||||
while (1) {
|
||||
|
||||
MbapType mbap={counter,0,0,0};
|
||||
PduType pdu;
|
||||
u8_t*request;
|
||||
|
||||
int mesg_len=GenerateModbusRequest(&mbap,&pdu,MBTCP,&request);
|
||||
SendModbus(fd,&request,mesg_len);
|
||||
GetRequest(fd,&mbap,&pdu);
|
||||
counter++;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TestModbusTcpClient(int argc, char *argv[])
|
||||
{
|
||||
if(argc >= 2) {
|
||||
lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
TcpSocketConfigParam(argv[1]);
|
||||
}
|
||||
|
||||
#ifdef ADD_XIZI_FEATURES
|
||||
lwip_config_tcp(0, tcp_demo_ipaddr, tcp_demo_netmask, tcp_demo_gwaddr);
|
||||
|
||||
#endif
|
||||
#ifdef ADD_NUTTX_FEATURES
|
||||
pthread_attr_t attr = PTHREAD_ATTR_INITIALIZER;
|
||||
attr.priority = LWIP_TCP_DEMO_TASK_PRIO;
|
||||
attr.stacksize = LWIP_TCP_DEMO_TASK_STACK_SIZE;
|
||||
#endif
|
||||
|
||||
ModbusTcpClient(NULL);
|
||||
}
|
||||
PRIV_SHELL_CMD_FUNCTION(TestModbusTcpClient, a modbustcpC test sample, PRIV_SHELL_CMD_MAIN_ATTR);
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
基数树节点设计为:
|
||||
|
||||
```c
|
||||
typedef struct _node {
|
||||
void* value;
|
||||
struct _node* next[NODE_SIZE];
|
||||
} node;
|
||||
typedef struct radix_node
|
||||
{
|
||||
void *value;
|
||||
struct radix_node *child[NODE_SIZE];
|
||||
struct radix_node *parent;
|
||||
} radix_node;
|
||||
```
|
||||
|
||||
其中,节点在树中的路径即为键,`value` 存储值,`NODE_SIZE` 定义为 128,足以容纳所有 ASCII 值。
|
||||
其中,节点在树中的路径即为键,为`unsigned int`类型,`value` 存储值,`NODE_SIZE` 定义为 4,即每个树节点包含2个bit位,可以根据实际需求调整。
|
||||
|
||||
一共实现了 5 个函数,分别为:
|
||||
|
||||
@@ -32,20 +34,19 @@ typedef struct _node {
|
||||
测试程序定义了以下键值对:
|
||||
|
||||
```c
|
||||
char keys[][MAX_WORD_LEN] = {
|
||||
char values[][16] = {
|
||||
"what",
|
||||
"where",
|
||||
"why",
|
||||
"how",
|
||||
"hello!",
|
||||
"apple",
|
||||
"12345"
|
||||
};
|
||||
int values[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
"12345"};
|
||||
unsigned int keys[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
```
|
||||
|
||||
1. 程序的第一部分创建了基数树,并且将定义的 7 个键值对的前 6 个插入了基数树,然后分别查找 7 个键,前 6 个均可以找到对应的值,最后一个未插入,因此无法找到
|
||||
2. 程序的第二部分从基数树中删除了 `where` 和 `how` 两个键,再次分别查找 7 个键,删除的键值对和未插入的键值对均无法找到
|
||||
2. 程序的第二部分从基数树中删除了 `where` 和 `how` 两个值的键,再次分别查找 7 个键,删除的键值对和未插入的键值对均无法找到
|
||||
3. 程序的第三部分重新插入了已删除的 `where` 和未插入过的 `12345` ,再次分别查找 7 个键,新插入的值可以检索到
|
||||
4. 程序的第四部分将基数树销毁,再次分别查找 7 个键,所有的键值对均无法找到
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 96 KiB |
@@ -1,23 +1,27 @@
|
||||
/**
|
||||
* @file: test_radix_tree.c
|
||||
* @brief: Implement a simple radix tree
|
||||
* @version: 1.0
|
||||
* @date: 2023/5/24
|
||||
*/
|
||||
* @file: test_radix_tree.c
|
||||
* @brief: Implement a simple radix tree
|
||||
* @version: 1.0
|
||||
* @date: 2023/5/24
|
||||
*/
|
||||
|
||||
#include <transform.h>
|
||||
#include "test_radix_tree.h"
|
||||
|
||||
/**
|
||||
* @description: Create a radix tree node
|
||||
* @return node pointer
|
||||
*/
|
||||
node* CreateNode()
|
||||
radix_node *CreateNode()
|
||||
{
|
||||
node* n = (node*)malloc(sizeof(node));
|
||||
n->value = NULL;
|
||||
for (int i = 0; i < NODE_SIZE; i++) {
|
||||
n->next[i] = NULL;
|
||||
radix_node *n = (radix_node *)malloc(sizeof(radix_node));
|
||||
if (n != NULL)
|
||||
{
|
||||
n->parent = NULL;
|
||||
n->value = NULL;
|
||||
for (int i = 0; i < NODE_SIZE; ++i)
|
||||
{
|
||||
n->child[i] = NULL;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -29,21 +33,32 @@ node* CreateNode()
|
||||
* @param value - new node value
|
||||
* @return void
|
||||
*/
|
||||
void InsertNode(node* root, const char* key, void* value)
|
||||
int InsertNode(radix_node *root, unsigned int key, void *value)
|
||||
{
|
||||
if (root == NULL) {
|
||||
return;
|
||||
if (root == NULL)
|
||||
{
|
||||
return -1; // The root node is empty
|
||||
}
|
||||
node* cur = root;
|
||||
size_t len = strlen(key);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t b = (uint8_t)key[i];
|
||||
if (cur->next[b] == NULL) {
|
||||
cur->next[b] = CreateNode();
|
||||
radix_node *cur = root;
|
||||
int temp;
|
||||
for (int i = radix_tree_height - 1; i >= 0; --i)
|
||||
{
|
||||
temp = CHECK_BITS(key, i);
|
||||
if (!cur->child[temp])
|
||||
{
|
||||
cur->child[temp] = CreateNode();
|
||||
if (!cur->child[temp])
|
||||
return -2; // Failed to apply for a node
|
||||
cur->child[temp]->parent = cur;
|
||||
}
|
||||
cur = cur->next[b];
|
||||
cur = cur->child[temp];
|
||||
}
|
||||
if (cur->value == value)
|
||||
return -3; // Repeat insertion
|
||||
if (cur->value != NULL)
|
||||
return -4; // Already occupied
|
||||
cur->value = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,38 +67,27 @@ void InsertNode(node* root, const char* key, void* value)
|
||||
* @param key - key which is needed to delete
|
||||
* @return void
|
||||
*/
|
||||
void DeleteNode(node* root, const char* key)
|
||||
void DeleteNode(radix_node *root, unsigned int key)
|
||||
{
|
||||
if (root == NULL) {
|
||||
if (root == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
node** cur = &root;
|
||||
size_t len = strlen(key);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t b = (uint8_t)key[i];
|
||||
if ((*cur)->next[b] == NULL) {
|
||||
return;
|
||||
}
|
||||
cur = &((*cur)->next[b]);
|
||||
}
|
||||
|
||||
if ((*cur)->value == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(*cur)->value = NULL;
|
||||
|
||||
int has_children = 0;
|
||||
for (int i = 0; i < NODE_SIZE; i++) {
|
||||
if ((*cur)->next[i] != NULL) {
|
||||
has_children = 1;
|
||||
radix_node *cur = root;
|
||||
int temp;
|
||||
for (int i = radix_tree_height - 1; i >= 0; --i)
|
||||
{
|
||||
temp = CHECK_BITS(key, i);
|
||||
cur = cur->child[temp];
|
||||
if (!cur)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_children) {
|
||||
free(*cur);
|
||||
(*cur) = NULL;
|
||||
}
|
||||
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
cur->parent->child[temp] = NULL;
|
||||
free(cur);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,20 +96,23 @@ void DeleteNode(node* root, const char* key)
|
||||
* @param key - key which is needed to find
|
||||
* @return value pointer corresponding to key
|
||||
*/
|
||||
void* FindNode(node* root, const char* key)
|
||||
void *FindNode(radix_node *root, unsigned int key)
|
||||
{
|
||||
if (root == NULL) {
|
||||
if (root == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
node* cur = root;
|
||||
size_t len = strlen(key);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t b = (uint8_t)key[i];
|
||||
if (cur->next[b] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cur = cur->next[b];
|
||||
radix_node *cur = root;
|
||||
int temp;
|
||||
for (int i = radix_tree_height - 1; i >= 0; --i)
|
||||
{
|
||||
temp = CHECK_BITS(key, i);
|
||||
cur = cur->child[temp];
|
||||
if (!cur)
|
||||
break;
|
||||
}
|
||||
if (!cur)
|
||||
return NULL;
|
||||
return cur->value;
|
||||
}
|
||||
|
||||
@@ -114,73 +121,88 @@ void* FindNode(node* root, const char* key)
|
||||
* @param root - radix tree root
|
||||
* @return void
|
||||
*/
|
||||
void DestroyTree(node* root)
|
||||
void DestroyTree(radix_node *root)
|
||||
{
|
||||
if (root == NULL) {
|
||||
if (root == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < NODE_SIZE; i++) {
|
||||
DestroyTree(root->next[i]);
|
||||
for (int i = 0; i < NODE_SIZE; i++)
|
||||
{
|
||||
DestroyTree(root->child[i]);
|
||||
}
|
||||
free(root);
|
||||
}
|
||||
|
||||
void TestRadix()
|
||||
{
|
||||
char keys[][MAX_WORD_LEN] = {
|
||||
char values[][16] = {
|
||||
"what",
|
||||
"where",
|
||||
"why",
|
||||
"how",
|
||||
"hello!",
|
||||
"apple",
|
||||
"12345"
|
||||
};
|
||||
int values[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
"12345"};
|
||||
unsigned int keys[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
printf("\nCreate tree and add key & value:\n");
|
||||
node* root = CreateNode();
|
||||
if (!root) printf("Create node failed.\n");
|
||||
radix_node *root = CreateNode();
|
||||
if (!root)
|
||||
printf("Create node failed.\n");
|
||||
|
||||
int num = sizeof(keys) / sizeof(keys[0]);
|
||||
for (int i = 0; i < num - 1; ++i) {
|
||||
for (int i = 0; i < num - 1; ++i)
|
||||
{
|
||||
InsertNode(root, keys[i], &values[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)FindNode(root, keys[i]);
|
||||
if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
|
||||
else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
char *v = (char *)FindNode(root, keys[i]);
|
||||
if (v)
|
||||
printf("keys[%d] %x, values[%d] = %s\n", i, keys[i], i, v);
|
||||
else
|
||||
printf("keys[%d] %x not found\n", i, keys[i]);
|
||||
}
|
||||
|
||||
printf("\nDelete \"where\" and \"how\":\n");
|
||||
DeleteNode(root, keys[1]);
|
||||
DeleteNode(root, keys[3]);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)FindNode(root, keys[i]);
|
||||
if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
|
||||
else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
char *v = (char *)FindNode(root, keys[i]);
|
||||
if (v)
|
||||
printf("keys[%d] %x, values[%d] = %s\n", i, keys[i], i, v);
|
||||
else
|
||||
printf("keys[%d] %x not found\n", i, keys[i]);
|
||||
}
|
||||
|
||||
printf("\nInsert \"where\" and \"12345\":\n");
|
||||
InsertNode(root, keys[1], &values[1]);
|
||||
InsertNode(root, keys[6], &values[6]);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)FindNode(root, keys[i]);
|
||||
if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
|
||||
else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
char *v = (char *)FindNode(root, keys[i]);
|
||||
if (v)
|
||||
printf("keys[%d] %x, values[%d] = %s\n", i, keys[i], i, v);
|
||||
else
|
||||
printf("keys[%d] %x not found\n", i, keys[i]);
|
||||
}
|
||||
|
||||
printf("\nDestroy tree:\n");
|
||||
DestroyTree(root);
|
||||
root = NULL;
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
int* v = (int*)FindNode(root, keys[i]);
|
||||
if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
|
||||
else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
char *v = (char *)FindNode(root, keys[i]);
|
||||
if (v)
|
||||
printf("keys[%d] %x, values[%d] = %s\n", i, keys[i], i, v);
|
||||
else
|
||||
printf("keys[%d] %x not found\n", i, keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
/**
|
||||
* @file: test_radix_tree.h
|
||||
* @brief: Implement a simple radix tree
|
||||
* @version: 1.0
|
||||
* @date: 2023/5/24
|
||||
*/
|
||||
* @file: test_radix_tree.h
|
||||
* @brief: Implement a simple radix tree
|
||||
* @version: 1.0
|
||||
* @date: 2023/5/24
|
||||
*/
|
||||
|
||||
#define NODE_SIZE 128
|
||||
#define MAX_WORD_LEN 128
|
||||
#include <transform.h>
|
||||
|
||||
typedef struct _node {
|
||||
void* value;
|
||||
struct _node* next[NODE_SIZE];
|
||||
} node;
|
||||
#define NODE_SIZE 4
|
||||
#define BITS 2
|
||||
#define CHECK_BITS(key, pos) ((((unsigned int)(key)) << (sizeof(int) * 8 - (pos + 1) * BITS)) >> (sizeof(int) * 8 - BITS))
|
||||
|
||||
node* CreateNode();
|
||||
void InsertNode(node* root, const char* key, void* value);
|
||||
void DeleteNode(node* root, const char* key);
|
||||
void* FindNode(node* root, const char* key);
|
||||
void DestroyTree(node* root);
|
||||
const int radix_tree_height = sizeof(void *) * 8 / BITS; // Height of tree
|
||||
|
||||
typedef struct radix_node
|
||||
{
|
||||
void *value;
|
||||
struct radix_node *child[NODE_SIZE];
|
||||
struct radix_node *parent;
|
||||
} radix_node;
|
||||
|
||||
radix_node *CreateNode();
|
||||
int InsertNode(radix_node *root, unsigned int key, void *value);
|
||||
void DeleteNode(radix_node *root, unsigned int key);
|
||||
void *FindNode(radix_node *root, unsigned int key);
|
||||
void DestroyTree(radix_node *root);
|
||||
@@ -22,26 +22,94 @@
|
||||
#include <transform.h>
|
||||
#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;
|
||||
|
||||
347
APP_Framework/Applications/app_test/test_socket.c
Normal 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));
|
||||
95
APP_Framework/Applications/app_test/test_uart.c
Normal 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
|
||||
@@ -15,7 +15,6 @@
|
||||
// #include <user_api.h>
|
||||
#include <transform.h>
|
||||
|
||||
|
||||
extern int FrameworkInit();
|
||||
extern void ApplicationOtaTaskInit(void);
|
||||
int main(void)
|
||||
|
||||
3
APP_Framework/Applications/webnet/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
SRC_DIR += WebNet_XiUOS
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||