/***************************************************************************** * 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 * *

© 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 "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, ¶m); 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<= 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 ****/