3610 lines
145 KiB
C
3610 lines
145 KiB
C
#include "main.h"
|
||
#include "json-c/json.h"
|
||
#include "uart_utils/uart_utils.h"
|
||
#include "uart_can/uart_can.h"
|
||
#include "mqtt_utils/mqtt_utils.h"
|
||
#include "queue/queue.h"
|
||
#define PRINT_TIME_TAG
|
||
#define DBG_TAG "main"
|
||
#define DBG_LVL DBG_INFO
|
||
#include "debug_print/debug_print.h"
|
||
#include <errno.h>
|
||
|
||
// UUID generation functions (defined in mqtt/WebSocket.c)
|
||
typedef unsigned char uuid_t[16];
|
||
extern void uuid_generate(uuid_t out);
|
||
extern void uuid_unparse(uuid_t uu, char *out);
|
||
|
||
// 全局变量声明
|
||
jt_led_or_group_package_t tags;
|
||
jt_led_or_group_package_t led_ctrl;
|
||
|
||
// 灯光命令队列结构体 - 解决竞态条件问题
|
||
#define MAX_LIGHT_COMMANDS 32
|
||
|
||
typedef struct {
|
||
char deviceName[16]; // 设备名称(12位十六进制)
|
||
char fullTagId[16]; // 完整的灯条ID
|
||
char taskId[64]; // 任务ID
|
||
uint16_t tagCodeHead; // 灯条ID头部
|
||
uint32_t tagCode; // 灯条ID
|
||
uint8_t color; // 颜色设置
|
||
uint8_t sound; // 声音设置
|
||
uint8_t flash; // 闪烁设置
|
||
int duration; // 持续时间
|
||
int beep; // 蜂鸣器状态
|
||
int flash_value; // 闪烁值(用于上报)
|
||
int light_r; // 红色
|
||
int light_g; // 绿色
|
||
int light_b; // 蓝色
|
||
bool is_valid; // 命令是否有效
|
||
uint64_t sequence; // 序列号,用于跟踪
|
||
} light_command_t;
|
||
|
||
// 命令队列和相关变量
|
||
light_command_t light_commands[MAX_LIGHT_COMMANDS];
|
||
int light_command_head = 0;
|
||
int light_command_tail = 0;
|
||
pthread_mutex_t lightCommandMutex = PTHREAD_MUTEX_INITIALIZER;
|
||
uint64_t command_sequence = 0;
|
||
|
||
// 函数声明
|
||
void light_status_report(void);
|
||
void update_app(void);
|
||
|
||
// MQTT协议相关常量定义
|
||
#define MQTT_ALGORITHM "AUK1_MQTT_HMAC_SHA1"
|
||
#define MQTT_SECURE_MODE "TCP"
|
||
#define MQTT_AUTH_TYPE_REGISTER "REGISTER"
|
||
#define MQTT_AUTH_TYPE_AUTH "AUTH"
|
||
|
||
pthread_t pt_uart_send;
|
||
pthread_t pt_uart_recv_ack;
|
||
pthread_t pt_uart_recv_data;
|
||
pthread_t pt_uart_recv_back;
|
||
pthread_t pt_mqtt_recv;
|
||
pthread_t pt_readqr;
|
||
pthread_t pt_reporttag;
|
||
pthread_t pt_mqtt;
|
||
pthread_t pt_removelog;
|
||
pthread_t pt_watchdog;
|
||
pthread_t pt_removeduplicatetag;
|
||
pthread_t pt_keycheck;
|
||
pthread_t pt_mqtt_status;
|
||
pthread_t pt_station_heartbeat;
|
||
pthread_t pt_simulate_light;
|
||
pthread_t pt_all_light;
|
||
pthread_t pt_simulate_mqtt_topic;
|
||
uart_utils_t uartSend = {0};
|
||
uart_utils_t uartRecvData = {0};
|
||
uart_utils_t uartRecvBack = {0};
|
||
mqtt_parm_t mqtt_parm={0};
|
||
mqtt_utils_t mqtt_config;
|
||
struct input_event buff;
|
||
|
||
bool newappDownloaded=false;
|
||
bool isLightOn=false;
|
||
bool isLightOnById=false;
|
||
bool isLightOnByGroup=false;
|
||
bool isBindTag=false;
|
||
bool isSendComEnd=true;
|
||
bool isStopBroadcast=false;
|
||
bool isStopBroadcastBegin=false;
|
||
bool isAllLightOn=false; // 全场亮灯标志
|
||
uint8_t allLightColor=4; // 全场亮灯颜色,默认红色
|
||
uint8_t allLightFlash=3; // 全场亮灯闪烁模式,默认闪烁
|
||
uint8_t allLightSound=0; // 全场亮灯蜂鸣,默认关闭
|
||
int allLightDuration=30; // 全场亮灯持续时间(秒)
|
||
bool isOtaEnable=false;
|
||
bool isMqttConnected=false; // MQTT连接状态标志
|
||
jt_only_tag_t onlyTags[200]={0};
|
||
int tagCount=0;
|
||
|
||
// 心跳检测相关
|
||
#define HEARTBEAT_TIMEOUT_SEC (30 * 60) // 30分钟超时
|
||
#define MAX_LIGHTBAR_NUM 5000
|
||
typedef struct {
|
||
uint16_t tagCodeHead; // 灯条ID头部
|
||
uint32_t tagCode; // 灯条ID主体
|
||
char fullTagId[16]; // 完整的灯条ID (12位十六进制)
|
||
time_t lastHeartbeat; // 最后心跳时间
|
||
bool isOnline; // 是否在线
|
||
} lightbar_heartbeat_t;
|
||
lightbar_heartbeat_t lightbarHeartbeat[MAX_LIGHTBAR_NUM] = {0};
|
||
int lightbarHeartbeatCount = 0;
|
||
pthread_mutex_t heartbeatMutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
||
// 亮灯任务确认相关
|
||
#define MAX_PENDING_LIGHT_TASKS 1024
|
||
typedef struct {
|
||
uint16_t tagCodeHead; // 灯条ID头部
|
||
uint32_t tagCode; // 灯条ID主体(tag的后6位)
|
||
char fullTagId[16]; // 完整的灯条ID (12位十六进制)
|
||
char taskId[64]; // 任务ID
|
||
int beep; // 蜂鸣器状态(0或1)
|
||
int flash; // 闪烁状态(0或1)
|
||
int light_r; // 红色(0或1)
|
||
int light_g; // 绿色(0或1)
|
||
int light_b; // 蓝色(0或1)
|
||
int duration; // 持续时间(秒)
|
||
time_t reportTime; // 上报时间
|
||
bool reported; // 是否已上报
|
||
bool lightOffReported; // 是否已上报灭灯
|
||
} pending_light_task_t;
|
||
pending_light_task_t pendingLightTasks[MAX_PENDING_LIGHT_TASKS] = {0};
|
||
int pendingLightTaskCount = 0;
|
||
pthread_mutex_t lightTaskMutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
||
// 按键防抖相关
|
||
#define MAX_KEY_DEBOUNCE 50
|
||
typedef struct {
|
||
uint16_t tagCodeHead; // 灯条ID头部
|
||
uint32_t tagCode;
|
||
time_t lastKeyTime;
|
||
} key_debounce_t;
|
||
key_debounce_t keyDebounceList[MAX_KEY_DEBOUNCE] = {0};
|
||
int keyDebounceCount = 0;
|
||
pthread_mutex_t keyDebounceMutex = PTHREAD_MUTEX_INITIALIZER;
|
||
pthread_t pt_heartbeat_check;
|
||
pthread_t pt_light_off_check;
|
||
int lightbars_size=0;
|
||
int lightbars_count=0;
|
||
uint8_t changecolor=0;
|
||
uint8_t changesound=0;
|
||
uint8_t changeflash=3; // 1=常亮, 3=闪烁
|
||
uint8_t groupno=0;
|
||
int fd;
|
||
int UPCASE=0;
|
||
int count_value=0;
|
||
int getPayloadTime=100*1000;//usecond
|
||
char softwareVersion[16]="2.1.27";
|
||
//char stationsn[16]="d126ei4lj4cc00";//TJ250995217957
|
||
//char productid[8]="10045";
|
||
//char appSecret[64]="s3izIliw0CF48Pcsi16rjOmoFRf5WEt8";
|
||
char stationsn[32]="90A9F73002CD";
|
||
char productid[16]="WcLightStrip";
|
||
char appKey[32]="fdhQmhqhvbL1cf1K9mUqt";
|
||
char appSecret[64]="RxU8NZjfZaxsKg2B3Dr6sx";
|
||
char hostDomain[64]="auk-iot.test1.zservey.com";
|
||
int mqtt_port=1883;
|
||
//char hostDomain[64]="127.0.0.1";
|
||
//int mqtt_port=1884;
|
||
char mqttRawPassword[64]="";
|
||
char input_value[1024]={0};//94b4e39caf1d45ee9a071d701cc037b4
|
||
char input_value_copy[1024]={0};
|
||
char *getDevRegisterStatusUrl="https://gaea-zt-express.com/device/modifyRegisterInfo";
|
||
char *updateUrl="https://idata-creat.oss-cn-shenzhen.aliyuncs.com/jd_ota.zip";
|
||
char *getDevRawPasswordUrl="https://gaea.zt-express.com/device/modifyRegisterInfo";
|
||
//char *hostDomain="emqx.thingtalk.jdl.com";
|
||
char lightsn1[7]={0};
|
||
char lightsn2[7]={0};
|
||
char lightsn3[7]={0};
|
||
char lightsn4[7]={0};
|
||
char lightsn5[7]={0};
|
||
char lightsn6[7]={0};
|
||
char lightsn7[7]={0};
|
||
char lightsn8[7]={0};
|
||
char lightsn9[7]={0};
|
||
char lightsn10[7]={0};
|
||
char lightsn11[7]={0};
|
||
char lightsn12[7]={0};
|
||
char lightsn13[7]={0};
|
||
char lightsn14[7]={0};
|
||
char lightsn15[7]={0};
|
||
char lightsn16[7]={0};
|
||
char lightsn17[7]={0};
|
||
char lightsn18[7]={0};
|
||
char lightsn19[7]={0};
|
||
char lightsn20[7]={0};
|
||
char lightsn21[7]={0};
|
||
char lightsn22[7]={0};
|
||
|
||
// 【修复】添加全局变量保存当前设备的tagCode,避免竞态条件
|
||
uint32_t g_current_tagCode = 0;
|
||
uint16_t g_current_tagCodeHead = 0;
|
||
|
||
// 【增强】添加设备特定的tagCode映射,解决多设备并发问题
|
||
typedef struct {
|
||
char deviceName[16];
|
||
uint32_t tagCode;
|
||
uint16_t tagCodeHead;
|
||
uint64_t timestamp; // 时间戳,用于清理过期映射
|
||
} device_tag_mapping_t;
|
||
|
||
#define MAX_DEVICE_MAPPINGS 16
|
||
device_tag_mapping_t g_device_mappings[MAX_DEVICE_MAPPINGS];
|
||
pthread_mutex_t deviceMappingMutex = PTHREAD_MUTEX_INITIALIZER;
|
||
char lightsn23[7]={0};
|
||
char lightsn24[7]={0};
|
||
char lightsn25[7]={0};
|
||
char lightsn26[7]={0};
|
||
char lightsn27[7]={0};
|
||
char lightsn28[7]={0};
|
||
char lightsn29[7]={0};
|
||
char lightsn30[7]={0};
|
||
int lightsnNum=0;
|
||
|
||
void hmacsha1_hex(char *key, char* data, char *signhex, int signhex_len);
|
||
void *thread_mqtt_status_check(void *arg);
|
||
void *thread_station_heartbeat(void *arg);
|
||
void *thread_heartbeat_check(void *arg);
|
||
void *thread_light_off_check(void *arg);
|
||
void *thread_simulate_light(void *arg);
|
||
void *thread_all_light(void *arg);
|
||
void *thread_simulate_mqtt_topic(void *arg);
|
||
void update_lightbar_heartbeat(uint16_t tagCodeHead, uint32_t tagCode);
|
||
void report_lightbar_login(uint16_t tagCodeHead, uint32_t tagCode);
|
||
void report_lightbar_logout(uint16_t tagCodeHead, uint32_t tagCode);
|
||
void add_pending_light_task(uint16_t tagCodeHead, uint32_t tagCode, const char *taskId, int beep, int flash, int r, int g, int b, int duration);
|
||
void report_light_success(uint16_t tagCodeHead, uint32_t tagCode);
|
||
void report_light_off(uint16_t tagCodeHead, uint32_t tagCode);
|
||
|
||
// 命令队列操作函数
|
||
int add_light_command(const char *deviceName, const char *taskId, uint16_t tagCodeHead, uint32_t tagCode,
|
||
uint8_t color, uint8_t sound, uint8_t flash, int duration,
|
||
int beep, int flash_value, int r, int g, int b);
|
||
int get_light_command(light_command_t *cmd);
|
||
void clear_light_command_queue(void);
|
||
|
||
// 【新增】设备映射管理函数
|
||
void add_device_mapping(const char *deviceName, uint16_t tagCodeHead, uint32_t tagCode);
|
||
int get_device_tag_mapping(const char *deviceName, uint32_t *tagCode, uint16_t *tagCodeHead);
|
||
void cleanup_expired_mappings(void);
|
||
|
||
/*================================================================================*/
|
||
// 上报灯条子设备登录
|
||
void report_lightbar_login(uint16_t tagCodeHead, uint32_t tagCode) {
|
||
char subDeviceKey[32] = {0};
|
||
char topic[256] = {0};
|
||
char payload[512] = {0};
|
||
char password[64] = {0};
|
||
char stringToSign[256] = {0};
|
||
char timestamp_str[32] = {0};
|
||
struct timeval tv;
|
||
|
||
// 构建subDeviceKey: 使用完整的tagID (tagCodeHead + tagCode)
|
||
snprintf(subDeviceKey, sizeof(subDeviceKey), "%04X%08X", tagCodeHead, tagCode);
|
||
|
||
// 获取当前时间戳(毫秒)
|
||
gettimeofday(&tv, NULL);
|
||
long timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
snprintf(timestamp_str, sizeof(timestamp_str), "%ld", timestamp);
|
||
|
||
// 构建待签名串: subDeviceKey + subDeviceKey + productKey + algorithm + timestamp
|
||
snprintf(stringToSign, sizeof(stringToSign), "%s%s%s%s%s",
|
||
subDeviceKey, subDeviceKey, "WcSubLightStrip", MQTT_ALGORITHM, timestamp_str);
|
||
|
||
// 使用HMAC-SHA1计算password
|
||
hmacsha1_hex("EKmmjqyLRgghANEiQAA5LZ", stringToSign, password, sizeof(password));
|
||
|
||
// 构建topic
|
||
snprintf(topic, sizeof(topic), "/auk/iot/things/v1/sub/device/up/login/WcSubLightStrip/%s/%ld",
|
||
subDeviceKey, timestamp);
|
||
|
||
// 构建JSON payload
|
||
snprintf(payload, sizeof(payload),
|
||
"{\"password\":\"%s\",\"timestamp\":%ld,\"signingAlgorithm\":\"%s\"}",
|
||
password, timestamp, MQTT_ALGORITHM);
|
||
|
||
//LOG_I("Lightbar login report - topic: %s\n", topic);
|
||
//LOG_I("Lightbar login report - payload: %s\n", payload);
|
||
|
||
// 发送MQTT消息
|
||
mqtt_utils_publish(&mqtt_config, topic, 0, payload, strlen(payload));
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 添加待确认的亮灯任务
|
||
void add_pending_light_task(uint16_t tagCodeHead, uint32_t tagCode, const char *taskId, int beep, int flash, int r, int g, int b, int duration) {
|
||
pthread_mutex_lock(&lightTaskMutex);
|
||
|
||
// 检查是否已存在
|
||
for (int i = 0; i < pendingLightTaskCount; i++) {
|
||
if (pendingLightTasks[i].tagCode == tagCode && pendingLightTasks[i].tagCodeHead == tagCodeHead && !pendingLightTasks[i].reported) {
|
||
// 更新任务信息
|
||
strncpy(pendingLightTasks[i].taskId, taskId, sizeof(pendingLightTasks[i].taskId) - 1);
|
||
pendingLightTasks[i].beep = beep;
|
||
pendingLightTasks[i].flash = flash;
|
||
pendingLightTasks[i].light_r = r;
|
||
pendingLightTasks[i].light_g = g;
|
||
pendingLightTasks[i].light_b = b;
|
||
pendingLightTasks[i].duration = duration;
|
||
pendingLightTasks[i].reportTime = time(NULL);
|
||
LOG_I("Updated pending light task for tag %08X, taskId: %s, beep: %d, flash: %d, RGB: %d,%d,%d, duration: %d\n",
|
||
tagCode, taskId, beep, flash, r, g, b, duration);
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 添加新任务
|
||
if (pendingLightTaskCount < MAX_PENDING_LIGHT_TASKS) {
|
||
pendingLightTasks[pendingLightTaskCount].tagCodeHead = tagCodeHead;
|
||
pendingLightTasks[pendingLightTaskCount].tagCode = tagCode;
|
||
snprintf(pendingLightTasks[pendingLightTaskCount].fullTagId, sizeof(pendingLightTasks[pendingLightTaskCount].fullTagId), "%04X%08X", tagCodeHead, tagCode);
|
||
strncpy(pendingLightTasks[pendingLightTaskCount].taskId, taskId,
|
||
sizeof(pendingLightTasks[pendingLightTaskCount].taskId) - 1);
|
||
pendingLightTasks[pendingLightTaskCount].beep = beep;
|
||
pendingLightTasks[pendingLightTaskCount].flash = flash;
|
||
pendingLightTasks[pendingLightTaskCount].light_r = r;
|
||
pendingLightTasks[pendingLightTaskCount].light_g = g;
|
||
pendingLightTasks[pendingLightTaskCount].light_b = b;
|
||
pendingLightTasks[pendingLightTaskCount].reported = false;
|
||
pendingLightTasks[pendingLightTaskCount].lightOffReported = false;
|
||
pendingLightTasks[pendingLightTaskCount].reportTime = time(NULL);
|
||
pendingLightTasks[pendingLightTaskCount].duration = duration;
|
||
LOG_I("Added pending light task for tag %08X, taskId: %s, beep: %d, flash: %d, RGB: %d,%d,%d, duration: %d\n",
|
||
tagCode, taskId, beep, flash, r, g, b, duration);
|
||
pendingLightTaskCount++;
|
||
} else {
|
||
LOG_I("Pending light task queue full!\n");
|
||
}
|
||
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 上报亮灯成功
|
||
void report_light_success(uint16_t tagCodeHead, uint32_t tagCode) {
|
||
pthread_mutex_lock(&lightTaskMutex);
|
||
|
||
// 查找对应的待确认任务
|
||
for (int i = 0; i < pendingLightTaskCount; i++) {
|
||
if (pendingLightTasks[i].tagCode == tagCode && pendingLightTasks[i].tagCodeHead == tagCodeHead && !pendingLightTasks[i].reported) {
|
||
// 构建上报topic和payload
|
||
char topic[256] = {0};
|
||
char payload[1024] = {0};
|
||
|
||
// 使用完整的tagID
|
||
snprintf(topic, sizeof(topic), "/sys/WcSubLightStrip/%s/thing/service/lightOperate/invoke_reply", pendingLightTasks[i].fullTagId);
|
||
|
||
// 获取当前时间戳(毫秒)
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
long long timestamp = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
|
||
// 使用任务中的真实数据构建payload
|
||
// light是一个struct,包含R、G、B三个bool字段
|
||
snprintf(payload, sizeof(payload),
|
||
"{\"id\":\"%s\",\"code\":0,\"msg\":\"success\",\"data\":{\"beep\":{\"value\":%d,\"time\":%lld},\"flash\":{\"value\":%d,\"time\":%lld},\"light\":{\"value\":{\"R\":%d,\"G\":%d,\"B\":%d},\"time\":%lld}},\"method\":\"thing.service.lightOperate.invoke\",\"time\":%lld}",
|
||
pendingLightTasks[i].taskId,
|
||
pendingLightTasks[i].beep,
|
||
timestamp,
|
||
pendingLightTasks[i].flash,
|
||
timestamp,
|
||
pendingLightTasks[i].light_r,
|
||
pendingLightTasks[i].light_g,
|
||
pendingLightTasks[i].light_b,
|
||
timestamp,
|
||
timestamp);
|
||
|
||
LOG_I("Reporting light success - topic: %s\n", topic);
|
||
LOG_I("Reporting light success - payload: %s\n", payload);
|
||
LOG_I("Task ID: %s, beep: %d, flash: %d, RGB: %d,%d,%d\n",
|
||
pendingLightTasks[i].taskId, pendingLightTasks[i].beep,
|
||
pendingLightTasks[i].flash, pendingLightTasks[i].light_r,
|
||
pendingLightTasks[i].light_g, pendingLightTasks[i].light_b);
|
||
|
||
// 发送MQTT消息
|
||
mqtt_utils_publish(&mqtt_config, topic, 0, payload, strlen(payload));
|
||
|
||
// 标记为已上报
|
||
pendingLightTasks[i].reported = true;
|
||
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
return;
|
||
}
|
||
}
|
||
|
||
LOG_I("No pending light task found for tag %08X\n", tagCode);
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 上报灭灯(调用时必须已持有lightTaskMutex锁)
|
||
void report_light_off(uint16_t tagCodeHead, uint32_t tagCode) {
|
||
// 查找对应的已上报亮灯成功的任务
|
||
for (int i = 0; i < pendingLightTaskCount; i++) {
|
||
if (pendingLightTasks[i].tagCode == tagCode && pendingLightTasks[i].tagCodeHead == tagCodeHead &&
|
||
pendingLightTasks[i].reported &&
|
||
!pendingLightTasks[i].lightOffReported) {
|
||
|
||
// 构建上报topic和payload
|
||
char topic[256] = {0};
|
||
char payload[1024] = {0};
|
||
char uuid_str[37] = {0};
|
||
uuid_t uuid;
|
||
|
||
// 生成随机UUID
|
||
uuid_generate(uuid);
|
||
uuid_unparse(uuid, uuid_str);
|
||
|
||
// 使用完整的tagID
|
||
snprintf(topic, sizeof(topic), "/sys/WcSubLightStrip/%s/thing/property/post", pendingLightTasks[i].fullTagId);
|
||
|
||
// 获取当前时间戳(毫秒)
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
long long timestamp = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
|
||
// 使用任务中的真实数据构建payload
|
||
snprintf(payload, sizeof(payload),
|
||
"{\"id\":\"%s\",\"version\":\"1.0\",\"arg\":{\"beep\":{\"value\":%d,\"time\":%lld},\"flash\":{\"value\":%d,\"time\":%lld},\"light\":{\"value\":{\"R\":%d,\"G\":%d,\"B\":%d},\"time\":%lld}},\"method\":\"thing.property.post\",\"time\":%lld}",
|
||
uuid_str,
|
||
0,
|
||
timestamp,
|
||
0,
|
||
timestamp,
|
||
0,
|
||
0,
|
||
0,
|
||
timestamp,
|
||
timestamp);
|
||
|
||
LOG_I("Reporting light off - topic: %s\n", topic);
|
||
LOG_I("Reporting light off - payload: %s\n", payload);
|
||
LOG_I("Tag: %08X, UUID: %s\n", tagCode, uuid_str);
|
||
|
||
// 发送MQTT消息
|
||
mqtt_utils_publish(&mqtt_config, topic, 0, payload, strlen(payload));
|
||
|
||
// 标记为已上报灭灯
|
||
pendingLightTasks[i].lightOffReported = true;
|
||
|
||
// 清理已完成的任务 - 将最后一个任务移到当前位置
|
||
if (i < pendingLightTaskCount - 1) {
|
||
pendingLightTasks[i] = pendingLightTasks[pendingLightTaskCount - 1];
|
||
}
|
||
pendingLightTaskCount--;
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
LOG_I("No pending light task found for light-off report for tag %08X\n", tagCode);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 命令队列操作函数实现
|
||
|
||
// 添加灯光命令到队列
|
||
int add_light_command(const char *deviceName, const char *taskId, uint16_t tagCodeHead, uint32_t tagCode,
|
||
uint8_t color, uint8_t sound, uint8_t flash, int duration,
|
||
int beep, int flash_value, int r, int g, int b) {
|
||
pthread_mutex_lock(&lightCommandMutex);
|
||
|
||
// 检查队列是否已满
|
||
int next_tail = (light_command_tail + 1) % MAX_LIGHT_COMMANDS;
|
||
if (next_tail == light_command_head) {
|
||
LOG_I("Light command queue is full!\n");
|
||
pthread_mutex_unlock(&lightCommandMutex);
|
||
return -1;
|
||
}
|
||
|
||
// 添加新命令
|
||
light_command_t *cmd = &light_commands[light_command_tail];
|
||
memset(cmd, 0, sizeof(light_command_t));
|
||
|
||
strncpy(cmd->deviceName, deviceName, sizeof(cmd->deviceName) - 1);
|
||
strncpy(cmd->fullTagId, deviceName, sizeof(cmd->fullTagId) - 1);
|
||
strncpy(cmd->taskId, taskId, sizeof(cmd->taskId) - 1);
|
||
cmd->tagCodeHead = tagCodeHead;
|
||
cmd->tagCode = tagCode;
|
||
cmd->color = color;
|
||
cmd->sound = sound;
|
||
cmd->flash = flash;
|
||
cmd->duration = duration;
|
||
cmd->beep = beep;
|
||
cmd->flash_value = flash_value;
|
||
cmd->light_r = r;
|
||
cmd->light_g = g;
|
||
cmd->light_b = b;
|
||
cmd->is_valid = true;
|
||
cmd->sequence = ++command_sequence;
|
||
|
||
LOG_I("Added light command to queue - device: %s, seq: %llu, RGB: %d,%d,%d\n",
|
||
deviceName, cmd->sequence, r, g, b);
|
||
|
||
light_command_tail = next_tail;
|
||
pthread_mutex_unlock(&lightCommandMutex);
|
||
return 0;
|
||
}
|
||
|
||
// 从队列获取灯光命令
|
||
int get_light_command(light_command_t *cmd) {
|
||
pthread_mutex_lock(&lightCommandMutex);
|
||
|
||
if (light_command_head == light_command_tail) {
|
||
// 队列为空
|
||
pthread_mutex_unlock(&lightCommandMutex);
|
||
return -1;
|
||
}
|
||
|
||
// 获取命令
|
||
*cmd = light_commands[light_command_head];
|
||
light_command_head = (light_command_head + 1) % MAX_LIGHT_COMMANDS;
|
||
|
||
LOG_I("Got light command from queue - device: %s, seq: %llu\n",
|
||
cmd->deviceName, cmd->sequence);
|
||
|
||
pthread_mutex_unlock(&lightCommandMutex);
|
||
return 0;
|
||
}
|
||
|
||
// 清空命令队列
|
||
void clear_light_command_queue(void) {
|
||
pthread_mutex_lock(&lightCommandMutex);
|
||
light_command_head = 0;
|
||
light_command_tail = 0;
|
||
memset(light_commands, 0, sizeof(light_commands));
|
||
LOG_I("Light command queue cleared\n");
|
||
pthread_mutex_unlock(&lightCommandMutex);
|
||
}
|
||
|
||
// 【新增】设备映射管理函数实现
|
||
void add_device_mapping(const char *deviceName, uint16_t tagCodeHead, uint32_t tagCode) {
|
||
pthread_mutex_lock(&deviceMappingMutex);
|
||
|
||
// 查找是否已存在该设备的映射
|
||
int existing_index = -1;
|
||
for (int i = 0; i < MAX_DEVICE_MAPPINGS; i++) {
|
||
if (strcmp(g_device_mappings[i].deviceName, deviceName) == 0) {
|
||
existing_index = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果不存在,找一个空位
|
||
if (existing_index == -1) {
|
||
for (int i = 0; i < MAX_DEVICE_MAPPINGS; i++) {
|
||
if (strlen(g_device_mappings[i].deviceName) == 0) {
|
||
existing_index = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果找到位置,更新映射
|
||
if (existing_index != -1) {
|
||
strncpy(g_device_mappings[existing_index].deviceName, deviceName, sizeof(g_device_mappings[existing_index].deviceName) - 1);
|
||
g_device_mappings[existing_index].tagCodeHead = tagCodeHead;
|
||
g_device_mappings[existing_index].tagCode = tagCode;
|
||
g_device_mappings[existing_index].timestamp = time(NULL) * 1000; // 毫秒时间戳
|
||
LOG_I("Added/Updated device mapping: %s -> %08X\n", deviceName, tagCode);
|
||
} else {
|
||
LOG_I("Device mapping table full!\n");
|
||
}
|
||
|
||
pthread_mutex_unlock(&deviceMappingMutex);
|
||
}
|
||
|
||
int get_device_tag_mapping(const char *deviceName, uint32_t *tagCode, uint16_t *tagCodeHead) {
|
||
pthread_mutex_lock(&deviceMappingMutex);
|
||
|
||
for (int i = 0; i < MAX_DEVICE_MAPPINGS; i++) {
|
||
if (strcmp(g_device_mappings[i].deviceName, deviceName) == 0) {
|
||
*tagCode = g_device_mappings[i].tagCode;
|
||
*tagCodeHead = g_device_mappings[i].tagCodeHead;
|
||
pthread_mutex_unlock(&deviceMappingMutex);
|
||
return 0; // 找到
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&deviceMappingMutex);
|
||
return -1; // 未找到
|
||
}
|
||
|
||
void cleanup_expired_mappings(void) {
|
||
pthread_mutex_lock(&deviceMappingMutex);
|
||
|
||
uint64_t current_time = time(NULL) * 1000;
|
||
uint64_t expire_time = 30 * 1000; // 30秒过期
|
||
|
||
for (int i = 0; i < MAX_DEVICE_MAPPINGS; i++) {
|
||
if (strlen(g_device_mappings[i].deviceName) > 0) {
|
||
if (current_time - g_device_mappings[i].timestamp > expire_time) {
|
||
LOG_I("Cleaning up expired mapping: %s\n", g_device_mappings[i].deviceName);
|
||
memset(&g_device_mappings[i], 0, sizeof(device_tag_mapping_t));
|
||
}
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&deviceMappingMutex);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 上报灯条子设备登出
|
||
void report_lightbar_logout(uint16_t tagCodeHead, uint32_t tagCode) {
|
||
char subDeviceKey[32] = {0};
|
||
char topic[256] = {0};
|
||
char payload[512] = {0};
|
||
char password[64] = {0};
|
||
char stringToSign[256] = {0};
|
||
char timestamp_str[32] = {0};
|
||
struct timeval tv;
|
||
|
||
// 构建subDeviceKey: 使用完整的tagID (tagCodeHead + tagCode)
|
||
snprintf(subDeviceKey, sizeof(subDeviceKey), "%04X%08X", tagCodeHead, tagCode);
|
||
|
||
// 获取当前时间戳(毫秒)
|
||
gettimeofday(&tv, NULL);
|
||
long timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
snprintf(timestamp_str, sizeof(timestamp_str), "%ld", timestamp);
|
||
|
||
// 构建待签名串: subDeviceKey + subDeviceKey + productKey + algorithm + timestamp
|
||
snprintf(stringToSign, sizeof(stringToSign), "%s%s%s%s%s",
|
||
subDeviceKey, subDeviceKey, "WcSubLightStrip", MQTT_ALGORITHM, timestamp_str);
|
||
|
||
// 使用HMAC-SHA1计算password
|
||
hmacsha1_hex("EKmmjqyLRgghANEiQAA5LZ", stringToSign, password, sizeof(password));
|
||
|
||
// 构建topic (logout)
|
||
snprintf(topic, sizeof(topic), "/auk/iot/things/v1/sub/device/up/logout/WcSubLightStrip/%s/%ld",
|
||
subDeviceKey, timestamp);
|
||
|
||
// 构建JSON payload
|
||
snprintf(payload, sizeof(payload),
|
||
"{\"password\":\"%s\",\"timestamp\":%ld,\"signingAlgorithm\":\"%s\"}",
|
||
password, timestamp, MQTT_ALGORITHM);
|
||
|
||
LOG_I("Lightbar logout report - topic: %s\n", topic);
|
||
LOG_I("Lightbar logout report - payload: %s\n", payload);
|
||
|
||
// 发送MQTT消息
|
||
mqtt_utils_publish(&mqtt_config, topic, 0, payload, strlen(payload));
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 更新灯条心跳时间
|
||
void update_lightbar_heartbeat(uint16_t tagCodeHead, uint32_t tagCode) {
|
||
pthread_mutex_lock(&heartbeatMutex);
|
||
|
||
// 查找是否已存在该灯条
|
||
int found = -1;
|
||
for (int i = 0; i < lightbarHeartbeatCount; i++) {
|
||
if (lightbarHeartbeat[i].tagCode == tagCode && lightbarHeartbeat[i].tagCodeHead == tagCodeHead) {
|
||
found = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
time_t now = time(NULL);
|
||
|
||
if (found >= 0) {
|
||
// 心跳丢失后心跳返回,更新已存在灯条的心跳时间
|
||
lightbarHeartbeat[found].lastHeartbeat = now;
|
||
if (!lightbarHeartbeat[found].isOnline) {
|
||
lightbarHeartbeat[found].isOnline = true;
|
||
LOG_I("Lightbar %04X%08X back online\n", tagCodeHead, tagCode);
|
||
// 只有MQTT连接后才上报登录
|
||
if (isMqttConnected) {
|
||
report_lightbar_login(tagCodeHead, tagCode);
|
||
} else {
|
||
LOG_I("MQTT not connected yet, skip lightbar login report\n");
|
||
}
|
||
}
|
||
} else {
|
||
// 添加新的灯条记录
|
||
if (lightbarHeartbeatCount < MAX_LIGHTBAR_NUM) {
|
||
lightbarHeartbeat[lightbarHeartbeatCount].tagCodeHead = tagCodeHead;
|
||
lightbarHeartbeat[lightbarHeartbeatCount].tagCode = tagCode;
|
||
snprintf(lightbarHeartbeat[lightbarHeartbeatCount].fullTagId, sizeof(lightbarHeartbeat[lightbarHeartbeatCount].fullTagId), "%04X%08X", tagCodeHead, tagCode);
|
||
lightbarHeartbeat[lightbarHeartbeatCount].lastHeartbeat = now;
|
||
lightbarHeartbeat[lightbarHeartbeatCount].isOnline = true;
|
||
lightbarHeartbeatCount++;
|
||
//LOG_I("New lightbar %04X%08X registered, total: %d\n", tagCodeHead, tagCode, lightbarHeartbeatCount);
|
||
// 只有MQTT连接后才上报登录
|
||
if (isMqttConnected) {
|
||
report_lightbar_login(tagCodeHead, tagCode);
|
||
} else {
|
||
LOG_I("MQTT not connected yet, skip lightbar login report\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&heartbeatMutex);
|
||
}
|
||
|
||
// 心跳检测线程 - 每分钟检查一次
|
||
void *thread_heartbeat_check(void *arg) {
|
||
LOG_I("Heartbeat check thread started\n");
|
||
|
||
while (1) {
|
||
sleep(60); // 每60秒检查一次
|
||
|
||
time_t now = time(NULL);
|
||
|
||
pthread_mutex_lock(&heartbeatMutex);
|
||
|
||
for (int i = 0; i < lightbarHeartbeatCount; i++) {
|
||
// 只检查已经有过心跳记录的灯条(避免启动时误报)
|
||
if (lightbarHeartbeat[i].isOnline && lightbarHeartbeat[i].lastHeartbeat > 0) {
|
||
time_t elapsed = now - lightbarHeartbeat[i].lastHeartbeat;
|
||
if (elapsed > HEARTBEAT_TIMEOUT_SEC) {
|
||
lightbarHeartbeat[i].isOnline = false;
|
||
LOG_I("!!! Lightbar %06X OFFLINE - no heartbeat for %ld seconds (>%d sec)\n",
|
||
lightbarHeartbeat[i].tagCode, (long)elapsed, HEARTBEAT_TIMEOUT_SEC);
|
||
report_lightbar_logout(lightbarHeartbeat[i].tagCodeHead, lightbarHeartbeat[i].tagCode);
|
||
}
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&heartbeatMutex);
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
// 灭灯检测线程 - 每5秒检查一次
|
||
void *thread_light_off_check(void *arg) {
|
||
LOG_I("Light off check thread started\n");
|
||
|
||
while (1) {
|
||
sleep(5); // 每5秒检查一次
|
||
|
||
time_t now = time(NULL);
|
||
|
||
pthread_mutex_lock(&lightTaskMutex);
|
||
|
||
// 先清理已完成的任务
|
||
for (int i = 0; i < pendingLightTaskCount; ) {
|
||
if (pendingLightTasks[i].reported && pendingLightTasks[i].lightOffReported) {
|
||
// 清理已完成的任务 - 将最后一个任务移到当前位置
|
||
if (i < pendingLightTaskCount - 1) {
|
||
pendingLightTasks[i] = pendingLightTasks[pendingLightTaskCount - 1];
|
||
}
|
||
pendingLightTaskCount--;
|
||
// 不增加i,因为当前位置现在是新任务
|
||
} else {
|
||
i++;
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < pendingLightTaskCount; i++) {
|
||
// 只检查已上报亮灯成功但未上报灭灯的任务
|
||
if (pendingLightTasks[i].reported && !pendingLightTasks[i].lightOffReported) {
|
||
time_t elapsed = now - pendingLightTasks[i].reportTime;
|
||
|
||
// 检查是否超过持续时间
|
||
if (elapsed >= pendingLightTasks[i].duration) {
|
||
LOG_I("Light-off triggered for tag %08X - elapsed %ld seconds (duration: %d)\n",
|
||
pendingLightTasks[i].tagCode, (long)elapsed, pendingLightTasks[i].duration);
|
||
|
||
// 上报灭灯
|
||
report_light_off(pendingLightTasks[i].tagCodeHead, pendingLightTasks[i].tagCode);
|
||
}
|
||
}
|
||
}
|
||
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 模拟亮灯线程函数 - 每30秒发送一次亮灯任务
|
||
void *thread_simulate_light(void *arg){
|
||
LOG_I("thread_simulate_light started\n");
|
||
|
||
char sim_payload[1024] = {0};
|
||
char device_specific_payload[1024] = {0};
|
||
char last_deviceName[256] = {0}; // 记录上次的deviceName
|
||
int first_run = 1; // 首次运行标志
|
||
|
||
while(1){
|
||
sleep(30); // 每30秒执行一次
|
||
|
||
// 检查是否有从topic解析出的deviceName
|
||
if(strlen(g_mqtt_deviceName) > 0) {
|
||
// 检查deviceName是否有变化
|
||
if(strcmp(g_mqtt_deviceName, last_deviceName) != 0 || first_run) {
|
||
LOG_I("simulate_light: detected new deviceName from topic: %s\n", g_mqtt_deviceName);
|
||
|
||
// 保存当前deviceName
|
||
strcpy(last_deviceName, g_mqtt_deviceName);
|
||
first_run = 0;
|
||
|
||
// 立即响应,使用deviceName构建设备特定的payload
|
||
snprintf(device_specific_payload, sizeof(device_specific_payload),
|
||
"{\"deviceId\":\"%s\",\"params\":{\"LightSwitch\":1}}",
|
||
g_mqtt_deviceName);
|
||
|
||
LOG_I("simulate_light: immediate response with device_specific payload: %s\n", device_specific_payload);
|
||
|
||
// 直接把设备特定的payload放入消息队列
|
||
PutDataIntoMQueue(device_specific_payload);
|
||
} else {
|
||
LOG_I("simulate_light: deviceName unchanged: %s, skipping duplicate simulation\n", g_mqtt_deviceName);
|
||
}
|
||
} else {
|
||
// 从/root/payload文件读取内容(原有逻辑)
|
||
FILE *fp = fopen("/root/payload", "r");
|
||
if(fp == NULL){
|
||
LOG_I("simulate_light: cannot open /root/payload and no deviceName from topic\n");
|
||
continue;
|
||
}
|
||
|
||
memset(sim_payload, 0, sizeof(sim_payload));
|
||
if(fgets(sim_payload, sizeof(sim_payload), fp) != NULL){
|
||
// 去掉换行符
|
||
int len = strlen(sim_payload);
|
||
if(len > 0 && sim_payload[len-1] == '\n'){
|
||
sim_payload[len-1] = '\0';
|
||
}
|
||
|
||
LOG_I("simulate_light: using payload from file\n");
|
||
LOG_I("payload: %s\n", sim_payload);
|
||
|
||
// 直接把payload放入消息队列,由thread_mqtt_recv处理
|
||
PutDataIntoMQueue(sim_payload);
|
||
}
|
||
fclose(fp);
|
||
}
|
||
}
|
||
pthread_exit(NULL);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 模拟MQTT topic线程 - 监控文件并模拟接收MQTT消息
|
||
void *thread_simulate_mqtt_topic(void *arg){
|
||
LOG_I("thread_simulate_mqtt_topic started\n");
|
||
|
||
char sim_topic[512] = {0};
|
||
char sim_payload[1024] = {0};
|
||
|
||
while(1){
|
||
sleep(2); // 每2秒检查一次
|
||
|
||
// 检查模拟topic文件
|
||
FILE *fp_topic = fopen("/root/sim_topic", "r");
|
||
if(fp_topic == NULL){
|
||
continue;
|
||
}
|
||
|
||
// 读取topic内容
|
||
memset(sim_topic, 0, sizeof(sim_topic));
|
||
if(fgets(sim_topic, sizeof(sim_topic), fp_topic) != NULL){
|
||
// 去掉换行符
|
||
int len = strlen(sim_topic);
|
||
if(len > 0 && sim_topic[len-1] == '\n'){
|
||
sim_topic[len-1] = '\0';
|
||
}
|
||
|
||
// 检查是否是lightOperate/invoke topic
|
||
if(strstr(sim_topic, "/sys/") && strstr(sim_topic, "/thing/service/lightOperate/invoke")) {
|
||
// 解析topic获取deviceName
|
||
char productKey[256] = {0};
|
||
char deviceName[256] = {0};
|
||
|
||
// 使用类似mqtt_utils_parse_sys_lightOperate_invoke_topic的逻辑
|
||
if(sscanf(sim_topic, "/sys/%255[^/]/%255[^/]/thing/service/lightOperate/invoke", productKey, deviceName) == 2) {
|
||
LOG_I("simulate_mqtt_topic: parsed productKey=%s, deviceName=%s\n", productKey, deviceName);
|
||
|
||
// 设置全局变量(模拟mqtt_utils_message_arrived的行为)
|
||
memset(g_mqtt_deviceName, 0, sizeof(g_mqtt_deviceName));
|
||
strncpy(g_mqtt_deviceName, deviceName, sizeof(g_mqtt_deviceName) - 1);
|
||
LOG_I("simulate_mqtt_topic: set g_mqtt_deviceName=%s\n", g_mqtt_deviceName);
|
||
|
||
// 读取payload文件
|
||
FILE *fp_payload = fopen("/root/sim_payload", "r");
|
||
if(fp_payload != NULL) {
|
||
memset(sim_payload, 0, sizeof(sim_payload));
|
||
if(fgets(sim_payload, sizeof(sim_payload), fp_payload) != NULL) {
|
||
// 去掉换行符
|
||
len = strlen(sim_payload);
|
||
if(len > 0 && sim_payload[len-1] == '\n'){
|
||
sim_payload[len-1] = '\0';
|
||
}
|
||
|
||
LOG_I("simulate_mqtt_topic: sending payload to queue: %s\n", sim_payload);
|
||
|
||
// 将payload放入消息队列(模拟接收到的MQTT消息)
|
||
PutDataIntoMQueue(sim_payload);
|
||
}
|
||
fclose(fp_payload);
|
||
|
||
// 删除payload文件
|
||
unlink("/root/sim_payload");
|
||
} else {
|
||
// 使用默认payload
|
||
char default_payload[] = "{\"method\":\"thing.service.lightOperate\",\"params\":{\"LightSwitch\":1}}";
|
||
LOG_I("simulate_mqtt_topic: using default payload: %s\n", default_payload);
|
||
PutDataIntoMQueue(default_payload);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
fclose(fp_topic);
|
||
|
||
// 删除topic文件
|
||
unlink("/root/sim_topic");
|
||
}
|
||
|
||
pthread_exit(NULL);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
// 全场亮灯线程 - 从/root/all_light文件读取配置并触发全场亮灯
|
||
void *thread_all_light(void *arg){
|
||
LOG_I("thread_all_light started\n");
|
||
|
||
char all_light_payload[256] = {0};
|
||
|
||
while(1){
|
||
sleep(5); // 每5秒检查一次
|
||
|
||
// 从/root/all_light文件读取内容
|
||
FILE *fp = fopen("/root/all_light", "r");
|
||
if(fp == NULL){
|
||
continue;
|
||
}
|
||
|
||
memset(all_light_payload, 0, sizeof(all_light_payload));
|
||
if(fgets(all_light_payload, sizeof(all_light_payload), fp) != NULL){
|
||
// 去掉换行符
|
||
int len = strlen(all_light_payload);
|
||
if(len > 0 && all_light_payload[len-1] == '\n'){
|
||
all_light_payload[len-1] = '\0';
|
||
}
|
||
|
||
// 解析配置: 格式为 "color,flash,sound,duration" 例如 "4,3,0,30"
|
||
// color: 0=不亮,1=蓝,2=绿,3=青,4=红,5=紫,6=黄,7=白
|
||
// flash: 1=常亮,3=闪烁
|
||
// sound: 0=关闭,1=开启
|
||
// duration: 持续时间(秒)
|
||
int color=4, flash=3, sound=0, duration=30;
|
||
if(sscanf(all_light_payload, "%d,%d,%d,%d", &color, &flash, &sound, &duration) >= 1){
|
||
LOG_I("all_light: color=%d, flash=%d, sound=%d, duration=%d\n", color, flash, sound, duration);
|
||
|
||
// 设置全场亮灯参数
|
||
allLightColor = color;
|
||
allLightFlash = flash;
|
||
allLightSound = sound;
|
||
allLightDuration = duration;
|
||
|
||
// 等待上一个命令完成
|
||
while(!isSendComEnd){
|
||
usleep(100*1000);
|
||
}
|
||
|
||
// 清空串口缓冲区
|
||
tcflush(uartSend.uart_fd, TCIOFLUSH);
|
||
|
||
// 设置全场亮灯标志
|
||
isSendComEnd = false;
|
||
isLightOnByGroup = false;
|
||
isLightOnById = false;
|
||
isLightOn = false;
|
||
isBindTag = false;
|
||
isAllLightOn = true;
|
||
|
||
// 发送按ID范围点亮命令 '*' 表示按ID点亮
|
||
// timeout单位是5秒,所以 duration(秒) / 5 = timeout
|
||
uart_data_send_head(&uartSend, '*', 5, duration/5, 0);
|
||
|
||
LOG_I("all_light: command sent\n");
|
||
}
|
||
}
|
||
fclose(fp);
|
||
|
||
// 删除文件,避免重复触发
|
||
remove("/root/all_light");
|
||
}
|
||
pthread_exit(NULL);
|
||
}
|
||
|
||
/*================================================================================*/
|
||
void doCommand_help(int argc, char *argv[])
|
||
{
|
||
printf("************************************************************\r\n"\
|
||
"all commands are case insensitive\r\n"\
|
||
"help print this message\r\n"\
|
||
"SND [01-60] set sound S01-S60\r\n"\
|
||
"************************************************************\r\n");
|
||
}
|
||
|
||
void doCommand(int argc, char *argv[])
|
||
{
|
||
//sendData(argv[1],argv[0]);
|
||
}
|
||
|
||
__command_initialize("RON", doCommand);
|
||
__command_initialize("help",doCommand_help);
|
||
|
||
/*================================================================================*/
|
||
void do_removelog(void)
|
||
{
|
||
LOG_I("%s\n",__func__);
|
||
FILE *fp;
|
||
char buffer[5];
|
||
char syscmd[32];
|
||
int logcount=0;
|
||
|
||
fp=popen("ls Log.*|wc -l", "r");
|
||
fgets(buffer,sizeof(buffer),fp);
|
||
logcount=atoi(buffer);
|
||
LOG_I("logcount:%d\n",logcount);
|
||
if(logcount>=3){
|
||
sprintf(syscmd,"ls Log.*|head -%d|xargs rm -fr",logcount-2);
|
||
LOG_I("%s\n",syscmd);
|
||
system(syscmd);
|
||
}else{
|
||
LOG_I("logcount less than 3,not remove\n");
|
||
}
|
||
}
|
||
|
||
void removeLog(){
|
||
int len=0;
|
||
char *savedtime=NULL;
|
||
char nowtime[16]={0};
|
||
long now=0;
|
||
long saved=0;
|
||
|
||
while(1){
|
||
now=getCurrentTime();
|
||
sprintf(nowtime,"%ld",now);
|
||
savedtime=file_to_buffer("logTime",&len);
|
||
if(savedtime==NULL){
|
||
buffer_to_file("logTime",nowtime,strlen(nowtime),"wb");
|
||
savedtime=file_to_buffer("logTime",&len);
|
||
}
|
||
saved=atol(savedtime);
|
||
LOG_I("now=%ld,saved=%ld,nowtime=%s,savedtime=%s\n",now,saved,nowtime,savedtime);
|
||
if(now-saved>=(60*60*24*5)){
|
||
//if(now-saved>=10){
|
||
buffer_to_file("logTime",nowtime,strlen(nowtime),"wb");
|
||
do_removelog();
|
||
}
|
||
sleep(60*60*1);
|
||
}
|
||
}
|
||
|
||
void enableWatchDog(){
|
||
system("echo 1 > /sys/class/gpio/export");//watchdog enable pin SGM820
|
||
system("echo 112 > /sys/class/gpio/export");//feed watchdog pin red
|
||
system("echo out > /sys/class/gpio/gpio1/direction");
|
||
system("echo out > /sys/class/gpio/gpio112/direction");
|
||
system("echo 1 > /sys/class/gpio/gpio1/value");
|
||
LOG_I("enable watchdog\n");
|
||
system("echo 1 > /sys/class/gpio/gpio112/value");
|
||
}
|
||
|
||
void feedWatchDog(){
|
||
while(1){
|
||
//LOG_I("feed watchdog\n");
|
||
system("echo 0 > /sys/class/gpio/gpio112/value");
|
||
usleep(100*1000);
|
||
system("echo 1 > /sys/class/gpio/gpio112/value");
|
||
sleep(1);
|
||
}
|
||
}
|
||
|
||
void report_tag(void){
|
||
while(1){
|
||
sleep(60*10);
|
||
LOG_I("report_tag\n");
|
||
//light_status_report();
|
||
}
|
||
}
|
||
|
||
// GPIO113控制函数
|
||
void setGpio113High() {
|
||
int fd = open("/sys/class/gpio/gpio113/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio113 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
usleep(100*1000);
|
||
write(fd, "1", 1);
|
||
close(fd);
|
||
LOG_I("GPIO113 set to HIGH\n");
|
||
}
|
||
|
||
// GPIO114控制函数
|
||
void setGpio114High() {
|
||
int fd = open("/sys/class/gpio/gpio114/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio114 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
usleep(100*1000);
|
||
write(fd, "1", 1);
|
||
close(fd);
|
||
LOG_I("GPIO114 set to HIGH\n");
|
||
}
|
||
|
||
void setGpio113Low() {
|
||
int fd = open("/sys/class/gpio/gpio113/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio113 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
close(fd);
|
||
LOG_I("GPIO113 set to LOW\n");
|
||
}
|
||
|
||
// GPIO115控制函数
|
||
void setGpio115High() {
|
||
int fd = open("/sys/class/gpio/gpio115/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio115 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
usleep(100*1000);
|
||
write(fd, "1", 1);
|
||
close(fd);
|
||
LOG_I("GPIO115 set to HIGH\n");
|
||
}
|
||
|
||
void setGpio115Low() {
|
||
int fd = open("/sys/class/gpio/gpio115/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio115 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
close(fd);
|
||
LOG_I("GPIO115 set to LOW\n");
|
||
}
|
||
|
||
// GPIO117控制函数
|
||
void setGpio117High() {
|
||
int fd = open("/sys/class/gpio/gpio117/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio117 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
usleep(100*1000);
|
||
write(fd, "1", 1);
|
||
close(fd);
|
||
LOG_I("GPIO117 set to HIGH\n");
|
||
}
|
||
|
||
void setGpio117Low() {
|
||
int fd = open("/sys/class/gpio/gpio117/value", O_WRONLY);
|
||
if (fd < 0) {
|
||
LOG_I("Failed to open gpio117 value: %s\n", strerror(errno));
|
||
return;
|
||
}
|
||
write(fd, "0", 1);
|
||
close(fd);
|
||
LOG_I("GPIO117 set to LOW\n");
|
||
}
|
||
|
||
int readQrcode()
|
||
{
|
||
fd = open("/dev/input/event2", O_RDONLY);
|
||
if (fd < 0)
|
||
{
|
||
LOG_I("can not open scanner input event2!\n");
|
||
goto error;
|
||
}
|
||
|
||
while (1)
|
||
{
|
||
while (read(fd, &buff, sizeof(struct input_event)) == 0)
|
||
{
|
||
;
|
||
}
|
||
if (buff.type == EV_KEY){
|
||
if(buff.value==0){
|
||
#if 0
|
||
LOG_I("type:%d code:%d value:%d\n", buff.type, buff.code, buff.value);
|
||
#else
|
||
switch(buff.code){
|
||
case 2:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='!';
|
||
}else{
|
||
input_value[count_value]='1';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 3:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='@';
|
||
}else{
|
||
input_value[count_value]='2';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 4:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='#';
|
||
}else{
|
||
input_value[count_value]='3';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 5:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='$';
|
||
}else{
|
||
input_value[count_value]='4';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 6:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='%';
|
||
}else{
|
||
input_value[count_value]='5';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 7:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='^';
|
||
}else{
|
||
input_value[count_value]='6';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 8:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='&';
|
||
}else{
|
||
input_value[count_value]='7';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 9:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='*';
|
||
}else{
|
||
input_value[count_value]='8';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 10:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='(';
|
||
}else{
|
||
input_value[count_value]='9';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 11:
|
||
if(UPCASE==1){
|
||
input_value[count_value]=')';
|
||
}else{
|
||
input_value[count_value]='0';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 12:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='_';
|
||
}else{
|
||
input_value[count_value]='-';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 13:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='+';
|
||
}else{
|
||
input_value[count_value]='=';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 16:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='Q';
|
||
}else{
|
||
input_value[count_value]='q';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 17:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='W';
|
||
}else{
|
||
input_value[count_value]='w';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 18:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='E';
|
||
}else{
|
||
input_value[count_value]='e';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 19:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='R';
|
||
}else{
|
||
input_value[count_value]='r';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 20:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='T';
|
||
}else{
|
||
input_value[count_value]='T';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 21:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='Y';
|
||
}else{
|
||
input_value[count_value]='y';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 22:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='U';
|
||
}else{
|
||
input_value[count_value]='u';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 23:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='I';
|
||
}else{
|
||
input_value[count_value]='i';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 24:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='O';
|
||
}else{
|
||
input_value[count_value]='o';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 25:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='P';
|
||
}else{
|
||
input_value[count_value]='p';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 26:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='{';
|
||
}else{
|
||
input_value[count_value]='[';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 27:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='}';
|
||
}else{
|
||
input_value[count_value]=']';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 28:
|
||
input_value[count_value]='\0';
|
||
//LOG_I("%s\n",input_value);
|
||
memset(input_value_copy,0,1024);
|
||
memcpy(input_value_copy,input_value,1024);
|
||
memset(input_value,0,1024);
|
||
count_value=0;
|
||
int ret=-1;
|
||
pthread_t pt_handleqrcode;
|
||
ret = pthread_create(&pt_handleqrcode,NULL,actHandleQrcode,input_value_copy);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create handleqrcode fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_handleqrcode);
|
||
}
|
||
break;
|
||
case 30:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='A';
|
||
}else{
|
||
input_value[count_value]='a';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 31:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='S';
|
||
}else{
|
||
input_value[count_value]='s';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 32:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='D';
|
||
}else{
|
||
input_value[count_value]='d';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 33:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='F';
|
||
}else{
|
||
input_value[count_value]='f';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 34:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='G';
|
||
}else{
|
||
input_value[count_value]='g';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 35:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='H';
|
||
}else{
|
||
input_value[count_value]='h';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 36:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='J';
|
||
}else{
|
||
input_value[count_value]='j';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 37:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='K';
|
||
}else{
|
||
input_value[count_value]='k';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 38:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='L';
|
||
}else{
|
||
input_value[count_value]='l';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 39:
|
||
if(UPCASE==1){
|
||
input_value[count_value]=':';
|
||
}else{
|
||
input_value[count_value]=';';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 40:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='"';
|
||
}else{
|
||
input_value[count_value]='\'';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 42:
|
||
UPCASE=1;
|
||
break;
|
||
case 43:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='|';
|
||
}else{
|
||
input_value[count_value]='\\';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 44:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='Z';
|
||
}else{
|
||
input_value[count_value]='z';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 45:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='X';
|
||
}else{
|
||
input_value[count_value]='x';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 46:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='C';
|
||
}else{
|
||
input_value[count_value]='c';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 47:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='V';
|
||
}else{
|
||
input_value[count_value]='v';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 48:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='B';
|
||
}else{
|
||
input_value[count_value]='b';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 49:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='N';
|
||
}else{
|
||
input_value[count_value]='n';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 50:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='M';
|
||
}else{
|
||
input_value[count_value]='m';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 51:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='<';
|
||
}else{
|
||
input_value[count_value]=',';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 52:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='>';
|
||
}else{
|
||
input_value[count_value]='.';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
case 53:
|
||
if(UPCASE==1){
|
||
input_value[count_value]='?';
|
||
}else{
|
||
input_value[count_value]='/';
|
||
}
|
||
UPCASE=0;
|
||
count_value++;
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
close(fd);
|
||
return 0;
|
||
error:
|
||
return 1;
|
||
}
|
||
#if 0
|
||
void writeWpa(char *filename,char *ssid,char *psw){
|
||
LOG_I("%s\n",__func__);
|
||
buffer_to_file(filename,"# WPA-PSK/TKIP\n",strlen("# WPA-PSK/TKIP\n"),"wb");
|
||
buffer_to_file(filename,"ap_scan=1\n",strlen("ap_scan=1\n"),"a");
|
||
buffer_to_file(filename,"ctrl_interface=/var/run/wpa_supplicant\n",strlen("ctrl_interface=/var/run/wpa_supplicant\n"),"a");
|
||
buffer_to_file(filename,"network={\n",strlen("network={\n"),"a");
|
||
buffer_to_file(filename,"ssid=\"",strlen("ssid=\""),"a");
|
||
buffer_to_file(filename,ssid,strlen(ssid),"a");
|
||
buffer_to_file(filename,"\"",strlen("\""),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"key_mgmt=WPA-PSK\n",strlen("key_mgmt=WPA-PSK\n"),"a");
|
||
buffer_to_file(filename,"proto=WPA RSN\n",strlen("proto=WPA RSN\n"),"a");
|
||
buffer_to_file(filename,"pairwise=CCMP TKIP\n",strlen("pairwise=CCMP TKIP\n"),"a");
|
||
buffer_to_file(filename,"group=CCMP TKIP\n",strlen("group=CCMP TKIP\n"),"a");
|
||
buffer_to_file(filename,"psk=\"",strlen("psk=\""),"a");
|
||
buffer_to_file(filename,psw,strlen(psw),"a");
|
||
buffer_to_file(filename,"\"",strlen("\""),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"}\n",strlen("}\n"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
}
|
||
|
||
void writeWlan(char *filename,char *netway,char *gate,char *ip){
|
||
LOG_I("%s\n",__func__);
|
||
buffer_to_file(filename,"METHOD=",strlen("METHOD="),"wb");
|
||
buffer_to_file(filename,netway,strlen(netway),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
if(strcmp(netway,"STATIC")==0){
|
||
buffer_to_file(filename,"IPADDR=",strlen("IPADDR="),"a");
|
||
buffer_to_file(filename,ip,strlen(ip),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"NETMASK=255.255.255.0\n",strlen("NETMASK=255.255.255.0\n"),"a");
|
||
buffer_to_file(filename,"GATEWAY=",strlen("GATEWAY="),"a");
|
||
buffer_to_file(filename,gate,strlen(gate),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
}
|
||
}
|
||
|
||
void removeFile(char *filename){
|
||
char cmd[32]={0};
|
||
sprintf(cmd,"rm %s",filename);
|
||
//LOG_I("%s\n",cmd);
|
||
system(cmd);
|
||
}
|
||
#endif
|
||
|
||
void hmacsha1_hex(char *key, char* data, char *signhex, int signhex_len) {
|
||
unsigned char result[256] = {0};
|
||
size_t len = sizeof(result);
|
||
|
||
hmac_sha1((const uint8_t*)key, strlen(key), (const uint8_t*)data, strlen(data), result, &len);
|
||
|
||
// 转换为十六进制格式
|
||
for (int i = 0; i < len && i * 2 + 1 < signhex_len; i++) {
|
||
snprintf(signhex + i * 2, 3, "%02x", result[i]);
|
||
}
|
||
}
|
||
|
||
void writeNetworkInterface(char *filename,char *dest){
|
||
buffer_to_file(filename,"# interfaces(5) file used by ifup(8) and ifdown(8)",
|
||
strlen("# interfaces(5) file used by ifup(8) and ifdown(8)"),"wb");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"# Include files from /etc/network/interfaces.d:",strlen("# Include files from /etc/network/interfaces.d:"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"source-directory /etc/network/interfaces.d",strlen("source-directory /etc/network/interfaces.d"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"auto lo",strlen("auto lo"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"iface lo inet loopback",strlen("iface lo inet loopback"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"auto eth0",strlen("auto eth0"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"iface eth0 inet dhcp",strlen("iface eth0 inet dhcp"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"# address 10.10.12.12",strlen("# address 10.10.12.12"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"# netmask 255.255.255.0",strlen("# netmask 255.255.255.0"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"# gateway 10.10.12.1",strlen("# gateway 10.10.12.1"),"a");
|
||
buffer_to_file(filename,"\n",strlen("\n"),"a");
|
||
buffer_to_file(filename,"hwaddress ether ",strlen("hwaddress ether "),"a");
|
||
buffer_to_file(filename,dest,strlen(dest),"a");
|
||
system("sync");
|
||
}
|
||
|
||
char* insert_colon(const char* src, int interval) {
|
||
if (!src || interval <= 0) return NULL;
|
||
|
||
size_t len = strlen(src);
|
||
if (len == 0) { // 空字符串返回空
|
||
char* res = malloc(1);
|
||
if (res) res[0] = '\0';
|
||
return res;
|
||
}
|
||
|
||
// 计算新字符串长度
|
||
size_t sections = (len + interval - 1) / interval; // 总段数
|
||
size_t new_len = len + (sections - 1); // 新长度 = 原长 + 冒号数
|
||
char* new_str = malloc(new_len + 1); // 分配内存:ml-citation{ref="2" data="citationList"}
|
||
if (!new_str) return NULL;
|
||
|
||
size_t src_idx = 0, dst_idx = 0;
|
||
while (src_idx < len) {
|
||
// 计算本次复制的字符数
|
||
size_t copy_size = (len - src_idx < (size_t)interval) ? (len - src_idx) : (size_t)interval;
|
||
memcpy(new_str + dst_idx, src + src_idx, copy_size); // 块复制:ml-citation{ref="3" data="citationList"}
|
||
src_idx += copy_size;
|
||
dst_idx += copy_size;
|
||
|
||
// 非末尾段时插入冒号
|
||
if (src_idx < len) new_str[dst_idx++] = ':';
|
||
}
|
||
new_str[dst_idx] = '\0'; // 终止符:ml-citation{ref="7" data="citationList"}
|
||
return new_str;
|
||
}
|
||
|
||
void *actHandleQrcode(void *parm){
|
||
char *str=(char *)parm;
|
||
LOG_I("scan:%s\n",str);
|
||
if(strstr(str,"{")!=NULL){
|
||
#if 0
|
||
char deviceSecret[64]={0};
|
||
char deviceCode[64]={0};
|
||
char netWorkType[64]={0};
|
||
char netWorkSsid[64]={0};
|
||
char netWorkPassword[64]={0};
|
||
get_string_from_json_string_by_key_unescape(str, "deviceSecret",deviceSecret,64);
|
||
LOG_I("deviceSecret:%s\n",deviceSecret);
|
||
get_string_from_json_string_by_key_unescape(str, "deviceCode",deviceCode,64);
|
||
LOG_I("deviceCode:%s\n",deviceCode);
|
||
if(strcmp(deviceSecret,"")!=0 && strcmp(deviceCode,"")!=0){
|
||
buffer_to_file("deviceSecret",deviceSecret,strlen(deviceSecret),"wb");
|
||
buffer_to_file("savedDevSn",deviceCode,strlen(deviceCode),"wb");
|
||
}
|
||
get_string_from_json_string_by_key_unescape(str, "netWorkType",netWorkType,64);
|
||
LOG_I("netWorkType:%s\n",netWorkType);
|
||
|
||
if(strcmp(netWorkType,"net_wifi")==0){
|
||
buffer_to_file("nettype","net_wifi",strlen("net_wifi"),"wb");
|
||
get_string_from_json_string_by_key_unescape(str, "netWorkSsid",netWorkSsid,64);
|
||
LOG_I("netWorkSsid:%s\n",netWorkSsid);
|
||
get_string_from_json_string_by_key_unescape(str, "netWorkPassword",netWorkPassword,64);
|
||
LOG_I("netWorkPassword:%s\n",netWorkPassword);
|
||
if(strcmp(netWorkSsid,"")!=0 && strcmp(netWorkPassword,"")!=0){
|
||
writeWpa("/etc/wpa_supplicant.conf",netWorkSsid,netWorkPassword);
|
||
sleep(1);
|
||
system("reboot");
|
||
}else{
|
||
}
|
||
}else if(strcmp(netWorkType,"net_wired")==0){
|
||
buffer_to_file("nettype","net_wired",strlen("net_wired"),"wb");
|
||
LOG_I("use wired\n");
|
||
sleep(1);
|
||
system("reboot");
|
||
}else if(strcmp(netWorkType,"net_mobile")==0){
|
||
buffer_to_file("nettype","net_mobile",strlen("net_mobile"),"wb");
|
||
LOG_I("use mobile\n");
|
||
sleep(1);
|
||
system("reboot");
|
||
}
|
||
#endif
|
||
}else{
|
||
#if 1
|
||
if(strstr(str,"d")!=NULL && strlen(str)>=27){
|
||
LOG_I("ok\n");
|
||
char *result=NULL;
|
||
char *p;
|
||
result=strtok_r(str,":",&p);
|
||
while(result!=NULL){
|
||
if(strstr(result,"d")!=NULL){
|
||
LOG_I("save sn:%s\n",result);
|
||
buffer_to_file("savedDevSn",result,strlen(result),"wb");
|
||
}else{
|
||
//LOG_I("save mac:%s\n",result);
|
||
//buffer_to_file("savedDevMac",result,strlen(result),"wb");
|
||
char* destmac = insert_colon(result, 2);
|
||
LOG_I("save mac:%s\n",destmac);
|
||
writeNetworkInterface("/etc/network/interfaces",destmac);
|
||
}
|
||
result=strtok_r(NULL,",",&p);
|
||
}
|
||
}
|
||
#else
|
||
if(strstr(str,"d1")!=NULL){
|
||
buffer_to_file("savedDevSn",str,strlen(str),"wb");
|
||
}
|
||
#endif
|
||
}
|
||
pthread_exit(NULL);
|
||
}
|
||
|
||
char *file_to_buffer(const char *pathname, unsigned int *size){
|
||
FILE *fp = NULL;
|
||
char *temp = NULL;
|
||
fp = fopen(pathname, "rb");
|
||
if(fp==NULL){
|
||
//LOG_I("open %s error\n", pathname);
|
||
}else{
|
||
fseek(fp,0,2);
|
||
*size = ftell(fp);
|
||
rewind(fp);
|
||
temp = (char *)malloc(*size);
|
||
fread(temp, 1, *size, fp);
|
||
fclose(fp);
|
||
}
|
||
return temp;
|
||
}
|
||
|
||
/*================================================================================*/
|
||
void showShellInfo(char *command){
|
||
FILE *fp;
|
||
char buffer[512]={0};
|
||
fp=popen(command, "r");
|
||
fread(buffer,1,sizeof(buffer),fp);
|
||
LOG_I("\n%s",buffer);
|
||
}
|
||
|
||
void getTimeStr(char *buffer,int len){
|
||
time_t timep;
|
||
struct tm *p;
|
||
time (&timep);
|
||
p=localtime(&timep);
|
||
strftime (buffer,len,"%Y-%m-%d %H:%M:%S",p);
|
||
}
|
||
|
||
long getCurrentTime(){
|
||
struct timeval begin;
|
||
gettimeofday(&begin,NULL);
|
||
long long beginTime = (long long)begin.tv_sec * 1000 + (long long)begin.tv_usec / 1000;
|
||
long last=beginTime/1000;
|
||
return last;
|
||
}
|
||
|
||
void myrand(char *randnum,int len){
|
||
int i;
|
||
srand((unsigned)time(0));
|
||
for(i=0;i<=len-1;i++)
|
||
randnum[i]=rand()%10 +'0';
|
||
randnum[len]='\0';
|
||
}
|
||
|
||
void removeSpaces(char *str) {
|
||
int i = 0, j = 0;
|
||
while (str[i] != '\0') {
|
||
if (str[i] != ' ') {
|
||
str[j++] = str[i];
|
||
}
|
||
i++;
|
||
}
|
||
str[j] = '\0';
|
||
}
|
||
|
||
void getDevRawPassword(char *devsn){
|
||
LOG_I("devsn:%s\n",devsn);
|
||
json_object *root = NULL;
|
||
const char *payload = NULL;
|
||
char send_request[256]={0};
|
||
char signbase64[256]={0};
|
||
char signtmp[256]={0};
|
||
char jsondata[256] = {0};
|
||
char tmpdata[256] = {0};
|
||
//char tmpdata1[64] = {0};
|
||
char buffer[512];
|
||
FILE *fp;
|
||
root = json_object_new_object();
|
||
if(root == NULL){
|
||
LOG_I("json_object_new_object error\n");
|
||
}else{
|
||
json_object_object_add(root, "deviceId",json_object_new_string(devsn));
|
||
json_object_object_add(root, "oldPassword",json_object_new_string("12345"));
|
||
payload = json_object_to_json_string(root);
|
||
removeSpaces(payload);
|
||
strcpy(signtmp,payload);
|
||
strcat(signtmp,appSecret);
|
||
//LOG_I("signtmp:%s\n",signtmp);
|
||
get_base64_md5_from_string(signbase64, sizeof(signbase64), signtmp, strlen(signtmp));
|
||
//LOG_I("signbase64:%s\n",signbase64);
|
||
sprintf(send_request,"curl -X POST -H 'x-appKey:%s' -H 'x-datadigest:%s' -H 'Content-Type: application/json' -d '%s' %s",
|
||
appKey,signbase64,payload,getDevRawPasswordUrl);
|
||
LOG_I("send_request:%s\n",send_request);
|
||
fp=popen(send_request,"r");
|
||
fgets(buffer,sizeof(buffer),fp);
|
||
//get_string_from_json_string_by_key_unescape(buffer, "message", tmpdata1, sizeof(tmpdata1));
|
||
//LOG_I("message: %s\n",tmpdata1);
|
||
get_string_from_json_string_by_key_unescape(buffer, "result", tmpdata, sizeof(tmpdata));
|
||
LOG_I("result: %s\n",tmpdata);
|
||
|
||
snprintf(jsondata, sizeof(jsondata), "{%s}", tmpdata);
|
||
//LOG_I("jsondata:%s\n",jsondata);
|
||
get_string_from_json_string_by_key_unescape(jsondata, "password", mqttRawPassword, sizeof(mqttRawPassword));
|
||
LOG_I("save mqttRawPassword:%s\n",mqttRawPassword);
|
||
|
||
if(strcmp(mqttRawPassword,"")!=0){
|
||
buffer_to_file("mqttRawPassword",mqttRawPassword,strlen(mqttRawPassword),"wb");
|
||
}
|
||
}
|
||
}
|
||
|
||
void checkOtaKey(void){
|
||
int len=0;
|
||
int keycount=0;
|
||
char *readresult=NULL;
|
||
while(1){
|
||
if(isOtaEnable){
|
||
//system("echo 0 > /sys/class/gpio/gpio113/value");
|
||
//sleep(1);
|
||
//system("echo 1 > /sys/class/gpio/gpio113/value");
|
||
sleep(1);
|
||
}else{
|
||
readresult=file_to_buffer("/sys/class/gpio/gpio63/value",&len);
|
||
//LOG_I("resetKey:%s\n",readresult);
|
||
if(readresult!=NULL){
|
||
if(strcmp(readresult,"0\n")==0){
|
||
keycount++;
|
||
if(keycount==3){
|
||
keycount=0;
|
||
isOtaEnable=true;
|
||
//isLEDOtaSuccess=false;
|
||
//isAPOtaSuccess=false;
|
||
//isSendComEnd=true;
|
||
LOG_I("OTA enable\n");
|
||
update_app();
|
||
}
|
||
}
|
||
}
|
||
usleep(100*1000);
|
||
}
|
||
}
|
||
}
|
||
|
||
void update_app(void){
|
||
system("rm -fr ota");
|
||
system("mkdir ota");
|
||
char otaCmd[256]={0};
|
||
sprintf(otaCmd,"curl -o /root/ota/jd_ota.zip %s",updateUrl);
|
||
system(otaCmd);
|
||
sleep(15);
|
||
system("unzip ota/jd_ota.zip");
|
||
system("mv jd_ota/* ota");
|
||
system("rm -fr jd_ota");
|
||
system("mv ota/start.sh /root");
|
||
sleep(1);
|
||
system("reboot");
|
||
}
|
||
/*================================================================================*/
|
||
void mqtt_init(){
|
||
int ret=0;
|
||
char username[64] = {0};
|
||
char password[64] = {0};
|
||
char clientid[256] = {0};
|
||
char stringToSign[512] = {0}; // 待签名串
|
||
char hostip[16]={0};
|
||
struct timeval tv;
|
||
|
||
// 获取当前时间戳(毫秒)
|
||
gettimeofday(&tv, NULL);
|
||
long timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
|
||
// 使用实时时间戳,确保与服务器时间同步
|
||
LOG_I("%ld\n", timestamp);
|
||
|
||
// 使用白名单中的设备ID
|
||
char unique_device_id[32];
|
||
|
||
// 使用白名单中的设备ID
|
||
strcpy(unique_device_id, stationsn);
|
||
LOG_I("使用白名单设备ID: %s\n", unique_device_id);
|
||
|
||
// 使用REGISTER模式进行设备注册
|
||
// 因为设备在白名单中但还没注册,需要先注册
|
||
const char* authType = MQTT_AUTH_TYPE_AUTH;
|
||
char* secretKey = appSecret; // 使用ProductSecret进行注册
|
||
|
||
LOG_I("%s\n", unique_device_id);
|
||
|
||
// 根据新协议格式构建ClientId: ProductKey&/DeviceClientId/SecureMode/Algorithm/Timestamp/AuthType
|
||
snprintf(clientid, sizeof(clientid), "%s&/%s/%s/%s/%ld/%s",
|
||
productid, unique_device_id, MQTT_SECURE_MODE, MQTT_ALGORITHM, timestamp, authType);
|
||
|
||
// 根据新协议格式构建Username: /ProductKey/DeviceKey
|
||
snprintf(username, sizeof(username), "/%s/%s", productid, unique_device_id);
|
||
|
||
// 构建待签名串: deviceKey + deviceKey + productKey + algorithm + timestamp
|
||
// 格式与Python代码保持一致: deviceKey + deviceKey + productKey + 'AUK1_MQTT_HMAC_SHA1' + timestamp
|
||
char timestamp_str[32];
|
||
snprintf(timestamp_str, sizeof(timestamp_str), "%ld", timestamp);
|
||
snprintf(stringToSign, sizeof(stringToSign), "%s%s%s%s%s",
|
||
unique_device_id, unique_device_id, productid, MQTT_ALGORITHM, timestamp_str);
|
||
|
||
// 使用HMAC-SHA1算法生成密码签名(十六进制格式)
|
||
// 根据设备注册状态选择签名密钥:
|
||
// - REGISTER模式:使用ProductSecret (appSecret)
|
||
// - AUTH模式:使用DeviceSecret (mqttRawPassword)
|
||
hmacsha1_hex(secretKey, stringToSign, password, sizeof(password));
|
||
|
||
LOG_I("=== 白名单设备注册信息 ===\n");
|
||
LOG_I("设备Key: %s\n", unique_device_id);
|
||
LOG_I("设备密钥: %s\n", secretKey);
|
||
LOG_I("认证模式: %s\n", authType);
|
||
LOG_I("ClientId: %s\n", clientid);
|
||
LOG_I("Username: %s\n", username);
|
||
LOG_I("StringToSign: %s\n", stringToSign);
|
||
LOG_I("Password: %s\n", password);
|
||
LOG_I("时间戳: %ld\n", timestamp);
|
||
LOG_I("========================\n");
|
||
|
||
mqtt_config.tracelevel=MQTTASYNC_TRACE_PROTOCOL;
|
||
mqtt_config.retain=0;
|
||
mqtt_config.port=mqtt_port;
|
||
mqtt_config.keepalive=180;
|
||
|
||
memset(mqtt_config.clientid,0,sizeof(mqtt_config.clientid));
|
||
memcpy(mqtt_config.clientid, clientid, strlen(clientid)+1);
|
||
|
||
memset(mqtt_config.productcode, 0, sizeof(mqtt_config.productcode));
|
||
memcpy(mqtt_config.productcode, productid, strlen(productid)+1);
|
||
memset(mqtt_config.username, 0, sizeof(mqtt_config.username));
|
||
memcpy(mqtt_config.username, username, strlen(username)+1);
|
||
memset(mqtt_config.password, 0, sizeof(mqtt_config.password));
|
||
memcpy(mqtt_config.password, password, strlen(password)+1);
|
||
|
||
get_ip_by_domain(hostDomain,hostip,16);
|
||
LOG_I("MQTT服务器域名: %s, 解析IP: %s\n", hostDomain, hostip);
|
||
|
||
// 如果DNS解析失败,使用硬编码的IP地址
|
||
if (strlen(hostip) == 0 || strcmp(hostip, "0.0.0.0") == 0) {
|
||
LOG_I("DNS解析失败,使用硬编码IP地址\n");
|
||
strcpy(hostip, "103.37.154.120"); // 使用日志中看到的IP
|
||
}
|
||
|
||
memset(mqtt_config.host, 0, sizeof(mqtt_config.host));
|
||
memcpy(mqtt_config.host, hostip, strlen(hostip)+1);
|
||
mqtt_config.MQTTVersion = 4;
|
||
|
||
/* will options */
|
||
mqtt_config.will_topic = NULL;
|
||
mqtt_config.will_payload = NULL;
|
||
mqtt_config.will_qos = 1;
|
||
mqtt_config.will_retain = 0;
|
||
/* TLS options */
|
||
mqtt_config.insecure = 0;
|
||
mqtt_config.capath = NULL;
|
||
mqtt_config.cert = NULL;
|
||
mqtt_config.cafile = NULL;
|
||
mqtt_config.key = NULL;
|
||
mqtt_config.keypass = NULL;
|
||
mqtt_config.ciphers = NULL;
|
||
|
||
ret = sem_init(&mqtt_config.sem_connect, 0, 0);
|
||
if (ret != 0)
|
||
{
|
||
LOG_I("sem_connect init error\n");
|
||
goto error;
|
||
}
|
||
|
||
ret = mqtt_utils_init(&mqtt_config);
|
||
if (ret < 0)
|
||
{
|
||
LOG_I("mqtt_utils_init error\n");
|
||
ret = -1;
|
||
goto error;
|
||
}
|
||
sem_wait(&mqtt_config.sem_connect);
|
||
ret = 0;
|
||
error:
|
||
return;
|
||
}
|
||
|
||
/*================================================================================*/
|
||
void *thread_keycheck(void *arg){
|
||
checkOtaKey();
|
||
}
|
||
|
||
void *thread_reporttag(void *arg){
|
||
report_tag();
|
||
}
|
||
|
||
void *thread_mqtt(void *arg){
|
||
mqtt_init();
|
||
}
|
||
|
||
void *thread_removelog(void *arg){
|
||
removeLog();
|
||
}
|
||
|
||
void *thread_feed_watchdog(void *arg){
|
||
feedWatchDog();
|
||
return NULL;
|
||
}
|
||
|
||
void *thread_readqr(void *arg){
|
||
readQrcode();
|
||
}
|
||
|
||
void *thread_uart_recv_ack(void *arg){
|
||
uint16_t parm_ack;
|
||
int ret=0;
|
||
while(1){
|
||
// 只有在发送命令后才等待ACK,避免读取残留数据
|
||
if(isSendComEnd){
|
||
usleep(100*1000);
|
||
continue;
|
||
}
|
||
ret=uart_data_receive_ack(&uartSend,&parm_ack);
|
||
if(ret>0){
|
||
LOG_I("ack:%x\n",parm_ack);
|
||
if(parm_ack==0x2323){
|
||
// 【关键修改】从命令队列获取命令,而不是使用全局变量
|
||
light_command_t cmd;
|
||
if(get_light_command(&cmd) != 0) {
|
||
LOG_I("No light command in queue, using fallback global variables\n");
|
||
// 队列为空时的回退处理(保持兼容性)
|
||
memset(&cmd, 0, sizeof(cmd));
|
||
strncpy(cmd.deviceName, g_mqtt_deviceName, sizeof(cmd.deviceName) - 1);
|
||
cmd.color = changecolor;
|
||
cmd.sound = changesound;
|
||
cmd.flash = changeflash;
|
||
// 【修复】明确设置RGB值,确保熄灭命令检测正确工作
|
||
if (changecolor == 0) {
|
||
cmd.light_r = 0;
|
||
cmd.light_g = 0;
|
||
cmd.light_b = 0;
|
||
}
|
||
|
||
// 【增强】优先使用设备映射,解决多设备并发问题
|
||
uint32_t mapped_tagCode;
|
||
uint16_t mapped_tagCodeHead;
|
||
// 【修复】优先使用命令中保存的deviceName,而不是可能被覆盖的全局变量
|
||
const char *target_deviceName = cmd.deviceName;
|
||
if (strlen(target_deviceName) == 0) {
|
||
// 如果命令中没有deviceName,才使用全局变量
|
||
target_deviceName = g_mqtt_deviceName;
|
||
}
|
||
|
||
// 【新增】检查是否是熄灭命令,如果是,避免在多设备场景下处理
|
||
if (cmd.light_r == 0 && cmd.light_g == 0 && cmd.light_b == 0) {
|
||
LOG_I("Fallback detected OFF command for %s (RGB=0,0,0), skipping to avoid multi-device conflicts\n", target_deviceName);
|
||
continue; // 直接跳过所有熄灭回退命令,避免干扰点亮命令
|
||
}
|
||
|
||
if (get_device_tag_mapping(target_deviceName, &mapped_tagCode, &mapped_tagCodeHead) == 0) {
|
||
cmd.tagCode = mapped_tagCode;
|
||
cmd.tagCodeHead = mapped_tagCodeHead;
|
||
LOG_I("Fallback: using device mapping for %s -> %08X\n", target_deviceName, cmd.tagCode);
|
||
} else {
|
||
// 回退到全局变量
|
||
cmd.tagCode = g_current_tagCode;
|
||
cmd.tagCodeHead = g_current_tagCodeHead;
|
||
LOG_I("Fallback: using global variables for %s -> %08X\n", target_deviceName, cmd.tagCode);
|
||
}
|
||
}
|
||
|
||
// 使用队列中的命令参数构建控制包
|
||
jt_led_or_group_package_t led_ctrl={
|
||
.s.color=cmd.color,
|
||
.s.sound=cmd.sound,
|
||
.s.single=0,
|
||
.s.flash=cmd.flash,
|
||
};//0xC1 11000001 flash高位
|
||
jt_led_or_group_package_t group={
|
||
.group=groupno,
|
||
};//0xC1 11000001 flash高位
|
||
//jt_led_or_group_package_t stop={
|
||
// .group=0x72,
|
||
//};//0xC1 11000001 flash高位
|
||
jt_group_package_t groups[1]={{groupno,led_ctrl}};
|
||
//jt_group_package_t groups_stop[2]={{0x58,stop},{0xE3,0x00}};
|
||
#if 0
|
||
uint32_t tag1=strtol(lightsn1,NULL,16);
|
||
uint32_t tag2=strtol(lightsn2,NULL,16);
|
||
uint32_t tag3=strtol(lightsn3,NULL,16);
|
||
uint32_t tag4=strtol(lightsn4,NULL,16);
|
||
uint32_t tag5=strtol(lightsn5,NULL,16);
|
||
uint32_t tag6=strtol(lightsn6,NULL,16);
|
||
uint32_t tag7=strtol(lightsn7,NULL,16);
|
||
uint32_t tag8=strtol(lightsn8,NULL,16);
|
||
uint32_t tag9=strtol(lightsn9,NULL,16);
|
||
uint32_t tag10=strtol(lightsn10,NULL,16);
|
||
uint32_t tag11=strtol(lightsn11,NULL,16);
|
||
uint32_t tag12=strtol(lightsn12,NULL,16);
|
||
uint32_t tag13=strtol(lightsn13,NULL,16);
|
||
uint32_t tag14=strtol(lightsn14,NULL,16);
|
||
uint32_t tag15=strtol(lightsn15,NULL,16);
|
||
uint32_t tag16=strtol(lightsn16,NULL,16);
|
||
uint32_t tag17=strtol(lightsn17,NULL,16);
|
||
uint32_t tag18=strtol(lightsn18,NULL,16);
|
||
uint32_t tag19=strtol(lightsn19,NULL,16);
|
||
uint32_t tag20=strtol(lightsn20,NULL,16);
|
||
uint32_t tag21=strtol(lightsn21,NULL,16);
|
||
uint32_t tag22=strtol(lightsn22,NULL,16);
|
||
uint32_t tag23=strtol(lightsn23,NULL,16);
|
||
uint32_t tag24=strtol(lightsn24,NULL,16);
|
||
uint32_t tag25=strtol(lightsn25,NULL,16);
|
||
uint32_t tag26=strtol(lightsn26,NULL,16);
|
||
uint32_t tag27=strtol(lightsn27,NULL,16);
|
||
uint32_t tag28=strtol(lightsn28,NULL,16);
|
||
uint32_t tag29=strtol(lightsn29,NULL,16);
|
||
uint32_t tag30=strtol(lightsn30,NULL,16);
|
||
#else
|
||
//low power
|
||
#if 0
|
||
uint32_t tag1=strtol("000511",NULL,16);
|
||
uint32_t tag2=strtol("00051C",NULL,16);
|
||
uint32_t tag3=strtol("000E99",NULL,16);
|
||
uint32_t tag4=strtol("004137",NULL,16);
|
||
uint32_t tag5=strtol("004348",NULL,16);
|
||
uint32_t tag6=strtol("004391",NULL,16);
|
||
uint32_t tag7=strtol("004DB8",NULL,16);
|
||
uint32_t tag8=strtol("005966",NULL,16);
|
||
uint32_t tag9=strtol("014BEE",NULL,16);
|
||
uint32_t tag10=strtol("014BF0",NULL,16);
|
||
#else
|
||
// 【关键修改】使用从队列获取的命令参数
|
||
uint32_t tag1=cmd.tagCode;
|
||
LOG_I("Using command from queue - device: %s, seq: %llu, tag1=%08X, RGB: %d,%d,%d\n",
|
||
cmd.deviceName, cmd.sequence, tag1, cmd.light_r, cmd.light_g, cmd.light_b);
|
||
|
||
#endif
|
||
|
||
// 【修复】在多设备场景下,只发送给目标设备,其他设备设为0
|
||
uint32_t tag2=0, tag3=0, tag4=0, tag5=0, tag6=0, tag7=0, tag8=0, tag9=0, tag10=0;
|
||
uint32_t tag11=0, tag12=0, tag13=0, tag14=0, tag15=0;
|
||
uint32_t tag16=0, tag17=0, tag18=0, tag19=0, tag20=0;
|
||
uint32_t tag21=0, tag22=0, tag23=0, tag24=0, tag25=0;
|
||
uint32_t tag26=0, tag27=0, tag28=0, tag29=0, tag30=0;
|
||
|
||
#endif
|
||
#if 0
|
||
if(isStopBroadcast){
|
||
uart_data_send_lighton_by_group(&uartSend,groups_stop,2);
|
||
isStopBroadcast=false;
|
||
}
|
||
#endif
|
||
if(isLightOn){
|
||
jt_tag_package_t tags[30]={{(tag1>>16)&0xFF,(tag1>>8)&0xFF,(tag1)&0xFF,led_ctrl},
|
||
{(tag2>>16)&0xFF,(tag2>>8)&0xFF,(tag2)&0xFF,led_ctrl},
|
||
{(tag3>>16)&0xFF,(tag3>>8)&0xFF,(tag3)&0xFF,led_ctrl},
|
||
{(tag4>>16)&0xFF,(tag4>>8)&0xFF,(tag4)&0xFF,led_ctrl},
|
||
{(tag5>>16)&0xFF,(tag5>>8)&0xFF,(tag5)&0xFF,led_ctrl},
|
||
{(tag6>>16)&0xFF,(tag6>>8)&0xFF,(tag6)&0xFF,led_ctrl},
|
||
{(tag7>>16)&0xFF,(tag7>>8)&0xFF,(tag7)&0xFF,led_ctrl},
|
||
{(tag8>>16)&0xFF,(tag8>>8)&0xFF,(tag8)&0xFF,led_ctrl},
|
||
{(tag9>>16)&0xFF,(tag9>>8)&0xFF,(tag9)&0xFF,led_ctrl},
|
||
{(tag10>>16)&0xFF,(tag10>>8)&0xFF,(tag10)&0xFF,led_ctrl},
|
||
{(tag11>>16)&0xFF,(tag11>>8)&0xFF,(tag11)&0xFF,led_ctrl},
|
||
{(tag12>>16)&0xFF,(tag12>>8)&0xFF,(tag12)&0xFF,led_ctrl},
|
||
{(tag13>>16)&0xFF,(tag13>>8)&0xFF,(tag13)&0xFF,led_ctrl},
|
||
{(tag14>>16)&0xFF,(tag14>>8)&0xFF,(tag14)&0xFF,led_ctrl},
|
||
{(tag15>>16)&0xFF,(tag15>>8)&0xFF,(tag15)&0xFF,led_ctrl},
|
||
{(tag16>>16)&0xFF,(tag16>>8)&0xFF,(tag16)&0xFF,led_ctrl},
|
||
{(tag17>>16)&0xFF,(tag17>>8)&0xFF,(tag17)&0xFF,led_ctrl},
|
||
{(tag18>>16)&0xFF,(tag18>>8)&0xFF,(tag18)&0xFF,led_ctrl},
|
||
{(tag19>>16)&0xFF,(tag19>>8)&0xFF,(tag19)&0xFF,led_ctrl},
|
||
{(tag20>>16)&0xFF,(tag20>>8)&0xFF,(tag20)&0xFF,led_ctrl},
|
||
{(tag21>>16)&0xFF,(tag21>>8)&0xFF,(tag21)&0xFF,led_ctrl},
|
||
{(tag22>>16)&0xFF,(tag22>>8)&0xFF,(tag22)&0xFF,led_ctrl},
|
||
{(tag23>>16)&0xFF,(tag23>>8)&0xFF,(tag23)&0xFF,led_ctrl},
|
||
{(tag24>>16)&0xFF,(tag24>>8)&0xFF,(tag24)&0xFF,led_ctrl},
|
||
{(tag25>>16)&0xFF,(tag25>>8)&0xFF,(tag25)&0xFF,led_ctrl},
|
||
{(tag26>>16)&0xFF,(tag26>>8)&0xFF,(tag26)&0xFF,led_ctrl},
|
||
{(tag27>>16)&0xFF,(tag27>>8)&0xFF,(tag27)&0xFF,led_ctrl},
|
||
{(tag28>>16)&0xFF,(tag28>>8)&0xFF,(tag28)&0xFF,led_ctrl},
|
||
{(tag29>>16)&0xFF,(tag29>>8)&0xFF,(tag29)&0xFF,led_ctrl},
|
||
{(tag30>>16)&0xFF,(tag30>>8)&0xFF,(tag30)&0xFF,led_ctrl}};
|
||
uart_data_send_lighton_or_group(&uartSend,tags,lightbars_size);
|
||
isLightOn=false;
|
||
#if 0
|
||
isStopBroadcastBegin=false;
|
||
while(1){
|
||
usleep(150*1000);
|
||
if(isStopBroadcastBegin){
|
||
break;
|
||
}
|
||
}
|
||
uart_data_send_head(&uartSend,'R',5,30/5,1);//stop broadcast by groupno
|
||
isStopBroadcast=true;
|
||
#endif
|
||
}
|
||
|
||
if(isBindTag){
|
||
jt_tag_package_t tags[30]={{(tag1>>16)&0xFF,(tag1>>8)&0xFF,(tag1)&0xFF,group},
|
||
{(tag2>>16)&0xFF,(tag2>>8)&0xFF,(tag2)&0xFF,group},
|
||
{(tag3>>16)&0xFF,(tag3>>8)&0xFF,(tag3)&0xFF,group},
|
||
{(tag4>>16)&0xFF,(tag4>>8)&0xFF,(tag4)&0xFF,group},
|
||
{(tag5>>16)&0xFF,(tag5>>8)&0xFF,(tag5)&0xFF,group},
|
||
{(tag6>>16)&0xFF,(tag6>>8)&0xFF,(tag6)&0xFF,group},
|
||
{(tag7>>16)&0xFF,(tag7>>8)&0xFF,(tag7)&0xFF,group},
|
||
{(tag8>>16)&0xFF,(tag8>>8)&0xFF,(tag8)&0xFF,group},
|
||
{(tag9>>16)&0xFF,(tag9>>8)&0xFF,(tag9)&0xFF,group},
|
||
{(tag10>>16)&0xFF,(tag10>>8)&0xFF,(tag10)&0xFF,group},
|
||
{(tag11>>16)&0xFF,(tag11>>8)&0xFF,(tag11)&0xFF,group},
|
||
{(tag12>>16)&0xFF,(tag12>>8)&0xFF,(tag12)&0xFF,group},
|
||
{(tag13>>16)&0xFF,(tag13>>8)&0xFF,(tag13)&0xFF,group},
|
||
{(tag14>>16)&0xFF,(tag14>>8)&0xFF,(tag14)&0xFF,group},
|
||
{(tag15>>16)&0xFF,(tag15>>8)&0xFF,(tag15)&0xFF,group},
|
||
{(tag16>>16)&0xFF,(tag16>>8)&0xFF,(tag16)&0xFF,group},
|
||
{(tag17>>16)&0xFF,(tag17>>8)&0xFF,(tag17)&0xFF,group},
|
||
{(tag18>>16)&0xFF,(tag18>>8)&0xFF,(tag18)&0xFF,group},
|
||
{(tag19>>16)&0xFF,(tag19>>8)&0xFF,(tag19)&0xFF,group},
|
||
{(tag20>>16)&0xFF,(tag20>>8)&0xFF,(tag20)&0xFF,group},
|
||
{(tag21>>16)&0xFF,(tag21>>8)&0xFF,(tag21)&0xFF,group},
|
||
{(tag22>>16)&0xFF,(tag22>>8)&0xFF,(tag22)&0xFF,group},
|
||
{(tag23>>16)&0xFF,(tag23>>8)&0xFF,(tag23)&0xFF,group},
|
||
{(tag24>>16)&0xFF,(tag24>>8)&0xFF,(tag24)&0xFF,group},
|
||
{(tag25>>16)&0xFF,(tag25>>8)&0xFF,(tag25)&0xFF,group},
|
||
{(tag26>>16)&0xFF,(tag26>>8)&0xFF,(tag26)&0xFF,group},
|
||
{(tag27>>16)&0xFF,(tag27>>8)&0xFF,(tag27)&0xFF,group},
|
||
{(tag28>>16)&0xFF,(tag28>>8)&0xFF,(tag28)&0xFF,group},
|
||
{(tag29>>16)&0xFF,(tag29>>8)&0xFF,(tag29)&0xFF,group},
|
||
{(tag30>>16)&0xFF,(tag30>>8)&0xFF,(tag30)&0xFF,group}};
|
||
uart_data_send_lighton_or_group(&uartSend,tags,lightbars_size);
|
||
isBindTag=false;
|
||
}
|
||
|
||
if(isLightOnById){
|
||
// 【关键修改】使用从队列获取的命令参数
|
||
uart_data_send_lighton_by_id(&uartSend,0x00,0xFF,cmd.tagCode,cmd.tagCode,led_ctrl,0x0000);
|
||
LOG_I("LightOnById: sent command for device %s, tagCode=%08X\n", cmd.deviceName, cmd.tagCode);
|
||
isLightOnById=false;
|
||
}
|
||
|
||
if(isLightOnByGroup){
|
||
uart_data_send_lighton_by_group(&uartSend,groups,1);
|
||
isLightOnByGroup=false;
|
||
}
|
||
|
||
if(isAllLightOn){
|
||
// 全场亮灯 - 使用ID范围0x00000000到0xFFFFFFFF点亮所有灯条
|
||
jt_led_or_group_package_t all_led_ctrl={
|
||
.s.color=allLightColor,
|
||
.s.sound=allLightSound,
|
||
.s.single=0,
|
||
.s.flash=allLightFlash,
|
||
};
|
||
uart_data_send_lighton_by_id(&uartSend, 0x00, 0xFF, 0x00000000, 0xFFFFFFFF, all_led_ctrl, 0x0000);
|
||
isAllLightOn=false;
|
||
LOG_I("all_light: id range command sent, color=%d, flash=%d, sound=%d\n",
|
||
allLightColor, allLightFlash, allLightSound);
|
||
}
|
||
}else if(parm_ack==0x4646){
|
||
isSendComEnd=true;
|
||
}else if(parm_ack==0x5252){
|
||
uart_data_receive_version(&uartSend);
|
||
isSendComEnd=true;
|
||
}
|
||
}else{
|
||
isSendComEnd=true;
|
||
}
|
||
usleep(100*1000);
|
||
}
|
||
}
|
||
|
||
void *thread_uart_recv_data(void *arg){
|
||
uint16_t parmAck;
|
||
uint16_t tagCodeHead;
|
||
uint32_t tagCode;
|
||
uint8_t tagSignal;
|
||
uint8_t totalLen;
|
||
uint8_t tagFeature;
|
||
uint8_t count;
|
||
uint8_t batteryV;
|
||
uint16_t version;
|
||
uint8_t ledCtrl;
|
||
uint16_t signCode;
|
||
uint16_t reserve;
|
||
uint32_t lableParm;
|
||
while(1){
|
||
uart_data_receive_data_back(&uartRecvData,&parmAck,&tagCodeHead,&tagCode,&tagSignal,&totalLen,&tagFeature,
|
||
&count,&batteryV,&version,&ledCtrl,&signCode,&reserve,&lableParm);
|
||
LOG_I("recv_data:%04x,%04x,tag:%08x,%02x,%02x,%02x,%02x,battery:%02x,%04x,%02x,%04x,reserve:%04x,%08x\n",
|
||
parmAck,tagCodeHead,tagCode,tagSignal,totalLen,tagFeature,count,batteryV,version,ledCtrl,signCode,reserve,lableParm);
|
||
|
||
// 检查是否有待确认的亮灯任务,如果tag匹配则上报亮灯成功
|
||
report_light_success(tagCodeHead, tagCode);
|
||
|
||
isStopBroadcastBegin=true;
|
||
//sleep(2);
|
||
}
|
||
}
|
||
|
||
void *thread_uart_recv_back(void *arg){
|
||
uint16_t parmAck;
|
||
uint16_t tagCodeHead;
|
||
uint32_t tagCode;
|
||
uint8_t tagSignal;
|
||
uint8_t totalLen;
|
||
uint8_t tagFeature;
|
||
uint8_t count;
|
||
uint8_t batteryV;
|
||
uint16_t version;
|
||
uint8_t ledCtrl;
|
||
uint16_t signCode;
|
||
uint16_t reserve;
|
||
uint32_t lableParm;
|
||
while(1){
|
||
uart_data_receive_data_back(&uartRecvBack,&parmAck,&tagCodeHead,&tagCode,&tagSignal,&totalLen,&tagFeature,
|
||
&count,&batteryV,&version,&ledCtrl,&signCode,&reserve,&lableParm);
|
||
|
||
// 打印除心跳外的所有接收数据
|
||
if(tagFeature != 0xFF) {
|
||
LOG_I("recv_back:%04x,%04x,tag:%08x,%02x,%02x,%02x,%02x,battery:%02x,%04x,%02x,%04x,reserve:%04x,%08x\n",
|
||
parmAck,tagCodeHead,tagCode,tagSignal,totalLen,tagFeature,count,batteryV,version,ledCtrl,signCode,reserve,lableParm);
|
||
}
|
||
|
||
PutDataIntoQueue(tagCode,batteryV,reserve);
|
||
if(tagFeature==0xFF){
|
||
//LOG_I("heart beat from lightbar %06X\n", tagCode);
|
||
update_lightbar_heartbeat(tagCodeHead, tagCode);
|
||
}else if(tagFeature==0xFD){
|
||
LOG_I("key pressed from tag %08X\n", tagCode);
|
||
|
||
// 按键防抖:2秒内只处理一次
|
||
time_t now = time(NULL);
|
||
pthread_mutex_lock(&keyDebounceMutex);
|
||
bool shouldProcess = true;
|
||
int debounceIndex = -1;
|
||
|
||
// 查找是否已有该tag的记录
|
||
for (int i = 0; i < keyDebounceCount; i++) {
|
||
if (keyDebounceList[i].tagCode == tagCode && keyDebounceList[i].tagCodeHead == tagCodeHead) {
|
||
debounceIndex = i;
|
||
if (now - keyDebounceList[i].lastKeyTime < 2) {
|
||
shouldProcess = false;
|
||
LOG_I("Key debounce: ignoring key press from tag %08X (within 2s)\n", tagCode);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 更新或添加记录
|
||
if (shouldProcess) {
|
||
if (debounceIndex >= 0) {
|
||
keyDebounceList[debounceIndex].lastKeyTime = now;
|
||
} else if (keyDebounceCount < MAX_KEY_DEBOUNCE) {
|
||
keyDebounceList[keyDebounceCount].tagCodeHead = tagCodeHead;
|
||
keyDebounceList[keyDebounceCount].tagCode = tagCode;
|
||
keyDebounceList[keyDebounceCount].lastKeyTime = now;
|
||
keyDebounceCount++;
|
||
}
|
||
}
|
||
pthread_mutex_unlock(&keyDebounceMutex);
|
||
|
||
if (!shouldProcess) {
|
||
continue; // 跳过此次按键处理
|
||
}
|
||
|
||
// 按键按下时立即上报灭灯
|
||
pthread_mutex_lock(&lightTaskMutex);
|
||
bool found = false;
|
||
for (int i = 0; i < pendingLightTaskCount; i++) {
|
||
if (pendingLightTasks[i].tagCode == tagCode &&
|
||
pendingLightTasks[i].reported &&
|
||
!pendingLightTasks[i].lightOffReported) {
|
||
LOG_I("Key pressed - triggering immediate light-off for tag %08X (with task)\n", tagCode);
|
||
report_light_off(tagCodeHead, tagCode);
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 即使没有任务也要上报灭灯
|
||
if (!found) {
|
||
LOG_I("Key pressed - sending light-off for tag %08X (no task)\n", tagCode);
|
||
char topic[256] = {0};
|
||
char payload[1024] = {0};
|
||
char tagStr[16] = {0};
|
||
char uuid_str[37] = {0};
|
||
uuid_t uuid;
|
||
|
||
uuid_generate(uuid);
|
||
uuid_unparse(uuid, uuid_str);
|
||
|
||
// 使用完整的tagID
|
||
snprintf(tagStr, sizeof(tagStr), "%04X%08X", tagCodeHead, tagCode);
|
||
snprintf(topic, sizeof(topic), "/sys/WcSubLightStrip/%s/thing/property/post", tagStr);
|
||
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
long long timestamp = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||
|
||
snprintf(payload, sizeof(payload),
|
||
"{\"id\":\"%s\",\"version\":\"1.0\",\"arg\":{\"beep\":{\"value\":0,\"time\":%lld},\"flash\":{\"value\":0,\"time\":%lld},\"light\":{\"value\":{\"R\":0,\"G\":0,\"B\":0},\"time\":%lld}},\"method\":\"thing.property.post\",\"time\":%lld}",
|
||
uuid_str,
|
||
timestamp,
|
||
timestamp,
|
||
timestamp,
|
||
timestamp);
|
||
|
||
LOG_I("Key light-off - topic: %s\n", topic);
|
||
LOG_I("Key light-off - payload: %s\n", payload);
|
||
|
||
mqtt_utils_publish(&mqtt_config, topic, 0, payload, strlen(payload));
|
||
}
|
||
pthread_mutex_unlock(&lightTaskMutex);
|
||
}else if(tagFeature==0xFC){
|
||
LOG_I("broadcast parm\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
void functions_reply(char *task_id,char *msg_id){
|
||
json_object *functions = NULL;
|
||
functions=json_object_new_array();
|
||
json_object *function = json_object_new_object();
|
||
json_object *out = json_object_new_object();
|
||
json_object_object_add(function, "key", json_object_new_string("relay-lightbar.control"));
|
||
json_object_object_add(out, "dev-name", json_object_new_string(""));
|
||
json_object_object_add(out, "task-id", json_object_new_string(task_id));
|
||
json_object_object_add(out, "code", json_object_new_int(200));
|
||
json_object_object_add(out, "desc", json_object_new_string("success"));
|
||
json_object_object_add(out, "ext1", json_object_new_string(""));
|
||
json_object_object_add(out, "ext2", json_object_new_string(""));
|
||
json_object_object_add(function, "parameters", out);
|
||
json_object_array_add(functions,function);
|
||
mqtt_server_reply(stationsn,msg_id,functions);
|
||
}
|
||
|
||
void station_status_report(){
|
||
char myid[32]={0};
|
||
char time_buffer[16] = "";
|
||
char app_time_buffer[16] = "";
|
||
struct timeval tv;
|
||
myrand(myid,19);
|
||
gettimeofday(&tv, NULL);
|
||
snprintf(time_buffer,sizeof(time_buffer),"%ld",tv.tv_sec*1000+tv.tv_usec);
|
||
snprintf(app_time_buffer,sizeof(app_time_buffer),"%ld",tv.tv_sec*1000+tv.tv_usec);
|
||
|
||
json_object *root = json_object_new_object();
|
||
json_object *arg = json_object_new_object();
|
||
json_object *app = json_object_new_object();
|
||
json_object *value = json_object_new_object();
|
||
|
||
// 构建value对象
|
||
json_object_object_add(value, "version", json_object_new_string(softwareVersion));
|
||
|
||
// 构建APP对象
|
||
json_object_object_add(app, "value", value);
|
||
json_object_object_add(app, "time", json_object_new_string(app_time_buffer));
|
||
|
||
// 构建arg对象
|
||
json_object_object_add(arg, "APP", app);
|
||
|
||
// 构建根对象
|
||
json_object_object_add(root, "id", json_object_new_string(myid));
|
||
json_object_object_add(root, "version", json_object_new_string("1.0"));
|
||
json_object_object_add(root, "method", json_object_new_string("thing.firmware.ota.inform"));
|
||
json_object_object_add(root, "arg", arg);
|
||
json_object_object_add(root, "time", json_object_new_string(time_buffer));
|
||
|
||
mqtt_server_events_report(stationsn,myid,root,productid);
|
||
}
|
||
|
||
void light_status_report(){
|
||
LOG_I("%s:tagCount:%d\n",__func__,tagCount);
|
||
|
||
if(tagCount <= 0) {
|
||
return;
|
||
}
|
||
|
||
// 创建TaskResult根对象
|
||
json_object *task_result = json_object_new_object();
|
||
json_object *results_array = json_object_new_array();
|
||
|
||
char myid[32]={0};
|
||
char time_buffer[16] = "";
|
||
struct timeval tv;
|
||
|
||
myrand(myid,19);
|
||
gettimeofday(&tv, NULL);
|
||
snprintf(time_buffer,sizeof(time_buffer),"%ld",tv.tv_sec*1000+tv.tv_usec/1000);
|
||
|
||
// 添加TaskResult字段
|
||
json_object_object_add(task_result, "ID", json_object_new_string(stationsn)); // 使用基站ID
|
||
json_object_object_add(task_result, "TotalCount", json_object_new_int(tagCount));
|
||
json_object_object_add(task_result, "SendCount", json_object_new_int(tagCount));
|
||
|
||
// 构建Results数组,每个元素是TaskItemResult
|
||
for(int i=0;i<tagCount;i++){
|
||
char tagName[9]={0};
|
||
char group[3]={0};
|
||
int readType = 0; // 数据回收类型,默认0
|
||
|
||
sprintf(tagName,"%06X",onlyTags[i].name);
|
||
sprintf(group,"%02X",(onlyTags[i].reserve>>8)&0xFF);
|
||
|
||
// 根据分组判断readType
|
||
if(strcmp(group,"00")==0 || strcmp(group,"FF")==0){
|
||
readType = 1; // 0xFD 接触返回
|
||
}else{
|
||
readType = 2; // 0xFE 通信返回
|
||
}
|
||
|
||
// 创建TaskItemResult对象
|
||
json_object *task_item = json_object_new_object();
|
||
json_object_object_add(task_item, "TagID", json_object_new_string(tagName));
|
||
json_object_object_add(task_item, "Version", json_object_new_string("1.0"));
|
||
json_object_object_add(task_item, "ReadType", json_object_new_int(readType));
|
||
json_object_object_add(task_item, "RfPowerSend", json_object_new_int(-25)); // AP方发送RF功率,dBm
|
||
json_object_object_add(task_item, "RfPowerRecv", json_object_new_int(-30)); // 灯条RF功率,dBm
|
||
|
||
// 电池电量处理
|
||
int battery_percent = 0;
|
||
if(onlyTags[i].battery>=30){
|
||
battery_percent = 100;
|
||
}else if(onlyTags[i].battery>=29){
|
||
battery_percent = 90;
|
||
}else if(onlyTags[i].battery>=28){
|
||
battery_percent = 70;
|
||
}else if(onlyTags[i].battery>=27){
|
||
battery_percent = 60;
|
||
}else if(onlyTags[i].battery>=26){
|
||
battery_percent = 50;
|
||
}else if(onlyTags[i].battery>=25){
|
||
battery_percent = 40;
|
||
}else if(onlyTags[i].battery>=24){
|
||
battery_percent = 30;
|
||
}else{
|
||
battery_percent = 0;
|
||
}
|
||
json_object_object_add(task_item, "Battery", json_object_new_int(battery_percent));
|
||
|
||
// Colors RGB数组
|
||
json_object *colors = json_object_new_object();
|
||
json_object_object_add(colors, "R", json_object_new_boolean(false)); // 红色状态
|
||
json_object_object_add(colors, "G", json_object_new_boolean(false)); // 绿色状态
|
||
json_object_object_add(colors, "B", json_object_new_boolean(false)); // 蓝色状态
|
||
json_object_object_add(task_item, "Colors", colors);
|
||
|
||
// Group分组号
|
||
int group_num = (int)strtol(group, NULL, 16);
|
||
json_object_object_add(task_item, "Group", json_object_new_int(group_num));
|
||
|
||
json_object_array_add(results_array, task_item);
|
||
}
|
||
|
||
json_object_object_add(task_result, "Results", results_array);
|
||
|
||
// 发送到MQTT主题 /estation/{ID}/result
|
||
char topic[128] = {0};
|
||
snprintf(topic, sizeof(topic), "/estation/%s/result", stationsn);
|
||
|
||
const char *json_string = json_object_to_json_string(task_result);
|
||
LOG_I("Light status report JSON: %s\n", json_string);
|
||
|
||
// TODO: 发送到MQTT服务器
|
||
// mqtt_publish(topic, json_string);
|
||
|
||
json_object_put(task_result);
|
||
|
||
// 清空标签数据
|
||
tagCount=0;
|
||
memset(onlyTags,0,sizeof(onlyTags));
|
||
}
|
||
|
||
|
||
void *thread_station_heartbeat(void *arg){
|
||
while(1){
|
||
sleep(20); // 20秒间隔
|
||
|
||
char local_mac[32] = {0};
|
||
char local_ip[32] = {0};
|
||
getLocalMac(local_mac);
|
||
getLocalIp(local_ip);
|
||
|
||
json_object *root = json_object_new_object();
|
||
json_object *estation_info = json_object_new_object();
|
||
|
||
// 添加基站心跳信息
|
||
json_object_object_add(estation_info, "ID", json_object_new_string(stationsn));
|
||
json_object_object_add(estation_info, "MAC", json_object_new_string(local_mac));
|
||
json_object_object_add(estation_info, "Alias", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "ClientType", json_object_new_int(2));
|
||
json_object_object_add(estation_info, "ServerAddress", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "Parameters", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "LocalIP", json_object_new_string(local_ip));
|
||
json_object_object_add(estation_info, "SubnetMask", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "Gateway", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "Heartbeat", json_object_new_int(20));
|
||
json_object_object_add(estation_info, "DummyVersion", json_object_new_string(""));
|
||
json_object_object_add(estation_info, "AppVersion", json_object_new_string(softwareVersion));
|
||
json_object_object_add(estation_info, "TotalCount", json_object_new_int(0));
|
||
json_object_object_add(estation_info, "SendCount", json_object_new_int(0));
|
||
|
||
json_object_object_add(root, "eStationInfor", estation_info);
|
||
|
||
const char *json_string = json_object_to_json_string(root);
|
||
//LOG_I("station_heartbeat:%s\n", json_string);
|
||
|
||
// 发送心跳到 /estation/{ID}/heartbeat topic
|
||
char topic[128] = {0};
|
||
snprintf(topic, sizeof(topic), "/estation/%s/heartbeat", stationsn);
|
||
// 这里需要使用MQTT发送函数,暂时用LOG输出
|
||
//LOG_I("Sending heartbeat to topic: %s\n", topic);
|
||
|
||
json_object_put(root);
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void addOnlyTag(uint32_t tagname,uint16_t battery,uint16_t reserve){
|
||
int i=0;
|
||
if(tagCount==0){
|
||
jt_only_tag_t jt_only_tag = {
|
||
.name=tagname,
|
||
.battery=battery,
|
||
.reserve=reserve,
|
||
};
|
||
onlyTags[tagCount]=jt_only_tag;
|
||
tagCount++;
|
||
}else{
|
||
for(i=0;i<tagCount;i++){
|
||
if(tagname==onlyTags[i].name){
|
||
break;
|
||
}
|
||
}
|
||
if(i==tagCount){
|
||
jt_only_tag_t jt_only_tag = {
|
||
.name=tagname,
|
||
.battery=battery,
|
||
.reserve=reserve,
|
||
};
|
||
onlyTags[tagCount]=jt_only_tag;
|
||
tagCount++;
|
||
}
|
||
}
|
||
if(tagCount==100){
|
||
//light_status_report();
|
||
}
|
||
}
|
||
|
||
void *thread_remove_duplicate_tag(void *arg){
|
||
uint32_t tagname=0;
|
||
uint16_t battery=0;
|
||
uint16_t reserve=0;
|
||
while(1){
|
||
if(GetDataFromQueue(&tagname,&battery,&reserve)==0){
|
||
//LOG_I("%08x,%04x\n",tagname,battery);
|
||
addOnlyTag(tagname,battery,reserve);
|
||
}
|
||
}
|
||
}
|
||
|
||
void *thread_mqtt_recv(void *arg){
|
||
char payload[1024]={0};
|
||
char deviceName[16]={0}; // 【新增】从队列获取的设备名称
|
||
char msg_items[1024] ={0};
|
||
char msg_item_value[1024] ={0};
|
||
char msg_colors[512] ={0};
|
||
char msg_color_value[512] ={0};
|
||
char msg_lightbars[4] ={0};
|
||
int items_size = 0;
|
||
int colors_size = 0;
|
||
int task_id = 0;
|
||
while(1){
|
||
if(isSendComEnd){
|
||
// 【修复】优先使用带设备名称的版本
|
||
if(GetDataFromMQueueWithDevice(payload, deviceName)==0){
|
||
// 如果获取到了设备名称,使用它;否则使用全局变量
|
||
if (strlen(deviceName) > 0) {
|
||
strncpy(g_mqtt_deviceName, deviceName, sizeof(g_mqtt_deviceName) - 1);
|
||
LOG_I("Using device from queue: %s\n", g_mqtt_deviceName);
|
||
}
|
||
} else if(GetDataFromMQueue(payload)==0) {
|
||
// 回退到原来的版本(兼容性)
|
||
LOG_I("Using legacy queue without device name\n");
|
||
} else {
|
||
Sleep(100);
|
||
continue;
|
||
}
|
||
// 调试用固定payload
|
||
//strcpy(payload, "{ \"Items\": [ { \"Beep\": true, \"Colors\": [ { \"B\": false, \"G\": false, \"R\": true } ], \"Flashing\": true, \"TagID\": \"AD1000014C17\" } ], \"Time\": 120 }");
|
||
|
||
// 清理payload,截断最后一个'}'之后的内容
|
||
char clean_payload[4096] = {0};
|
||
strcpy(clean_payload, payload);
|
||
char *last_brace = strrchr(clean_payload, '}');
|
||
if (last_brace != NULL) {
|
||
*(last_brace + 1) = '\0'; // 在最后一个'}'之后截断
|
||
}
|
||
strcpy(payload, clean_payload); // 将清理后的内容复制回原payload
|
||
|
||
LOG_I("payload:%s\n",payload);
|
||
|
||
// 重置变量
|
||
items_size = 0;
|
||
colors_size = 0;
|
||
|
||
// 清空设备名称,避免串用上一次的值
|
||
//memset(g_mqtt_deviceName, 0, sizeof(g_mqtt_deviceName));
|
||
|
||
// 解析新格式payload
|
||
LOG_I("Parsing new payload format with params\n");
|
||
|
||
// 先打印完整的payload以便调试
|
||
LOG_I("Complete payload: %s\n", payload);
|
||
|
||
// 解析params中的各个字段
|
||
char params_str[1024] = {0};
|
||
char params_json[1024] = {0}; // 【修复】移到外面,扩大作用域
|
||
char color_json[512] = {0}; // 提前声明color_json
|
||
int params_ret = get_string_from_json_string_by_key(payload, "params", params_str, sizeof(params_str));
|
||
LOG_I("get_string_from_json_string_by_key return: %d\n", params_ret);
|
||
LOG_I("params_str: %s\n", params_str);
|
||
|
||
// 如果params_str为空,尝试直接从payload解析
|
||
if(strlen(params_str) == 0) {
|
||
LOG_I("params_str is empty, trying direct parse from payload\n");
|
||
// 直接从payload解析各个字段
|
||
|
||
// 【新增】解析LightSwitch字段
|
||
int light_switch = 1; // 默认为开灯
|
||
if(get_int_from_json_string_by_key(payload, "LightSwitch", &light_switch) == 0) {
|
||
LOG_I("Direct parse LightSwitch = %d\n", light_switch);
|
||
}
|
||
|
||
int beep_enable = 0;
|
||
get_int_from_json_string_by_key(payload, "beep", &beep_enable);
|
||
LOG_I("Direct parse Beep = %d\n", beep_enable);
|
||
changesound = beep_enable ? 1 : 0;
|
||
|
||
int flashing_enable = 0;
|
||
get_int_from_json_string_by_key(payload, "flashing", &flashing_enable);
|
||
changeflash = flashing_enable ? 3 : 1;
|
||
LOG_I("Direct parse Flashing = %d, changeflash = %d\n", flashing_enable, changeflash);
|
||
|
||
int duration = 0;
|
||
get_int_from_json_string_by_key(payload, "duration", &duration);
|
||
mqtt_parm.msg_duration = duration;
|
||
LOG_I("Direct parse Duration = %d\n", mqtt_parm.msg_duration);
|
||
if(mqtt_parm.msg_duration <= 5) {
|
||
mqtt_parm.msg_duration = 5;
|
||
LOG_I("new msg_duration = %d\n", mqtt_parm.msg_duration);
|
||
} else {
|
||
// 向上取整到5的倍数,避免硬件提前灭灯
|
||
mqtt_parm.msg_duration = ((mqtt_parm.msg_duration + 4) / 5) * 5;
|
||
LOG_I("Rounded up msg_duration = %d\n", mqtt_parm.msg_duration);
|
||
}
|
||
|
||
// 解析颜色
|
||
char color_str[512] = {0};
|
||
get_string_from_json_string_by_key(payload, "color", color_str, sizeof(color_str));
|
||
LOG_I("Direct parse color_str: %s\n", color_str);
|
||
|
||
// 包装color_str为有效的JSON对象
|
||
snprintf(color_json, sizeof(color_json), "{%s}", color_str);
|
||
LOG_I("color_json: %s\n", color_json);
|
||
} else {
|
||
// 包装params_str为有效的JSON对象
|
||
snprintf(params_json, sizeof(params_json), "{%s}", params_str);
|
||
LOG_I("params_json: %s\n", params_json);
|
||
|
||
// 【新增】解析LightSwitch字段
|
||
int light_switch = 1; // 默认为开灯
|
||
if(get_int_from_json_string_by_key(params_json, "LightSwitch", &light_switch) == 0) {
|
||
LOG_I("Parse LightSwitch = %d\n", light_switch);
|
||
}
|
||
|
||
int beep_enable = 0;
|
||
get_int_from_json_string_by_key(params_json, "beep", &beep_enable);
|
||
LOG_I("Beep = %d\n", beep_enable);
|
||
changesound = beep_enable ? 1 : 0;
|
||
|
||
int flash_enable = 0;
|
||
get_int_from_json_string_by_key(params_json, "flash", &flash_enable);
|
||
changeflash = flash_enable ? 3 : 1; // 1=闪烁, 3=常亮(注意:flash=1表示闪烁)
|
||
LOG_I("Flash = %d, changeflash = %d\n", flash_enable, changeflash);
|
||
|
||
int duration = 0;
|
||
get_int_from_json_string_by_key(params_json, "duration", &duration);
|
||
mqtt_parm.msg_duration = duration;
|
||
LOG_I("Duration = %d\n", mqtt_parm.msg_duration);
|
||
if(mqtt_parm.msg_duration <= 5) {
|
||
mqtt_parm.msg_duration = 5;
|
||
LOG_I("new msg_duration = %d\n", mqtt_parm.msg_duration);
|
||
} else {
|
||
// 向上取整到5的倍数,避免硬件提前灭灯
|
||
mqtt_parm.msg_duration = ((mqtt_parm.msg_duration + 4) / 5) * 5;
|
||
LOG_I("Rounded up msg_duration = %d\n", mqtt_parm.msg_duration);
|
||
}
|
||
|
||
// 解析颜色
|
||
char color_str[512] = {0};
|
||
get_string_from_json_string_by_key(params_json, "color", color_str, sizeof(color_str));
|
||
LOG_I("color_str: %s\n", color_str);
|
||
|
||
// 包装color_str为有效的JSON对象
|
||
snprintf(color_json, sizeof(color_json), "{%s}", color_str);
|
||
LOG_I("color_json: %s\n", color_json);
|
||
}
|
||
|
||
// 解析RED/GREEN/BLUE或R/G/B作为键值
|
||
int r_val = 0, g_val = 0, b_val = 0;
|
||
|
||
// 先尝试完整名称
|
||
get_int_from_json_string_by_key(color_json, "RED", &r_val);
|
||
get_int_from_json_string_by_key(color_json, "GREEN", &g_val);
|
||
get_int_from_json_string_by_key(color_json, "BLUE", &b_val);
|
||
|
||
// 如果完整名称没有值,尝试缩写
|
||
if(r_val == 0 && g_val == 0 && b_val == 0) {
|
||
get_int_from_json_string_by_key(color_json, "R", &r_val);
|
||
get_int_from_json_string_by_key(color_json, "G", &g_val);
|
||
get_int_from_json_string_by_key(color_json, "B", &b_val);
|
||
}
|
||
|
||
LOG_I("RGB values: R=%d, G=%d, B=%d\n", r_val, g_val, b_val);
|
||
|
||
// 根据RGB值设置颜色(0=不亮, 1=亮)
|
||
// 【修复】先保存原始RGB值,用于判断是否是关灯命令
|
||
bool is_off_command = false;
|
||
|
||
// 如果LightSwitch=0,标记为关灯命令
|
||
int light_switch = 1;
|
||
if(strlen(params_str) > 0) {
|
||
get_int_from_json_string_by_key(params_json, "LightSwitch", &light_switch);
|
||
} else {
|
||
get_int_from_json_string_by_key(payload, "LightSwitch", &light_switch);
|
||
}
|
||
|
||
if(light_switch == 0) {
|
||
is_off_command = true;
|
||
LOG_I("LightSwitch=0 detected, this is an OFF command\n");
|
||
}
|
||
|
||
if(r_val == 0 && g_val == 0 && b_val == 0 && !is_off_command) {
|
||
changecolor = 0; // 不亮(非关灯命令时的默认值)
|
||
} else if(r_val == 1 && g_val == 0 && b_val == 0) {
|
||
changecolor = 4; // 红色
|
||
} else if(r_val == 0 && g_val == 1 && b_val == 0) {
|
||
changecolor = 2; // 绿色
|
||
} else if(r_val == 0 && g_val == 0 && b_val == 1) {
|
||
changecolor = 1; // 蓝色
|
||
} else if(r_val == 1 && g_val == 1 && b_val == 0) {
|
||
changecolor = 6; // 黄色
|
||
} else if(r_val == 1 && g_val == 0 && b_val == 1) {
|
||
changecolor = 5; // 紫色
|
||
} else if(r_val == 0 && g_val == 1 && b_val == 1) {
|
||
changecolor = 3; // 青色
|
||
} else if(r_val == 1 && g_val == 1 && b_val == 1) {
|
||
changecolor = 7; // 白色
|
||
} else if(is_off_command) {
|
||
changecolor = 0; // 关灯命令强制设置为不亮
|
||
}
|
||
LOG_I("changecolor=%d (is_off_command=%d)\n", changecolor, is_off_command);
|
||
|
||
// 判断任务类型:根据method字段判断是灯条任务还是OTA任务
|
||
char method[128] = {0};
|
||
int has_method = get_string_from_json_string_by_key(payload, "method", method, sizeof(method));
|
||
|
||
int is_lightbar_task = 0;
|
||
if(has_method == 0 && strstr(method, "lightOperate") != NULL) {
|
||
// 灯条任务
|
||
is_lightbar_task = 1;
|
||
items_size = 1;
|
||
lightbars_size = 1;
|
||
|
||
// 解析id字段
|
||
char taskId[64] = {0};
|
||
get_string_from_json_string_by_key(payload, "id", taskId, sizeof(taskId));
|
||
LOG_I("Task ID: %s\n", taskId);
|
||
|
||
// 从topic解析出的deviceName获取设备ID
|
||
LOG_I("Processing lightbar command, g_mqtt_deviceName: %s\n", g_mqtt_deviceName);
|
||
// 【关键修复】使用从队列获取的设备名称,而不是可能被覆盖的全局变量
|
||
if (strlen(deviceName) > 0) {
|
||
// 【关键修复】立即保存deviceName到局部变量,避免被其他并发MQTT消息覆盖
|
||
char current_deviceName[16] = {0};
|
||
strncpy(current_deviceName, deviceName, sizeof(current_deviceName) - 1);
|
||
|
||
LOG_I("Device ID from queue: %s\n", current_deviceName);
|
||
// 将deviceName设置为灯条ID
|
||
memset(mqtt_parm.msg_sn, 0, sizeof(mqtt_parm.msg_sn));
|
||
strncpy(mqtt_parm.msg_sn, current_deviceName, sizeof(mqtt_parm.msg_sn) - 1);
|
||
LOG_I("Set light bar ID: %s\n", mqtt_parm.msg_sn);
|
||
|
||
// 获取完整的12位设备ID
|
||
int len = strlen(current_deviceName);
|
||
LOG_I("Device name length: %d\n", len);
|
||
if(len == 12) {
|
||
char fullTagId[13] = {0};
|
||
strncpy(fullTagId, current_deviceName, 12);
|
||
|
||
// 解析前4位作为tagCodeHead和后8位作为tagCode
|
||
uint16_t tagCodeHead = 0;
|
||
uint32_t tagCode = 0;
|
||
char head[5] = {0};
|
||
char tail[9] = {0};
|
||
|
||
strncpy(head, fullTagId, 4);
|
||
strncpy(tail, fullTagId + 4, 8);
|
||
sscanf(head, "%hx", &tagCodeHead);
|
||
sscanf(tail, "%x", &tagCode);
|
||
|
||
// 【修复】更新全局变量,保存当前设备的tagCode
|
||
g_current_tagCodeHead = tagCodeHead;
|
||
g_current_tagCode = tagCode;
|
||
|
||
// 【增强】添加设备映射,解决多设备并发问题
|
||
add_device_mapping(current_deviceName, tagCodeHead, tagCode);
|
||
|
||
// 获取后6位设置到lightsn1(保留兼容性)
|
||
char *last6 = fullTagId + 6;
|
||
memset(lightsn1, 0, sizeof(lightsn1));
|
||
strncpy(lightsn1, last6, 6);
|
||
LOG_I("Full tag ID: %s, head: %04X, tail: %08X, lightsn1: %s\n", fullTagId, tagCodeHead, tagCode, lightsn1);
|
||
|
||
// 添加待确认的亮灯任务,传入真实的beep、flash、RGB数据
|
||
// flash值需要转换:changeflash=1表示常亮(上报0),changeflash=3表示闪烁(上报1)
|
||
int flash_value = (changeflash == 3) ? 1 : 0;
|
||
if(strlen(taskId) > 0) {
|
||
add_pending_light_task(tagCodeHead, tagCode, taskId, changesound, flash_value, r_val, g_val, b_val, mqtt_parm.msg_duration);
|
||
}
|
||
|
||
// 【关键修改】将命令添加到队列,而不是设置全局变量
|
||
// 这样可以避免快速连续命令时的竞态条件
|
||
if(add_light_command(current_deviceName, taskId, tagCodeHead, tagCode,
|
||
changecolor, changesound, changeflash, mqtt_parm.msg_duration,
|
||
changesound, flash_value, r_val, g_val, b_val) == 0) {
|
||
LOG_I("Light command added to queue successfully\n");
|
||
} else {
|
||
LOG_I("Failed to add light command to queue - queue full!\n");
|
||
}
|
||
} else {
|
||
LOG_I("Device name length is not 12 characters: %s (len=%d)\n", current_deviceName, len);
|
||
}
|
||
|
||
// 【新增】立即处理队列中的命令,确保不被其他消息干扰
|
||
// 这样可以确保每个MQTT消息都能立即触发UART处理
|
||
LOG_I("Immediately processing command queue for %s\n", current_deviceName);
|
||
|
||
} else {
|
||
LOG_I("g_mqtt_deviceName is empty or null\n");
|
||
}
|
||
} else {
|
||
// OTA任务或其他任务
|
||
items_size = 0;
|
||
lightbars_size = 0;
|
||
}
|
||
|
||
// 根据任务类型进行处理
|
||
// 任务1:发布灯条指令 (topic: /estation/设备ID/task)
|
||
// 任务2:发布基站OTA任务 (topic: /estation/设备ID/ota)
|
||
|
||
// 判断任务类型:如果有Items数组且包含TagID,则为灯条任务
|
||
if(items_size > 0) {
|
||
LOG_I("Processing lightbar task (task_id: lightbar)\n");
|
||
|
||
// 灯条点亮任务
|
||
lightbars_count += lightbars_size;
|
||
|
||
if(lightbars_count >= 30) {
|
||
// 处理超过30个灯条的情况
|
||
} else {
|
||
// 正常处理
|
||
}
|
||
|
||
// 清空串口缓冲区,避免残留数据干扰
|
||
tcflush(uartSend.uart_fd, TCIOFLUSH);
|
||
|
||
isSendComEnd = false;
|
||
isLightOnByGroup = false;
|
||
isLightOnById = false;
|
||
isLightOn = true;
|
||
isBindTag = false;
|
||
|
||
// P点灯 B绑定 &群控(不支持) *根据id点亮
|
||
// timeout单位是5秒,所以 Time(秒) / 5 = timeout
|
||
// 只发送头包,数据包在thread_uart_recv_ack中处理
|
||
uart_data_send_head(&uartSend, 'P', 5, mqtt_parm.msg_duration/5, lightbars_size);
|
||
} else {
|
||
LOG_I("Processing OTA task (task_id: ota)\n");
|
||
|
||
// 解析新的OTA任务JSON格式
|
||
LOG_I("OTA payload debug: %s\n", payload);
|
||
|
||
LOG_I("OTA payload after cleaning: %s\n", payload);
|
||
|
||
// 首先检查是否存在data数组
|
||
int data_array_size = 0;
|
||
int size_check_result = get_size_from_json_string_arry_by_key(payload, "data", &data_array_size);
|
||
LOG_I("Data array size check result: %d, size: %d\n", size_check_result, data_array_size);
|
||
|
||
int has_data_array = (size_check_result == 0 && data_array_size > 0);
|
||
|
||
if (has_data_array) {
|
||
LOG_I("Found data array with %d items\n", data_array_size);
|
||
// 从data数组中获取第一个对象的完整JSON字符串
|
||
char data_item[2048] = {0};
|
||
int extract_result = get_string_from_json_string_arry_by_key_unescape(payload, "data", data_item, sizeof(data_item), 0);
|
||
LOG_I("Extract data array item result: %d\n", extract_result);
|
||
|
||
if (extract_result == 0) {
|
||
LOG_I("Found data array item: %s\n", data_item);
|
||
// 构造完整的JSON对象字符串(添加花括号)
|
||
char complete_json[2048] = {0};
|
||
snprintf(complete_json, sizeof(complete_json), "{%s}", data_item);
|
||
LOG_I("Complete JSON object: %s\n", complete_json);
|
||
|
||
// 解析data项中的各个字段
|
||
get_string_from_json_string_by_key_unescape(complete_json, "url", mqtt_parm.msg_zipPath, sizeof(mqtt_parm.msg_zipPath));
|
||
get_string_from_json_string_by_key_unescape(complete_json, "sign", mqtt_parm.msg_md5, sizeof(mqtt_parm.msg_md5));
|
||
get_string_from_json_string_by_key_unescape(complete_json, "firmware", mqtt_parm.msg_type, sizeof(mqtt_parm.msg_type));
|
||
get_string_from_json_string_by_key_unescape(complete_json, "tv", mqtt_parm.msg_version, sizeof(mqtt_parm.msg_version));
|
||
} else {
|
||
LOG_I("Failed to extract data array item\n");
|
||
}
|
||
} else {
|
||
LOG_I("No data array found, trying legacy format\n");
|
||
// 如果没有data数组,尝试旧格式兼容
|
||
get_string_from_json_string_by_key_unescape(payload, "Firmware", mqtt_parm.msg_zipPath, sizeof(mqtt_parm.msg_zipPath));
|
||
get_string_from_json_string_by_key_unescape(payload, "MD5", mqtt_parm.msg_md5, sizeof(mqtt_parm.msg_md5));
|
||
get_string_from_json_string_by_key_unescape(payload, "Type", mqtt_parm.msg_type, sizeof(mqtt_parm.msg_type));
|
||
get_string_from_json_string_by_key_unescape(payload, "Version", mqtt_parm.msg_version, sizeof(mqtt_parm.msg_version));
|
||
}
|
||
|
||
LOG_I("OTA firmware path: %s\n", mqtt_parm.msg_zipPath);
|
||
LOG_I("OTA firmware MD5: %s\n", mqtt_parm.msg_md5);
|
||
LOG_I("OTA firmware Type: %s\n", mqtt_parm.msg_type);
|
||
LOG_I("OTA firmware Version: %s\n", mqtt_parm.msg_version);
|
||
|
||
// 如果解析到了firmware路径,执行下载命令
|
||
if (strlen(mqtt_parm.msg_zipPath) > 0) {
|
||
char otaCmd[1024];
|
||
sprintf(otaCmd, "curl -o /root/mt_ota.zip %s", mqtt_parm.msg_zipPath);
|
||
LOG_I("Executing OTA download command: %s\n", otaCmd);
|
||
|
||
// 执行下载命令
|
||
int result = system(otaCmd);
|
||
if (result == 0) {
|
||
LOG_I("OTA firmware download successful\n");
|
||
sleep(15);
|
||
|
||
// 下载成功后执行解压和安装操作
|
||
system("unzip /root/mt_ota.zip");
|
||
system("rm -fr /root/ota");
|
||
system("mv /root/mt_ota /root/ota");
|
||
system("cp /root/ota/mt_server /tmp/mt_server_new");
|
||
LOG_I("cp /root/ota/mt_server /tmp/mt_server_new\n");
|
||
system("chmod +x /tmp/mt_server_new");
|
||
system("mv /tmp/mt_server_new /root/mt_server");
|
||
LOG_I("mv /tmp/mt_server_new /root/mt_server\n");
|
||
system("systemctl restart mt_server");
|
||
|
||
// OTA成功后重置状态
|
||
isSendComEnd = false;
|
||
isLightOnByGroup = false;
|
||
isLightOnById = false;
|
||
isLightOn = false;
|
||
isBindTag = false;
|
||
} else {
|
||
LOG_I("OTA firmware download failed with code: %d\n", result);
|
||
// OTA失败时保持isSendComEnd为true,允许后续消息处理
|
||
isSendComEnd = true;
|
||
isLightOnByGroup = false;
|
||
isLightOnById = false;
|
||
isLightOn = false;
|
||
isBindTag = false;
|
||
}
|
||
} else {
|
||
LOG_I("No firmware path found in OTA task\n");
|
||
// OTA解析失败时保持isSendComEnd为true,允许后续消息处理
|
||
isSendComEnd = true;
|
||
isLightOnByGroup = false;
|
||
isLightOnById = false;
|
||
isLightOn = false;
|
||
isBindTag = false;
|
||
}
|
||
}
|
||
|
||
// 发送回复消息(如果需要)
|
||
// functions_reply(mqtt_parm.msg_taskId, mqtt_parm.msg_messageId);
|
||
}
|
||
}
|
||
usleep(getPayloadTime);
|
||
|
||
}
|
||
|
||
/*================================================================================*/
|
||
void hmacsha1(char *key,char* data,char *signbase64,int signbase64_len){
|
||
char result[256]={0};
|
||
size_t len=sizeof(result);
|
||
//LOG_I("key_len:%d,data_len:%d\n",strlen(key),strlen(data));
|
||
hmac_sha1(key,strlen(key),data,strlen(data),result,&len);
|
||
//LOG_I("result_len:%d\n",len);
|
||
int t_i;
|
||
//for(t_i=0;t_i<len;t_i++)
|
||
// printf("%x ",result[t_i]);
|
||
Base64_encode( signbase64, signbase64_len, result,strlen(result));
|
||
//printf("last:%s\n",signbase64);
|
||
}
|
||
|
||
void getLocalIp(char *local_ip){
|
||
FILE *fp;
|
||
char buffer[64]={0};
|
||
fp=popen("ifconfig eth0 | grep 'inet' | awk '{print $2}' | cut -d':' -f2","r");
|
||
fgets(buffer,sizeof(buffer),fp);
|
||
//LOG_I("buffer:%s\n",buffer);
|
||
memcpy(local_ip,buffer,strlen(buffer)-1);
|
||
}
|
||
void getLocalMac(char *local_mac){
|
||
FILE *fp;
|
||
char buffer[64]={0};
|
||
fp=popen("ifconfig eth0 | grep 'ether' | awk '{print $2}' | tr -d ':'","r");
|
||
fgets(buffer,sizeof(buffer),fp);
|
||
//LOG_I("buffer:%s\n",buffer);
|
||
memcpy(local_mac,buffer,strlen(buffer)-1);
|
||
}
|
||
|
||
void saveStartUpTime(){
|
||
system("rm ./startUpTime");
|
||
struct timeval tv;
|
||
char startUpTime[32] = {0};
|
||
gettimeofday(&tv, NULL);
|
||
snprintf(startUpTime,sizeof(startUpTime),"%ld",tv.tv_sec);
|
||
buffer_to_file("startUpTime",startUpTime,strlen(startUpTime),"wb");
|
||
}
|
||
|
||
void calculateStartUpTime(char *startTime){
|
||
char *result=NULL;
|
||
struct timeval tv;
|
||
int len=0;
|
||
result=file_to_buffer("startUpTime",&len);
|
||
if(result!=NULL){
|
||
LOG_I("startUpTime:%s\n",result);
|
||
gettimeofday(&tv, NULL);
|
||
LOG_I("nowUpTime:%ld\n",tv.tv_sec);
|
||
snprintf(startTime,11,"%ld",tv.tv_sec-atoi(result));
|
||
}
|
||
}
|
||
|
||
void updateStationInfo(char *msg_id){
|
||
char local_ip[32] = {0};
|
||
char startTime[11]={0};
|
||
getLocalIp(local_ip);
|
||
LOG_I("local_ip:%s\n",local_ip);
|
||
calculateStartUpTime(startTime);
|
||
LOG_I("Time:%s\n",startTime);
|
||
//mqtt_server_station_status_report(msg_id,productid,stationsn,local_ip,softwareVersion,"1",startTime);
|
||
}
|
||
|
||
bool timeNew(){
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
long gettime=tv.tv_sec*1000+tv.tv_usec;
|
||
LOG_I("gettime:%ld\n",gettime);
|
||
if(gettime<1744000000000){
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
//==========================================================================================
|
||
int main(int argc, char *argv[])
|
||
{
|
||
int ret = -1;
|
||
uint32_t can_id;
|
||
char recv_data[8]={0};
|
||
char command_buffer[256] = "";
|
||
int len=0;
|
||
int getTimeCount=0;
|
||
char *readresult=NULL;
|
||
char networktype[32]={0};
|
||
|
||
LOG_I("version:%s\n",softwareVersion);
|
||
|
||
// 【新增】初始化命令队列
|
||
memset(light_commands, 0, sizeof(light_commands));
|
||
light_command_head = 0;
|
||
light_command_tail = 0;
|
||
command_sequence = 0;
|
||
LOG_I("Light command queue initialized\n");
|
||
|
||
// 【新增】初始化设备映射
|
||
memset(g_device_mappings, 0, sizeof(g_device_mappings));
|
||
LOG_I("Device mapping table initialized\n");
|
||
|
||
system("insmod /system/lib/modules/wk2xxx_spi.ko");
|
||
system("timedatectl set-timezone Asia/Shanghai");
|
||
uart_open(&uartSend,"/dev/ttyS0");//U12 ttyS0,U14 ttyS4,U21 ttysWK0 U13 ttysWK1 U15 ttysWK2 U22 ttysWK3 U20 ttyS1
|
||
uart_init(&uartSend,115200,8,1,'N',0);
|
||
uart_open(&uartRecvData,"/dev/ttyS4");
|
||
uart_init(&uartRecvData,115200,8,1,'N',0);
|
||
|
||
uart_open(&uartRecvBack,"/dev/ttysWK0");
|
||
uart_init(&uartRecvBack,115200,8,1,'N',0);
|
||
//doCommand_help(0, NULL);
|
||
system("echo 113 > /sys/class/gpio/export");//pin 113 yellow
|
||
system("echo out > /sys/class/gpio/gpio113/direction");
|
||
system("echo 63 > /sys/class/gpio/export");//pin 63 key
|
||
system("echo in > /sys/class/gpio/gpio63/direction");
|
||
#if 1
|
||
enableWatchDog();
|
||
ret = pthread_create(&pt_watchdog,NULL,thread_feed_watchdog,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create watchdog fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create watchdog success\n");
|
||
pthread_detach(pt_watchdog);
|
||
}
|
||
#endif
|
||
ret = pthread_create(&pt_uart_recv_ack,NULL,thread_uart_recv_ack,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create uart_recv_ack fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_uart_recv_ack);
|
||
LOG_I("pthread_create uart_recv_ack success\n");
|
||
}
|
||
|
||
ret = pthread_create(&pt_uart_recv_data,NULL,thread_uart_recv_data,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create uart_recv_data fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_uart_recv_data);
|
||
LOG_I("pthread_create uart_recv_data success\n");
|
||
}
|
||
|
||
ret = pthread_create(&pt_uart_recv_back,NULL,thread_uart_recv_back,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create uart_recv_back fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_uart_recv_back);
|
||
LOG_I("pthread_create uart_recv_back success\n");
|
||
}
|
||
|
||
ret = pthread_create(&pt_mqtt_recv,NULL,thread_mqtt_recv,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create mqtt_recv fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_mqtt_recv);
|
||
LOG_I("pthread_create mqtt_recv success\n");
|
||
}
|
||
|
||
ret = pthread_create(&pt_removeduplicatetag,NULL,thread_remove_duplicate_tag,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create remove duplicate tag send fail\n");
|
||
}else{
|
||
LOG_I("pthread_create remove duplicate tag success\n");
|
||
pthread_detach(pt_removeduplicatetag);
|
||
}
|
||
|
||
ret = pthread_create(&pt_removelog,NULL,thread_removelog,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create removelog fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create removelog success\n");
|
||
pthread_detach(pt_removelog);
|
||
}
|
||
#if 0
|
||
ret = pthread_create(&pt_readqr,NULL,thread_readqr,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create readqr fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create readqr success\n");
|
||
pthread_detach(pt_readqr);
|
||
}
|
||
#endif
|
||
ret = pthread_create(&pt_reporttag,NULL,thread_reporttag,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create reporttag fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create reporttag success\n");
|
||
pthread_detach(pt_reporttag);
|
||
}
|
||
|
||
ret = pthread_create(&pt_keycheck,NULL,thread_keycheck,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create keycheck fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create keycheck success\n");
|
||
pthread_detach(pt_keycheck);
|
||
}
|
||
|
||
ret = pthread_create(&pt_station_heartbeat,NULL,thread_station_heartbeat,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create station_heartbeat fail\n");
|
||
system("reboot");
|
||
}else{
|
||
LOG_I("pthread_create station_heartbeat success\n");
|
||
pthread_detach(pt_station_heartbeat);
|
||
}
|
||
|
||
ret = pthread_create(&pt_heartbeat_check,NULL,thread_heartbeat_check,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create heartbeat_check fail\n");
|
||
}else{
|
||
LOG_I("pthread_create heartbeat_check success\n");
|
||
pthread_detach(pt_heartbeat_check);
|
||
}
|
||
|
||
#if 0
|
||
ret = pthread_create(&pt_simulate_light,NULL,thread_simulate_light,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create simulate_light fail\n");
|
||
}else{
|
||
LOG_I("pthread_create simulate_light success\n");
|
||
pthread_detach(pt_simulate_light);
|
||
}
|
||
|
||
ret = pthread_create(&pt_all_light,NULL,thread_all_light,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create all_light fail\n");
|
||
}else{
|
||
LOG_I("pthread_create all_light success\n");
|
||
pthread_detach(pt_all_light);
|
||
}
|
||
#endif
|
||
|
||
#if 0
|
||
readresult=file_to_buffer("mqttRawPassword",&len);
|
||
if(readresult!=NULL){
|
||
strncpy(mqttRawPassword,readresult,len);
|
||
readresult=NULL;
|
||
LOG_I("saved mqttRawPassword:%s\n",mqttRawPassword);
|
||
}else{
|
||
if((ping("8.8.8.8") == 0)||(ping("8.8.4.4") == 0)){
|
||
getDevRawPassword(stationsn);
|
||
}else{
|
||
LOG_I("getDevRawPassword net not ready\n");
|
||
sleep(3);
|
||
}
|
||
}
|
||
|
||
readresult=file_to_buffer("LightEnable",&len);
|
||
if(readresult!=NULL){
|
||
if(strcmp(readresult,"enable")==0){
|
||
isLightEnable=true;
|
||
}else{
|
||
isLightEnable=false;
|
||
}
|
||
readresult=NULL;
|
||
}
|
||
|
||
#endif
|
||
// 字符串清理函数,去除末尾的空白字符
|
||
void trim_whitespace(char *str) {
|
||
if (str == NULL) return;
|
||
int len = strlen(str);
|
||
while (len > 0 && (str[len-1] == '\n' || str[len-1] == '\r' ||
|
||
str[len-1] == ' ' || str[len-1] == '\t')) {
|
||
str[--len] = '\0';
|
||
}
|
||
}
|
||
|
||
readresult=file_to_buffer("savedDevSn",&len);
|
||
while(readresult==NULL){
|
||
readresult=file_to_buffer("savedDevSn",&len);
|
||
sleep(5);
|
||
LOG_I("please scan sn\n");
|
||
}
|
||
strncpy(stationsn,readresult,len);
|
||
trim_whitespace(stationsn); // 清理空白字符
|
||
readresult=NULL;
|
||
LOG_I("saved stationsn:%s\n",stationsn);
|
||
|
||
// 读取productid配置
|
||
readresult=file_to_buffer("productid",&len);
|
||
if(readresult!=NULL){
|
||
memset(productid, 0, sizeof(productid));
|
||
strncpy(productid,readresult,len);
|
||
trim_whitespace(productid); // 清理空白字符
|
||
readresult=NULL;
|
||
LOG_I("saved productid:%s\n",productid);
|
||
} else {
|
||
LOG_I("use default productid:%s\n",productid);
|
||
}
|
||
|
||
// 读取appSecret配置
|
||
readresult=file_to_buffer("appSecret",&len);
|
||
if(readresult!=NULL){
|
||
memset(appSecret, 0, sizeof(appSecret));
|
||
strncpy(appSecret,readresult,len);
|
||
trim_whitespace(appSecret); // 清理空白字符
|
||
readresult=NULL;
|
||
LOG_I("saved appSecret:%s\n",appSecret);
|
||
} else {
|
||
LOG_I("use default appSecret:%s\n",appSecret);
|
||
}
|
||
|
||
// 读取hostDomain配置
|
||
readresult=file_to_buffer("hostDomain",&len);
|
||
if(readresult!=NULL){
|
||
memset(hostDomain, 0, sizeof(hostDomain));
|
||
strncpy(hostDomain,readresult,len);
|
||
trim_whitespace(hostDomain); // 清理空白字符
|
||
readresult=NULL;
|
||
LOG_I("saved hostDomain:%s\n",hostDomain);
|
||
} else {
|
||
LOG_I("use default hostDomain:%s\n",hostDomain);
|
||
}
|
||
#if 0
|
||
isSendComEnd=false;
|
||
isLightOnByGroup=false;
|
||
isLightOnById=false;
|
||
isLightOn=true;
|
||
isBindTag=false;
|
||
lightbars_size=5;
|
||
changecolor=4;
|
||
changesound=1;
|
||
groupno=1;
|
||
//uart_data_send_head(&uartSend,'B',5,0,lightbars_size);//bind groupno
|
||
uart_data_send_head(&uartSend,'P',5,10/5,lightbars_size);//lighton by tag
|
||
//uart_data_send_head(&uartSend,'*',5,5/5,0);//lighton by id
|
||
//uart_data_send_head(&uartSend,'&',5,5/5,1);//lighton by groupno
|
||
//uart_data_send_head(&uartSend,'R',5,30/5,1);//stop broadcast by groupno
|
||
//isStopBroadcast=true;
|
||
#endif
|
||
#if 1
|
||
while(1){
|
||
if((ping("8.8.8.8") == 0)||(ping("8.8.4.4") == 0)){
|
||
LOG_I("net ok\n");
|
||
while(!timeNew()){
|
||
//LOG_I("sleep\n");
|
||
getTimeCount++;
|
||
if(getTimeCount==100){
|
||
break;
|
||
}
|
||
sleep(1);
|
||
}
|
||
//saveStartUpTime();
|
||
ret = pthread_create(&pt_mqtt,NULL,thread_mqtt,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create mqtt fail\n");
|
||
system("reboot");
|
||
}else{
|
||
pthread_detach(pt_mqtt);
|
||
LOG_I("pthread_create mqtt success\n");
|
||
}
|
||
|
||
#if 0
|
||
// 添加MQTT连接状态检查线程
|
||
ret = pthread_create(&pt_mqtt_status,NULL,thread_mqtt_status_check,NULL);
|
||
if(ret!=0){
|
||
LOG_I("pthread_create mqtt_status_check fail\n");
|
||
}else{
|
||
pthread_detach(pt_mqtt_status);
|
||
LOG_I("pthread_create mqtt_status_check success\n");
|
||
}
|
||
#endif
|
||
break;
|
||
}else{
|
||
LOG_I("net not ready\n");
|
||
sleep(3);
|
||
}
|
||
}
|
||
#endif
|
||
while(1)
|
||
{
|
||
fgets(command_buffer, sizeof(command_buffer), stdin);
|
||
if(execute_command(command_buffer, (command_t *)&__start_command, (&__stop_command - &__start_command)/2) < 0)
|
||
{
|
||
LOG_I("unsupport command!\r\n");
|
||
}
|
||
}
|
||
return 0;
|
||
} |