wheel/components/modbus_tcp/modbus_tcp.c
2024-01-22 03:36:10 +08:00

119 lines
3.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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