/***************************************************************************** * @copyright 1997-2050, . POWER SUPPLY CO., LTD. * @file app_task_regedit.c * @brief xx功能 * @author Gary * @date 2024-09-05 * @remark *****************************************************************************/ #define _XOPEN_SOURCE 700 #include #include "kit_db.h" #include "drv_4g.h" #include "drv_wifi.h" #include "mw_schedule_handle.h" #include "app_task_regedit.h" // /***************************************************************************** // * @brief 将 YYYY/DD/MM HH:MM:SS 格式的字符串转换为 timeval 结构体 // * @param[in] timeString: YYYY/DD/MM HH:MM:SS 格式的时间字符串 // * @param[out] tv: 转换后的 timeval 结构体指针 // * @return 0: 成功;1: 失败 (无效的时间字符串格式或转换错误) // *****************************************************************************/ // static int stringToTimeval(const char *timeString, struct timeval *tv) // { // struct tm tm = {0}; // 初始化 tm 结构体 // char *strptime_result; // time_t t; // // 检查字符串长度 // if (strlen(timeString) != 19) // { // KITLOG(LOG_APP_EN, ERROR_EN, "错误:时间字符串长度错误: %s\n", timeString); // return 1; // } // // 使用 strptime 解析时间字符串,注意格式字符串要与 timeString 格式完全匹配 // strptime_result = strptime(timeString, "%Y/%m/%d %H:%M:%S", &tm); // 修改为 %m/%d // if (strptime_result == NULL) // { // KITLOG(LOG_APP_EN, ERROR_EN, "错误:strptime 解析时间字符串失败: %s\n", timeString); // return 1; // } // // 将 struct tm 转换为 time_t // t = mktime(&tm); // if (t == -1) // { // KITLOG(LOG_APP_EN, ERROR_EN, "错误:mktime 转换失败: %s\n", timeString); // return 1; // } // tv->tv_sec = t; // tv->tv_usec = 0; // return 0; // } /********************************************************************* * @brief EMS时间处理初始化函数,根据配置信息设置系统时间(NTP或手动) * @param[in] rtc_dev_config: 设备配置信息 (包含NTP和手动时间设置参数,通常为JSON格式) * @return 0: 成功;1: 失败 (内存分配失败,JSON解析失败,NTP同步失败,或设置系统时间失败) *********************************************************************/ static int systimeInitHandle(ems_dev_config_t *rtc_dev_config) { int ret = 0; ems_dev_rtc_config_t rtcInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)rtc_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "isNtp"); rtcInfo.isNtp = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 判断是否使用 NTP 自动对时 if (rtcInfo.isNtp) { item = cJSON_GetObjectItem(json_obj, "port"); rtcInfo.port = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; item = cJSON_GetObjectItem(json_obj, "address"); strncpy((char *)rtcInfo.address, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_ADDR_LEN); rtcInfo.address[MAX_ADDR_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 ret = sync_ntp_timestamp((char *)rtcInfo.address, rtcInfo.port, (char *)AdvancedSettingTable[kLinux_Password].value); // 调用NTP对时函数 if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:NTP同步失败: %s\n", strerror(errno)); } } // 自启动时不进行手动对时 // else // { // item = cJSON_GetObjectItem(json_obj, "manualTime"); // strncpy((char *)rtcInfo.manualTime, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", sizeof(rtcInfo.manualTime)); // rtcInfo.manualTime[sizeof(rtcInfo.manualTime) - 1] = '\0'; // 确保字符串以'\0'结尾 // struct timeval tv; // if (stringToTimeval((const char *)rtcInfo.manualTime, &tv) != 0) // { // return 1; // stringToTimeval函数已经打印了错误信息 // } // time_t seconds = tv.tv_sec; // ret = setSysTime(seconds); // 使用bsp_rtc.c中的setSysTime函数设置系统时间 // if (ret != 0) // { // KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); // return 1; // } // } cJSON_Delete(json_obj); // 释放JSON对象 return ret; } /********************************************************************* * @brief 初始化系统的IP、mack地址、网关等配置 * @param[in] eth_dev_config: 以太网口配置信息 * @return 0-成功 1-失败 *********************************************************************/ static int netInitHandble(ems_dev_config_t *eth_dev_config) { int ret = 0; ems_dev_eth_config_t ethInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)eth_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "netId"); ethInfo.netId = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; item = cJSON_GetObjectItem(json_obj, "isDHCP"); ethInfo.isDHCP = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; item = cJSON_GetObjectItem(json_obj, "address"); strncpy((char *)ethInfo.address, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_ADDR_LEN); ethInfo.address[MAX_ADDR_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 char temp[300] = {0}; // 命令缓冲区 char buffer[256]; // 获取执行返回结果 // 关闭netplan自动覆盖IP配置 snprintf(temp, sizeof(temp), "systemctl stop systemd-networkd.service"); // 使用 DHCP 获取 IP ret = kit_popen_exec(temp, buffer, sizeof(buffer)); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "systemctl 执行失败: %s\n", temp); return 1; } // 判断是否使用 DHCP 动态分配 IP if (ethInfo.isDHCP == 1) { snprintf(temp, sizeof(temp), "udhcpc -i eth%d -n", ethInfo.netId); // 使用 DHCP 获取 IP ret = kit_popen_exec(temp, buffer, sizeof(buffer)); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "udhcpc 执行失败: %s\n", temp); return 1; } } else { item = cJSON_GetObjectItem(json_obj, "ip"); strncpy((char *)ethInfo.ip, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_IP_LEN); ethInfo.ip[MAX_IP_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 item = cJSON_GetObjectItem(json_obj, "mask"); strncpy((char *)ethInfo.mask, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_IP_LEN); ethInfo.mask[MAX_IP_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 item = cJSON_GetObjectItem(json_obj, "gateway"); strncpy((char *)ethInfo.gateway, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_IP_LEN); ethInfo.gateway[MAX_IP_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 snprintf(temp, sizeof(temp), "ifconfig eth%d %s netmask %s", ethInfo.netId, ethInfo.ip, ethInfo.mask); // 静态分配 IP 地址和子网掩码 KITPTF(LOG_APP_EN, INFO_EN, "执行IP设置:%s", temp); ret = kit_popen_exec(temp, buffer, sizeof(buffer)); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "ifconfig 执行失败: %s\n", temp); return 1; } // 设置网关(暂时不用网关地址) // memset(temp, 0, sizeof(temp)); // snprintf(temp, sizeof(temp), "route add default gw %s eth%d", config->gateway, config->netId); // ret = kit_popen_exec(temp, buffer, sizeof(buffer)); // if (ret != 0) { // KITLOG(LOG_APP_EN, ERROR_EN, "route add default gw 执行失败: %s\n", temp); // return 1; // } } cJSON_Delete(json_obj); // 释放JSON对象 return ret; } /********************************************************************* * @brief 初始化系统Wifi配置 * @param[in] wifi_dev_config: wifi配置信息 * @return 0-成功 1-失败 *********************************************************************/ static int sysWifiInitHandle(ems_dev_config_t *wifi_dev_config) { int ret = 0; drv_wifi_t wifiInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)wifi_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "enable"); wifiInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 在使能关闭时,直接返回 if (wifiInfo.enable == 0) { return ret; } item = cJSON_GetObjectItem(json_obj, "wifiName"); strncpy((char *)wifiInfo.wifiName, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_NAME_LEN); wifiInfo.wifiName[MAX_WIFI_NAME_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 item = cJSON_GetObjectItem(json_obj, "wifiPassword"); strncpy((char *)wifiInfo.wifiPassword, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_PASS_LEN); wifiInfo.wifiPassword[MAX_WIFI_PASS_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 cJSON_Delete(json_obj); // 释放JSON对象 ret = drvOpenWifi(&wifiInfo); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); return 1; } return ret; } /********************************************************************* * @brief 初始化系统4G配置 * @param[in] fourthg_dev_config:4G相关配置 * @return 0-成功 1-失败 *********************************************************************/ static int sys4GInitHandle(ems_dev_config_t *fourthg_dev_config) { int ret = 0; drv_4g_t fourthgInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)fourthg_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "enable"); fourthgInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 在使能关闭时,直接返回 if (fourthgInfo.enable == 0) { return ret; } item = cJSON_GetObjectItem(json_obj, "cmdContent"); strncpy((char *)fourthgInfo.cmdContent, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_CMD_4G_LEN); fourthgInfo.cmdContent[MAX_CMD_4G_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 cJSON_Delete(json_obj); // 释放JSON对象 ret = drvOpen4G(&fourthgInfo); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); return 1; } return ret; } /********************************************************************* * @brief 初始化ems配置 * @param[in] void * @return 0-成功 1-失败 *********************************************************************/ int initEmsConfig(void) { UT_array *emsDevConfigs = {0}; int ret = 0; if (0 != kit_get_config_db_data(&emsDevConfigs)) { return 1; } utarray_foreach(emsDevConfigs, ems_dev_config_t *, p_emsDevConfig) { switch (p_emsDevConfig->type) { case kEms_Config_Uart: // 系统串口不需要初始化 break; case kEms_Config_Net: // 初始化系统的IP、MAC地址、网关等配置 ret = netInitHandble(p_emsDevConfig); break; case kEms_Config_DI: break; case kEms_Config_DO: break; case kEms_Config_Rtc: // 初始化系统时间将rtc时钟同步到linux系统 ret = systimeInitHandle(p_emsDevConfig); break; case kEms_Config_Wifi: ret = sysWifiInitHandle(p_emsDevConfig); break; case kEms_Config_4G: ret = sys4GInitHandle(p_emsDevConfig); break; default: printf("Unknown EMS device config type: %d\n", p_emsDevConfig->type); ret = 1; break; } if (ret != 0) { // 初始化失败,释放资源并返回错误 utarray_free(emsDevConfigs); return 1; } } // 释放数组内存 utarray_free(emsDevConfigs); // gpio口初始化 ret = drvGpioOpen(); if (ret != 0) { return 1; } return ret; } /********************************************************************* * @brief 初始化数据库 * @param[in] void * @return 0-成功 1-失败 *********************************************************************/ int initSqliteDb(void) // 初始化系统时间 { int ret = 0; // 初始化数据库,"./config"是打包里的sql文件路径 ret = kit_init_db("../initsql"); return ret; } /********************************************************************* * @brief EMS初始化 * @param[in] arg:相关配置 * @return 0-成功 1-失败 *********************************************************************/ uint8_t initEmsSystem(void *arg) { int ret = 0; ret = initSqliteDb(); if (ret != 0) { KITPTF(LOG_APP_EN, ERROR_EN, "Sqlite数据库初始化失败!"); KITLOG(LOG_APP_EN, ERROR_EN, "Sqlite数据库初始化失败!"); return ret; } #if HARDWARE_TYPE == -99 ret = initEmsConfig(); if (ret != 0) { KITPTF(LOG_APP_EN, ERROR_EN, "EMS盒子配置初始化失败!"); KITLOG(LOG_APP_EN, ERROR_EN, "EMS盒子配置初始化失败!"); return ret; } #endif ret = initDevInfo(); if (ret != 0) { KITPTF(LOG_APP_EN, ERROR_EN, "读取设备配置、电位配置信息失败!"); KITLOG(LOG_APP_EN, ERROR_EN, "读取设备配置、电位配置信息失败!"); return ret; } ret = initNorthInfo(); if (ret != 0) { KITPTF(LOG_APP_EN, ERROR_EN, "读取北向配置失败!"); KITLOG(LOG_APP_EN, ERROR_EN, "读取北向配置失败!"); return ret; } ret = initAdvancedSettingInfo(); if (ret != 0) { KITPTF(LOG_APP_EN, ERROR_EN, "读取高级配置失败!"); KITLOG(LOG_APP_EN, ERROR_EN, "读取高级配置失败!"); return ret; } ret = initRtdb(rtdbType, NULL, kEE_SHM_CREAT); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "RTDB初始化失败!"); KITPTF(LOG_APP_EN, ERROR_EN, "RTDB初始化失败!"); return ret; } ret = initWebSign(kSign_ShMem, kEE_SHM_CREAT); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "websign初始化失败!"); KITPTF(LOG_APP_EN, ERROR_EN, "websign初始化失败!"); return ret; } return ret; } /********************************************************************* * @brief 创建任务的总入口 * @param[in] arg:相关配置 * @return void *********************************************************************/ void regeditThreadEntry(void *map_t) // 创建线程入口 { // 创建各种采集任务 creatUartModbusTaskEntry(&protoTable[kProto_ModbusRTU_Master]); creatNetModbusTaskEntry(&protoTable[kProto_ModbusTCP_Master]); creatGetLocalParamTaskEntry(100); // 100*50 ms 换算5秒执行一次 /* 创建各种转发任务 */ //creatNetMqttTaskEntry(); /*创建存储任务*/ creatScheduledStorageTask(); /*创建gpio任务*/ //creatGpioModTaskEntry(10); // 初始化 GPIO模块 10*50 ms 换算500ms执行一次 /*创建温控任务*/ //creatLogicTempCtrlEntry(); /*创建策略任务*/ //creatLogicCtrTaskEntry(); } /********************************************************************* * @brief 启动EMS的web后台 * @return void *********************************************************************/ // void runEmsWebApi() // { // char temp[300] = {0}; // char buffer[256] = {0}; // char original_dir[500]; // // 获取当前工作目录 // if (getcwd(original_dir, sizeof(original_dir)) == NULL) // { // KITLOG(LOG_APP_EN, ERROR_EN, "获取当前工作目录失败: %s\n", strerror(errno)); // return; // } // // 更改工作目录 // if (chdir("/opt/ems") != 0) // { // KITLOG(LOG_APP_EN, ERROR_EN, "更改工作目录失败: %s\n", strerror(errno)); // return; // } // snprintf(temp, sizeof(temp), "nohup /opt/ems/edge-ems-server > /opt/ems/output.log 2>&1 &"); // int ret = kit_popen_exec(temp, buffer, sizeof(buffer)); // if (ret != 0) // { // KITLOG(LOG_APP_EN, ERROR_EN, "启动 Ems Web 失败: %s\n", buffer); // } // // 恢复原始工作目录 // if (chdir(original_dir) != 0) // { // KITLOG(LOG_APP_EN, ERROR_EN, "恢复原始工作目录失败: %s\n", strerror(errno)); // } // }