2023_open_source_contest_warmup_2nd_issue1 from 好果汁有限公司

it is OK
This commit is contained in:
IACU 2023-09-01 11:03:57 +08:00
commit a1df906d16
20 changed files with 1477 additions and 0 deletions

View File

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

View File

@ -121,6 +121,10 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),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 +=
endif

View 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

View 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等待主设备的连接。
![alt 图1从设备等到主设备连接](./img/modbusTCP_S1.png)
主设备采用Modbus Poll应用程序建立TCP连接如图2所示。
![alt 图2主设备与从设备建立TCP连接](./img/modbusTCP_S2.png)
此时modbus poll程序便会不断的向从设备发送请求如图3。
![alt 图3从设备接收从设备请求报文并响应](./img/modbusTCP_S3.png)
可以看到解析出的功能码、地址以及对应的响应报文然后我们在modbus poll上修改一下存储区数据。如图4所示。
![alt 图4](./img/modbusTCP_S4.png)
因为修改的是寄存器存储区的值因此对应0x10功能码然后看看从设备的反映。如图5所示。
![alt 图5](./img/modbusTCP_S6.png)
可见成功收到功能码,并返回了响应的报文。
![alt 图6](./img/modbusTCP_S5.png)
modbus poll显示响应成功存储区已成功修改期望的值。
![alt 图7](./img/modbusTCP_S7.png)
可见存储区已成功修改。
线圈部分的查询修改同理,不再赘述。
### 4.2主设备通信测试
首先打开modbus slave应用程序用以作为从设备然后将存储区数据修改用以测试并打开TCP端口等待主设备的连接如图8所示。
![alt 图8](./img/modbusTCP_C2.png)
同样在终端打开从设备程序从设备的ipport在源码中已定义好所以打开时已经连接上如图9所示。
![alt 图9](./img/modbusTCP_C1.png)
开始输入从设备id功能码以及其他信息用以生成请求报文。
![alt 图10](./img/modbusTCP_C3.png)
如图10所示输入功能码3对应读取寄存器功能地址从0开始数量4然后便会生成请求报文然后发送结果如图11所示。
![alt](./img/modbusTCP_C4.png)
可见,已成功查询到寄存器的值。
然后测试写入功能输入功能码15(0xf)对应写入多个线圈功能如图12modbus slave对应的响应结果如图13所示。
![alt 图12](./img/modbusTCP_C5.png)
写入线圈的值为5个分别为1 0 1 0 1。发送成功后modbus salve中显示如图13所示。
![alt 图13](./img/modbusTCP_C6.png)
可见,已成功修改。
其他功能码测试过程类似,不再赘述。

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View 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);
}

View 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

View File

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