This commit is contained in:
edisondeng
2026-05-09 19:53:47 +08:00
parent 6e2b13dbb3
commit ee67076ec7
29 changed files with 4793 additions and 101 deletions

View File

@ -0,0 +1,175 @@
/**
******************************************************************************
* @file modbus_tcp_client.c
* @brief Modbus TCP 客户端模块实现 (针对寄存器 40031 轮询)
******************************************************************************
*/
#include "modbus_tcp_client.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "main.h"
#include "debug_log.h"
#include <string.h>
/* 私有变量 */
static uint8_t g_sn = 0;
static modbus_client_state_t g_state = MODBUS_STATE_IDLE;
static uint32_t g_last_tick = 0;
static uint16_t g_transaction_id = 0;
/* 服务器信息 */
static uint8_t dest_ip[4] = MODBUS_SERVER_IP;
static uint16_t dest_port = MODBUS_SERVER_PORT;
/**
* @brief 构造 Modbus TCP 请求包 (FC 03)
*/
static uint16_t build_read_request(uint8_t *buf, uint16_t addr, uint16_t qty)
{
g_transaction_id++;
/* MBAP Header */
buf[0] = (uint8_t)(g_transaction_id >> 8);
buf[1] = (uint8_t)(g_transaction_id & 0xFF);
buf[2] = 0x00; /* Protocol ID (0 for Modbus) */
buf[3] = 0x00;
buf[4] = 0x00; /* Length (6 bytes follow UnitID) */
buf[5] = 0x06;
buf[6] = MODBUS_UNIT_ID;
/* PDU */
buf[7] = 0x03; /* Function Code: Read Holding Registers */
buf[8] = (uint8_t)(addr >> 8);
buf[9] = (uint8_t)(addr & 0xFF);
buf[10] = (uint8_t)(qty >> 8);
buf[11] = (uint8_t)(qty & 0xFF);
return 12;
}
void ModbusTCP_Client_Init(uint8_t sn)
{
g_sn = sn;
g_state = MODBUS_STATE_IDLE;
g_last_tick = HAL_GetTick();
/* 动态重新加载配置,防止静态初始化带来的宏定义未生效问题 */
uint8_t ip[4] = MODBUS_SERVER_IP;
dest_ip[0] = ip[0]; dest_ip[1] = ip[1]; dest_ip[2] = ip[2]; dest_ip[3] = ip[3];
dest_port = MODBUS_SERVER_PORT;
LOG_INFO("MODBUS", "Client initialized on Socket %d, Target: %d.%d.%d.%d:%d",
sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
}
void ModbusTCP_Client_Task(void)
{
uint8_t tmp_buf[128]; // 临时接收缓存
uint16_t len; // 接收长度
int32_t ret; // 返回值
switch (g_state) // 客户端状态机切换
{
case MODBUS_STATE_IDLE: // 空闲状态
if (HAL_GetTick() - g_last_tick >= MODBUS_POLL_INTERVAL) { // 检查轮询间隔 (2秒)
g_state = MODBUS_STATE_CONNECTING; // 切换到连接状态
}
break;
case MODBUS_STATE_CONNECTING: // 连接中状态
{
uint8_t sr = getSn_SR(g_sn);
switch(sr) // 获取当前 Socket 状态
{
case SOCK_CLOSED: // 如果 Socket 已关闭
// 打开 TCP 模式的 Socket分配随机本地端口以避免冲突
if (socket(g_sn, Sn_MR_TCP, 50000 + (HAL_GetTick() % 10000), 0x00) == g_sn) {
LOG_DEBUG("MODBUS", "Socket opened");
}
break;
case SOCK_INIT: // Socket 初始化成功,开始连接
LOG_INFO("MODBUS", "Connecting to %d.%d.%d.%d:%d",
dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
ret = connect(g_sn, dest_ip, dest_port); // 发起连接请求
if (ret != SOCK_OK) {
LOG_ERROR("MODBUS", "Connect failed: %d", ret);
close(g_sn);
g_state = MODBUS_STATE_IDLE;
g_last_tick = HAL_GetTick();
}
break;
case SOCK_ESTABLISHED: // 连接已建立
LOG_INFO("MODBUS", "TCP Connected!");
g_state = MODBUS_STATE_SEND_QUERY; // 切换到发送请求状态
break;
case SOCK_CLOSE_WAIT: // 对方已关闭连接
disconnect(g_sn); // 本地断开连接
break;
default:
if (HAL_GetTick() % 5000 == 0) { // 每 5 秒打印一次未处理的状态
LOG_WARN("MODBUS", "Unhandled socket state: 0x%02X", sr);
}
break;
}
break;
}
case MODBUS_STATE_SEND_QUERY: // 发送查询请求状态
len = build_read_request(tmp_buf, TARGET_REG_ADDR, 1); // 构造 Modbus TCP FC03 报文
ret = send(g_sn, tmp_buf, len); // 发送 TCP 数据
if (ret > 0) { // 发送成功
LOG_DEBUG("MODBUS", "Request sent (TID: %d)", g_transaction_id);
g_state = MODBUS_STATE_WAIT_RESPONSE; // 切换到等待响应状态
g_last_tick = HAL_GetTick(); // 更新计时器
} else { // 发送失败
LOG_ERROR("MODBUS", "Send failed, reconnecting...");
close(g_sn); // 关闭 Socket
g_state = MODBUS_STATE_IDLE; // 返回空闲重试
}
break;
case MODBUS_STATE_WAIT_RESPONSE: // 等待响应状态
if ((len = getSn_RX_RSR(g_sn)) > 0) { // 检查是否有数据到达
if (len > sizeof(tmp_buf)) len = sizeof(tmp_buf); // 防止缓存溢出
ret = recv(g_sn, tmp_buf, len); // 接收数据
if (ret > 0) { // 接收成功
g_state = MODBUS_STATE_PROCESS_DATA; // 切换到处理数据状态
}
} else if (HAL_GetTick() - g_last_tick > 3000) { // 等待超时 (3秒)
LOG_WARN("MODBUS", "Response timeout");
close(g_sn); // 关闭连接
g_state = MODBUS_STATE_IDLE; // 返回空闲重试
}
break;
case MODBUS_STATE_PROCESS_DATA: // 处理数据状态
/* 校验响应 (检查 MBAP 长度、功能码等) */
if (len >= 9 && tmp_buf[7] == 0x03) { // 基本校验
uint16_t reg_val = (tmp_buf[9] << 8) | tmp_buf[10]; // 提取寄存器值
LOG_INFO("MODBUS", "Read Register %d OK: 0x%04X", TARGET_REG_ADDR + 40001, reg_val);
/* 🚀 关键步骤:通过 433 无线转发结果 */
uint8_t payload[2]; // 构造 433 负载
payload[0] = tmp_buf[9]; // 寄存器高位
payload[1] = tmp_buf[10]; // 寄存器低位
RF433_SendPacket(PROTO_TYPE_NET, payload, 2); // 打包并通过无线发出
g_state = MODBUS_STATE_IDLE; // 处理完成,返回空闲
g_last_tick = HAL_GetTick(); // 记录本次完成时间
} else { // 响应格式非法
LOG_ERROR("MODBUS", "Invalid response format");
g_state = MODBUS_STATE_IDLE; // 返回空闲
g_last_tick = HAL_GetTick(); // 更新计时
}
break;
default: // 异常保护
g_state = MODBUS_STATE_IDLE;
break;
}
}