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.
2015 lines
56 KiB
C
2015 lines
56 KiB
C
/*****************************************************************************
|
|
* file lib/process/ca_collect.c
|
|
* author YuLiang
|
|
* version 1.0.0
|
|
* date 28-Nov-2023
|
|
* brief This file provides all the collect related operation functions.
|
|
******************************************************************************
|
|
* Attention
|
|
*
|
|
* <h2><center>© COPYRIGHT(c) 2023 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_CA
|
|
/* 标准 C 库头文件 */
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/ioctl.h>
|
|
#include <linux/serial.h>
|
|
#include <asm-generic/ioctls.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <sys/msg.h>
|
|
#include <arpa/inet.h>
|
|
#include <termios.h>
|
|
#include <ifaddrs.h>
|
|
|
|
/* 私有头文件 */
|
|
#include "cmd.h"
|
|
#include "hwgpio.h"
|
|
|
|
#include "ca_collect.h"
|
|
#include "ca_db.h"
|
|
#include "ca_dbg.h"
|
|
#include "ca_land.h"
|
|
#include "ca_mqtt.h"
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
#define CA_COLL_USART_NAME "ttymxc4"
|
|
#define CA_COLL_GPIO_RS485_TX_EN 13
|
|
#define CA_COLL_GPIO_RS485_TX_EN1 15
|
|
#define CA_COLL_GPIO_4G_PW_EN 78
|
|
#define CA_COLL_GPIO_4G_RST 70
|
|
#define CA_COLL_LOOP_INR 3
|
|
#define CA_COLL_BUF_LEN 1512
|
|
#define CA_COLL_CRC32_LEN 4
|
|
#define CA_COLL_ERR_CNT_MAX 9
|
|
#define CA_COLL_SEND_ERR_MAX 3
|
|
#define CA_COLL_SHIQUCHA (28800)
|
|
#define CA_COLL_CABLE_FILE "cableMonitor.bak"
|
|
#define CA_COLL_4G_FILE_MAX 256
|
|
#define CA_COLL_4G_MODE_MAX 128
|
|
#define CA_COLL_APN_NAME "3gnet"
|
|
#define CA_COLL_LAND_IP "192.168.1.20"
|
|
#define CA_COLL_LAND_PORT 9456
|
|
|
|
#define CA_COLL_RS485_TX_EN(_v_) \
|
|
do { \
|
|
gpio_val_set(ca_coll_ctrl.gpio_rs485_tx_en, _v_); \
|
|
gpio_val_set(ca_coll_ctrl.gpio_rs485_tx_en1, _v_); \
|
|
} while(0)
|
|
|
|
#define CA_COLL_4G_PW_EN(_v_) \
|
|
do { \
|
|
gpio_val_set(ca_coll_ctrl.gpio_4g_pw, _v_); \
|
|
} while(0)
|
|
|
|
#define CA_COLL_4G_RST(_v_) \
|
|
do { \
|
|
gpio_val_set(ca_coll_ctrl.gpio_4g_rst, _v_); \
|
|
} while(0)
|
|
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* 用于命令行模式节点注册配置保存函数 */
|
|
typedef int ca_coll_rs485_cmd_save_config_f(vty_t*, uint8_t);
|
|
|
|
/* 端口节点配置优先级 */
|
|
typedef enum
|
|
{
|
|
CA_COLL_RS485_CMD_PRI = 0,
|
|
CA_COLL_RS485_CMD_PRI_COUNT
|
|
} CA_COLL_RS485_CMD_PRI_E;
|
|
|
|
/* 命令类型. */
|
|
enum CA_COLL_CMD_TYPE
|
|
{
|
|
CA_COLL_CT_REQUEST = 1, // 通用请求
|
|
CA_COLL_CT_REPLY = 2, // 通用回复
|
|
CA_COLL_CT_PRV_REQUEST = 128, // 私有请求
|
|
CA_COLL_CT_PRV_REPLY = 129, // 私有回复
|
|
};
|
|
|
|
/* 共有命令字. */
|
|
enum CA_COLL_CMD
|
|
{
|
|
CA_COLL_C_DEV_INFO = 1, // 获取设备信息
|
|
CA_COLL_C_DEV_INFO_SET = 2, // 设置设备信息
|
|
CA_COLL_C_RESET = 3, // 重启
|
|
CA_COLL_C_DEFAULT = 4, // 回复默认配置
|
|
CA_COLL_C_UPDATE_APP = 5, // 升级 APP
|
|
CA_COLL_C_UPDATE_IAP = 6, // 升级 IAP
|
|
CA_COLL_C_DEV_CONFIG = 7, // 获取设备配置
|
|
CA_COLL_C_DEV_CONFIG_SET = 8, // 设置设备配置
|
|
CA_COLL_C_UPDATE_APP_RT = 9, // 升级 APP 结果回复
|
|
CA_COLL_C_KEEPALIVE = 10 // 保活
|
|
};
|
|
|
|
/* 私有命令字. */
|
|
enum CA_COLL_CM_CMD
|
|
{
|
|
CA_COLL_PRV_ADJ_INFO = 1, // 校准信息获取
|
|
CA_COLL_PRV_REAL_DATA = 2, // 实时数据获取
|
|
CA_COLL_PRV_POWER_FRE = 3, // 工频数据获取
|
|
CA_COLL_PRV_ADJ_INFO_SET = 4, // 校准信息设置
|
|
CA_COLL_PRV_ADJ_AUTO = 5, // 自动校准
|
|
CA_COLL_PRV_WAVE = 6, // 高频数据获取
|
|
CA_COLL_PRV_DEV_STATE = 7, // 设备状态获取
|
|
CA_COLL_PRV_WAVE_COL = 8, // 手动高频采样
|
|
CA_COLL_PRV_WAVE_CAL = 9, // 高频系数计算
|
|
CA_COLL_PRV_WAVE_MAX = 10, // 高频采样最大值
|
|
CA_COLL_PRV_LOG = 11, // log 获取
|
|
CA_COLL_PRV_HISTORY_DATA = 12, // 历史数据获取
|
|
CA_COLL_PRV_ADJ_MANUAL = 13, // 手动校准
|
|
CA_COLL_PRV_CSG_CONFIG = 14, // 南网配置获取
|
|
CA_COLL_PRV_CSG_CONFIG_SET = 15 // 南网配置下发
|
|
};
|
|
|
|
/* 4G 拨号文件枚举 */
|
|
enum CA_COLL_4G_FILE_E
|
|
{
|
|
CA_COLL_4G_FILE_PPP_CONN = 0, // 本地连接脚本
|
|
CA_COLL_4G_FILE_PPP_CONN_ETC, // 实际使用的连接脚本
|
|
CA_COLL_4G_FILE_CNT
|
|
};
|
|
|
|
/* 协议头 */
|
|
typedef struct
|
|
{
|
|
uint16_t len; // 报文总长度, 包括报文头, 数据段和报文尾总长度
|
|
uint8_t dev_type_m; // 设备主设备号: 有效值 (1-240), 255 表示广播设备号, 表示接收设备无需在意设备号, 其他值暂时预留
|
|
uint8_t dev_type_s; // 设备次设备号: 有效值 (1-240), 255 表示广播设备号, 表示接收设备无需在意设备号, 其他值暂时预留
|
|
uint32_t dev_id; // 设备 id: 有效值 (1-0xEFFFFFFF), 0xFFFFFFFF 表示广播设备 id, 其他值暂时预留
|
|
uint8_t cmd_type; // 命令类型: 有效值(1-240), (1-120) 为共有命令类型, (121-240) 为私有命令类型, 其他值暂时预留
|
|
uint8_t cmd; // 命令: 有效值(1-240), 其他值暂时预留
|
|
uint16_t pkt_id; // 报文 id, 设备启动后的第一条命令为 1, 依次累加
|
|
uint8_t reserve[8]; // 预留位
|
|
} ca_coll_proto_head_t;
|
|
|
|
/* 连续报文头 */
|
|
typedef struct
|
|
{
|
|
uint32_t index; // 报文索引
|
|
uint32_t len; // 报文长度
|
|
} ca_coll_proto_mul_head_t;
|
|
|
|
/* 联络报文 */
|
|
typedef struct
|
|
{
|
|
uint32_t utc; // UTC 时间戳
|
|
uint16_t interval; // 环流采集间隔, 单位: m
|
|
uint8_t wave_force; // 强制高频采样: 0 - 否 1 - 是
|
|
uint8_t wave_interval; // 高频采样间隔, 单位: h
|
|
uint16_t threshold; // 工频采样阈值, 单位: A
|
|
uint16_t wave_threshold; // 高频采样阈值, 单位: mv
|
|
uint8_t is_updata; // 是否升级设备 APP: 0 - 否 1 - 是
|
|
uint8_t main_cable; // 主缆 ID (0-6) 默认 5
|
|
uint8_t normal_sleep; // 正常模式是否休眠: 0 - 否 1 - 是默认 0
|
|
uint8_t is_voltage_col; // 是否开启电流采集
|
|
uint8_t is_temp_col; // 是否开启温度震度
|
|
uint8_t is_wave_col; // 是否开启高频录波
|
|
uint8_t reserve[2]; // 4 byte 对齐保留
|
|
} ca_coll_proto_contact_t;
|
|
|
|
/* 采集模块属性结构体 */
|
|
typedef struct
|
|
{
|
|
char buf_tx[CA_COLL_BUF_LEN]; // 发报文 buf
|
|
char buf_rx[CA_COLL_BUF_LEN]; // 收报文 buf
|
|
char cmd_buf[CA_COLL_BUF_LEN]; // 收到的完整报文 buf
|
|
uint16_t pkt_id; // 报文索引
|
|
uint8_t cmd_type; // 当前处理的命令类型
|
|
uint8_t cmd; // 当前处理的命令
|
|
ca_coll_dev_info_t dev_info; // 环流信息
|
|
ca_coll_dev_cfg_t dev_cfg; // 环流设备配置
|
|
ca_coll_dev_data_t dev_data; // 当前环流数据
|
|
ca_coll_cfg_t cfg; // 配置
|
|
ca_coll_state_t state; // 状态
|
|
int32_t gpio_rs485_tx_en; // RS485 tx enable gpio
|
|
int32_t gpio_rs485_tx_en1; // RS485 tx enable gpio
|
|
int32_t gpio_4g_pw; // 4G power enable gpio
|
|
int32_t gpio_4g_rst; // 4G reset gpio
|
|
pthread_mutex_t mutex; // 收发线程同步使用.
|
|
} ca_coll_ctrl_t;
|
|
|
|
/* 4G 文件备份结构体 */
|
|
typedef struct
|
|
{
|
|
char source[CA_COLL_4G_FILE_MAX]; // 备份文件
|
|
char dest[CA_COLL_4G_FILE_MAX]; // 实际文件
|
|
char mode[CA_COLL_4G_MODE_MAX]; // 文件权限
|
|
} ca_coll_4g_file_t;
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
ca_coll_ctrl_t ca_coll_ctrl; // 环流采集全局控制结构
|
|
/* 串口配置命令行节点 */
|
|
cmd_node_t ca_coll_rs485_node =
|
|
{
|
|
COLL_RS485_NODE,
|
|
CONFIG_NODE,
|
|
1,
|
|
NULL,
|
|
};
|
|
|
|
/* 4G 文件备份列表 */
|
|
ca_coll_4g_file_t ca_coll_4g_file[CA_COLL_4G_FILE_CNT] =
|
|
{
|
|
{"/home/Cable/bak/quectel-chat-connect", "/home/Cable/quectel-chat-connect", "600"},
|
|
{"/home/Cable/quectel-chat-connect", "/etc/ppp/peers/quectel-chat-connect", "600"}
|
|
};
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/* description: 配置主机采样间隔
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_inr,
|
|
ca_coll_inr_cmd,
|
|
"collect interval <1-86400>",
|
|
"Collect\n"
|
|
"Collect interval\n"
|
|
"Second\n")
|
|
{
|
|
ca_coll_ctrl.cfg.coll_inr = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 4g 功能使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_4g,
|
|
ca_coll_4g_cmd,
|
|
"collect 4g (enable|disable)",
|
|
"Collect\n"
|
|
"4G\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.cfg.is_4G = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.cfg.is_4G = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 4g apn 配置
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_apn,
|
|
ca_coll_apn_cmd,
|
|
"collect apn WORD",
|
|
"Collect\n"
|
|
"VPN\n"
|
|
"Name\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
snprintf(cfg->apn, CA_COLL_VPN_LEN, "%s", argv[0]);
|
|
|
|
return CMD_SUCCESS;;
|
|
}
|
|
|
|
/* description: 朗德私有协议使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_land,
|
|
ca_coll_land_cmd,
|
|
"collect land (enable|disable)",
|
|
"Collect\n"
|
|
"LandPower protocol\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.cfg.is_land = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.cfg.is_land = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 朗德私有协议服务器地址配置
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_land_server_set,
|
|
ca_coll_land_server_set_cmd,
|
|
"collect land server A.B.C.D <1-65535>",
|
|
"Collect\n"
|
|
"LandPower protocol"
|
|
"Server\n"
|
|
"IPv4 address\n"
|
|
"Server port\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
snprintf(cfg->land_ip, INET_ADDRSTRLEN, argv[0]);
|
|
cfg->land_port = strtol((char*)argv[1], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 环流采样间隔
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_inr,
|
|
ca_coll_dev_inr_cmd,
|
|
"device interval <1-1440>",
|
|
"Device\n"
|
|
"Device interval\n"
|
|
"Minute\n")
|
|
{
|
|
ca_coll_ctrl.dev_cfg.interval = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置环流工频采样阈值
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_thr,
|
|
ca_coll_dev_thr_cmd,
|
|
"device threshold <1-5000>",
|
|
"Device\n"
|
|
"Device threshold\n"
|
|
"A\n")
|
|
{
|
|
ca_coll_ctrl.dev_cfg.threshold = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置高频采样间隔
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_wave_inr,
|
|
ca_coll_dev_wave_inr_cmd,
|
|
"device wave interval <1-255>",
|
|
"Device\n"
|
|
"Device wave\n"
|
|
"Device wave threshold\n"
|
|
"Hour\n")
|
|
{
|
|
ca_coll_ctrl.dev_cfg.wave_interval = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置高频采样阈值
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_wave_thr,
|
|
ca_coll_dev_wave_thr_cmd,
|
|
"device wave threshold <1-1000>",
|
|
"Device\n"
|
|
"Device wave\n"
|
|
"Device wave threshold\n"
|
|
"mA\n")
|
|
{
|
|
ca_coll_ctrl.dev_cfg.wave_threshold = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置环流主缆 id
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_main,
|
|
ca_coll_dev_main_cmd,
|
|
"device main cable <0-6>",
|
|
"Device\n"
|
|
"Device main\n"
|
|
"Device main cable\n"
|
|
"mA\n")
|
|
{
|
|
ca_coll_ctrl.dev_cfg.main_cable = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置环流电压采集使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_voltage,
|
|
ca_coll_dev_voltage_cmd,
|
|
"device voltage (enable|disable)",
|
|
"Device\n"
|
|
"Device voltage\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_voltage_col = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_voltage_col = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置环流温度采集使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_temp,
|
|
ca_coll_dev_temp_cmd,
|
|
"device temperature (enable|disable)",
|
|
"Device\n"
|
|
"Device temperature\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_temp_col = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_temp_col = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置高频采集使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_dev_wave,
|
|
ca_coll_dev_wave_cmd,
|
|
"device wave (enable|disable)",
|
|
"Device\n"
|
|
"Device wave\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_wave_col = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.dev_cfg.is_wave_col = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 朗德私有协议使能
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_mqtt_enable_set,
|
|
ca_coll_mqtt_enable_set_cmd,
|
|
"mqtt (enable|disable)",
|
|
"MQTT\n"
|
|
"Enable\n"
|
|
"Disable\n")
|
|
|
|
{
|
|
if (0 == strncmp(argv[0], "e", 1))
|
|
{
|
|
ca_coll_ctrl.cfg.is_MQTT = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.cfg.is_MQTT = FALSE;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 进入 RS485 端口模式
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_terminal,
|
|
ca_coll_rs485_terminal_cmd,
|
|
"interface rs485 collect",
|
|
"Interface\n"
|
|
"RS485\n"
|
|
"Collect\n")
|
|
{
|
|
uint8_t index = 0;
|
|
|
|
ca_coll_rs485_node.param_num = index;
|
|
snprintf(ca_coll_rs485_node.prompt, CA_COLL_USART_NAME_LEN, "%%s(interface rs485 coll)# ");
|
|
|
|
vty->node = COLL_RS485_NODE;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置 RS485 设备
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_dev,
|
|
ca_coll_rs485_dev_cmd,
|
|
"device WORD",
|
|
"RS485 device\n"
|
|
"Device name\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
snprintf(cfg->dev, CA_COLL_USART_NAME_LEN, "%s", argv[0]);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置 RS485 波特率
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_baud,
|
|
ca_coll_rs485_baud_cmd,
|
|
"baud <2400-921600>",
|
|
"RS485 baud\n"
|
|
"baud rate\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
int32_t baud = 0;
|
|
|
|
baud = strtol(argv[0], NULL, 10);
|
|
switch(baud)
|
|
{
|
|
case 2400:
|
|
case 4800:
|
|
case 9600:
|
|
case 19200:
|
|
case 38400:
|
|
case 57600:
|
|
case 115200:
|
|
case 460800:
|
|
case 921600:
|
|
break;
|
|
default:
|
|
return CMD_ERR_NO_MATCH;
|
|
}
|
|
|
|
cfg->baud = baud;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置 RS485 数据位
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_bits,
|
|
ca_coll_rs485_bits_cmd,
|
|
"bits <7-8>",
|
|
"RS485 bits\n"
|
|
"Bits number\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
cfg->bits = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* description: 配置 RS485 奇偶校验位
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_parity,
|
|
ca_coll_rs485_parity_cmd,
|
|
"parity (n|o|e)",
|
|
"RS485 parity\n"
|
|
"None\n"
|
|
"Odd\n"
|
|
"Even\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
cfg->parity = argv[0][0];
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
/* description: 配置 RS485 停止位
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_rs485_stop,
|
|
ca_coll_rs485_stop_cmd,
|
|
"stop <1-2>",
|
|
"RS485 stop\n"
|
|
"Stop number\n")
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
cfg->stop = strtol(argv[0], NULL, 10);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
/* description: 显示环流设备信息
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_show_device,
|
|
ca_coll_show_device_cmd,
|
|
"show device",
|
|
"Show\n"
|
|
"Device\n")
|
|
{
|
|
ca_coll_show_dev();
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
/* description: 显示当前环流数据
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_show_device_data,
|
|
ca_coll_show_device_data_cmd,
|
|
"show device data",
|
|
"Show\n"
|
|
"Device\n"
|
|
"Data\n")
|
|
{
|
|
ca_coll_show_dev_data();
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
/* description: 显示当前环流状态
|
|
param:
|
|
return: CMD_XXX */
|
|
CMD(ca_coll_show_device_state,
|
|
ca_coll_show_device_state_cmd,
|
|
"show device state",
|
|
"Show\n"
|
|
"Device\n"
|
|
"Data\n")
|
|
{
|
|
ca_coll_show_dev_state();
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* Internal functions --------------------------------------------------------*/
|
|
/* description: 获取线程超时锁
|
|
param: sec - 秒
|
|
nsec - 纳秒
|
|
return: E_XXX */
|
|
int32_t _ca_coll_lock_timeout(uint32_t sec, uint32_t nsec)
|
|
{
|
|
struct timespec time_out;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &time_out);
|
|
time_out.tv_sec += sec;
|
|
time_out.tv_nsec += nsec;
|
|
if (time_out.tv_nsec >= 1000000000)
|
|
{
|
|
time_out.tv_nsec -= 1000000000;
|
|
time_out.tv_sec++;
|
|
}
|
|
|
|
return pthread_mutex_timedlock(&ca_coll_ctrl.mutex, &time_out);
|
|
}
|
|
|
|
/* description: 释放线程超时锁
|
|
param:
|
|
return: */
|
|
void _ca_coll_unlock(void)
|
|
{
|
|
pthread_mutex_unlock(&ca_coll_ctrl.mutex);
|
|
}
|
|
|
|
/* description: 初始化报文头
|
|
param: buf - 数据缓冲
|
|
len - 报文长度, 不包含校验和
|
|
cmd_type - 命令类型
|
|
cmd - 命令字
|
|
return: */
|
|
void _ca_coll_pkt_head_init(char *buf, uint16_t len, uint8_t cmd_type, uint8_t cmd)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)buf;
|
|
|
|
head->len = len;
|
|
head->dev_type_m = ca_coll_ctrl.dev_info.type_m;
|
|
|
|
if (!ca_coll_ctrl.dev_info.type_s)
|
|
{
|
|
head->dev_type_s = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
head->dev_type_s = ca_coll_ctrl.dev_info.type_s;
|
|
}
|
|
|
|
if (!ca_coll_ctrl.dev_info.id)
|
|
{
|
|
head->dev_id = 0xFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
head->dev_id = ca_coll_ctrl.dev_info.id;
|
|
}
|
|
|
|
head->cmd_type = cmd_type;
|
|
head->cmd = cmd;
|
|
head->pkt_id = ca_coll_ctrl.pkt_id;
|
|
}
|
|
|
|
/* description: 报文发送
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_send(void)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)ca_coll_ctrl.buf_tx;
|
|
ca_coll_proto_mul_head_t *m_head = (ca_coll_proto_mul_head_t*)(ca_coll_ctrl.buf_tx + sizeof(ca_coll_proto_head_t));
|
|
uint16_t error_cnt = 0;
|
|
uint16_t len = 0;
|
|
uint32_t byte = 0;
|
|
|
|
/* 超时重发 3 次 */
|
|
while(error_cnt < CA_COLL_SEND_ERR_MAX)
|
|
{
|
|
/* 发送数据 */
|
|
len = head->len + CA_COLL_CRC32_LEN;
|
|
CA_COLL_RS485_TX_EN(1);
|
|
byte = write(ca_coll_ctrl.cfg.fd, ca_coll_ctrl.buf_tx, len);
|
|
usleep(byte * 90);
|
|
CA_COLL_RS485_TX_EN(0);
|
|
|
|
if (byte < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "COLL send ERR %d!\r\n", byte);
|
|
error_cnt++;
|
|
continue;
|
|
}
|
|
|
|
/* 调试打印 */
|
|
DBG(DBG_M_CA_COLL, "COLL send(%d): %d %d %d %d\r\n", len, time(NULL), head->cmd_type, head->cmd, m_head->index);
|
|
if (dbg_stat_get(DBG_M_CA_COLL))
|
|
{
|
|
buf_print(ca_coll_ctrl.buf_tx, len > 32 ? 32 : len);
|
|
}
|
|
|
|
/* 等待命令完成. */
|
|
if (_ca_coll_lock_timeout(1, 0) != 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "COLL send timeout ERR!\r\n");
|
|
error_cnt++;
|
|
continue;
|
|
}
|
|
|
|
/* 如果前 CA_COLL_ERR_CNT_MAX 发送失败, 这次就是恢复连接 */
|
|
if (ca_coll_ctrl.state.send_err_cnt >= CA_COLL_ERR_CNT_MAX)
|
|
{
|
|
log_err(LOG_COLL, "Cable device reconnect!");
|
|
}
|
|
|
|
/* 发送完成退出 */
|
|
ca_coll_ctrl.state.send_err_cnt = 0;
|
|
return E_NONE;
|
|
}
|
|
|
|
/* 错误计数处理 */
|
|
if (CA_COLL_ERR_CNT_MAX == ca_coll_ctrl.state.send_err_cnt)
|
|
{
|
|
ca_coll_ctrl.state.send_err_cnt++;
|
|
log_err(LOG_COLL, "Cable device is disconnect!");
|
|
}
|
|
else if(ca_coll_ctrl.state.send_err_cnt <= (CA_COLL_ERR_CNT_MAX + 1))
|
|
{
|
|
ca_coll_ctrl.state.send_err_cnt++;
|
|
}
|
|
|
|
return E_TIMEOUT;
|
|
}
|
|
|
|
/* description: 开机联络报文发送
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_contact(void)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)ca_coll_ctrl.buf_tx;
|
|
ca_coll_proto_contact_t *data = (ca_coll_proto_contact_t*)(ca_coll_ctrl.buf_tx + sizeof(ca_coll_proto_head_t));
|
|
uint32_t *crc = NULL;
|
|
|
|
/* 封装报文头 */
|
|
_ca_coll_pkt_head_init(ca_coll_ctrl.buf_tx, sizeof(ca_coll_proto_head_t) + sizeof(ca_coll_proto_contact_t), CA_COLL_CT_REQUEST, CA_COLL_C_DEV_INFO);
|
|
|
|
/* 封装数据 */
|
|
data->utc = time(NULL) - CA_COLL_SHIQUCHA;
|
|
data->interval = ca_coll_ctrl.dev_cfg.interval;
|
|
data->wave_force = FALSE;
|
|
data->wave_interval = ca_coll_ctrl.dev_cfg.wave_interval;
|
|
data->threshold = ca_coll_ctrl.dev_cfg.threshold;
|
|
data->wave_threshold = ca_coll_ctrl.dev_cfg.wave_threshold;
|
|
data->is_updata = FALSE;
|
|
data->main_cable = ca_coll_ctrl.dev_cfg.main_cable;
|
|
data->normal_sleep = ca_coll_ctrl.dev_cfg.normal_sleep;
|
|
data->is_voltage_col = ca_coll_ctrl.dev_cfg.is_voltage_col;
|
|
data->is_temp_col = ca_coll_ctrl.dev_cfg.is_temp_col;
|
|
data->is_wave_col = ca_coll_ctrl.dev_cfg.is_wave_col;
|
|
|
|
/* 计算校验和 */
|
|
crc = (uint32_t*)(ca_coll_ctrl.buf_tx + head->len);
|
|
*crc = crc32(ca_coll_ctrl.buf_tx, head->len);
|
|
|
|
/* 发送报文, 先置标志位, 再发送数据 */
|
|
ca_coll_ctrl.cmd_type = CA_COLL_CT_REPLY;
|
|
ca_coll_ctrl.cmd = CA_COLL_C_DEV_INFO;
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, _ca_coll_pkt_send());
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 请求实时数据报文发送
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_realdata(void)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)ca_coll_ctrl.buf_tx;
|
|
ca_land_state_t* state = ca_land_state_get();
|
|
ca_mqtt_state_t *ca_mqtt_state = ca_mqtt_state_get();
|
|
uint32_t *crc = NULL;
|
|
|
|
/* 封装报文头 */
|
|
_ca_coll_pkt_head_init(ca_coll_ctrl.buf_tx, sizeof(ca_coll_proto_head_t), CA_COLL_CT_PRV_REQUEST, CA_COLL_PRV_REAL_DATA);
|
|
|
|
/* 计算校验和 */
|
|
crc = (uint32_t*)(ca_coll_ctrl.buf_tx + head->len);
|
|
*crc = crc32(ca_coll_ctrl.buf_tx, head->len);
|
|
|
|
/* 发送报文, 先置标志位, 再发送数据 */
|
|
ca_coll_ctrl.cmd_type = CA_COLL_CT_PRV_REPLY;
|
|
ca_coll_ctrl.cmd = CA_COLL_PRV_REAL_DATA;
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, _ca_coll_pkt_send());
|
|
|
|
/* 通知向服务器发送数据 */
|
|
if (ca_coll_ctrl.cfg.is_land)
|
|
{
|
|
state->is_send_data = TRUE;
|
|
}
|
|
|
|
if (ca_mqtt_state->is_connect)
|
|
{
|
|
ca_mqtt_data_report(&ca_coll_ctrl.dev_data);
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: APP 升级报文发送
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_update(void)
|
|
{
|
|
char *buf = ca_coll_ctrl.buf_tx;
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)buf;
|
|
ca_coll_proto_mul_head_t *head_m = (ca_coll_proto_mul_head_t*)(buf + sizeof(ca_coll_proto_head_t));
|
|
char *data = buf + sizeof(ca_coll_proto_head_t) + sizeof(ca_coll_proto_mul_head_t);
|
|
uint32_t *crc = NULL;
|
|
int32_t len = 0;
|
|
|
|
/* 打开升级文件描述符 */
|
|
if (ca_coll_ctrl.state.fd_read <= 0)
|
|
{
|
|
ca_coll_ctrl.state.fd_read = open(CA_COLL_CABLE_FILE, O_RDONLY, 0777);
|
|
if (ca_coll_ctrl.state.fd_read < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Open " CA_COLL_CABLE_FILE " ERROR\r\n");
|
|
return E_SYS_CALL;
|
|
}
|
|
}
|
|
|
|
/* 置升级标志位 */
|
|
ca_coll_ctrl.cmd_type = CA_COLL_CT_REPLY;
|
|
ca_coll_ctrl.cmd = CA_COLL_C_UPDATE_APP;
|
|
|
|
/* 升级开始 */
|
|
while(1)
|
|
{
|
|
/* 封装报文头 */
|
|
head_m->index = ca_coll_ctrl.state.update_index;
|
|
len = read(ca_coll_ctrl.state.fd_read, data, 1024);
|
|
if (len < 0)
|
|
{
|
|
close(ca_coll_ctrl.state.fd_read);
|
|
ca_coll_ctrl.state.fd_read = 0;
|
|
DBG(DBG_M_CA_COLL_ERR, "read " CA_COLL_CABLE_FILE " ERROR\r\n");
|
|
return E_SYS_CALL;
|
|
}
|
|
head_m->len = len;
|
|
_ca_coll_pkt_head_init(buf, sizeof(ca_coll_proto_head_t) + sizeof(ca_coll_proto_mul_head_t) + len, CA_COLL_CT_REQUEST, CA_COLL_C_UPDATE_APP);
|
|
|
|
/* 计算校验和 */
|
|
crc = (uint32_t*)(ca_coll_ctrl.buf_tx + head->len);
|
|
*crc = crc32(ca_coll_ctrl.buf_tx, head->len);
|
|
|
|
/* 发送数据 */
|
|
if (_ca_coll_pkt_send() != E_NONE)
|
|
{
|
|
close(ca_coll_ctrl.state.fd_read);
|
|
ca_coll_ctrl.state.fd_read = 0;
|
|
DBG(DBG_M_CA_COLL_ERR, "send " CA_COLL_CABLE_FILE " ERROR\r\n");
|
|
return E_ERROR;
|
|
}
|
|
|
|
/* 长度小于 1024 表示是最后一个报文 */
|
|
if (len < 1024)
|
|
{
|
|
close(ca_coll_ctrl.state.fd_read);
|
|
ca_coll_ctrl.state.fd_read = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 请求 APP 升级结果报文发送
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_update_rt(void)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)ca_coll_ctrl.buf_tx;
|
|
uint32_t *crc = NULL;
|
|
|
|
/* 封装报文头 */
|
|
_ca_coll_pkt_head_init(ca_coll_ctrl.buf_tx, sizeof(ca_coll_proto_head_t), CA_COLL_CT_REQUEST, CA_COLL_C_UPDATE_APP_RT);
|
|
|
|
/* 计算校验和 */
|
|
crc = (uint32_t*)(ca_coll_ctrl.buf_tx + head->len);
|
|
*crc = crc32(ca_coll_ctrl.buf_tx, head->len);
|
|
|
|
/* 发送报文, 先置标志位, 再发送数据 */
|
|
ca_coll_ctrl.cmd_type = CA_COLL_CT_REPLY;
|
|
ca_coll_ctrl.cmd = CA_COLL_C_UPDATE_APP_RT;
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, _ca_coll_pkt_send());
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流数据发送处理线程
|
|
param:
|
|
return: */
|
|
void *_ca_coll_handle_send(void *arg)
|
|
{
|
|
int32_t utc = 0;
|
|
int32_t now = 0;
|
|
|
|
while(1)
|
|
{
|
|
/* 每 3s 轮询一次 */
|
|
sleep(CA_COLL_LOOP_INR);
|
|
|
|
/* 升级流程 */
|
|
if (ca_coll_ctrl.state.is_update_cable)
|
|
{
|
|
ca_coll_ctrl.state.update_index = 0;
|
|
if (E_NONE == _ca_coll_pkt_update())
|
|
{
|
|
_ca_coll_pkt_update_rt();
|
|
}
|
|
ca_coll_ctrl.state.is_update_cable = FALSE;
|
|
/* 升级完成后等待 60s 再取数据 */
|
|
utc += 60;
|
|
}
|
|
|
|
/* 判断采集间隔 */
|
|
now = time(NULL);
|
|
if (now - utc >= ca_coll_ctrl.cfg.coll_inr)
|
|
{
|
|
utc = now;
|
|
|
|
/* 开机联络 */
|
|
_ca_coll_pkt_contact();
|
|
|
|
/* 读取数据 */
|
|
_ca_coll_pkt_realdata();
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* description: 环流设备信息报文处理
|
|
param: cmd - 报文缓冲
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_dev_info(char *cmd)
|
|
{
|
|
ca_coll_dev_info_t *info = (ca_coll_dev_info_t*)(cmd + sizeof(ca_coll_proto_head_t));
|
|
|
|
memcpy(&ca_coll_ctrl.dev_info, info, sizeof(ca_coll_dev_info_t));
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流设备升级报文处理
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_update_reply(void)
|
|
{
|
|
ca_coll_ctrl.state.update_index++;
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流设备升级结果报文处理
|
|
param: cmd - 报文缓冲
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_update_rt_reply(char *cmd)
|
|
{
|
|
int32_t *rt = (int32_t*)(cmd + sizeof(ca_coll_proto_head_t));
|
|
|
|
ca_dbg_update_rt_send(*rt);
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流设备数据报文处理
|
|
param: cmd - 报文缓冲
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_data(char *cmd)
|
|
{
|
|
ca_coll_dev_data_t *data = (ca_coll_dev_data_t*)(cmd + sizeof(ca_coll_proto_head_t));
|
|
|
|
memcpy(&ca_coll_ctrl.dev_data, data, sizeof(ca_coll_dev_data_t));
|
|
ca_db_write(CA_DB_T_DATA, &ca_coll_ctrl.dev_data);
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流设备报文格式检查
|
|
param: cmd - 报文缓冲
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_check(char *cmd)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)cmd;
|
|
|
|
/* 对主次设备号进行识别 */
|
|
if ((head->dev_type_m != 1)
|
|
|| (ca_coll_ctrl.dev_info.type_s != 0 && head->dev_type_s != ca_coll_ctrl.dev_info.type_s))
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Dev type %d:%d error\r\n", head->dev_type_m, head->dev_type_s);
|
|
return E_NOT_FOUND;
|
|
}
|
|
|
|
/* 对设备 id 进行识别 */
|
|
if (ca_coll_ctrl.dev_info.id != 0 && head->dev_id != ca_coll_ctrl.dev_info.id)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Dev id %x error\r\n", head->dev_id);
|
|
return E_NOT_FOUND;
|
|
}
|
|
|
|
/* 验证 CRC32 */
|
|
if (crc32(cmd, head->len) != (*(uint32_t*)(cmd + head->len)))
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "CRC %x:%x error\r\n", crc32(cmd, head->len), *(uint32_t*)(cmd + head->len));
|
|
return E_ERROR;
|
|
}
|
|
|
|
/* pkt_id 验证 */
|
|
if (head->pkt_id != ca_coll_ctrl.pkt_id)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Pkt id %d:%d error\r\n", ca_coll_ctrl.pkt_id, head->pkt_id);
|
|
return E_ERROR;
|
|
}
|
|
|
|
/* cmd 验证 */
|
|
if (head->cmd_type != ca_coll_ctrl.cmd_type
|
|
|| head->cmd != ca_coll_ctrl.cmd)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Cmd type %d:%d error\r\n", head->cmd_type, head->cmd);
|
|
return E_ERROR;
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流设备报文处理
|
|
param: cmd - 报文缓冲
|
|
return: E_XXX */
|
|
int32_t _ca_coll_pkt_process(char *cmd)
|
|
{
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)cmd;
|
|
|
|
/* 报文头和 CRC 校验 */
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, _ca_coll_pkt_check(cmd));
|
|
|
|
if (CA_COLL_CT_REPLY == head->cmd_type)
|
|
{
|
|
/* 共有命令处理 */
|
|
switch (head->cmd)
|
|
{
|
|
case CA_COLL_C_DEV_INFO:
|
|
_ca_coll_pkt_dev_info(cmd);
|
|
break;
|
|
case CA_COLL_C_UPDATE_APP:
|
|
_ca_coll_pkt_update_reply();
|
|
break;
|
|
case CA_COLL_C_UPDATE_APP_RT:
|
|
_ca_coll_pkt_update_rt_reply(cmd);
|
|
break;
|
|
default:
|
|
DBG(DBG_M_CA_COLL_ERR, "Cmd %d not found\r\n", head->cmd);
|
|
return E_NOT_FOUND;
|
|
}
|
|
}
|
|
else if (CA_COLL_CT_PRV_REPLY == head->cmd_type)
|
|
{
|
|
/* 私有命令处理. */
|
|
switch (head->cmd)
|
|
{
|
|
case CA_COLL_PRV_REAL_DATA:
|
|
_ca_coll_pkt_data(cmd);
|
|
break;
|
|
default:
|
|
DBG(DBG_M_CA_COLL_ERR, "Cmd %d not found\r\n", head->cmd);
|
|
return E_NOT_FOUND;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Cmd type %d not found\r\n", head->cmd_type);
|
|
return E_NOT_FOUND;
|
|
}
|
|
|
|
/* 释放锁, 告知发送线程发送完成 */
|
|
_ca_coll_unlock();
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流数据接收处理线程
|
|
param:
|
|
return: */
|
|
void *_ca_coll_handle_recv(void *arg)
|
|
{
|
|
static uint8_t state = FALSE;
|
|
static uint32_t utc = 0;
|
|
static uint32_t cmd_buf_index = 0;
|
|
uint32_t now = 0;
|
|
ca_coll_proto_head_t *head = (ca_coll_proto_head_t*)ca_coll_ctrl.cmd_buf;
|
|
ca_coll_proto_mul_head_t *m_head = (ca_coll_proto_mul_head_t*)(ca_coll_ctrl.cmd_buf + sizeof(ca_coll_proto_head_t));
|
|
char *buf = ca_coll_ctrl.buf_rx;
|
|
uint16_t len = 0;
|
|
|
|
while(1)
|
|
{
|
|
/* 读取数据 */
|
|
len = read(ca_coll_ctrl.cfg.fd, buf, CA_COLL_BUF_LEN);
|
|
if (len < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "COLL recv ERR %d!\r\n", len);
|
|
sleep(3);
|
|
continue;
|
|
}
|
|
|
|
/* 超过 3s 没有收包说明收包超时, 重新开始收包 */
|
|
now = time(NULL);
|
|
if (now - utc > 3)
|
|
{
|
|
cmd_buf_index = 0;
|
|
state = 0;
|
|
}
|
|
utc = now;
|
|
|
|
/* 如果收包大于协议报文长度或者大于 buf 长度, 认为报文错误 */
|
|
if (cmd_buf_index + len >= CA_COLL_BUF_LEN
|
|
|| (cmd_buf_index >= 2 && (cmd_buf_index + len) > (head->len + CA_COLL_CRC32_LEN)))
|
|
{
|
|
cmd_buf_index = 0;
|
|
state = 0;
|
|
continue;
|
|
}
|
|
|
|
/* 将 buf 中的数据解析成命令 */
|
|
memcpy(&ca_coll_ctrl.cmd_buf[cmd_buf_index], buf, len);
|
|
cmd_buf_index += len;
|
|
|
|
if (!state)
|
|
{
|
|
if (cmd_buf_index < 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* 报文长度不对, 重新收包 */
|
|
if (head->len + CA_COLL_CRC32_LEN > CA_COLL_BUF_LEN)
|
|
{
|
|
cmd_buf_index = 0;
|
|
continue;
|
|
}
|
|
|
|
/* 报文长度与收包长度不对称, 等待后续报文 */
|
|
if (cmd_buf_index < head->len + CA_COLL_CRC32_LEN)
|
|
{
|
|
state = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 报文长度与收包长度不对称, 等待后续报文 */
|
|
if (cmd_buf_index < head->len + CA_COLL_CRC32_LEN)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
state = FALSE;
|
|
}
|
|
|
|
/* 调试打印 */
|
|
DBG(DBG_M_CA_COLL, "Recv(%d): %d %d %d %d\r\n", cmd_buf_index, utc, head->cmd_type, head->cmd, m_head->index);
|
|
if (dbg_stat_get(DBG_M_CA_COLL))
|
|
{
|
|
buf_print(ca_coll_ctrl.cmd_buf, cmd_buf_index > 32 ? 32 : cmd_buf_index);
|
|
//buf_print(ca_coll_ctrl.cmd_buf, cmd_buf_index);
|
|
}
|
|
|
|
/* 收报完成, 数据处理 */
|
|
_ca_coll_pkt_process(ca_coll_ctrl.cmd_buf);
|
|
cmd_buf_index = 0;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* description: 4G gpio 设置
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_4g_gpio_set(void)
|
|
{
|
|
int32_t gpio = 0;
|
|
|
|
gpio = gpio_export(CA_COLL_GPIO_4G_PW_EN);
|
|
if (gpio < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR return %d!\r\n", gpio);
|
|
return E_BAD_PARAM;
|
|
}
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, gpio_dir_set(gpio, GPIO_DIR_OUT));
|
|
ca_coll_ctrl.gpio_4g_pw = gpio;
|
|
|
|
gpio = gpio_export(CA_COLL_GPIO_4G_RST);
|
|
if (gpio < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR return %d!\r\n", gpio);
|
|
return E_BAD_PARAM;
|
|
}
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, gpio_dir_set(gpio, GPIO_DIR_OUT));
|
|
ca_coll_ctrl.gpio_4g_rst = gpio;
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 4G APN 配置修改
|
|
param: dest - 目标文件
|
|
apn - APN
|
|
return: E_XXX */
|
|
int32_t _ca_coll_4g_apn_change(char *dest, char *apn)
|
|
{
|
|
int32_t i = 0;
|
|
int32_t num = 0;
|
|
char str[100][128] = {0};
|
|
char linedata[128] = {0};
|
|
FILE *fp = NULL;
|
|
|
|
/* 打开文件 */
|
|
fp = fopen(dest, "r");
|
|
if (NULL == fp)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Open quectel-chat-connect ERROR\r\n");
|
|
return E_SYS_CALL;
|
|
}
|
|
|
|
/* 修改 APN */
|
|
// "OK \rAT+CGDCONT=1,"IP","3gnet",,0,0"
|
|
while(fgets(linedata, sizeof(linedata) - 1, fp))
|
|
{
|
|
if (strstr(linedata, "AT+CGDCONT") != NULL)
|
|
{
|
|
sprintf(str[i],"OK \\rAT+CGDCONT=1,\"IP\",\"%s\",,0,0\n", apn);
|
|
}
|
|
else
|
|
{
|
|
strcpy(str[i], linedata);
|
|
}
|
|
i++;
|
|
}
|
|
fclose(fp);
|
|
|
|
/* 回写文件 */
|
|
num = i;
|
|
fp = fopen(dest, "w");
|
|
if (NULL == fp)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "Open quectel-chat-connect ERROR\r\n");
|
|
return E_SYS_CALL;
|
|
}
|
|
|
|
for(i = 0; i < num; i++)
|
|
{
|
|
fputs(str[i], fp);
|
|
}
|
|
fflush(fp);
|
|
fclose(fp);
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 4G 文件备份检查
|
|
param: index - 文件列表索引
|
|
return: */
|
|
void _ca_coll_4g_file_backup(int32_t index)
|
|
{
|
|
struct stat file_stat;
|
|
char *source = ca_coll_4g_file[index].source;
|
|
char *dest = ca_coll_4g_file[index].dest;
|
|
char *mode = ca_coll_4g_file[index].mode;
|
|
char cmd[128] = {0};
|
|
int fd = -1;
|
|
off_t size = 0;
|
|
int32_t ret = -1;
|
|
|
|
/* 查找文件 */
|
|
if (!access(dest, F_OK))
|
|
{
|
|
fd = open(dest, O_RDONLY);
|
|
if (fd != -1)
|
|
{
|
|
ret = fstat(fd, &file_stat);
|
|
if (ret != -1)
|
|
{
|
|
size = file_stat.st_size;
|
|
}
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
/* 文件是否正常 */
|
|
if (size > 16)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* 备份文件 */
|
|
log_err(LOG_COLL, "Backup file, %s!", dest);
|
|
snprintf(cmd, 128, "cp %s %s", source, dest);
|
|
system(cmd);
|
|
snprintf(cmd, 128, "chmod %s %s", mode, dest);
|
|
system(cmd);
|
|
|
|
if (CA_COLL_4G_FILE_PPP_CONN == index)
|
|
{
|
|
_ca_coll_4g_apn_change(dest, ca_coll_ctrl.cfg.apn);
|
|
}
|
|
|
|
/* 重启设备 */
|
|
reboot_system(LOG_COLL, BOOT_FILE_RECOVER);
|
|
}
|
|
|
|
/* description: 4G 连接监护线程
|
|
param:
|
|
return: */
|
|
void *_ca_coll_handle_4g(void *arg)
|
|
{
|
|
struct ifaddrs *ifa = NULL, *ifList = NULL;
|
|
int8_t err_cnt = 0;
|
|
int8_t file_index = 0;
|
|
bool is_found = FALSE;
|
|
|
|
/* 4G 初始化 */
|
|
_ca_coll_4g_gpio_set();
|
|
CA_COLL_4G_PW_EN(1);
|
|
|
|
while(1)
|
|
{
|
|
/* 备份文件 */
|
|
_ca_coll_4g_file_backup(file_index);
|
|
file_index++;
|
|
if (CA_COLL_4G_FILE_CNT == file_index)
|
|
{
|
|
file_index = 0;
|
|
}
|
|
|
|
/* 查询 4G 是否连接 */
|
|
is_found = FALSE;
|
|
if (getifaddrs(&ifList) < 0)
|
|
{
|
|
err_cnt++;
|
|
sleep(20);
|
|
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)
|
|
{
|
|
ca_coll_ctrl.state.is_4g_connect = TRUE;
|
|
err_cnt = 0;
|
|
sleep(20);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
ca_coll_ctrl.state.is_4g_connect = FALSE;
|
|
DBG(DBG_M_CA_COLL, "4G connect start...\r\n");
|
|
err_cnt++;
|
|
if(err_cnt > 10)
|
|
{
|
|
reboot_system(LOG_COLL, BOOT_4G_ERR);
|
|
sleep(20);
|
|
continue;
|
|
}
|
|
|
|
system("killall pppd");
|
|
CA_COLL_4G_RST(1);
|
|
usleep(300*1000);
|
|
CA_COLL_4G_RST(0);
|
|
sleep(20);
|
|
system("pppd call quectel-ppp &");
|
|
sleep(20);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* description: RS485 GPIO 初始化
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_rs485_gpio_set(void)
|
|
{
|
|
int32_t gpio = 0;
|
|
|
|
gpio = gpio_export(CA_COLL_GPIO_RS485_TX_EN);
|
|
if (gpio < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR return %d!\r\n", gpio);
|
|
return E_BAD_PARAM;
|
|
}
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, gpio_dir_set(gpio, GPIO_DIR_OUT));
|
|
ca_coll_ctrl.gpio_rs485_tx_en = gpio;
|
|
|
|
gpio = gpio_export(CA_COLL_GPIO_RS485_TX_EN1);
|
|
if (gpio < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR return %d!\r\n", gpio);
|
|
return E_BAD_PARAM;
|
|
}
|
|
LD_E_RETURN(DBG_M_CA_COLL_ERR, gpio_dir_set(gpio, GPIO_DIR_OUT));
|
|
ca_coll_ctrl.gpio_rs485_tx_en1 = gpio;
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 串口配置通用设置
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_rs485_set(void)
|
|
{
|
|
struct termios opt;
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
|
|
/* 清空串口接收缓冲区 */
|
|
tcflush(cfg->fd, TCIOFLUSH);
|
|
|
|
/* 获取串口配置参数 */
|
|
tcgetattr(cfg->fd, &opt);
|
|
|
|
opt.c_cflag &= ~(CBAUD); // 清除数据位设置
|
|
opt.c_cflag &= ~(PARENB); // 清除校验位设置
|
|
|
|
opt.c_iflag &= ~(INLCR| ICRNL);
|
|
opt.c_iflag &= ~(IXON | IXOFF| IXANY);
|
|
opt.c_oflag &= ~(OPOST);
|
|
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
|
|
|
/* 设置波特率 */
|
|
switch(cfg->baud)
|
|
{
|
|
case 2400:
|
|
cfsetspeed(&opt, B2400);
|
|
break;
|
|
|
|
case 4800:
|
|
cfsetspeed(&opt, B4800);
|
|
break;
|
|
|
|
case 9600:
|
|
cfsetspeed(&opt, B9600);
|
|
break;
|
|
|
|
case 19200:
|
|
cfsetspeed(&opt, B9600);
|
|
break;
|
|
|
|
case 38400:
|
|
cfsetspeed(&opt, B38400);
|
|
break;
|
|
|
|
case 57600:
|
|
cfsetspeed(&opt, B57600);
|
|
break;
|
|
|
|
case 115200:
|
|
cfsetspeed(&opt, B115200);
|
|
break;
|
|
|
|
case 460800:
|
|
cfsetspeed(&opt, B460800);
|
|
break;
|
|
|
|
case 921600:
|
|
cfsetspeed(&opt, B921600);
|
|
break;
|
|
|
|
default:
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置数据位 */
|
|
switch(cfg->bits)
|
|
{
|
|
case 7:
|
|
opt.c_cflag |= CS7;
|
|
break;
|
|
|
|
case 8:
|
|
opt.c_cflag |= CS8;
|
|
break;
|
|
|
|
default:
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置校验位 */
|
|
switch(cfg->parity)
|
|
{
|
|
/* 无奇偶校验 */
|
|
case 'n':
|
|
case 'N':
|
|
opt.c_cflag &= (~PARENB);
|
|
break;
|
|
|
|
/* 奇校验 */
|
|
case 'o':
|
|
case 'O':
|
|
opt.c_cflag |= PARODD;
|
|
break;
|
|
|
|
/* 偶校验 */
|
|
case 'e':
|
|
case 'E':
|
|
opt.c_cflag |= PARENB;
|
|
opt.c_cflag &= (~PARODD);
|
|
break;
|
|
|
|
default:
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置停止位 */
|
|
switch(cfg->stop)
|
|
{
|
|
case 1:
|
|
opt.c_cflag &= ~CSTOPB;
|
|
break;
|
|
case 2:
|
|
opt.c_cflag |= CSTOPB;
|
|
break;
|
|
default:
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置串口 */
|
|
tcsetattr(cfg->fd, TCSANOW, &opt);
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 初始化 RS485 串口
|
|
param:
|
|
return: E_XXX */
|
|
int32_t _ca_coll_rs485_open(void)
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
char dev[CA_COLL_USART_NAME_LEN] = {0};
|
|
|
|
/* 打开驱动 */
|
|
snprintf(dev, CA_COLL_USART_NAME_LEN, "/dev/%s", cfg->dev);
|
|
cfg->fd = open(dev, O_RDWR | O_NOCTTY);
|
|
if (cfg->fd < 0)
|
|
{
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR at open RS485 return %s!\r\n", safe_strerror(errno));
|
|
cfg->fd = 0;
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置串口参数 */
|
|
if (_ca_coll_rs485_set() != E_NONE)
|
|
{
|
|
close(cfg->fd);
|
|
cfg->fd = 0;
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR at RS485 config!\r\n");
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
/* 设置 RS485 GPIO */
|
|
if (_ca_coll_rs485_gpio_set() != E_NONE)
|
|
{
|
|
close(cfg->fd);
|
|
cfg->fd = 0;
|
|
DBG(DBG_M_CA_COLL_ERR, "ERROR at RS485 GPIO config!\r\n");
|
|
return E_BAD_PARAM;
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 全局配置保存函数
|
|
param:
|
|
return: */
|
|
int _ca_coll_config_save(vty_t* vty)
|
|
{
|
|
vty_out(vty, "collect interval %d%s", ca_coll_ctrl.cfg.coll_inr, VTY_NEWLINE);
|
|
vty_out(vty, "collect 4g %s%s", ca_coll_ctrl.cfg.is_4G ? "enable" : "disable", VTY_NEWLINE);
|
|
vty_out(vty, "collect apn %s%s", ca_coll_ctrl.cfg.apn, VTY_NEWLINE);
|
|
vty_out(vty, "collect land %s%s", ca_coll_ctrl.cfg.is_land ? "enable" : "disable", VTY_NEWLINE);
|
|
vty_out(vty, "collect land server %s %d%s", ca_coll_ctrl.cfg.land_ip, ca_coll_ctrl.cfg.land_port, VTY_NEWLINE);
|
|
vty_out(vty, "!%s", VTY_NEWLINE);
|
|
|
|
vty_out(vty, "device interval %d%s", ca_coll_ctrl.dev_cfg.interval, VTY_NEWLINE);
|
|
vty_out(vty, "device threshold %d%s", ca_coll_ctrl.dev_cfg.threshold, VTY_NEWLINE);
|
|
vty_out(vty, "device wave interval %d%s", ca_coll_ctrl.dev_cfg.wave_interval, VTY_NEWLINE);
|
|
vty_out(vty, "device wave threshold %d%s", ca_coll_ctrl.dev_cfg.wave_threshold, VTY_NEWLINE);
|
|
vty_out(vty, "device main cable %d%s", ca_coll_ctrl.dev_cfg.main_cable, VTY_NEWLINE);
|
|
vty_out(vty, "device voltage %s%s", ca_coll_ctrl.dev_cfg.is_voltage_col ? "enable" : "disable", VTY_NEWLINE);
|
|
vty_out(vty, "device temperature %s%s", ca_coll_ctrl.dev_cfg.is_temp_col ? "enable" : "disable", VTY_NEWLINE);
|
|
vty_out(vty, "device wave %s%s", ca_coll_ctrl.dev_cfg.is_wave_col ? "enable" : "disable", VTY_NEWLINE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* description: 全局配置保存函数
|
|
param:
|
|
return: */
|
|
int32_t _ca_coll_rs485_config_save(vty_t *vty)
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
array_t *configs = ca_coll_rs485_node.configs;
|
|
ca_coll_rs485_cmd_save_config_f *func = NULL;
|
|
uint8_t i = 0;
|
|
|
|
vty_out(vty, "interface rs485 coll%s", VTY_NEWLINE);
|
|
|
|
for(i = 0; i < array_active(configs); i++)
|
|
{
|
|
func = array_lookup(configs, i);
|
|
if (!func)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
func(vty, 1);
|
|
}
|
|
|
|
vty_out(vty, " device %s%s", cfg->dev, VTY_NEWLINE);
|
|
vty_out(vty, " baud %d%s", cfg->baud, VTY_NEWLINE);
|
|
vty_out(vty, " bits %d%s", cfg->bits, VTY_NEWLINE);
|
|
vty_out(vty, " parity %c%s", cfg->parity, VTY_NEWLINE);
|
|
vty_out(vty, " stop %d%s", cfg->stop, VTY_NEWLINE);
|
|
vty_out(vty, "!%s", VTY_NEWLINE);
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* Interface functions -------------------------------------------------------*/
|
|
/* description: 环流采集程序初始化入口函数
|
|
param:
|
|
return: E_XXX */
|
|
int32_t ca_coll_init(void)
|
|
{
|
|
ca_coll_cfg_t *cfg = &ca_coll_ctrl.cfg;
|
|
int32_t rv = E_NONE;
|
|
|
|
/* 初始化变量 */
|
|
ca_coll_ctrl.pkt_id = 0;
|
|
ca_coll_ctrl.dev_info.type_m = 1;
|
|
snprintf(cfg->dev, CA_COLL_USART_NAME_LEN, CA_COLL_USART_NAME);
|
|
cfg->baud = 115200;
|
|
cfg->bits = 8;
|
|
cfg->parity = 'n';
|
|
cfg->stop = 1;
|
|
cfg->coll_inr = 60;
|
|
cfg->is_4G = FALSE;
|
|
snprintf(cfg->apn, CA_COLL_VPN_LEN, CA_COLL_APN_NAME);
|
|
cfg->is_land = FALSE;
|
|
snprintf(cfg->land_ip, INET_ADDRSTRLEN, CA_COLL_LAND_IP);
|
|
cfg->land_port = CA_COLL_LAND_PORT;
|
|
|
|
ca_coll_ctrl.dev_cfg.interval = 1;
|
|
ca_coll_ctrl.dev_cfg.threshold = 1;
|
|
ca_coll_ctrl.dev_cfg.wave_interval = 255;
|
|
ca_coll_ctrl.dev_cfg.wave_threshold = 1000;
|
|
ca_coll_ctrl.dev_cfg.main_cable = 0;
|
|
ca_coll_ctrl.dev_cfg.is_voltage_col = TRUE;
|
|
ca_coll_ctrl.dev_cfg.is_temp_col = FALSE;
|
|
ca_coll_ctrl.dev_cfg.is_wave_col = FALSE;
|
|
|
|
/* 注册 RS485 节点. */
|
|
cmd_install_node(&ca_coll_rs485_node, _ca_coll_rs485_config_save);
|
|
ca_coll_rs485_node.prompt = XMALLOC(MTYPE_CA_COLL, CA_COLL_USART_NAME_LEN);
|
|
ca_coll_rs485_node.configs = array_init(CA_COLL_RS485_CMD_PRI_COUNT, MTYPE_CA_COLL);
|
|
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_rs485_terminal_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_inr_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_4g_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_apn_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_land_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_land_server_set_cmd);
|
|
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_inr_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_thr_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_wave_inr_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_wave_thr_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_main_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_voltage_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_temp_cmd);
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_dev_wave_cmd);
|
|
|
|
cmd_install_element(CONFIG_NODE, &ca_coll_mqtt_enable_set_cmd);
|
|
|
|
cmd_install_element(COLL_RS485_NODE, &ca_coll_rs485_dev_cmd);
|
|
cmd_install_element(COLL_RS485_NODE, &ca_coll_rs485_baud_cmd);
|
|
cmd_install_element(COLL_RS485_NODE, &ca_coll_rs485_bits_cmd);
|
|
cmd_install_element(COLL_RS485_NODE, &ca_coll_rs485_parity_cmd);
|
|
cmd_install_element(COLL_RS485_NODE, &ca_coll_rs485_stop_cmd);
|
|
|
|
cmd_install_element(COMMON_NODE, &ca_coll_show_device_cmd);
|
|
cmd_install_element(COMMON_NODE, &ca_coll_show_device_data_cmd);
|
|
cmd_install_element(COMMON_NODE, &ca_coll_show_device_state_cmd);
|
|
|
|
/* 注册配置保存函数 */
|
|
rv = cmd_config_node_config_register(CONFIG_PRI_CA_COLL, _ca_coll_config_save);
|
|
if (rv != E_NONE)
|
|
{
|
|
log_err(LOG_COLL, "Command save register ERROR %d!", rv);
|
|
return rv;
|
|
}
|
|
|
|
return E_NONE;
|
|
}
|
|
|
|
/* description: 环流采集程序初始化
|
|
param:
|
|
return: E_XXX */
|
|
int32_t ca_coll_init_after(void)
|
|
{
|
|
struct sched_param param;
|
|
pthread_attr_t attr;
|
|
pthread_t pid;
|
|
int32_t rv = E_NONE;
|
|
|
|
/* 打开串口 */
|
|
if ((rv = _ca_coll_rs485_open()) != E_NONE)
|
|
{
|
|
log_err(LOG_COLL, "Cable can't open rs485 %d!", rv);
|
|
return rv;
|
|
}
|
|
|
|
/* 初始化线程锁, 用于发包线程与首保线程同步 */
|
|
pthread_mutex_init(&ca_coll_ctrl.mutex, NULL);
|
|
pthread_mutex_lock(&ca_coll_ctrl.mutex);
|
|
|
|
/* 初始化采集发包线程 */
|
|
/* 配置线程RR调度, 优先级 80 */
|
|
pthread_attr_init(&attr);
|
|
param.sched_priority = 80;
|
|
pthread_attr_setschedpolicy(&attr, SCHED_RR);
|
|
pthread_attr_setschedparam(&attr, ¶m);
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
rv = pthread_create(&pid, &attr, _ca_coll_handle_send, NULL);
|
|
if (rv != 0)
|
|
{
|
|
log_err(LOG_COLL, "Cable can't create collect pthread %d!", rv);
|
|
return rv;
|
|
}
|
|
else
|
|
{
|
|
thread_m_add("CA_COLL_SEND", pid);
|
|
}
|
|
pthread_attr_destroy(&attr);
|
|
|
|
/* 初始化采集收包线程 */
|
|
/* 配置线程RR调度, 优先级 79 */
|
|
pthread_attr_init(&attr);
|
|
param.sched_priority = 79;
|
|
pthread_attr_setschedpolicy(&attr, SCHED_RR);
|
|
pthread_attr_setschedparam(&attr, ¶m);
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
rv = pthread_create(&pid, &attr, _ca_coll_handle_recv, NULL);
|
|
if (rv != 0)
|
|
{
|
|
log_err(LOG_COLL, "Cable can't create collect pthread %d!", rv);
|
|
return rv;
|
|
}
|
|
else
|
|
{
|
|
thread_m_add("CA_COLL_RECV", pid);
|
|
}
|
|
pthread_attr_destroy(&attr);
|
|
|
|
if (ca_coll_ctrl.cfg.is_4G)
|
|
{
|
|
/* 初始化 4G 线程 */
|
|
/* 配置线程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, _ca_coll_handle_4g, NULL);
|
|
if (rv != 0)
|
|
{
|
|
log_err(LOG_COLL, "Cable can't create collect pthread %d!", rv);
|
|
return rv;
|
|
}
|
|
else
|
|
{
|
|
thread_m_add("CA_COLL_4G", pid);
|
|
}
|
|
pthread_attr_destroy(&attr);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* description: 设备配置结构体获取
|
|
param:
|
|
return: ca_coll_cfg_t - 设备配置结构体指针 */
|
|
ca_coll_cfg_t* ca_coll_cfg_get(void)
|
|
{
|
|
return &ca_coll_ctrl.cfg;
|
|
}
|
|
|
|
/* description: 环流信息结构体获取
|
|
param:
|
|
return: ca_coll_dev_info_t - 环流信息结构体指针 */
|
|
ca_coll_dev_info_t* ca_coll_cable_info_get(void)
|
|
{
|
|
return &ca_coll_ctrl.dev_info;
|
|
}
|
|
|
|
/* description: 环流配置结构体获取
|
|
param:
|
|
return: ca_coll_dev_cfg_t - 环流配置结构体指针 */
|
|
ca_coll_dev_cfg_t* ca_coll_cable_cfg_get(void)
|
|
{
|
|
return &ca_coll_ctrl.dev_cfg;
|
|
}
|
|
|
|
/* description: 环流数据结构体获取
|
|
param:
|
|
return: ca_coll_dev_data_t - 环流数据结构体指针 */
|
|
ca_coll_dev_data_t* ca_coll_cable_data_get(void)
|
|
{
|
|
return &ca_coll_ctrl.dev_data;
|
|
}
|
|
|
|
/* description: 设备状态结构体获取
|
|
param:
|
|
return: ca_coll_state_t - 设备状态结构体指针 */
|
|
ca_coll_state_t* ca_coll_cable_state_get(void)
|
|
{
|
|
return &ca_coll_ctrl.state;
|
|
}
|
|
|
|
/* description: 环流升级使能配置
|
|
param: enable - 使能标志
|
|
return: */
|
|
void ca_coll_cable_update_set(bool enable)
|
|
{
|
|
ca_coll_ctrl.state.is_update_cable = enable;
|
|
}
|
|
|
|
/* description: 环流信息显示
|
|
param:
|
|
return: */
|
|
void ca_coll_show_dev(void)
|
|
{
|
|
ca_coll_dev_info_t *info = &ca_coll_ctrl.dev_info;
|
|
|
|
printh("Boot version %s, compile time is %s\r\n", info->boot_version, info->boot_compile_time);
|
|
printh("Img version %s, compile time is %s\r\n", info->img_version, info->img_compile_time);
|
|
printh("Id: %08x\r\n", info->id);
|
|
printh("Name: %s\r\n", info->name);
|
|
printh("Device type %d:%d\r\n", info->type_m, info->type_s);
|
|
printh("Factory time: %s\r\n\n", info->factory_time);
|
|
}
|
|
|
|
/* description: 环流数据显示
|
|
param:
|
|
return: */
|
|
void ca_coll_show_dev_data(void)
|
|
{
|
|
ca_coll_dev_data_t *data = &ca_coll_ctrl.dev_data;
|
|
uint8_t i = 0;
|
|
|
|
printh("VCC %-0.3fv VBAT %-0.3fv VSC %-0.3fv ", data->vin / 1000.0, data->vbat / 1000.0, data->vsc / 1000.0);
|
|
printh("Temperature %-0.1f℃ Run %ds Mode %d\r\n\n", data->temperature / 10.0, data->run_time, data->energy_mode);
|
|
|
|
printh("Electricity(v):\r\n");
|
|
for(i = 1; i <= CA_COLL_ADC_CH_SUM - 2; i++)
|
|
{
|
|
printh("CH%d ", i);
|
|
}
|
|
printh("\r\n");
|
|
for(i = 0; i < CA_COLL_ADC_CH_SUM - 2; i++)
|
|
{
|
|
printh("%-8.3f ", data->elec[i] / 1000.0);
|
|
}
|
|
printh("\r\n\n");
|
|
|
|
printh("Sensor(℃) Short %s\r\n", data->sen_short ? "TRUE" : "FALSE");
|
|
printh("CH VA T X Y Z\r\n");
|
|
for(i = 0; i < CA_COLL_SENSOR_SUM; i++)
|
|
{
|
|
printh("%-2d %-2d %-5.1f ", i + 1, data->sen_valid[i], data->sen_temp[i]);
|
|
printh("%-5d %-5d %-5d\r\n", data->sen_x[i], data->sen_y[i], data->sen_z[i]);
|
|
}
|
|
printh("\r\n");
|
|
}
|
|
|
|
/* description: 设备状态显示
|
|
param:
|
|
return: */
|
|
void ca_coll_show_dev_state(void)
|
|
{
|
|
ca_coll_state_t *state = &ca_coll_ctrl.state;
|
|
|
|
printh("Connect: %s\r\n", state->send_err_cnt < CA_COLL_ERR_CNT_MAX ? "yes" : "no");
|
|
printh("4G connect: %s\r\n", ca_coll_ctrl.state.is_4g_connect ? "yes" : "no");
|
|
printh("Update state: %s\r\n", state->is_update_cable ? "yes" : "no");
|
|
printh("Update index: %d\r\n\n", state->update_index);
|
|
}
|
|
|
|
#endif
|
|
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/
|
|
|