/*****************************************************************************
* file lib/process/pd_dbg.c
* author YuLiang
* version 1.0.0
* date 01-June-2023
* brief This file provides all the debug server related operation functions.
******************************************************************************
* Attention
*
*
© COPYRIGHT(c) 2021 LandPower
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of LandPower nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef CFG_DEV_TYPE_LAND_PD
/* 标准C库头文件. */
#include
#include
#include
#include
#include
#include
/* 用户代码头文件. */
#include "cJSON.h"
#include "main.h"
#include "mtimer.h"
#include "pd_dbg.h"
#include "pd_csg.h"
#include "pd_dau.h"
#include "pd_upgrade.h"
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
enum DEBUG_CMD_TYPE
{
DEBUG_CMD_INFO_GET = 1,
DEBUG_CMD_INFO_SET = 2,
DEBUG_CMD_SLOT_GET = 3,
DEBUG_CMD_STATE_SEND = 4,
DEBUG_CMD_UPDATE = 5,
DEBUG_CMD_UPDATE_RV = 6
};
/* 报文头结构. */
typedef struct
{
uint16_t len;
uint8_t dev_type_m;
uint8_t dev_type_s;
uint32_t dev_id;
uint8_t cmd_type;
uint8_t cmd;
uint16_t pkt_id;
uint8_t version;
uint8_t reserve[19];
} debug_pkt_head_t;
/* 设备信息 */
typedef struct
{
uint8_t type_m; // 主设备号
uint8_t type_s; // 次设备号
uint8_t slot; // slot id
uint8_t reserved0[1]; // 保留
uint32_t dev_id; // 设备ID
char hostname[FILE_NAME_LEN]; // 设备名 128byte
uint32_t factory_date; // 出厂日期.
uint32_t deployment_date; // 部署日期.
uint8_t app_version[DEV_VERSION_STR_LEN]; // 软件版本
uint8_t app_compile_time[DEV_VERSION_STR_LEN]; // 软件编译时间
uint8_t hardware_version[DEV_VERSION_STR_LEN]; // 硬件版本
uint8_t FPGA_version[DEV_VERSION_STR_LEN]; // fpga版本
uint32_t ip; // 本机 IP.
uint32_t mask; // 本机 MASK.
uint32_t gw; // 本机网关
uint8_t mac[6]; // MAC地址.
uint16_t server_port; // 服务器端口号.
uint32_t server_ipv4; // 服务器 IP.
uint8_t port[8];
uint8_t port_type[8];
} debug_pkt_info_t;
/* 设备信息 */
typedef struct
{
uint8_t is_insert;
uint8_t is_connect;
uint8_t port_sum;
uint8_t reserved0;
} debug_pkt_slot_state_t;
/* 设备信息 */
typedef struct
{
debug_pkt_info_t info;
debug_pkt_slot_state_t state;
} debug_pkt_slot_t;
/* 设备信息 */
typedef struct
{
uint32_t utc;
uint32_t run_time;
uint8_t is_insert[PD_SLOTS_MAX];
uint8_t is_connect[PD_SLOTS_MAX];
} debug_pkt_state_t;
typedef struct
{
uint32_t index;
uint32_t len;
} debug_pkt_msg_t;
/* Private variables ---------------------------------------------------------*/
debug_ctrl_t debug_ctrl;
/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* 包头填充. */
void _debug_pkt_head_init(uint8_t *buf, uint16_t len, uint8_t cmd)
{
debug_pkt_head_t *head = (debug_pkt_head_t*)buf;
/* 封装报文头. */
head->len = len;
head->dev_type_m = device_info.type_m;
head->dev_type_s= device_info.type_s;
head->dev_id = device_info.dev_id;
head->cmd = cmd;
}
/* 数据发送 */
void _debug_pkt_send(uint8_t *buf, uint16_t len)
{
int32_t rv = 0;
//printh("#Send %d:\r\n", len);
//buf_print((char*)buf, len > 64 ? 64 : len);
//printh("\r\n");
rv = sendto(debug_ctrl.fd, buf, len, 0, (struct sockaddr*)&debug_ctrl.server, sizeof(debug_ctrl.server));
if (rv < 0)
{
DBG(DBG_M_DEBUG, "Sendto return %s!\r\n", safe_strerror(errno));
}
}
int32_t _debug_recv_info_get(uint8_t *buf, int32_t len)
{
debug_pkt_info_t *pinfo = (debug_pkt_info_t*)(buf + sizeof(debug_pkt_head_t));
memcpy(&debug_ctrl.server, &debug_ctrl.state.server, sizeof(struct sockaddr_in));
debug_ctrl.state.is_connect = TRUE;
pinfo->type_m = device_info.type_m;
pinfo->type_s = device_info.type_s;
pinfo->dev_id = device_info.dev_id;
snprintf(pinfo->hostname, FILE_NAME_LEN, "%s", device_info.hostname);
pinfo->factory_date = device_info.factory_date;
pinfo->deployment_date = device_info.deployment_date;
snprintf((char*)pinfo->app_version, DEV_VERSION_STR_LEN, "%s", device_info.app_version);
snprintf((char*)pinfo->app_compile_time, DEV_VERSION_STR_LEN, "%s", device_info.app_compile_time);
snprintf((char*)pinfo->hardware_version, DEV_VERSION_STR_LEN, "%s", device_info.hardware_version);
snprintf((char*)pinfo->FPGA_version, DEV_VERSION_STR_LEN, "%s", device_info.FPGA_version);
pinfo->ip = device_info.ip;
pinfo->mask = device_info.mask;
pinfo->gw = device_info.gw;
pinfo->server_port = csg.server_port;
pinfo->server_ipv4 = csg.server_ip;
/* 封装报文头. */
_debug_pkt_head_init(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_info_t), DEBUG_CMD_INFO_GET);
/* 发送报文 */
_debug_pkt_send(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_info_t));
return E_NONE;
}
int32_t _debug_recv_info_set(uint8_t *buf, int32_t len)
{
debug_pkt_info_t *pinfo = (debug_pkt_info_t*)(buf + sizeof(debug_pkt_head_t));
uint8_t mac[MAC_ADDR_LEN] = {0};
bool change_ip = FALSE;
device_info.dev_id = pinfo->dev_id;
snprintf(device_info.hostname, FILE_NAME_LEN, "%s", pinfo->hostname);
snprintf((char*)pinfo->hardware_version, DEV_VERSION_STR_LEN, "%s", device_info.hardware_version);
if (device_info.ip != pinfo->ip)
{
device_info.ip = pinfo->ip;
change_ip = TRUE;
}
device_info.mask = pinfo->mask;
device_info.gw = pinfo->gw;
csg.server_port = pinfo->server_port;
csg.server_ip = pinfo->server_ipv4;
device_info.factory_date = pinfo->factory_date;
/* 封装报文头. */
_debug_pkt_head_init(buf, sizeof(debug_pkt_head_t), DEBUG_CMD_INFO_SET);
/* 发送报文 */
_debug_pkt_send(buf, sizeof(debug_pkt_head_t));
/* 保存配置 */
vtysh_config_save();
if (change_ip)
{
mac_generate_from_ip(device_info.ip, mac);
memcpy(device_info.mac, mac, MAC_ADDR_LEN);
vtysh_eth0_save();
}
vtysh_device_save();
return E_NONE;
}
int32_t _debug_recv_slot_get(uint8_t *buf, int32_t len)
{
debug_pkt_slot_t *pinfo = (debug_pkt_slot_t*)(buf + sizeof(debug_pkt_head_t));
dau_contact_t *dau = NULL;
uint32_t slot = *(uint32_t*)(buf + sizeof(debug_pkt_head_t));
if (slot > PD_SLOTS_MAX
|| slot < 1)
{
return E_BAD_PARAM;
}
slot--;
if (daus[slot].state.is_connect)
{
dau = &daus[slot].info;
pinfo->info.type_m = dau->type_m;
pinfo->info.type_s = dau->type_s;
pinfo->info.slot = slot + 1;
pinfo->info.dev_id = dau->dev_id;
snprintf(pinfo->info.hostname, FILE_NAME_LEN, "%s", dau->hostname);
pinfo->info.factory_date = dau->factory_date;
pinfo->info.deployment_date = dau->deployment_date;
snprintf((char*)pinfo->info.app_version, DEV_VERSION_STR_LEN, "%s", dau->app_version);
snprintf((char*)pinfo->info.app_compile_time, DEV_VERSION_STR_LEN, "%s", dau->app_compile_time);
snprintf((char*)pinfo->info.hardware_version, DEV_VERSION_STR_LEN, "%s", dau->hardware_version);
snprintf((char*)pinfo->info.FPGA_version, DEV_VERSION_STR_LEN, "%s", dau->FPGA_version);
pinfo->info.ip = dau->ip;
pinfo->info.mask = dau->mask;
pinfo->info.gw = dau->gw;
pinfo->info.server_port = dau->server_port;
pinfo->info.server_ipv4 = dau->server_ipv4;
pinfo->state.is_insert = daus[slot].state.is_insert;
pinfo->state.is_connect = daus[slot].state.is_connect;
pinfo->state.port_sum = daus[slot].state.port_sum;
}
else
{
pinfo->info.type_m = 0;
pinfo->info.type_s = 0;
}
/* 封装报文头. */
_debug_pkt_head_init(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_slot_t), DEBUG_CMD_SLOT_GET);
/* 发送报文 */
_debug_pkt_send(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_slot_t));
return E_NONE;
}
int32_t _debug_recv_state_get(uint8_t *buf, int32_t len)
{
debug_ctrl.state.state_cnt = 0;
return E_NONE;
}
/* 升级文件接收 */
int32_t _debug_recv_update(uint8_t *buf, int32_t len)
{
static int fd = -1;
debug_pkt_msg_t *head_msg = (debug_pkt_msg_t*)(buf + sizeof(debug_pkt_head_t));
char *data = (char*)(buf + sizeof(debug_pkt_head_t) + sizeof(debug_pkt_msg_t));
int32_t len_wr = 0;
/* 首保处理, 打开文件描述符, 初始化变量 */
if (0 == head_msg->index)
{
if (fd > 0)
{
close(fd);
fd = -1;
}
fd = open(PD_UPG_SOFTWARE, O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd < 0)
{
DBG(DBG_M_DEBUG, "Open file " PD_UPG_SOFTWARE " error!\n");
return E_SYS_CALL;
}
}
/* 收包流程 */
len_wr = write(fd, data, head_msg->len);
if (len_wr != head_msg->len)
{
DBG(DBG_M_DEBUG, "Write file " PD_UPG_SOFTWARE " error!\n");
return E_SYS_CALL;
}
/* 封装报文头. */
_debug_pkt_head_init(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_msg_t), DEBUG_CMD_UPDATE);
/* 发送报文 */
_debug_pkt_send(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_msg_t));
/* 最后一个报文处理 */
if (head_msg->len < 1024)
{
close(fd);
fd = -1;
DBG(DBG_M_DEBUG, "Receive upgrade file end.\r\n");
pd_upg_start(PD_UPG_FROM_DBG, PD_UPG_SEL_CMU);
}
return E_NONE;
}
/* 报文校验. */
int32_t _debug_recv_check(uint8_t *buf, int len)
{
debug_pkt_head_t *head = (debug_pkt_head_t*)buf;
/* 报文长度检查 */
if (head->len > DEBUG_BUG_SIZE)
{
return E_ERROR;
}
/* 只收主控设备 */
if (head->dev_type_m != 3 || head->dev_type_s != 99)
{
return E_ERROR;
}
if (debug_ctrl.state.is_connect && debug_ctrl.server.sin_addr.s_addr != debug_ctrl.state.server.sin_addr.s_addr)
{
return E_ERROR;
}
return E_NONE;
}
/* 调试工具报文数据处理. */
int32_t _debug_recv_process(uint8_t *buf, int32_t len)
{
debug_pkt_head_t *head = (debug_pkt_head_t*)buf;
/* 报文格式检查. */
LD_E_RETURN(DBG_M_DEBUG, _debug_recv_check(buf, len));
/* 报文处理. */
switch(head->cmd)
{
case DEBUG_CMD_INFO_GET:
_debug_recv_info_get(buf, len);
break;
case DEBUG_CMD_INFO_SET:
_debug_recv_info_set(buf, len);
break;
case DEBUG_CMD_SLOT_GET:
_debug_recv_slot_get(buf, len);
break;
case DEBUG_CMD_STATE_SEND:
_debug_recv_state_get(buf, len);
break;
case DEBUG_CMD_UPDATE:
_debug_recv_update(buf, len);
break;
default:
DBG(DBG_M_DEBUG, "Debug not support cmd:%x\n", head->cmd);
break;
}
return E_NONE;
}
/* 调试工具报文接收处理线程. */
void *_debug_recv_handle(void *arg)
{
struct sockaddr_in server;
socklen_t server_len = sizeof(struct sockaddr_in);
uint16_t data_len = 0;
/* 等待初始化完成 */
while(!is_system_init)
{
sleep(1);
}
while(1)
{
/* 读取数据. */
data_len = recvfrom(debug_ctrl.fd, debug_ctrl.buf, DEBUG_BUG_SIZE, 0, (struct sockaddr*)&server, &server_len);
if (data_len <= 0)
{
DBG(DBG_M_DEBUG, "Recvfrom return ERROR %s!\r\n", safe_strerror(errno));
continue;
}
//printh("#Recv %d:\r\n", data_len);
//buf_print((char*)debug_ctrl.buf, data_len > 64 ? 64 : data_len);
//printh("\r\n");
/* 收包长度小于头长度则不处理 */
if (data_len < sizeof(debug_pkt_head_t))
{
continue;
}
memcpy(&debug_ctrl.state.server, &server, sizeof(struct sockaddr_in));
_debug_recv_process(debug_ctrl.buf, data_len);
}
return NULL;
}
int32_t _debug_send_state(void)
{
uint8_t *buf = debug_ctrl.buf_send;
debug_pkt_state_t *pinfo = (debug_pkt_state_t*)(buf + sizeof(debug_pkt_head_t));
uint8_t i = 0;
/* 封装报文头. */
_debug_pkt_head_init(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_state_t), DEBUG_CMD_STATE_SEND);
pinfo->utc = time(NULL);
pinfo->run_time = start_time;
for(i = 0; i < PD_SLOTS_MAX; i++)
{
pinfo->is_insert[i] = daus[i].state.is_insert;
pinfo->is_connect[i] = daus[i].state.is_connect;
}
/* 发送报文 */
_debug_pkt_send(buf, sizeof(debug_pkt_head_t) + sizeof(debug_pkt_state_t));
return E_NONE;
}
/* 调试工具报文接收处理线程. */
void *_debug_send_handle(void *arg)
{
/* 等待初始化完成 */
while(!is_system_init)
{
sleep(1);
}
while(1)
{
sleep(3);
if (debug_ctrl.state.is_connect)
{
_debug_send_state();
debug_ctrl.state.state_cnt++;
if (debug_ctrl.state.state_cnt > 3)
{
debug_ctrl.state.is_connect = FALSE;
debug_ctrl.state.state_cnt = 0;
}
}
}
return NULL;
}
/* Interface functions -------------------------------------------------------*/
/* 调试工具初始化. */
int32_t debug_handle_init(void)
{
return E_NONE;
}
int32_t debug_handle_init_after(void)
{
struct sockaddr_in server;
thread_param_t param = {0};
int fd = 0;
/* 创建 socket. */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
log_err(LOG_DEBUG, "ERROR at socket create 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(42971);
if(bind(fd, (struct sockaddr*)&server, sizeof(server)) < 0)
{
log_err(LOG_CSG, "ERROR at socket bind return %s!", safe_strerror(errno));
close(fd);
return E_SYS_CALL;
}
/* 保存数据. */
debug_ctrl.fd = fd;
param.priority = 25;
param.log_module = LOG_DEBUG;
snprintf(param.thread_name, THREAD_NAME_LEN, "DEBUG_RECV");
create_thread(_debug_recv_handle, ¶m);
param.priority = 25;
param.log_module = LOG_DEBUG;
snprintf(param.thread_name, THREAD_NAME_LEN, "DEBUG_STATE");
create_thread(_debug_send_handle, ¶m);
return E_NONE;
}
/* 升级结果回复处理 */
void debug_upgrade_result_send(int32_t rv, char *buf)
{
uint8_t *buf_send = debug_ctrl.buf_update;
int32_t *ret = (int32_t*)(buf_send + sizeof(debug_pkt_head_t));
/* 封装报文头. */
_debug_pkt_head_init(buf_send, sizeof(debug_pkt_head_t) + sizeof(int32_t), DEBUG_CMD_UPDATE_RV);
/* 0-错误 1-正常 */
*ret = rv;
/* 发送报文 */
_debug_pkt_send(buf_send, sizeof(debug_pkt_head_t) + sizeof(int32_t));
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/