Files

835 lines
24 KiB
C
Raw Permalink 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 "PCM_comm.h"
#include "lwip/sockets.h"
#include "mdu_comm/mdu_comm_task.h"
#include "mdu_comm/mdu_interface.h"
#include "app_init/app_init.h"
#include "mylog/mylog.h"
#include "publicdata/publicdata.h"
#include "wdt_task/wdt_task.h"
#include "app_init/app_init.h"
#include "app_init/app_test.h"
#include "app_init/task_lock.h"
#include "flowctrl/flowctrl_task.h"
#include "flowctrl/flow_interface.h"
#include "collect_ctrl/collect_task.h"
#include <string.h>
#include <stdio.h>
/*============================================================================
* PCM UDP 通信模块(终端角色)
*
* 功能:实现群充终端(分桩)与主机之间的UDP通信协议
* 协议定义参考:主机终端通信协议.md
*
* 本机角色:终端(分桩)
* - 主动发送:分桩心跳帧(0x10) 周期1000ms
* - 主动发送:分桩请求帧(0x12) 周期200ms
* - 接收处理:主机心跳帧(0x11)
* - 接收处理:分桩请求应答帧(0x13)
*
* 帧结构:
* 5A 99 - 帧头(2B)
* xx - 帧功能码(1B)
* xx - 数据长度(1B)
* data - 帧数据(NB)
* xx - CRC校验(1B)
* A5 - 帧尾(1B)
*============================================================================*/
/*============================================================================
* 局部宏定义
*============================================================================*/
#define PCM_COMM_TASK_ID (TASK_ID_MduComm)
#define PCM_COMM_LOG(fmt, ...) MYLOG_MSG(PCM_COMM_TASK_ID, (fmt), ##__VA_ARGS__)
/* 分桩请求帧:每组枪数据长度(11字节) */
#define PCM_TERM_REQUEST_GUN_DATA_LEN 11
/* 分桩请求应答帧:每组枪数据长度(9字节) */
#define PCM_HOST_RESPONSE_GUN_DATA_LEN 9
/* 0x12 分桩请求帧测试开关:
* 0: 使用系统实时数据
* 1: 使用本文件内置测试结构体数据(脱离系统数据源联调) */
#ifndef PCM_TERM_REQUEST_TEST_EN
#define PCM_TERM_REQUEST_TEST_EN 0
#endif
/* UDP收发内容打印开关(默认关闭,避免刷屏/占用CPU)
* 0: 关闭
* 1: 打印 TX/RX 数据(十六进制,截断到最大字节数) */
#ifndef PCM_UDP_PRINT_EN
#define PCM_UDP_PRINT_EN 0
#endif
#ifndef PCM_UDP_PRINT_MAX_BYTES
#define PCM_UDP_PRINT_MAX_BYTES 64U
#endif
/*============================================================================
* 局部变量
*============================================================================*/
/* UDP 套接字句柄 */
static int g_pcm_udp_sock = -1;
/* UDP 目标地址结构体(主机地址) */
static struct sockaddr_in g_pcm_peer_addr;
/* PCM 通信数据 */
S_PCM_COMM_DATA s_pcm_comm;
/* 接收缓冲区 */
static U8_T g_u8_recv_buf[PCM_FRAME_MAX_LEN];
#if (PCM_UDP_PRINT_EN != 0)
static void v_pcm_log_hex(const char *tag, const U8_T *data, U16_T len)
{
char line[PCM_UDP_PRINT_MAX_BYTES * 3U + 16U];
U16_T n = len;
U16_T i;
int pos = 0;
if ((tag == NULL) || (data == NULL)) {
return;
}
if (n > (U16_T)PCM_UDP_PRINT_MAX_BYTES) {
n = (U16_T)PCM_UDP_PRINT_MAX_BYTES;
}
for (i = 0U; i < n; i++) {
int w = snprintf(&line[pos], sizeof(line) - (size_t)pos, "%02X ", (unsigned)data[i]);
if (w <= 0) {
break;
}
pos += w;
if (pos >= (int)sizeof(line) - 1) {
break;
}
}
line[(pos < (int)sizeof(line)) ? pos : ((int)sizeof(line) - 1)] = '\0';
if (len > n) {
printf("%s len=%u show=%u: %s...\r\n", tag, (unsigned)len, (unsigned)n, line);
} else {
printf("%s len=%u: %s\r\n", tag, (unsigned)len, line);
}
}
#endif
#if (PCM_UDP_PRINT_EN != 0)
static void v_pcm_log_addr_port(const char *tag, const struct sockaddr_in *addr)
{
U32_T ip_host;
U16_T port_host;
if ((tag == NULL) || (addr == NULL)) {
return;
}
ip_host = PP_NTOHL(addr->sin_addr.s_addr);
port_host = PP_NTOHS(addr->sin_port);
printf("%s %u.%u.%u.%u:%u\r\n",
tag,
(unsigned)((ip_host >> 24) & 0xFFU),
(unsigned)((ip_host >> 16) & 0xFFU),
(unsigned)((ip_host >> 8) & 0xFFU),
(unsigned)(ip_host & 0xFFU),
(unsigned)port_host);
}
#endif
#if (PCM_TERM_REQUEST_TEST_EN != 0)
typedef struct
{
U8_T u8_gun_num;
S_PCM_GUN_TERM_DATA s_gun_data[GUN_MAX_CNT];
} S_PCM_TERM_REQUEST_TEST_DATA;
/* 0x12 测试固定数据(仅在 PCM_TERM_REQUEST_TEST_EN=1 时生效) */
static S_PCM_TERM_REQUEST_TEST_DATA s_pcm_term_req_test_data = {
2U,
{
/* gun_addr, work_state, contactor_dc, contactor_discharge, need_vol(0.1V), need_cur(0.1A), fault_state, fault_reason */
{1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U},
{2U, 0U, 0U, 0U, 0U, 0U, 0U, 0U}
}
};
#endif
/*============================================================================
* 局部函数声明
*============================================================================*/
static void v_pcm_udp_socket_init(void);
//static U8_T u8_pcm_verify_frame(const S_PCM_FRAME *ps_frame);
static S8_T s8_pcm_send_frame(U8_T u8_cmd, const U8_T *pu8_data, U8_T u8_len);
static void v_pcm_parse_host_heartbeat(const S_PCM_FRAME *ps_frame);
static void v_pcm_parse_host_response(const S_PCM_FRAME *ps_frame);
static void v_pcm_check_comm_timeout(U16_T u16_sleep_time_ms);
/*============================================================================
* 函数实现
*============================================================================*/
/**
* @brief 初始化 PCM UDP socket
*
* 参照 mylog.c 中 v_mylog_udp_init 的实现方式:
* - 创建 UDP socket
* - 绑定本地端口
* - 失败时关闭socket并重试
*/
static void v_pcm_udp_socket_init(void)
{
struct sockaddr_in local_addr;
if (g_pcm_udp_sock >= 0) {
return;
}
g_pcm_udp_sock = lwip_socket(AF_INET, SOCK_DGRAM, 0);
if (g_pcm_udp_sock < 0) {
PCM_COMM_LOG("pcm udp socket create fail");
return;
}
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_port = PP_HTONS(PCM_UDP_SRC_PORT);
local_addr.sin_addr.s_addr = PP_HTONL(INADDR_ANY);
if (lwip_bind(g_pcm_udp_sock, (const struct sockaddr *)&local_addr, sizeof(local_addr)) != 0) {
PCM_COMM_LOG("pcm udp bind fail, port=%d", PCM_UDP_SRC_PORT);
lwip_close(g_pcm_udp_sock);
g_pcm_udp_sock = -1;
return;
}
PCM_COMM_LOG("pcm udp socket init ok, port=%d", PCM_UDP_SRC_PORT);
}
///**
// * @brief 校验接收帧的合法性
// *
// * @param ps_frame 帧指针
// * @return U8_T 0无效 1有效
// */
//static U8_T u8_pcm_verify_frame(const S_PCM_FRAME *ps_frame)
//{
// U8_T u8_calc_crc;
// /* 校验帧头 */
// if (ps_frame->u16_head != PCM_FRAME_HEAD) {
// return 0;
// }
// /* 校验帧尾 */
// if (ps_frame->u8_tail != PCM_FRAME_TAIL) {
// return 0;
// }
// /* 校验数据长度合法性 */
// if (ps_frame->u8_len > PCM_FRAME_MAX_DATA_LEN) {
// return 0;
// }
// /* 校验CRC:计算范围 = 帧头(2) + 功能码(1) + 长度(1) + 数据(u8_len) */
// u8_calc_crc = u8_pcm_calc_crc((const U8_T *)&ps_frame->u16_head,
// (U16_T)(sizeof(U16_T) + sizeof(U8_T) + sizeof(U8_T) + ps_frame->u8_len));
// if (u8_calc_crc != ps_frame->u8_crc) {
// return 0;
// }
// return 1;
//}
/**
* @brief 发送PCM帧
*
* @param u8_cmd 帧功能码
* @param pu8_data 数据指针
* @param u8_len 数据长度
* @return S8_T 0成功 -1失败
*/
static S8_T s8_pcm_send_frame(U8_T u8_cmd, const U8_T *pu8_data, U8_T u8_len)
{
U8_T au8_send_buf[PCM_FRAME_MIN_LEN + PCM_FRAME_MAX_DATA_LEN];
U8_T u8_send_len;
U8_T u8_crc;
S8_T s8_ret;
if (g_pcm_udp_sock < 0) {
v_pcm_udp_socket_init();
}
if (g_pcm_udp_sock < 0) {
return -1;
}
if (u8_len > PCM_FRAME_MAX_DATA_LEN) {
return -1;
}
/* 手动组帧:紧凑排列,无空洞 */
u8_send_len = 0;
/* 帧头(2B) */
au8_send_buf[u8_send_len++] = (U8_T)(PCM_FRAME_HEAD >> 8);
au8_send_buf[u8_send_len++] = (U8_T)(PCM_FRAME_HEAD & 0xFF);
/* 功能码(1B) */
au8_send_buf[u8_send_len++] = u8_cmd;
/* 数据长度(1B) */
au8_send_buf[u8_send_len++] = u8_len;
/* 数据(NB) */
if (pu8_data != NULL && u8_len > 0) {
memcpy(&au8_send_buf[u8_send_len], pu8_data, u8_len);
u8_send_len += u8_len;
}
/* CRC校验(1B):计算范围 = 帧头 + 功能码 + 长度 + 数据 */
u8_crc = u16_crc_checksum(&au8_send_buf[4], u8_len);
au8_send_buf[u8_send_len++] = u8_crc;
/* 帧尾(1B) */
au8_send_buf[u8_send_len++] = PCM_FRAME_TAIL;
#if (PCM_UDP_PRINT_EN != 0)
v_pcm_log_addr_port("[PCM][UDP][TX][DST]", &g_pcm_peer_addr);
v_pcm_log_hex("[PCM][UDP][TX]", au8_send_buf, (U16_T)u8_send_len);
#endif
/* 发送 */
s8_ret = (S8_T)lwip_sendto(g_pcm_udp_sock,
(const void *)au8_send_buf,
(size_t)u8_send_len,
0,
(const struct sockaddr *)&g_pcm_peer_addr,
sizeof(g_pcm_peer_addr));
if (s8_ret < 0) {
return -1;
}
return 0;
}
/**
* @brief 解析主机心跳帧(功能码0x11)
*
* 数据格式:
* - 终端枪数量(1B)
* - 终端枪地址(1B) x N
*/
static void v_pcm_parse_host_heartbeat(const S_PCM_FRAME *ps_frame)
{
U8_T u8_gun_num;
if (ps_frame->u8_len < 1) {
return;
}
u8_gun_num = ps_frame->u8_data[0];
if (u8_gun_num == 0 || u8_gun_num > GUN_MAX_CNT) {
return;
}
/* 校验数据长度:1(枪数量) + u8_gun_num(枪地址) */
if (ps_frame->u8_len < (U8_T)(1 + u8_gun_num)) {
return;
}
/* 更新主机通信状态 */
s_pcm_comm.s_host.u32_last_recv_time = (U32_T)u64_get_current_millis();
s_pcm_comm.s_host.u8_comm_ok = 1;
PCM_COMM_LOG("recv host heartbeat, gun_num=%d", u8_gun_num);
}
/**
* @brief 解析分桩请求应答帧(功能码0x13)
*
* 数据格式(每组枪数据):
* - 终端枪地址(1B)
* - 模块启停状态(1B)
* - 输出电压(2B) BE 0.1V
* - 输出电流(2B) BE 0.1A
* - 主机故障状态(1B)
* - 主机故障原因(2B) BE
* 每组共 9 字节
*/
static void v_pcm_parse_host_response(const S_PCM_FRAME *ps_frame)
{
U8_T u8_gun_num;
U8_T i;
U8_T u8_offset;
U8_T u8_expected_len;
if (ps_frame->u8_len < 1) {
return;
}
u8_gun_num = ps_frame->u8_data[0];
if (u8_gun_num == 0 || u8_gun_num > GUN_MAX_CNT) {
return;
}
/* 校验数据长度:1(枪数量) + u8_gun_num * 9(每组枪数据) */
u8_expected_len = (U8_T)(1 + u8_gun_num * PCM_HOST_RESPONSE_GUN_DATA_LEN);
if (ps_frame->u8_len < u8_expected_len) {
return;
}
/* 更新主机通信状态 */
// s_pcm_comm.s_host.u32_last_recv_time = (U32_T)u64_get_current_millis();
s_pcm_comm.s_host.u8_comm_ok = 1;
s_pcm_comm.s_host.u8_gun_num = u8_gun_num;
u8_offset = 1;
for (i = 0; i < u8_gun_num && i < GUN_MAX_CNT; i++) {
S_PCM_GUN_HOST_DATA *ps_gun = &s_pcm_comm.s_host.s_gun_data[i];
U16_T u16_value;
ps_gun->u8_gun_addr = ps_frame->u8_data[u8_offset++];
ps_gun->u8_module_state = ps_frame->u8_data[u8_offset++];
/* 输出电压 BE: 高字节在前 */
u16_value = (U16_T)ps_frame->u8_data[u8_offset++] << 8;
u16_value |= (U16_T)ps_frame->u8_data[u8_offset++];
ps_gun->u16_out_vol = u16_value;
/* 输出电流 BE: 高字节在前 */
u16_value = (U16_T)ps_frame->u8_data[u8_offset++] << 8;
u16_value |= (U16_T)ps_frame->u8_data[u8_offset++];
ps_gun->u16_out_cur = u16_value;
ps_gun->u8_host_fault = ps_frame->u8_data[u8_offset++];
/* 主机故障原因 BE: 高字节在前 */
u16_value = (U16_T)ps_frame->u8_data[u8_offset++] << 8;
u16_value |= (U16_T)ps_frame->u8_data[u8_offset++];
ps_gun->u16_host_fault_reason = u16_value;
if(ps_gun->u16_out_vol > 2000 && ps_gun->u8_module_state == 0)
ps_gun->u8_module_state = 1;
// u8_offset += PCM_HOST_RESPONSE_GUN_DATA_LEN;
// PCM_COMM_LOG("recv host response, gun_addr=%d, module_state=%d, out_vol=%d, out_cur=%d, host_fault=%d, host_fault_reason=%d",
// ps_gun->u8_gun_addr, ps_gun->u8_module_state, ps_gun->u16_out_vol, ps_gun->u16_out_cur, ps_gun->u8_host_fault, ps_gun->u16_host_fault_reason);
}
}
/**
* @brief 检查主机通信超时
*
* @param u16_sleep_time_ms 任务周期时间(ms
*/
static void v_pcm_check_comm_timeout(U16_T u16_sleep_time_ms)
{ U64_T u64_now_ms __attribute__((unused));
U64_T u64_elapsed;
// (void)u16_sleep_time_ms;
if (s_pcm_comm.s_host.u32_last_recv_time == 0) {
return;
}
u64_now_ms = u64_get_current_millis();
u64_elapsed = u64_safe_millis_since(s_pcm_comm.s_host.u32_last_recv_time);
if (u64_elapsed >= PCM_COMM_TIMEOUT_MS) {
if (s_pcm_comm.s_host.u8_comm_ok != 0) {
s_pcm_comm.s_host.u8_comm_ok = 0;
PCM_COMM_LOG("pcm host comm timeout");
}
}
}
#if 1 //获取外部数据接口
#endif
/*============================================================================
* 全局函数实现
*============================================================================*/
/**
* @brief 初始化 PCM UDP 通信(终端角色)
*
* @param u8_term_no 终端编号(1开始,对应主机编号)
* @return S8_T 0成功 -1失败
*/
S8_T s8_pcm_udp_init(void)
{
/* 初始化socket */
v_pcm_udp_socket_init();
if (g_pcm_udp_sock < 0) {
return -1;
}
/* 初始化通信数据 */
memset(&s_pcm_comm, 0, sizeof(S_PCM_COMM_DATA));
//s_pcm_comm.u8_term_no = u8_term_no;
/* 构建本机(终端)IP地址:192.168.1.100 + (终端编号-1)*10 */
{
s_pcm_comm.u32_term_ip = PP_HTONL(LWIP_MAKEU32(g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_eth_ip[0],
g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_eth_ip[1],
g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_eth_ip[2],
g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_eth_ip[3]));
}
s_pcm_comm.u16_term_port = PP_HTONS(PCM_UDP_SRC_PORT);
/* 构建目标主机IP地址:192.168.1.200 + (终端编号-1) */
{
U8_T u8_ip3 = (U8_T)(PCM_HOST_IP_BASE3 + ((g_t_share_data.t_sys_fix_cfg.s_net_cfg.u8_eth_ip[3] - 100)/PCM_TERM_IP_OFFSET)*PCM_TERM_IP_OFFSET);
s_pcm_comm.u32_host_ip = PP_HTONL(LWIP_MAKEU32(PCM_HOST_IP_BASE0,
PCM_HOST_IP_BASE1,
PCM_HOST_IP_BASE2,
u8_ip3));
}
s_pcm_comm.u16_host_port = PP_HTONS(PCM_UDP_DST_PORT);
/* 设置目标地址(主机地址) */
memset(&g_pcm_peer_addr, 0, sizeof(g_pcm_peer_addr));
g_pcm_peer_addr.sin_family = AF_INET;
g_pcm_peer_addr.sin_port = s_pcm_comm.u16_host_port;
g_pcm_peer_addr.sin_addr.s_addr = s_pcm_comm.u32_host_ip;
/* 初始化定时器 */
s_pcm_comm.u32_heartbeat_tick = 0;
s_pcm_comm.u32_request_tick = 0;
return 0;
}
/**
* @brief 发送分桩心跳帧(功能码0x10)
*
* 数据格式:
* - 终端枪数量(1B)
* - 终端枪地址(1B) x N
*
* @return S8_T 0成功 -1失败
*/
S8_T s8_pcm_send_term_heartbeat()
{
SYS_FIX_CFG_T *t_sys_fix_cfg = &g_t_share_data.t_sys_fix_cfg;
U8_T au8_data[1 + GUN_MAX_CNT];
U8_T u8_len = 0;
au8_data[u8_len++] = u16_flow_get_sys_data(0,E_FLOW_GET_DATA_GUN_CNT,0); //获取枪数量
au8_data[u8_len++] = t_sys_fix_cfg->u8_terminal[0]; //枪1地址
au8_data[u8_len++] = t_sys_fix_cfg->u8_terminal[1]; //枪2地址
return s8_pcm_send_frame(PCM_CMD_TERM_HEARTBEAT, au8_data, u8_len);
}
/**
* @brief 发送分桩请求帧(功能码0x12)
*
* 数据格式(每组枪数据):
* - 终端枪地址(1B)
* - 终端枪工作状态(1B)
* - 直流输出接触器状态(1B)
* - 直流输出泄放接触器状态(1B)
* - 需求电压(2B) BE 0.1V
* - 需求电流(2B) BE 0.1A
* - 终端枪故障状态(1B)
* - 终端枪故障原因(2B) BE
* 每组共 11 字节
*
* @return S8_T 0成功 -1失败
*/
S8_T s8_pcm_send_term_request(void)
{
U8_T au8_data[1 + GUN_MAX_CNT * PCM_TERM_REQUEST_GUN_DATA_LEN];
U8_T u8_len = 0;
U8_T i;
U8_T u8_gun_num;
U16_T u16_data;
SYS_FIX_CFG_T *t_sys_fix_cfg = &g_t_share_data.t_sys_fix_cfg;
#if (PCM_TERM_REQUEST_TEST_EN != 0)
u8_gun_num = s_pcm_term_req_test_data.u8_gun_num;
if (u8_gun_num > GUN_MAX_CNT) {
u8_gun_num = GUN_MAX_CNT;
}
#else
u8_gun_num = u16_flow_get_sys_data(0, E_FLOW_GET_DATA_GUN_CNT, 0); //获取枪数量
au8_data[u8_len++] = u8_gun_num; /* 枪数量 */
#endif
// /* 枪数量 */
for (i = 0; i < u8_gun_num ; i++) {
#if (PCM_TERM_REQUEST_TEST_EN != 0)
const S_PCM_GUN_TERM_DATA *ps_test = &s_pcm_term_req_test_data.s_gun_data[i];
au8_data[u8_len++] = u16_flow_get_sys_data(0, E_FLOW_GET_DATA_GUN_CNT, 0);
au8_data[u8_len++] = ps_test->u8_gun_addr; /* 枪地址 */
au8_data[u8_len++] = ps_test->u8_work_state; /* 工作状态 */
au8_data[u8_len++] = ps_test->u8_contactor_dc; /* 直流接触器 */
au8_data[u8_len++] = ps_test->u8_contactor_discharge; /* 泄放接触器 */
/* 需求电压 BE */
u16_data = ps_test->u16_need_vol;
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
/* 需求电流 BE */
u16_data = ps_test->u16_need_cur;
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
au8_data[u8_len++] = ps_test->u8_fault_state; /* 故障状态 */
/* 故障原因 BE */
u16_data = ps_test->u16_fault_reason;
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
#else
au8_data[u8_len++] = t_sys_fix_cfg->u8_terminal[i]; /* 枪地址 */
au8_data[u8_len++] = u8_mdu_put_data(i); /* 工作状态 */
au8_data[u8_len++] = (U8_T)u8_get_gun_yx_data(YX_GUN_DC_KM,i); /* 直流接触器 */
au8_data[u8_len++] = (U8_T)u8_get_gun_yx_data(YX_GUN_RELIF,i); /* 泄放接触器 */
/* 需求电压 BE */
u16_data = (U16_T)u16_flow_put_data(i, E_FLOW_PUT_DATA_GUN_NEED_VOL, 0);
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
/* 需求电流 BE */
u16_data = (U16_T)u16_flow_put_data(i, E_FLOW_PUT_DATA_GUN_NEED_CUR, 0);
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
/* 故障状态 */
if(u8_get_fault_sum(i,0) > 0)
{
au8_data[u8_len++] = 1;
}
else
{
au8_data[u8_len++] = 0;
}
/* 故障原因 BE */
u16_data = u16_flow_get_sys_data(i, E_FLOW_GET_DATA_GUN_FAULT_INFO, 0);
au8_data[u8_len++] = (U8_T)((u16_data >> 8) & 0xFF);
au8_data[u8_len++] = (U8_T)(u16_data & 0xFF);
#endif
}
return s8_pcm_send_frame(PCM_CMD_TERM_REQUEST, au8_data, u8_len);
}
/**
* @brief PCM UDP 非阻塞接收处理
*
* 参照 mylog.c 中 v_mylog_udp_recv_echo 的实现方式:
* - 使用 MSG_DONTWAIT 非阻塞接收
* - 解析接收到的帧
*
* @return U8_T 0无数据 1收到有效数据
*/
U8_T u8_pcm_udp_recv_process(void)
{
int recv_len;
socklen_t peer_len;
struct sockaddr_in peer_addr;
S_PCM_FRAME s_frame;
S_PCM_FRAME *ps_frame = &s_frame;
if (g_pcm_udp_sock < 0) {
return 0;
}
peer_len = (socklen_t)sizeof(peer_addr);
recv_len = lwip_recvfrom(g_pcm_udp_sock,
(void *)g_u8_recv_buf,
sizeof(g_u8_recv_buf),
MSG_DONTWAIT,
(struct sockaddr *)&peer_addr,
&peer_len);
if (recv_len <= 0) {
return 0;
}
#if (PCM_UDP_PRINT_EN != 0)
v_pcm_log_addr_port("[PCM][UDP][RX][SRC]", &peer_addr);
v_pcm_log_hex("[PCM][UDP][RX]", g_u8_recv_buf, (U16_T)recv_len);
#endif
/* 检查最小帧长度 */
if (recv_len < PCM_FRAME_MIN_LEN) {
return 0;
}
memset(&s_frame, 0, sizeof(S_PCM_FRAME));
ps_frame->u16_head = (U16_T)((g_u8_recv_buf[0] << 8) | g_u8_recv_buf[1]);
ps_frame->u8_cmd = g_u8_recv_buf[2];
ps_frame->u8_len = g_u8_recv_buf[3];
// if (ps_frame->u8_len > PCM_FRAME_MAX_DATA_LEN) {
// return 0;
// }
memcpy(ps_frame->u8_data, &g_u8_recv_buf[4], ps_frame->u8_len);
ps_frame->u8_crc = g_u8_recv_buf[4 + ps_frame->u8_len];
ps_frame->u8_tail = g_u8_recv_buf[4 + ps_frame->u8_len + 1];
/* 校验帧合法性 */
// if (u8_pcm_verify_frame(ps_frame) == 0) {
// return 0;
// }
/* 根据功能码分发处理 */
switch (ps_frame->u8_cmd) {
case PCM_CMD_HOST_HEARTBEAT: /* 0x11 主机心跳帧 */
v_pcm_parse_host_heartbeat(ps_frame);
break;
case PCM_CMD_HOST_RESPONSE: /* 0x13 分桩请求应答帧 */
v_pcm_parse_host_response(ps_frame);
break;
default:
/* 未知功能码,忽略 */
break;
}
return 1;
}
/**
* @brief PCM UDP 周期处理函数(终端角色)
*
* 处理逻辑:
* - 每1000ms发送分桩心跳帧(0x10)
* - 每200ms发送分桩请求帧(0x12)
* - 每周期检查通信超时
*
* @param u16_sleep_time_ms 任务周期时间(ms
*/
void v_pcm_udp_periodic_handler(U16_T u16_sleep_time_ms)
{
if (g_pcm_udp_sock < 0) {
return;
}
/* 更新定时器 */
s_pcm_comm.u32_heartbeat_tick += u16_sleep_time_ms;
s_pcm_comm.u32_request_tick += u16_sleep_time_ms;
/* 每1000ms发送分桩心跳帧(0x10) */
if (s_pcm_comm.u32_heartbeat_tick >= PCM_HEARTBEAT_PERIOD_MS) {
s_pcm_comm.u32_heartbeat_tick = 0;
(void)s8_pcm_send_term_heartbeat();
}
/* 每200ms发送分桩请求帧(0x12) */
if (s_pcm_comm.u32_request_tick >= PCM_REQUEST_PERIOD_MS) {
s_pcm_comm.u32_request_tick = 0;
s8_pcm_send_term_request();
}
/* 检查通信超时 */
v_pcm_check_comm_timeout(u16_sleep_time_ms);
}
/**
* @brief 获取主机通信状态
*
* @return U8_T 0超时 1正常
*/
U8_T u8_pcm_get_host_comm_status(void)
{
return s_pcm_comm.s_host.u8_comm_ok;
}
/**
* @brief 获取主机应答枪数据
*
* @param u8_gun_index 枪索引
* @return S_PCM_GUN_HOST_DATA* 主机应答数据指针,失败返回NULL
*/
S_PCM_GUN_HOST_DATA* ps_pcm_get_host_gun_data(U8_T u8_gun_index)
{
if (u8_gun_index >= GUN_MAX_CNT) {
return NULL;
}
if (u8_gun_index >= s_pcm_comm.s_host.u8_gun_num) {
return NULL;
}
return &s_pcm_comm.s_host.s_gun_data[u8_gun_index];
}
/**
* @brief 更新本机(终端)枪数据(由外部模块调用)
*
* @param u8_gun_index 枪索引
* @param ps_data 终端枪数据指针
*/
void v_pcm_update_term_gun_data(U8_T u8_gun_index, const S_PCM_GUN_TERM_DATA *ps_data)
{
if (u8_gun_index >= GUN_MAX_CNT || ps_data == NULL) {
return;
}
memcpy(&s_pcm_comm.s_gun_data[u8_gun_index], ps_data, sizeof(S_PCM_GUN_TERM_DATA));
}
/**
* @brief PCM 通信主处理函数(由 mdu_comm_task 调用)
*
* 该函数在 u8_mdu_type == 0x02 时被 mdu_comm_task 主循环调用。
* 负责 PCM UDP 通信的初始化、周期收发和接收处理。
*
* @param u16_sleep_time_ms 任务周期时间(ms
*/
void v_pcm_comm_gw_action(U16_T u16_sleep_time_ms)
{
static U8_T u8_pcm_init_done = 0;
/* 首次运行时初始化 PCM UDP */
if (u8_pcm_init_done == 0) {
S8_T s8_ret = s8_pcm_udp_init();
if (s8_ret == 0) {
u8_pcm_init_done = 1;
PCM_COMM_LOG("pcm udp init success");
} else {
/* 初始化失败(可能lwIP网络协议栈未就绪),下次循环继续重试 */
return;
}
}
/* PCM UDP 周期处理:发送心跳(1000ms)、发送请求(200ms)、超时检测(5000ms) */
v_pcm_udp_periodic_handler(u16_sleep_time_ms);
/* PCM UDP 非阻塞接收处理 */
(void)u8_pcm_udp_recv_process();
}