/***************************************************************************** * 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 #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_slot_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); /* Internal functions --------------------------------------------------------*/ /* 进入 DAU 端口模式. */ CMD(pd_slot_terminal, pd_slot_terminal_cmd, "slot <1-8>", "Slot\n" "Port id: Ex: 1/1\n") { uint8_t slot = 0; /* 取出端口号. */ slot = strtol(argv[0], NULL, 10); pd_slot_node.param_num = slot; snprintf(pd_slot_node.prompt, PD_PORT_PROMPT_LEN, "%%s(slot %d)# ", slot); vty->node = PORT_NODE; return CMD_SUCCESS; } /* 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; } /* config模式配置保存函数: vty -- 相应的终端 */ void _pd_slot_config_save_all(vty_t *vty, uint8_t unit) { array_t *configs = pd_slot_node.configs; pd_slot_cmd_save_config_f *func = NULL; uint8_t i = 0; vty_out(vty, "slot %d%s", unit + 1, VTY_NEWLINE); for(i = 0; i < array_active(configs); i++) { func = array_lookup(configs, i); if (!func) { continue; } func(vty, unit); } vty_out(vty, "!%s", VTY_NEWLINE); } /* config模式配置保存函数: vty -- 相应的终端 */ int32_t _pd_slot_config_save(vty_t *vty) { uint8_t slot = 0; /* 其他配置保存 */ for(slot = 0; slot < PD_SLOTS_MAX; slot++) { _pd_slot_config_save_all(vty, slot); } 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,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, ¶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; } /* 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_SLOTS_MAX; i++) { pd_config.config_slot[i].slot = i; pd_config.config_slot[i].timeout = 3; } 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; } /* 注册端口节点. */ cmd_install_node(&pd_slot_node, _pd_slot_config_save); pd_slot_node.prompt = XMALLOC(MTYPE_DAU, PD_PORT_PROMPT_LEN); pd_slot_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(CONFIG_NODE, &pd_slot_terminal_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}; char cmd[256]; /* 初始化基本参数 */ if (pd_config.config.is_4G_enable) { param.arg = NULL; param.priority = 20; snprintf(param.thread_name, THREAD_NAME_LEN, "4G"); param.log_module = LOG_PD; create_thread(_pd_4G_handle, ¶m); } 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_slot_cmd_config_register(int32_t pri, pd_slot_cmd_save_config_f *func) { cmd_node_t *node = &pd_slot_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 ****/