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.

769 lines
20 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 "pd_dau.h"
#include "pd_csg.h"
#include "pd_main.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,
};
/* Private function prototypes -----------------------------------------------*/
extern int32_t _pd_port_str_to_unit_port(const char *port_str, uint8_t *unit, uint8_t *port);
extern void _pd_port_config_save_port(vty_t *vty, uint8_t unit, uint8_t port);
extern int32_t _dau_add(uint8_t unit, uint8_t port_num);
/* Internal functions --------------------------------------------------------*/
/* 进入 DAU 端口模式. */
CMD(pd_port_terminal,
pd_port_terminal_cmd,
"interface port WORD",
"Interface\n"
"Port\n"
"Port id: Ex: 1/1\n")
{
uint8_t unit = 0;
uint8_t port = 0;
int32_t vport = 0;
/* 取出端口号. */
if (_pd_port_str_to_unit_port(argv[0], &unit, &port) != E_NONE)
{
return CMD_ERR_NO_MATCH;
}
/* 计算虚拟端口. */
vport = dau_port_to_vport(unit, port);
if (vport <= 0)
{
return CMD_ERR_NO_MATCH;
}
pd_port_node.param_num = vport;
snprintf(pd_port_node.prompt, PD_PORT_PROMPT_LEN, "%%s(interface port %d/%d)# ", unit + 1, port + 1);
vty->node = PORT_NODE;
return CMD_SUCCESS;
}
/* 心跳上传间隔. */
CMD(pd_heartbeat_interval,
pd_heartbeat_interval_cmd,
"heartbeat-interval <1-10000>",
"heartbeat interval\n"
"Interval time: s\n")
{
pd_config.config.heartbeat_period = strtol(argv[0], NULL, 10);
return CMD_SUCCESS;
}
/* 趋势上升周期. */
CMD(pd_trend_interval,
pd_trend_interval_cmd,
"trend-interval <1-10000>",
"Trend interval\n"
"Interval time: s\n")
{
pd_config.config.trend_up_period = strtol(argv[0], NULL, 10);
return CMD_SUCCESS;
}
/* 采样中断传输间隔配置. */
CMD(pd_interrupt_interval,
pd_interrupt_interval_cmd,
"interrupt-interval <100-1000000>",
"Interrupt interval\n"
"interval: us\n")
{
dau_t * dau_node = dau[0];
if(strtol(argv[0], NULL, 10) <= 1000000)
{
pd_config.config.interrupt_interval = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.sample_interrupt_intveal_us = pd_config.config.interrupt_interval;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* 触发阈值设置. */
CMD(pd_trig_threshold,
pd_trig_threshold_cmd,
"trig threshold <1-32767>",
"Trigger\n"
"Threshold\n"
"mv\n")
{
dau_t * dau_node = dau[0];
if(strtol(argv[0], NULL, 10) <= 32767)
{
pd_config.config.trig_threshold = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.trig_threshold = pd_config.config.trig_threshold;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* 触发位置设置. */
CMD(pd_sample_numbers,
pd_sample_numbers_cmd,
"sample numbers <1000-10240>",
"Sample\n"
"Numbers\n"
"1000~10240\n")
{
if(strtol(argv[0], NULL, 10) <= 10240)
{
pd_config.config.trigger_sample_nums = strtol(argv[0], NULL, 10);
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* 触发位置设置. */
CMD(pd_trig_location,
pd_trig_location_cmd,
"trig location <0-12>",
"Trigger\n"
"Location\n"
"0~12\n")
{
dau_t * dau_node = dau[0];
if(strtol(argv[0], NULL, 10) <= 12)
{
pd_config.config.trig_location = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.trig_location = pd_config.config.trig_location;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* 触发间隔. */
CMD(pd_trig_gap,
pd_trig_gap_cmd,
"trig gap <1-100000>",
"Trigger\n"
"Gap\n"
"us\n")
{
dau_t * dau_node = dau[0];
if(strtol(argv[0], NULL, 10) <= 100000)
{
pd_config.config.trig_gap = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.trig_location = pd_config.config.trig_gap;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* IRIG-B 极性设置. */
CMD(pd_irigB_polarity,
pd_irigB_polarity_cmd,
"irigB polarity <0-1>",
"IrigB\n"
"Polarity\n"
"0-nanrui,1-normal\n")
{
dau_t * dau_node = dau[0];
if((strtol(argv[0], NULL, 10) <= 1)&&(strtol(argv[0], NULL, 10) >= 0))
{
pd_config.config.irigB_polarity = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.irigB_polarity = pd_config.config.irigB_polarity;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* PT和B码同步模式设置. */
CMD(pd_pt_B_sync_mode,
pd_pt_B_sync_mode_cmd,
"pt_igirB syncMode <0-3>",
"Pt_igirB\n"
"SyncMode\n"
"0-ptExt&BExt,1-ptInt&BExt,2-ptExt&BInt,3-ptInt&BInt\n")
{
dau_t * dau_node = dau[0];
if((strtol(argv[0], NULL, 10) <= 3)&&(strtol(argv[0], NULL, 10) >= 0))
{
pd_config.config.pt_B_sync_mode = strtol(argv[0], NULL, 10);
if(dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.pt_B_sync_mode = pd_config.config.pt_B_sync_mode;
if (IS_BITMAP_SET(pd_config.config.pt_B_sync_mode, PD_BIT_BCODE))
{
dau_node->reg->reg_global.ps_epoch_sec = time(NULL);
}
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* PT 内同步周期设置. */
CMD(pd_internal_freq,
pt_internal_freq_cmd,
"pt intFreq <40.00-300.00>",
"Pt\n"
"IntFreq\n"
"40.00-300.00Hz\n")
{
dau_t * dau_node = dau[0];
float freq = atof(argv[0]);
if (freq >= 40.0 && freq <= 300.0)
{
pd_config.config.pt_internal_period = (uint32_t)(1000000000.0 / freq);
if (dau_node->is_connect == TRUE)
{
dau_node->reg->reg_global.pt_selfsync_cycle = pd_config.config.pt_internal_period;
}
return CMD_SUCCESS;
}
else
{
return CMD_ERR_NO_MATCH;
}
}
/* 显示 DAU 状态. */
CMD(show_pd,
show_pd_cmd,
"show pd",
"Show\n"
"Partial discharge\n")
{
pd_show();
return CMD_SUCCESS;
}
/* 在终端上显示当前配置信息. */
CMD(show_running_port,
show_running_port_cmd,
"show running-config interface port WORD",
SHOW_STR
"Running configuration\n"
"Interface\n"
"Port\n"
"Port id: Ex: 1/1\n")
{
uint8_t unit = 0;
uint8_t port = 0;
int32_t vport = 0;
/* 取出端口号. */
if (_pd_port_str_to_unit_port(argv[0], &unit, &port) != E_NONE)
{
return CMD_ERR_NO_MATCH;
}
/* 计算虚拟端口. */
vport = dau_port_to_vport(unit, port);
if (vport <= 0)
{
return CMD_ERR_NO_MATCH;
}
vty_out(vty, "Current configuration:%s", VTY_NEWLINE);
vty_out(vty, "!%s", VTY_NEWLINE);
_pd_port_config_save_port(vty, unit, port);
vty_out(vty, "end%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
uint32_t _pd_get_frequency()
{
uint32_t frequency;
if (IS_BITMAP_SET(pd_config.config.pt_B_sync_mode, PD_BIT_PT))
{
frequency = (uint32_t)(1000000000UL / pd_config.config.pt_internal_period);
}
else
{
dau_t * dau_node = dau[0];
if (dau_node->is_connect != TRUE)
return E_ERROR;
frequency = (uint32_t)(1000000000UL / dau_node->reg->reg_global.pt_cycle);;
}
return frequency;
}
int _pd_read_register_century_second()
{
dau_t * dau_node = dau[0];
if (dau_node->is_connect != TRUE)
{
return E_ERROR;
}
return dau_node->reg->reg_global.b_time_epoch_sec;
}
/* 配置保存函数. */
int _pd_config_save(vty_t* vty)
{
int16_t i = 0;
vty_out(vty, "heartbeat-interval %d%s", pd_config.config.heartbeat_period, VTY_NEWLINE);
i++;
vty_out(vty, "interrupt-interval %d%s", pd_config.config.interrupt_interval, VTY_NEWLINE);
i++;
vty_out(vty, "trig gap %d%s", pd_config.config.trig_gap, VTY_NEWLINE);
i++;
vty_out(vty, "sample numbers %d%s", pd_config.config.trigger_sample_nums, VTY_NEWLINE);
i++;
vty_out(vty, "trig location %d%s", pd_config.config.trig_location, VTY_NEWLINE);
i++;
vty_out(vty, "trig threshold %d%s", pd_config.config.trig_threshold, VTY_NEWLINE);
i++;
vty_out(vty, "trend-interval %d%s", pd_config.config.trend_up_period, VTY_NEWLINE);
i++;
vty_out(vty, "pt_igirB syncMode %d%s", pd_config.config.pt_B_sync_mode, VTY_NEWLINE);
i++;
vty_out(vty, "pt intFreq %.2f%s", 1000000000.0 / pd_config.config.pt_internal_period, VTY_NEWLINE);
i++;
vty_out(vty, "irigB polarity %d%s", pd_config.config.irigB_polarity, VTY_NEWLINE);
i++;
return i;
}
/* config模式配置保存函数: vty -- 相应的终端 */
void _pd_port_config_save_port(vty_t *vty, uint8_t unit, uint8_t port)
{
array_t *configs = pd_port_node.configs;
pd_port_cmd_save_config_f *func = NULL;
uint8_t i = 0;
vty_out(vty, "interface port %d/%d%s", unit + 1, port + 1, VTY_NEWLINE);
for(i = 0; i < array_active(configs); i++)
{
func = array_lookup(configs, i);
if (!func)
{
continue;
}
func(vty, unit, port);
}
}
/* config模式配置保存函数: vty -- 相应的终端 */
int32_t _pd_port_config_save(vty_t *vty)
{
uint8_t unit = 0;
uint8_t port = 0;
/* 其他配置保存 */
for(unit = 0; unit < PD_DAU_SUM; unit++)
{
if (!dau_is_valid(dau[unit]))
{
continue;
}
for(port = 0; port < dau[unit]->port_num; port++)
{
_pd_port_config_save_port(vty, unit, port);
}
}
return E_NONE;
}
/* 将端口字符串, 转换成 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,DAU5G_V%s,", version_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;
}
int32_t _pd_main_init(void)
{
uint8_t i = 0;
uint8_t j = 0;
int32_t rv = 0;
_dau_add(0, PD_DAU_PORT_SUM);
/* 初始化基本参数. */
pd_config.config.heartbeat_period = DEFAULT_HEARTBEAT_INTVEAL;
pd_config.config.ch_en_mask = DEFAULT_PORT_ENBALE;
pd_config.config.interrupt_interval = DEFAULT_INTVEAL_TIME_US;
pd_config.config.trigger_sample_nums = DEFAULT_SAMPLE_NUM;
pd_config.config.sample_frequency = DEFAULT_SAMPLE_FREQ_MHZ;
pd_config.config.trig_gap = DEFAULT_TRIG_GAP;
pd_config.config.trig_location = DEFAULT_TRIG_LOCATION;
pd_config.config.trig_threshold = DEFAULT_TRIG_THRESHOLD;
pd_config.config.pt_B_sync_mode = DEFAULT_PT_B_SYNC_MODE;
pd_config.config.trend_up_period = DEFAULT_TREND_PERIOD;
pd_config.config.irigB_polarity = DEFAULT_IGIRB_MODE;
pd_config.config.pt_internal_period = DEFAULT_PT_INTFREQ;
for(i = 0; i < PD_DAU_SUM; i++)
{
for(j = 0; j < PD_DAU_PORT_SUM; j++)
{
/* 端口初始化*/
if(READ_BIT(pd_config.config.ch_en_mask, 0x1<<j))
{
pd_config.config_port[i][j].is_enbale = TRUE;
}
else
{
pd_config.config_port[i][j].is_enbale = FALSE;
}
pd_config.config_port[i][j].type = PD_PORT_TYPE_UHF;
pd_config.config_port[i][j].vport = dau_port_to_vport(i,j);
pd_config.config_port[i][j].send_port_num = pd_config.config_port[i][j].vport;
}
}
/* 注册配置保存函数 */
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;
}
/* 注册端口节点. */
cmd_install_node(&pd_port_node, _pd_port_config_save);
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_heartbeat_interval_cmd);
cmd_install_element(CONFIG_NODE, &pd_port_terminal_cmd);
cmd_install_element(PORT_NODE, &pd_port_terminal_cmd);
cmd_install_element(CONFIG_NODE, &pd_trig_threshold_cmd);
cmd_install_element(CONFIG_NODE, &pd_trig_gap_cmd);
cmd_install_element(CONFIG_NODE, &pd_sample_numbers_cmd);
cmd_install_element(CONFIG_NODE, &pd_trig_location_cmd);
cmd_install_element(CONFIG_NODE, &pd_interrupt_interval_cmd);
cmd_install_element(CONFIG_NODE, &pd_trend_interval_cmd);
cmd_install_element(CONFIG_NODE, &pd_irigB_polarity_cmd);
cmd_install_element(CONFIG_NODE, &pd_pt_B_sync_mode_cmd);
cmd_install_element(CONFIG_NODE, &pt_internal_freq_cmd);
cmd_install_element(COMMON_NODE, &show_pd_cmd);
cmd_install_element(COMMON_NODE, &show_running_port_cmd);
return E_NONE;
}
int32_t _pd_main_init_after(void)
{
// uint8_t i = 0;
// uint8_t j = 0;
/* 初始化基本参数 */
// for(i = 0; i < PD_DAU_SUM; i++)
// {
// for(j = 0; j < PD_DAU_PORT_SUM; j++)
// {
// pd_config.config_port[i][j].vport = dau_port_to_vport(i, j);
// }
// }
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();
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 |= _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)
{
dau_t * dau_node = dau[0];
printh("Connect: %s\r\n", csg.is_connect ? "yes" : "no");
//printh("ext sync: %dHz\r\n", _pd_read_pt_ext_sync_freq());
if(dau_node->is_connect == TRUE)
{
printh("pt_B_sync_mode=0x%x\r\n", dau_node->reg->reg_global.pt_B_sync_mode);
printh("b_time_epoch_sec:%ld\r\n", dau_node->reg->reg_global.b_time_epoch_sec);
}
}
#else
int32_t PD_main(void)
{
return 0;
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/