AP05/main.c
2025-12-08 11:32:44 +08:00

2644 lines
102 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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"
// 全局变量声明
jt_led_or_group_package_t tags;
jt_led_or_group_package_t led_ctrl;
// 函数声明
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;
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;
jt_only_tag_t onlyTags[200]={0};
int tagCount=0;
// 心跳检测相关
#define HEARTBEAT_TIMEOUT_SEC (30 * 60) // 30分钟超时
#define MAX_LIGHTBAR_NUM 200
typedef struct {
uint32_t tagCode; // 灯条ID
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;
pthread_t pt_heartbeat_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.22";
//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};
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_simulate_light(void *arg);
void *thread_all_light(void *arg);
void update_lightbar_heartbeat(uint32_t tagCode);
void report_lightbar_login(uint32_t tagCode);
void report_lightbar_logout(uint32_t tagCode);
/*================================================================================*/
// 上报灯条子设备登录
void report_lightbar_login(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: AD10 + tagCode (十六进制)
snprintf(subDeviceKey, sizeof(subDeviceKey), "AD10%08X", 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 report_lightbar_logout(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: AD10 + tagCode (十六进制)
snprintf(subDeviceKey, sizeof(subDeviceKey), "AD10%08X", 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(uint32_t tagCode) {
pthread_mutex_lock(&heartbeatMutex);
// 查找是否已存在该灯条
int found = -1;
for (int i = 0; i < lightbarHeartbeatCount; i++) {
if (lightbarHeartbeat[i].tagCode == tagCode) {
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 %08X back online\n", tagCode);
report_lightbar_login(tagCode);
}
} else if (lightbarHeartbeatCount < MAX_LIGHTBAR_NUM) {
// 新灯条心跳存储
lightbarHeartbeat[lightbarHeartbeatCount].tagCode = tagCode;
lightbarHeartbeat[lightbarHeartbeatCount].lastHeartbeat = now;
lightbarHeartbeat[lightbarHeartbeatCount].isOnline = true;
lightbarHeartbeatCount++;
LOG_I("New lightbar %08X registered, total: %d\n", tagCode, lightbarHeartbeatCount);
report_lightbar_login(tagCode);
}
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) {
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].tagCode);
}
}
}
pthread_mutex_unlock(&heartbeatMutex);
}
return NULL;
}
/*================================================================================*/
// 模拟亮灯线程函数 - 每30秒发送一次亮灯任务
void *thread_simulate_light(void *arg){
LOG_I("thread_simulate_light started\n");
char sim_payload[1024] = {0};
while(1){
sleep(30); // 每30秒执行一次
// 从/root/payload文件读取内容
FILE *fp = fopen("/root/payload", "r");
if(fp == NULL){
LOG_I("simulate_light: cannot open /root/payload\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: putting payload into queue\n");
LOG_I("payload: %s\n", sim_payload);
// 直接把payload放入消息队列由thread_mqtt_recv处理
PutDataIntoMQueue(sim_payload);
}
fclose(fp);
}
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();
}
}
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=60;
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();
}
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){
jt_led_or_group_package_t led_ctrl={
.s.color=changecolor,
.s.sound=changesound,
.s.single=0,
.s.flash=changeflash,
};//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=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);
#endif
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);
#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,0x00000000,0xFFFFFFFF,led_ctrl,0x0000);
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);
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);
//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(tagCode);
}else if(tagFeature==0xFD){
LOG_I("key\n");
}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 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(GetDataFromMQueue(payload)==0){
// 调试用固定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;
// 解析Items数组
get_size_from_json_string_arry_by_key(payload, "Items", &items_size);
LOG_I("Items size = %d\n", items_size);
// 解析Time字段常位时间
get_int_from_json_string_by_key(payload,"Time",&mqtt_parm.msg_duration);
LOG_I("msg_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);
}
// 遍历Items数组
for(int i = 0; i < items_size; i++){
get_string_from_json_string_arry_by_key(payload,"Items",msg_item_value,1024,i);
snprintf(msg_items, sizeof(msg_items), "{%s}", msg_item_value);
LOG_I("msg_items[%d] = %s\n", i, msg_items);
// 解析Beep字段蜂鸣
int beep_enable = 0;
get_int_from_json_string_by_key(msg_items,"Beep",&beep_enable);
LOG_I("Beep = %d\n", beep_enable);
changesound = beep_enable ? 1 : 0;
// 解析Flashing字段闪烁
int flashing_enable = 0;
get_int_from_json_string_by_key(msg_items,"Flashing",&flashing_enable);
changeflash = flashing_enable ? 3 : 1; // 3=闪烁, 1=常亮
LOG_I("Flashing = %d, changeflash = %d\n", flashing_enable, changeflash);
// 解析TagID字段灯条ID
LOG_I("Before parsing TagID, msg_items = %s\n", msg_items);
LOG_I("mqtt_parm.msg_sn buffer size = %d\n", (int)sizeof(mqtt_parm.msg_sn));
// 尝试使用不带unescape的函数
int tagid_ret = get_string_from_json_string_by_key(msg_items, "TagID", mqtt_parm.msg_sn,sizeof(mqtt_parm.msg_sn));
LOG_I("TagID parsing result = %d\n", tagid_ret);
LOG_I("Original TagID = %s\n", mqtt_parm.msg_sn);
// 只取TagID的后8位
int tag_len = strlen(mqtt_parm.msg_sn);
LOG_I("TagID length = %d\n", tag_len);
if(tag_len > 8) {
// 将后8位移动到字符串开头
memmove(mqtt_parm.msg_sn, mqtt_parm.msg_sn + (tag_len - 8), 8);
mqtt_parm.msg_sn[8] = '\0';
LOG_I("TagID after truncation = %s\n", mqtt_parm.msg_sn);
} else if(tag_len == 0) {
LOG_I("Warning: TagID is empty!\n");
}
LOG_I("TagID (last 8 chars) = %s\n", mqtt_parm.msg_sn);
// 解析Colors数组
get_size_from_json_string_arry_by_key(msg_items, "Colors", &colors_size);
LOG_I("Colors size = %d\n", colors_size);
// 默认颜色设置
changecolor = 1; // 默认蓝色
// 遍历Colors数组找到第一个为true的颜色
for(int j = 0; j < colors_size; j++){
get_string_from_json_string_arry_by_key(msg_items,"Colors",msg_color_value,512,j);
snprintf(msg_colors, sizeof(msg_colors), "{%s}", msg_color_value);
LOG_I("msg_colors[%d] = %s\n", j, msg_colors);
int r_enable = 0, g_enable = 0, b_enable = 0;
get_int_from_json_string_by_key(msg_colors,"R",&r_enable);
get_int_from_json_string_by_key(msg_colors,"G",&g_enable);
get_int_from_json_string_by_key(msg_colors,"B",&b_enable);
// 根据RGB组合设置颜色
if(!r_enable && !g_enable && !b_enable){
changecolor = 0; // 不亮
break;
}else if(r_enable && !g_enable && !b_enable){
changecolor = 4; // 红色
break;
}else if(!r_enable && g_enable && !b_enable){
changecolor = 2; // 绿色
break;
}else if(!r_enable && !g_enable && b_enable){
changecolor = 1; // 蓝色
break;
}else if(r_enable && g_enable && !b_enable){
changecolor = 6; // 黄色
break;
}else if(r_enable && !g_enable && b_enable){
changecolor = 5; // 紫色
break;
}else if(!r_enable && g_enable && b_enable){
changecolor = 3; // 青色
break;
}else if(r_enable && g_enable && b_enable){
changecolor = 7; // 白色
break;
}
}
LOG_I("changecolor=%d\n",changecolor);
// 将TagID存储到lightsn数组中保持兼容性
if(i < 30) {
char *lightsn_array[] = {lightsn1, lightsn2, lightsn3, lightsn4, lightsn5,
lightsn6, lightsn7, lightsn8, lightsn9, lightsn10,
lightsn11, lightsn12, lightsn13, lightsn14, lightsn15,
lightsn16, lightsn17, lightsn18, lightsn19, lightsn20,
lightsn21, lightsn22, lightsn23, lightsn24, lightsn25,
lightsn26, lightsn27, lightsn28, lightsn29, lightsn30};
memset(lightsn_array[i], 0, 7);
memcpy(lightsn_array[i], mqtt_parm.msg_sn, strlen(mqtt_parm.msg_sn));
LOG_I("lightsn[%d] = %s\n", i, lightsn_array[i]);
}
}
// 设置lightbars_size为items_size
lightbars_size = items_size;
LOG_I("lightbars_size = %d\n", lightbars_size);
// 根据任务类型进行处理
// 任务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
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);
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 0
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 1
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;
}