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.

633 lines
16 KiB
C

/*****************************************************************************
* file lib/process/pd_main.c
* author YuLiang
* version 1.0.0
* date 07-Feb-2023
* brief This file provides all the partial discharge related operation functions.
******************************************************************************
* Attention
*
* <h2><center>&copy; COPYRIGHT(c) 2021 LandPower</center></h2>
*
* 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 <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include "main.h"
#include "pd_csg.h"
#include "pd_main.h"
#include "pd_dau.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define PD_BOARD_PORT 12345
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
pd_data_t pd_data;
pd_config_t pd_config;
pd_state_t pd_state;
cmd_node_t pd_port_node =
{
PORT_NODE,
CONFIG_NODE,
1,
NULL,
};
/* DAU 端口类型分类. */
static const char *pd_sen_type_str[PD_SEN_TYPE_COUNT] =
{
"",
"sig",
"noise",
"sig-noise"
};
/* DAU 端口降噪类型分类. */
static const char *pd_noise_type_str[PD_DENOISE_TYPE_COUNT] =
{
"none",
"auto",
"manual",
"variance"
};
/* Private function prototypes -----------------------------------------------*/
extern int32_t _pd_port_str_to_unit_port(const char *port_str, uint8_t *unit, uint8_t *port);
/* Internal functions --------------------------------------------------------*/
/* 4G 模块是否使能. */
CMD(pd_4G_enable,
pd_4G_enable_cmd,
"wireless (enable|disable)",
"Wireless\n"
"Enable\n"
"Disable\n")
{
uint8_t enable = FALSE;
if (0 == strncmp(argv[0], "e", 1))
{
enable = TRUE;
}
else
{
enable = FALSE;
}
pd_config.config.is_4G_enable = enable;
return CMD_SUCCESS;
}
/* 4G 模块 APN. */
CMD(pd_4G_APN,
pd_4G_APN_cmd,
"wireless apn WORD",
"Wireless\n"
"APN\n"
"Enable\n"
"Disable\n")
{
snprintf(pd_config.config.APN, PD_4G_APN_LEN, "%s", argv[0]);
return CMD_SUCCESS;
}
/* 通信协议选择. */
CMD(pd_protocol_type,
pd_protocol_type_cmd,
"protocol-type (land|csg)",
"Protocol type\n"
"Land\n"
"Csg\n")
{
uint8_t type = 0;
if (0 == strncmp(argv[0], "land", 4))
{
type = PD_PROTOCOL_LAND;
}
else if (0 == strncmp(argv[0], "csg", 3))
{
type = PD_PROTOCOL_CSG;
}
else
{
type = PD_PROTOCOL_LAND;
}
pd_config.config.protocol_type = type;
return CMD_SUCCESS;
}
/* 显示 DAU 状态. */
CMD(show_pd,
show_pd_cmd,
"show pd",
"Show\n"
"Partial discharge\n")
{
pd_show();
return CMD_SUCCESS;
}
/* 配置保存函数. */
int _pd_config_save(vty_t* vty)
{
int16_t i = 0;
switch (pd_config.config.protocol_type)
{
case PD_PROTOCOL_LAND:
vty_out(vty, "protocol-type land%s", VTY_NEWLINE);
i++;
break;
case PD_PROTOCOL_CSG:
vty_out(vty, "protocol-type csg%s", VTY_NEWLINE);
i++;
break;
default:
break;
}
vty_out(vty, "evnet-amount %d%s", pd_config.config.event_storage, VTY_NEWLINE);
i++;
vty_out(vty, "trend-interval %d%s", pd_config.config.trend_period / 60, VTY_NEWLINE);
i++;
vty_out(vty, "trend-amount %d%s", pd_config.config.trend_storage, VTY_NEWLINE);
i++;
vty_out(vty, "heartbeat-interval %d%s", pd_config.config.heartbeat_period, VTY_NEWLINE);
i++;
switch(pd_config.config.sync_mode)
{
case PD_SYNC_PT:
vty_out(vty, "sync-mode pt%s", VTY_NEWLINE);
i++;
break;
case PD_SYNC_INSIDE:
vty_out(vty, "sync-mode inside%s", VTY_NEWLINE);
i++;
break;
case PD_SYNC_OUTSIDE:
vty_out(vty, "sync-mode outside%s", VTY_NEWLINE);
i++;
break;
default:
break;
}
vty_out(vty, "sync-inside %d%s", pd_config.config.power_frequency, VTY_NEWLINE);
i++;
switch(pd_config.config.pps_mode)
{
case PD_PPS_AUTO:
vty_out(vty, "pps-mode auto%s", VTY_NEWLINE);
i++;
break;
case PD_PPS_MASTER:
vty_out(vty, "pps-mode master%s", VTY_NEWLINE);
i++;
break;
case PD_PPS_SLAVE:
vty_out(vty, "pps-mode slave%s", VTY_NEWLINE);
i++;
break;
default:
break;
}
vty_out(vty, "wireless %s%s", pd_config.config.is_4G_enable ? "enable" : "disable", VTY_NEWLINE);
i++;
vty_out(vty, "wireless apn %s%s", pd_config.config.APN, VTY_NEWLINE);
i++;
return i;
}
/* 将端口字符串, 转换成 unit port 格式. */
int32_t _pd_port_str_to_unit_port(const char *port_str, uint8_t *unit, uint8_t *port)
{
char *str = NULL;
char *p = NULL;
char temp[8];
uint8_t len = 0;
uint8_t i = 0;
snprintf(temp, 8, "%s", port_str);
str = strtok_r(temp, "/", &p);
while(str != NULL)
{
/* 检查长度. */
if (len >= 2)
{
return E_BAD_PARAM;
}
/* 检查字符串 */
for(i = 0; str[i] && str[i] != '\0'; i++)
{
if (!(str[i] >= '0' && str[i] <= '9'))
{
return E_BAD_PARAM;
}
}
/* 检查数据长度 */
if (i != 1)
{
return E_BAD_PARAM;
}
/* 读取板卡和端口号. */
if (0 == len)
{
*unit = strtol(str, NULL, 10) - 1;
}
else
{
*port = strtol(str, NULL, 10) - 1;
}
len++;
/* 获取下个数据 */
str = strtok_r(NULL, "/", &p);
}
return E_NONE;
}
/* 广播接收程序 */
void *_pd_broadcast_handle(void *arg)
{
struct sockaddr_in broad_addr;
struct sockaddr_in peer_addr;
socklen_t addr_len = 0;
char packet[1024];
int fd = 0;
int len = 0;
int rv = -1;
/* 创建报文套接字 */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
log_err(LOG_PD, "Fail to open broadcast socket.");
return NULL;
}
bzero(&broad_addr, sizeof(broad_addr));
broad_addr.sin_family = AF_INET;
broad_addr.sin_port = htons(PD_BOARD_PORT);
broad_addr.sin_addr.s_addr = INADDR_ANY;
rv = bind(fd, (struct sockaddr *)&broad_addr, sizeof(broad_addr));
if (-1 == rv)
{
log_err(LOG_PD, "Fail to bind broad socket.");
return NULL;
}
while (1)
{
/* 接收广播 */
len = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addr_len);
if (-1 == len)
{
continue;
}
packet[len] = '\0';
if (strncmp(packet, "hello", 5) == 0)
{
len = snprintf(packet, 1024, "world,GIS7.0_V%s,", softversion_get());
snprintf(packet + len, 1024 - len, "%s", device_info.hostname);
sendto(fd, packet, strlen(packet) + 1, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));
}
}
/* 关闭套接字 */
close(fd);
return NULL;
}
int32_t _pd_broadcast_init(void)
{
struct sched_param param;
pthread_attr_t attr;
pthread_t pid;
int32_t rv = E_NONE;
/* 初始化广播报文处理线程. */
/* 配置线程RR调度, 优先级25 */
pthread_attr_init(&attr);
param.sched_priority = 25;
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
rv = pthread_create(&pid, &attr, _pd_broadcast_handle, NULL);
if (rv != 0)
{
log_err(LOG_PD, "PD can't create broadcast pthread %d!", rv);
return E_SYS_CALL;
}
else
{
thread_m_add("PD_BROADCAST", pid);
}
pthread_attr_destroy(&attr);
return E_NONE;
}
/* 4G 模块服务程序 */
void *_pd_4G_handle(void *arg)
{
struct ifaddrs *ifa = NULL, *ifList = NULL;
int8_t err_cnt = 0;
bool is_found = FALSE;
char cmd[256];
/* 上电拨号 */
sleep(30);
snprintf(cmd, 256, "/etc/ppp/peers/quectel-pppd.sh /dev/ttyUSB3 %s", pd_config.config.APN);
system(cmd);
while(1)
{
sleep(40);
/* 查询 4G 是否连接 */
is_found = FALSE;
if (getifaddrs(&ifList) < 0)
{
//err_cnt++;
continue;
}
for(ifa = ifList; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
{
continue;
}
if (ifa->ifa_addr->sa_family != AF_INET)
{
continue;
}
if (strncmp(ifa->ifa_name, "ppp0", 4))
{
continue;
}
is_found = TRUE;
break;
}
freeifaddrs(ifList);
/* 没有连接, 重新拨号 */
if (is_found)
{
pd_state.is_4G_connect = TRUE;
err_cnt = 0;
continue;
}
else
{
pd_state.is_4G_connect = FALSE;
DBG(DBG_M_PD, "4G connect start...\r\n");
err_cnt++;
if(err_cnt > 64)
{
/* 每 64 分钟没有拨号成功则重启 */
reboot_system(LOG_PD, REBOOT_4G_ERROR);
continue;
}
/* 每 8 分钟拨号一次 */
if (0 == (err_cnt & 0x7))
{
/* 重新拨号 */
log_warn(LOG_PD, "Wireless dialing restart!");
system("/etc/ppp/peers/quectel-ppp-kill");
sleep(20);
snprintf(cmd, 256, "/etc/ppp/peers/quectel-pppd.sh /dev/ttyUSB3 %s", pd_config.config.APN);
system(cmd);
}
}
}
return NULL;
}
int32_t _pd_main_init(void)
{
uint8_t i = 0;
uint8_t j = 0;
int32_t rv = 0;
/* 初始化基本参数. */
for(i = 0; i < PD_DAU_SUM; i++)
{
for(j = 0; j < PD_DAU_PORT_SUM; j++)
{
pd_config.config_port[i][j].port_type = PD_PORT_TYPE_HF;
pd_config.config_port[i][j].sensor_type = PD_SEN_TYPE_SIG;
pd_config.config_port[i][j].is_auto_noise = TRUE;
pd_config.config_port[i][j].filter = CSG_FILTER_TYPE_FR;
pd_config.config_real[i][j].filter_cfg = CSG_FILTER_TYPE_FR;
pd_config.config_real[i][j].denoise_type = PD_DENOISE_TYPE_AOTU;
pd_config.config_real[i][j].denoise_manual = 1000;
pd_config.config_port[i][j].denoise_type = PD_DENOISE_TYPE_AOTU;
pd_config.config_port[i][j].denoise_variance = 100;
pd_config.config_port[i][j].burst_time = 5;
pd_config.config_port[i][j].burst_thr = 800;
pd_config.config_port[i][j].event_counter_h = 8000;
pd_config.config_port[i][j].event_sec_h = 800;
pd_config.config_port[i][j].event_counter_thr_h = 8000;
pd_config.config_port[i][j].event_thr_h = 1000;
pd_config.config_port[i][j].event_counter_l = 8000;
pd_config.config_port[i][j].event_sec_l = 800;
pd_config.config_port[i][j].event_counter_thr_l = 8000;
pd_config.config_port[i][j].event_thr_l = 1000;
pd_config.config_port[i][j].denoise_manual = 100;
pd_config.config_port[i][j].denoise_auto = 100;
pd_config.config_port[i][j].auto_noise_cnt = 1600;
}
}
pd_config.config.protocol_type = PD_PROTOCOL_LAND;
pd_config.config.power_frequency = 500;
pd_config.config.sync_mode = PD_SYNC_PT;
pd_config.config.is_4G_enable = FALSE;
snprintf(pd_config.config.APN, PD_4G_APN_LEN, "3gnet");
pd_config.config.trend_period = 900;
pd_config.config.trend_storage = 10;
pd_config.config.event_storage = 500;
pd_config.config.heartbeat_period = 5;
/* 注册配置保存函数 */
rv = cmd_config_node_config_register(CONFIG_PRI_PD, _pd_config_save);
if (rv != E_NONE)
{
log_err(LOG_PD, "Command save register ERROR %d!", rv);
return rv;
}
/* 注册端口节点. */
pd_port_node.prompt = XMALLOC(MTYPE_DAU, PD_PORT_PROMPT_LEN);
pd_port_node.configs = array_init(PD_PORT_CMD_PRI_COUNT, MTYPE_DAU);
cmd_install_element(CONFIG_NODE, &pd_4G_enable_cmd);
cmd_install_element(CONFIG_NODE, &pd_4G_APN_cmd);
cmd_install_element(CONFIG_NODE, &pd_protocol_type_cmd);
cmd_install_element(COMMON_NODE, &show_pd_cmd);
return E_NONE;
}
int32_t _pd_main_init_after(void)
{
struct sockaddr_in addr;
thread_param_t param = {0};
uint8_t i = 0;
uint8_t j = 0;
char cmd[256];
/* 初始化基本参数 */
if (pd_config.config.is_4G_enable)
{
param.arg = NULL;
param.priority = 20;
param.thread_name = "4G";
param.log_module = LOG_PD;
create_thread(_pd_4G_handle, &param);
}
else
{
addr.sin_addr.s_addr = device_info.gw;
snprintf(cmd, 256, "route add default gw %s", inet_ntoa(addr.sin_addr));
printf("%s\r\n", cmd);
system(cmd);
}
return E_NONE;
}
/* Interface functions -------------------------------------------------------*/
/* description: 局放程序入口函数.
param:
return: */
int32_t pd_main(void)
{
int32_t rv = 0;
rv |= _pd_main_init();
rv |= dau_handle_init();
rv |= csg_handle_init();
//rv |= debug_handle_init();
return E_NONE;
}
int32_t pd_main_after(void)
{
int32_t rv = E_NONE;
rv |= _pd_main_init_after();
rv |= dau_handle_init_after();
rv |= csg_handle_init_after();
//rv |= debug_handle_init_after();
rv |= _pd_broadcast_init();
return rv;
}
int32_t pd_port_cmd_config_register(int32_t pri, pd_port_cmd_save_config_f *func)
{
cmd_node_t *node = &pd_port_node;
/* 参数检查 */
if (pri >= PD_PORT_CMD_PRI_COUNT || !func)
{
return E_BAD_PARAM;
}
/* 加入列表 */
array_set(node->configs, pri, func, MTYPE_DAU);
return 0;
}
void pd_show(void)
{
printh("Connect: %s\r\n", csg.is_connect ? "yes" : "no");
printh("Synchronization: %s\r\n", pd_state.sync ? "valid" : "invalid");
printh("PT: %s\r\n", (pd_state.state & 0x2) ? "valid" : "invalid");
printh("PPS: %s\r\n", (pd_state.state & 0x4) ? "valid" : "invalid");
printh("PPS mode: %s\r\n", (pd_state.state & 0x8) ? "slave" : "master");
}
#else
int32_t PD_main(void)
{
return 0;
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/