/** ****************************************************************************** * @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 /* 私有变量 */ 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; } }