You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

637 lines
15 KiB
C

/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef CFG_DEV_TYPE_LAND_PD
/* 标准C库头文件. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/prctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <termios.h>
#include <fcntl.h>
/* 用户代码头文件. */
#include "main.h"
#include "cmd.h"
#include "fifo.h"
#include "pd_dau.h"
#include "pd_hf.h"
#include "pd_csg.h"
/* Define --------------------------------------------------------------------*/
#define DUA_UDP_PORT 23760
#define DUA_SEND_FIFO_NUM (8)
/* Private typedef -----------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
dau_t daus[PD_SLOTS_MAX];
const char *pd_sync_str[PD_SYNC_MAX] =
{
"",
"pt",
"inside",
"outside"
};
const char *pd_pps_str[PD_PPS_MAX] =
{
"auto",
"master",
"slave"
};
const char *pd_protocol_str[PD_PROTOCOL_MAX] =
{
"land",
"csg"
};
/* DAU 端口类型分类 */
const char *dau_port_type_str[PD_PORT_TYPE_COUNT] =
{
"",
"uhf",
"ae",
"tev",
"hf"
};
/* DAU 端口降噪类型分类. */
const char *pd_noise_type_str[PD_DENOISE_TYPE_COUNT] =
{
"none",
"auto",
"manual",
"variance"
};
/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* 显示 DAU */
void _dau_show_slot(uint8_t slot)
{
struct sockaddr_in server;
dau_contact_t *dau = &daus[slot].info;
char buf[128] = {0};
time_t temp = 0;
printh("APP version %s (%08x)\r\n", dau->app_version, dau->dev_id);
printh("APP Compile date: %s\r\n", dau->app_compile_time);
printh("FPGA version %s\r\n", dau->FPGA_version);
printh("HW version %s\r\n", dau->hardware_version);
printh("Id: %03d.%03d\r\n", dau->type_m, dau->type_s);
printh("Mac: %02x:%02x:%02x:%02x:%02x:%02x\r\n",dau->mac[0], dau->mac[1], dau->mac[2],
dau->mac[3], dau->mac[4], dau->mac[5]);
server.sin_addr.s_addr = dau->ip;
printh("ip: %s\r\n", inet_ntoa(server.sin_addr));
server.sin_addr.s_addr = dau->mask;
printh("%s\r\n", inet_ntoa(server.sin_addr));
server.sin_addr.s_addr = dau->gw;
printh("route: %s\r\n", inet_ntoa(server.sin_addr));
temp = dau->factory_date;
strftime(buf, 128, "%Y-%m-%d %H:%M:%S", localtime(&temp));
printh("factory date: %s\r\n", buf);
temp = dau->deployment_date;
strftime(buf, 128, "%Y-%m-%d %H:%M:%S", localtime(&temp));
printh("deployment date: %s\r\n\n", buf);
return;
}
/* 显示 DAU 状态 */
void _dau_show_state(void)
{
uint8_t i = 0;
dau_state_t *state = NULL;
printh("SL IN CO PS TO\r\n");
for(i = 0; i < PD_SLOTS_MAX; i++)
{
state = &daus[i].state;
printh("%-02d %-02d %-02d %-02d %-05d\r\n", i + 1, state->is_insert, state->is_connect, state->port_sum, state->beat_cnt);
}
printh("\n");
return;
}
/* 连接超时时间 */
CMD(dau_connect_timeout,
dau_connect_timeout_cmd,
"connect-timeout <1-1440>",
"Connect timeout\n"
"Timeout time: min\n")
{
uint8_t slot = pd_slot_node.param_num;
pd_config.config_slot[slot].timeout = strtol(argv[0], NULL, 10);
return CMD_SUCCESS;
}
/* Slot 状态显示 */
CMD(dau_slot_show,
dau_slot_show_cmd,
"show slot <1-8>",
"Show\n"
"Slot\n"
"Slot id\n")
{
uint8_t slot = strtol(argv[0], NULL, 10);
_dau_show_slot(slot - 1);
return CMD_SUCCESS;
}
/* Slot 状态显示 */
CMD(dau_state_show,
dau_state_show_cmd,
"show slot state",
"Show\n"
"Slot\n"
"State\n")
{
_dau_show_state();
return CMD_SUCCESS;
}
/* Slot 全局配置显示 */
CMD(dau_cfg_show,
dau_cfg_show_cmd,
"show slot cfg <1-8>",
"Show\n"
"Slot\n"
"Config\n"
"Slot id\n")
{
uint8_t slot = strtol(argv[0], NULL, 10);
dau_t *dau = &daus[slot - 1];
if (dau->show_cfg_cb)
{
dau->show_cfg_cb(dau->slot);
}
return CMD_SUCCESS;
}
/* Slot 端口配置显示 */
CMD(dau_port_show,
dau_port_show_cmd,
"show slot <1-8> port <1-8> ",
"Show\n"
"Slot\n"
"Slot id\n"
"Port\n"
"Port id\n")
{
uint8_t slot = strtol(argv[0], NULL, 10);
uint8_t port = strtol(argv[1], NULL, 10);
dau_t *dau = &daus[slot - 1];
if (port > dau->state.port_sum)
{
return CMD_ERR_NO_MATCH;
}
if (dau->show_port_cb)
{
dau->show_port_cb(dau->slot, port - 1);
}
return CMD_SUCCESS;
}
/* 包头填充 */
void _dau_head_init(dau_t *dau, dau_head_init_t *head_data)
{
dau_pkt_head_t *head = (dau_pkt_head_t*)head_data->pkt;
/* 封装报文头. */
head->len = head_data->len;
head->dev_type_m = dau->info.type_m;
head->dev_type_s= dau->info.type_s;
head->dev_id = dau->info.dev_id;
head->cmd_type = head_data->cmd_type;
head->cmd = head_data->cmd;
head->version = 1;
head->pkt_id = head_data->pkt_id;
}
/* dau 接入处理 */
int _dau_insert(dau_t *dau)
{
if (3 == dau->info.type_m && 1 == dau->info.type_s)
{
/* 申请和释放放在一起, 避免地址失效 */
if (dau->private_data && dau->free_cb)
{
dau->free_cb(dau->slot);
}
dau->private_data = hf_data_malloc();
dau->recv_cb = hf_recv_process;
dau->send_cb = hf_send_process;
dau->free_cb = hf_data_free;
dau->show_cfg_cb = hf_show_cfg;
dau->show_port_cb = hf_show_port;
}
else
{
return E_NOT_FOUND;
}
dau->state.beat_cnt = 0;
dau->state.is_connect = TRUE;
return E_NONE;
}
/* dau 移除处理 */
int _dau_remove(dau_t *dau)
{
dau->recv_cb = NULL;
dau->send_cb = NULL;
dau->show_cfg_cb = NULL;
dau->show_port_cb = NULL;
dau->state.is_connect = FALSE;
return E_NONE;
}
/* 初始化UDP服务器 */
int32_t _dau_udp_server_init(dau_t *dau)
{
struct sockaddr_in server = {0};
int fd = -1;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
log_err(LOG_DAU, "ERROR at socket creating return %s!", safe_strerror(errno));
return E_SYS_CALL;
}
/* 绑定端口 */
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(DUA_UDP_PORT + dau->slot);
if (bind(fd, (struct sockaddr*)&server, sizeof(server)) < 0)
{
log_err(LOG_DAU, "ERROR at socket bind return %s!", safe_strerror(errno));
close(fd);
return E_SYS_CALL;
}
dau->fd = fd;
return E_NONE;
}
/* dau 开机联络处理函数 */
void _dau_recv_connect(dau_t *dau, uint16_t recv_len)
{
dau_head_init_t head_data;
dau_pkt_head_t *head = (dau_pkt_head_t*)dau->buf_recv;
dau_contact_t *pnet = (dau_contact_t*)(dau->buf_recv + sizeof(dau_pkt_head_t));
dau_ack_t *ack = (dau_ack_t*)(dau->buf_recv + sizeof(dau_pkt_head_t));
dau_contact_t *info = NULL;
uint8_t i = 0;
/* 如果当前状态还是连接状态先释放内存 */
if (dau->state.is_connect)
{
LD_N_RETURN_N(_dau_remove(dau));
}
/* 复制设备信息 */
memcpy(&dau->info, pnet, sizeof(dau_contact_t));
dau->state.port_sum = 0;
for(i = 0; i < PD_DAU_PORT_SUM; i++)
{
if (pnet->port[i])
{
dau->state.port_sum++;
}
}
/* 回复报文 */
ack->result = 0;
head_data.cmd_type = DAU_REQUEST;
head_data.cmd = DAU_C_CONTACT;
head_data.pkt_id = head->pkt_id;
head_data.pkt = dau->buf_recv;
head_data.len = sizeof(dau_pkt_head_t) + sizeof(dau_ack_t);
dau_data_send(dau, &head_data);
/* 添加 dau */
LD_N_RETURN_N(_dau_insert(dau));
/* 给后台发送添加信息 */
/* 申请内存 */
info = XMALLOC(MTYPE_CSG, sizeof(dau_contact_t));
if (!info)
{
DBG(DBG_M_PD_DAU_ERR, "XMALLOC ERROR!\r\n");
return;
}
/* 复制设备信息 */
memcpy(info, &dau->info, sizeof(dau_contact_t));
/* 发送给后台 */
if (dau_msg_send_cmd(DAU_SEND_ADD, dau->slot, info) != E_NONE)
{
XFREE(MTYPE_CSG, info);
}
return;
}
/* dau 数据包处理函数 */
void _dau_recv_data_process(dau_t *dau, uint16_t recv_len, struct sockaddr_in *server)
{
dau_pkt_head_t *head = (dau_pkt_head_t*)dau->buf_recv;
if (DAU_REPLY == head->cmd_type && DAU_C_CONTACT == head->cmd)
{
/* 响应连接报文 */
if (head->len > DAU_BUF_SIZE)
{
DBG(DBG_M_PD_DAU_ERR, "Recvfrom len %d ERROR!\r\n", head->len);
return;
}
memcpy(&dau->server, server, sizeof(struct sockaddr_in));
_dau_recv_connect(dau, recv_len);
}
else
{
/* 响应其他报文 */
if (dau->recv_cb)
{
dau->recv_cb(dau->slot, dau->buf_recv, recv_len);
}
}
return;
}
/* dau 收包线程 */
void *_dau_recv_handle(void *arg)
{
dau_t *dau = (dau_t*)arg;
struct sockaddr_in server;
socklen_t server_len = sizeof(struct sockaddr_in);
uint16_t data_len = 0;
/* 初始化 socket */
if (_dau_udp_server_init(dau) != E_NONE)
{
return NULL;
}
/* 等待初始化完成 */
while(!is_system_init)
{
sleep(1);
}
while(1)
{
/* 读取数据. */
data_len = recvfrom(dau->fd, dau->buf_recv, DAU_BUF_SIZE, 0, (struct sockaddr*)&server, &server_len);
if (data_len <= 0)
{
DBG(DBG_M_PD_DAU_ERR, "Recvfrom return ERROR %s!\r\n", safe_strerror(errno));
continue;
}
_dau_recv_data_process(dau, data_len, &server);
}
return NULL;
}
/* dau 收包线程 */
void *_dau_send_handle(void *arg)
{
dau_t *dau = (dau_t*)arg;
dau_send_msg_t *recv_msg = NULL;
/* 等待初始化完成 */
while(!is_system_init)
{
sleep(1);
}
while(1)
{
if (fifo_read(dau->fifo_send, (void**)&recv_msg) != 0)
{
DBG(DBG_M_PD_DAU_ERR, "ERROR at fifo %d read!\r\n", dau->fifo_send);
continue;
}
/* 响应其他报文 */
if (dau->send_cb)
{
dau->send_cb(dau->slot, recv_msg->type, recv_msg->data);
}
/* 释放数据内存, 注意一定要在 fifo_push 之前调用, 因为 fifo_push 后 recv_msg 已被释放. */
XFREE(MTYPE_CSG, recv_msg->data);
fifo_push(dau->fifo_send);
}
return NULL;
}
/* dau 收包线程 */
void *_dau_state_handle(void *arg)
{
dau_state_t *state = NULL;
uint8_t i = 0;
/* 等待初始化完成 */
while(!is_system_init)
{
sleep(1);
}
while(1)
{
sleep(1);
for(i = 0; i < PD_SLOTS_MAX; i++)
{
state = &daus[i].state;
if (state->is_connect)
{
state->beat_cnt++;
if (state->beat_cnt > pd_config.config_slot[i].timeout * 60)
{
log_warn(LOG_DAU, "Slot %d remove!", i);
_dau_remove(&daus[i]);
}
}
}
}
return NULL;
}
/* config模式配置保存函数: vty -- 相应的终端 */
int _dau_port_config_save(vty_t *vty, uint8_t slot)
{
vty_out(vty, " connect-timeout %d%s", pd_config.config_slot[slot].timeout, VTY_NEWLINE);
return E_NONE;
}
/* Interface functions -------------------------------------------------------*/
/* dau 预初始化 */
int32_t dau_handle_init(void)
{
uint8_t i = 0;
int32_t rv = E_ERROR;
memset(&daus, 0, sizeof(dau_t) * PD_SLOTS_MAX);
for (i = 0; i < PD_SLOTS_MAX; i++)
{
daus[i].slot = i;
}
cmd_install_element(PORT_NODE, &dau_connect_timeout_cmd);
cmd_install_element(COMMON_NODE, &dau_slot_show_cmd);
cmd_install_element(COMMON_NODE, &dau_state_show_cmd);
cmd_install_element(COMMON_NODE, &dau_cfg_show_cmd);
cmd_install_element(COMMON_NODE, &dau_port_show_cmd);
rv = pd_slot_cmd_config_register(PD_PORT_CMD_PRI_DAU, _dau_port_config_save);
if (rv != E_NONE)
{
log_err(LOG_DAU, "DAU port command save register ERROR %d!", rv);
return rv;
}
return E_NONE;
}
/* dau 初始化 */
int32_t dau_handle_init_after(void)
{
thread_param_t param = {0};
char fifo_name[THREAD_NAME_LEN];
uint8_t i = 0;
/* 初始收包线程 */
for (i = 0; i < DAU_ETH_SLOTS_SUM; i++)
{
snprintf(fifo_name, THREAD_NAME_LEN, "DAU_SEND_%d", i);
daus[i].fifo_send = fifo_create(fifo_name, DUA_SEND_FIFO_NUM);
param.arg = (void*)(&daus[i]);
param.priority = 80;
param.log_module = LOG_DAU;
snprintf(param.thread_name, THREAD_NAME_LEN, "DAU_RECV_%d", i);
create_thread(_dau_recv_handle, &param);
param.arg = (void*)(&daus[i]);
param.priority = 50;
param.log_module = LOG_DAU;
snprintf(param.thread_name, THREAD_NAME_LEN, "DAU_SEND_%d", i);
create_thread(_dau_send_handle, &param);
}
/* 监控 dau 状态 */
param.arg = NULL;
param.priority = 20;
param.log_module = LOG_DAU;
snprintf(param.thread_name, THREAD_NAME_LEN, "DAU_STATE");
create_thread(_dau_state_handle, &param);
return E_NONE;
}
/* 数据发送 */
void dau_data_send(dau_t *dau, dau_head_init_t *head_data)
{
int32_t rv = 0;
/* 封装报文头. */
_dau_head_init(dau, head_data);
rv = sendto(dau->fd, head_data->pkt, head_data->len, 0, (struct sockaddr*)&dau->server, sizeof(dau->server));
if (rv < 0)
{
DBG(DBG_M_PD_DAU_ERR, "Sendto return %s!\r\n", safe_strerror(errno));
}
}
/* 发送数据到后台通讯进程. */
int32_t dau_msg_send(uint32_t type, uint8_t slot, void *data)
{
uint32_t fifo = 0;
dau_send_msg_t msg;
if (DAU_SEND_PRPS == type)
{
fifo = csg.fifo_prps_id;
}
else
{
DBG(DBG_M_PD_DAU_ERR, "DAU write ERROR! type=%d\r\n", type);
return E_BAD_PARAM;
}
/* 封装消息. */
msg.type = type;
msg.slot = slot;
msg.data = data;
/* 发送消息 */
if (fifo_write(fifo, (void*)(&msg), sizeof(dau_send_msg_t)) != sizeof(dau_send_msg_t))
{
return E_ERROR;
}
return E_NONE;
}
/* 发送数据到后台通讯进程. */
int32_t dau_msg_send_cmd(uint32_t type, uint8_t slot, void *data)
{
dau_send_msg_t msg;
/* 封装消息. */
msg.type = type;
msg.slot = slot;
msg.data = data;
/* 发送消息 */
if (fifo_write(csg.fifo_cmd_id, (void*)(&msg), sizeof(dau_send_msg_t)) != sizeof(dau_send_msg_t))
{
return E_ERROR;
}
return E_NONE;
}
#endif