wheel/components/modbus_tcp/modbus_tcp.c

119 lines
3.5 KiB
C
Raw Normal View History

2024-01-22 03:36:10 +08:00
#include "modbus.h"
#include "lwip/tcp.h"
#include "esp_log.h"
static const char *TAG = "modbus tcp";
/* 修正应该将整个包的解析都放到Modbus的处理中这里有一点纠缠了 */
static err_t ModBusSlave_recv(void *arg, struct tcp_pcb *newpcb, struct pbuf *p, err_t err) {
// ESP_LOGI(TAG, "ModBusSlave_recv");
/* 处理接收到的包信息存储在pbuf中并发送包回应 */
if (p != NULL) {
uint8_t *txbuf;
uint8_t *rxbuf;
int txlen, rxlen;
/* 接收数据 */
tcp_recved(newpcb, p->tot_len);
rxbuf = (uint8_t *)p->payload; /* 修正pbuf的数据是用链表存储的p->payload仅是该节点的数据并不是所有的但是目前只取了第一个节点 */
rxlen = p->len;
/* MBAP报文头7Byte事务处理标识2Byte + 协议标识2Byte + 长度2Byte(此字节往后的字节个数) + 单元标识符1Byte*/
/* 这里忽略了前面的6Byte未处理 */
if (rxlen < 6) {
ESP_LOGI(TAG, "err: rxlen less 6");
pbuf_free(p);
return tcp_close(newpcb); /* 修正tcp_close的处理是否合理 */
}
txbuf = (uint8_t *)mem_malloc(1024 + 16);
if (txbuf == NULL) {
ESP_LOGI(TAG, "err:tx malloc fault");
return tcp_close(newpcb);
}
/* 使用Modbus协议解析接收数据同时准备应答包txbuf数据发送应答包 */
/* 包含: */
/* MBAP单元标识符1Byte */
/* PUD帧结构功能码1Byte + 地址2Byte(H+L) + ... */
txlen = ModbusSlaveProcess(&txbuf[6], &rxbuf[6], (rxlen - 6), 0);
if (txlen > 0) {
int i;
for (i = 0; i < 4; i++) {
txbuf[i] = rxbuf[i];
}
txbuf[4] = (uint8_t)(txlen >> 8);
txbuf[5] = (uint8_t)(txlen & 0xff);
tcp_write(newpcb, txbuf, txlen + 6, 1);
}
mem_free(txbuf);
pbuf_free(p);
}
else if (err == ERR_OK) {
/* 有错误关闭tcp */
tcp_err(newpcb, NULL);
tcp_recv(newpcb, NULL);
tcp_poll(newpcb, NULL, 120);
err_t err_p = tcp_close(newpcb);
if (ERR_OK != err_p) {
// log_printf(LERROR, LOG_TAG "close error. err:%d\n", err_p);
}
return err_p;
}
return ERR_OK;
}
static void ModBusSlave_conn_err(void *arg, err_t err) {
ESP_LOGI(TAG, "connection error, err:%d\n", err);
}
/* 修正这里的实现时关闭tcp为什么要60s定时关闭一次tcp呢会不会影响程序 */
static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *newpcb) {
ESP_LOGI(TAG, "ModBusSlave_poll");
if (newpcb) {
ESP_LOGI(TAG, "close pcb");
tcp_close(newpcb);
newpcb = NULL;
}
return ERR_OK;
}
/*
* tcp连接请求时触发该回调函数
* pcb
*/
static err_t ModBusSlave_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
ESP_LOGI(TAG, "accept assess");
/* 设置各种回调函数 */
tcp_err(pcb, ModBusSlave_conn_err);
tcp_recv(pcb, ModBusSlave_recv);
tcp_poll(pcb, ModBusSlave_poll, 120); /* 轮询函数,定时会触发 120表示60s触发一次 */
return ERR_OK;
}
void ModBusTCPSlave_init(void) {
ESP_LOGI(TAG, "ModBusTCPSlave_init");
struct tcp_pcb *pcb;
pcb = tcp_new();
/* IP_ADDR_ANY表示绑定到主机的所有IP上 502端口是专门分配给Modbus的 */
tcp_bind(pcb, IP_ADDR_ANY, 502);
/* 开启被动监听 */
pcb = tcp_listen(pcb);
/* 设置ModBusSlave_accept回调函数在有tcp连接请求时触发 */
tcp_accept(pcb, ModBusSlave_accept);
}