Files

526 lines
16 KiB
C

#include <stdarg.h>
#include "ql_type.h"
#include "ql_data_call.h"
#include "ql_rtos.h"
#include "ql_application.h"
#include <stdio.h>
#include "sockets.h"
#include "ql_uart.h"
#include "ql_func.h"
#include "netdb.h"
#include "ql_sim.h"
#include "ql_dev.h"
#include "ql_wtd.h"
#include "MQTTClient.h"
#include "ql_fs.h"
#include "ql_fota.h"
#include "ql_sim.h"
#include "ql_ping.h"
#include "ql_nw.h"
#include "ql_atcmd.h"
#include "cJSON.h"
#include "build_macro.h"
#define MQTT_SERVER_DOMAIN "47.113.99.138"
#define MQTT_SERVER_PORT 1883
#define FOTA_TITLE_DEFAULT "EG800AK_AI"
#define MQTT_DOWNLOAD_CHUNK 512
#define MAX_PAYLOAD_LEN 512 // 限制payload大小防止缓冲区溢出
//#define MINIFOTA
#define FULLFOTA
ql_task_t mqtt_auth_task = NULL;
int mqtt_task_run_flag = 0;
int mqtt_task_fota_check_flag = 0;
MQTTClient mqtt_client = {0};
static char g_imei_buf[32]={0};
int fota_start = 0;
typedef struct
{
int type;
uint8_t *buf;
int buf_len;
}app_queue_msg;
static ql_queue_t mqtt_data_task_msg_queue = NULL;
#define TARGET_VER_FILE "U:/target_ver_file.txt"
int read_target_ver(uint8_t *buff, int len)
{
QFILE * fp = NULL;
int ret = -1;
if(ql_access(TARGET_VER_FILE, 0)!=0){
printf("read %s not is exist\n", TARGET_VER_FILE);
return -1;
}
fp = ql_fopen(TARGET_VER_FILE, "r");
if(NULL == fp)
{
printf("[FS]ERROR!!! *** file open fail: %s \r\n", TARGET_VER_FILE);
return -1;
}
ret = ql_fread(buff, len, 1, fp);
if(ret < 0)
{
printf("[FS]ERROR!!! *** file read fail: %s \r\n", TARGET_VER_FILE);
}
ql_fclose(fp);
fp = NULL;
return ret;
}
int save_target_ver(uint8_t *buff, int len)
{
QFILE * fp = NULL;
int ret = -1;
fp = ql_fopen(TARGET_VER_FILE, "w+");
if(NULL == fp)
{
printf("[FS]ERROR!!! *** file open fail: %s \r\n", TARGET_VER_FILE);
return -1;
}
ret = ql_fwrite(buff, len, 1, fp);
if(ret < 0)
{
printf("[FS]ERROR!!! *** file write fail: %s \r\n", TARGET_VER_FILE);
}
ql_fclose(fp);
fp = NULL;
return ret;
}
static void messageArrived(MessageData* data)
{
printf("Message arrived on topic %.*s: %.*s\r\n", data->topicName->lenstring.len, (char*)data->topicName->lenstring.data,data->message->payloadlen, (char*)data->message->payload);
if(!strncmp(data->topicName->lenstring.data,"v1/devices/me/attributes/response/",strlen("v1/devices/me/attributes/response/"))){
app_queue_msg *msg = NULL;
msg = malloc(sizeof(app_queue_msg));
if(msg){
msg->buf = malloc(data->message->payloadlen+1);
msg->buf_len = data->message->payloadlen;
msg->type = 1;
if(msg->buf){
memset(msg->buf,0,msg->buf_len+1);
memcpy(msg->buf,data->message->payload,msg->buf_len);
}
ql_rtos_queue_release(mqtt_data_task_msg_queue, sizeof(app_queue_msg *), (u8*)(&msg), 3000);
}
}
#if 0
else if(!strncmp(data->topicName->lenstring.data,"v2/fw/response/",strlen("v2/fw/response/"))){
app_queue_msg *msg = NULL;
msg = malloc(sizeof(app_queue_msg));
if(msg){
msg->buf = malloc(data->message->payloadlen);
msg->buf_len = data->message->payloadlen;
msg->type = 2;
if(msg->buf){
memset(msg->buf,0,msg->buf_len);
memcpy(msg->buf,data->message->payload,msg->buf_len);
}
ql_rtos_queue_release(mqtt_data_task_msg_queue, sizeof(app_queue_msg *), (u8*)(&msg), 3000);
}
}
#endif
}
static void MQTTEchoTask(void *argv)
{
/* connect to m2m.eclipse.org, subscribe to a topic, send and receive messages regularly for 3 times */
Network network = {0};
MQTTMessage message={0};
char payload[128];
char tempbuf[128]={0};
unsigned char sendbuf[512] = {0};
int rc = 0;
static uint32_t request_id = 1;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
unsigned char *readbuf=NULL;
qlFotaImgProcCtxPtr fota_ctx = NULL;
app_queue_msg *msg = NULL;
uint32_t file_size = 0;
int i;
int read_len = 0;
int dl_len = 0;
int update_flag = 0;
char target_ver[128]={0};
char buf_fw_url[128]={0};
char download_url1[128]={0};
char download_url2[128]={0};
char buf_talkingq_id[64]={0};
char buf_talkingq_sn[64]={0};
char buf_talkingq_url[64]={0};
char build_ver[128]={0};
cJSON *recv = NULL;
readbuf = malloc(MQTT_DOWNLOAD_CHUNK+128);
if(readbuf == NULL){
printf("MQTTEchoTask: malloc readbuf failed\r\n");
goto exit;
}
hal_os_get_build_ver(build_ver);
NetworkInit(&network, NULL, 1);
MQTTClientInit(&mqtt_client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, MQTT_DOWNLOAD_CHUNK+128);
char* address = MQTT_SERVER_DOMAIN;
if ((rc = NetworkConnect(&network, address, MQTT_SERVER_PORT)) != 0)
{
printf("Return code from network connect is %d\r\n", rc);
MQTTClientDeinit(&mqtt_client);
goto exit;
}
connectData.MQTTVersion = 3;
connectData.clientID.cstring = g_imei_buf;
connectData.username.cstring = g_imei_buf;
connectData.password.cstring = g_imei_buf;
if ((rc = MQTTConnect(&mqtt_client, &connectData)) != 0)
{
printf("Return code from MQTT connect is %d\r\n", rc);
NetworkDisconnect(&network);
MQTTClientDeinit(&mqtt_client);
goto exit;
}
else{
printf("MQTT Connected\r\n");
}
//上次更新是否成功
read_target_ver(target_ver,sizeof(target_ver));
if(strlen(target_ver)>0){
printf("read target:%s\r\n", target_ver);
message.qos = 1;
message.retained = 0;
message.payload = payload;
if(!strcmp(target_ver,build_ver)){
// 安全修复:使用snprintf防止缓冲区溢出
snprintf(payload, sizeof(payload), "{\"current_fw_title\":\"%s\",\"current_fw_version\":\"%s\",\"fw_state\":\"UPDATED\"}",FOTA_TITLE_DEFAULT,build_ver);
message.payloadlen = strlen(payload);
}else{
snprintf(payload, sizeof(payload), "{\"current_fw_title\":\"%s\",\"current_fw_version\":\"%s\",\"fw_state\":\"FAILED\"}",FOTA_TITLE_DEFAULT,build_ver);
message.payloadlen = strlen(payload);
}
if ((rc = MQTTPublish(&mqtt_client, "v1/devices/me/telemetry", &message)) != 0){
printf("Return code from MQTT publish v1/devices/me/telemetry UPDATED is %d\r\n", rc);
}
memset(target_ver,0,sizeof(target_ver));
//把版本信息清除
save_target_ver(target_ver,sizeof(target_ver));
}
memset(target_ver,0,sizeof(target_ver));
#if defined(MQTT_TASK)
if ((rc = MQTTStartTask(&mqtt_client)) != 0)
{
printf("Return code from start tasks is %d\r\n", rc);
NetworkDisconnect(&network);
MQTTClientDeinit(&mqtt_client);
goto exit;
}
#endif
if ((rc = MQTTSubscribe(&mqtt_client, "v1/devices/me/attributes/response/+", 1, messageArrived)) != 0)
{
printf("Return code from MQTT subscribe attributes/response is %d", rc);
goto dis_exit;
}
if ((rc = MQTTSubscribe(&mqtt_client, "v1/devices/me/attributes", 1, messageArrived)) != 0)
{
printf("Return code from MQTT subscribe attributes is %d", rc);
goto dis_exit;
}
message.qos = 1;
message.retained = 0;
message.payload = payload;
// 安全修复:使用snprintf防止缓冲区溢出
snprintf(payload, sizeof(payload), "{\"current_fw_title\":\"%s\",\"current_fw_version\":\"%s\"}",FOTA_TITLE_DEFAULT,build_ver);
message.payloadlen = strlen(payload);
if ((rc = MQTTPublish(&mqtt_client, "v1/devices/me/telemetry", &message)) != 0){
printf("Return code from MQTT publish current_fw is %d\r\n", rc);
}
message.qos = 1;
message.retained = 0;
message.payload = payload;
#if 0
sprintf(payload, "{\"sharedKeys\":\"fw_checksum,fw_checksum_algorithm,fw_size,fw_title,fw_version\"}");
#else
// 安全修复:使用snprintf
snprintf(payload, sizeof(payload), "{\"sharedKeys\":\"talkingq_url,talkingq_id,talkingq_sn,fw_title,fw_version,fw_url\"}");
#endif
message.payloadlen = strlen(payload);
// 安全修复:使用snprintf
snprintf(tempbuf, sizeof(tempbuf), "v1/devices/me/attributes/request/%d",request_id);
if ((rc = MQTTPublish(&mqtt_client, tempbuf, &message)) != 0){
printf("Return code from MQTT publish request is %d\r\n", rc);
goto dis_exit;
}
if(0!=ql_rtos_queue_wait(mqtt_data_task_msg_queue, (u8*)(&msg), sizeof(msg), 5000)){
printf("wait for request req errrrrrrrr\r\n");
goto dis_exit;
}
if(msg->type!=1){
printf("wait for request type errrrrrrrr %d\r\n",msg->type);
goto dis_exit;
}
if(msg->buf==NULL){
printf("msg->buf null errrrrrrrr \r\n");
goto dis_exit;
}
//maybe cJSON
recv = cJSON_Parse(msg->buf);
if(recv){
cJSON *sharedkeys = cJSON_GetObjectItem(recv,"shared");
if(sharedkeys){
cJSON *item = cJSON_GetObjectItem(sharedkeys,"talkingq_url");
if(item){
strcpy(tempbuf,item->valuestring);
printf("talkingq_url: %s\r\n",tempbuf);
hal_os_get_talkingq_url(buf_talkingq_url);
if(strlen(tempbuf)>0 && strcmp(tempbuf,buf_talkingq_url)){
hal_os_set_talkingq_url(tempbuf);
}
}else{
printf("not find talkingq_url,\r\n");
}
item = cJSON_GetObjectItem(sharedkeys,"talkingq_id");
if(item){
strcpy(tempbuf,item->valuestring);
printf("talkingq_id: %s\r\n",tempbuf);
hal_os_get_device_id(buf_talkingq_id);
if(strlen(tempbuf)>0 && strcmp(tempbuf,buf_talkingq_id)){
hal_os_set_device_id(tempbuf);
}
}else{
printf("not find talkingq_id,\r\n");
}
item = cJSON_GetObjectItem(sharedkeys,"talkingq_sn");
if(item){
strcpy(tempbuf,item->valuestring);
printf("talkingq_sn: %s\r\n",tempbuf);
hal_os_get_device_sn(buf_talkingq_sn);
if(strlen(tempbuf)>0 && strcmp(tempbuf,buf_talkingq_sn)){
hal_os_set_device_sn(tempbuf);
}
}else{
printf("not find talkingq_sn,\r\n");
}
item = cJSON_GetObjectItem(sharedkeys,"fw_version");
if(item){
strcpy(target_ver,item->valuestring);
printf("fw_version: %s\r\n",target_ver);
}else{
printf("not find fw_version,\r\n");
memset(target_ver,0,sizeof(target_ver));
}
item = cJSON_GetObjectItem(sharedkeys,"fw_url");
if(item){
strcpy(buf_fw_url,item->valuestring);
printf("fw_url: %s\r\n",buf_fw_url);
}else{
printf("not find fw_url\r\n");
memset(buf_fw_url,0,sizeof(buf_fw_url));
}
}else{
printf("shared item not json error.\r\n");
memset(target_ver,0,sizeof(target_ver));
memset(buf_fw_url,0,sizeof(buf_fw_url));
goto dis_exit;
}
cJSON_Delete(recv);
recv = NULL;
}else{
printf("shared keys parse not json error.\r\n");
goto dis_exit;
}
memset(buf_talkingq_id,0,sizeof(buf_talkingq_id));
memset(buf_talkingq_sn,0,sizeof(buf_talkingq_sn));
memset(buf_talkingq_url,0,sizeof(buf_talkingq_url));
hal_os_get_device_id(buf_talkingq_id);
hal_os_get_device_sn(buf_talkingq_sn);
hal_os_get_talkingq_url(buf_talkingq_url);
message.qos = 1;
message.retained = 0;
message.payload = payload;
// 安全修复:使用snprintf防止溢出
snprintf(payload, sizeof(payload), "{\"current_talkingq_url\":\"%s\",\"current_talkingq_id\":\"%s\",\"current_talkingq_sn\":\"%s\"}",buf_talkingq_url,buf_talkingq_id,buf_talkingq_sn);
message.payloadlen = strlen(payload);
if ((rc = MQTTPublish(&mqtt_client, "v1/devices/me/telemetry", &message)) != 0){
printf("Return code from MQTT publish current_talkingq is %d\r\n", rc);
}
if(!strcmp(build_ver,target_ver)){
printf("version not need update!!!!!!\r\n");
mqtt_task_fota_check_flag = 1;
goto dis_exit;
}
if(strlen(buf_fw_url)<=0 || strlen(target_ver)<=0){
printf("no buf_fw_url or target_ver not need update!!!!!!\r\n");
goto dis_exit;
}
/*
.\adiff.exe system_old.img system_new.img jx_fota.bin -a1 customer_app customer_app.bin -u updater.bin
*/
//download url:"http://405j9o6444.qicp.vip/jx_fota.bin_1"
printf("download url:%s\r\n", buf_fw_url);
if(strstr(buf_fw_url, "bin")!=NULL)
{
//#define FOTA_SERVER_ADDRESS_STEP1 "http://405j9o6444.qicp.vip/jx_fota.bin_1"
//#define FOTA_SERVER_ADDRESS_STEP2 "http://405j9o6444.qicp.vip/jx_fota.bin_2"
//进入升级前 保存升级版本信息
save_target_ver(target_ver,strlen(target_ver)+1);
memcpy(download_url1,buf_fw_url, strlen(buf_fw_url)+1);
//memcpy(download_url2,buf_fw_url, strlen(buf_fw_url)+1);
//download_url2[strlen(download_url2)] = '2';
printf("download_url1:%s\r\n", download_url1);
//printf("download_url2:%s\r\n", download_url2);
update_flag = 1;
message.qos = 1;
message.retained = 0;
message.payload = payload;
// 安全修复:使用snprintf防止溢出
snprintf(payload, sizeof(payload), "{\"current_fw_title\":\"%s\",\"current_fw_version\":\"%s\",\"fw_state\":\"UPDATING\"}",FOTA_TITLE_DEFAULT,build_ver);
message.payloadlen = strlen(payload);
if ((rc = MQTTPublish(&mqtt_client, "v1/devices/me/telemetry", &message)) != 0){
printf("Return code from MQTT publish v1/devices/me/telemetry DOWNLOADED is %d\r\n", rc);
}
app_play_tips_file(3);
fota_start = 1;
ql_rtos_task_sleep_ms(5000);
#ifdef MINIFOTA
//printf("download_url1:%s\r\n",download_url1);
//printf("download_url2:%s\r\n",download_url2);
ql_fota_mini_system(1, QL_FOTA_DWNLD_MOD_HTTP, download_url1 ,download_url2, NULL,NULL);
#endif
#ifdef FULLFOTA
ql_fullfota_app_start(download_url1);
#endif
}
dis_exit:
request_id++;
mqtt_task_fota_check_flag = 1;
if(update_flag){
message.qos = 1;
message.retained = 0;
message.payload = payload;
// 安全修复:使用snprintf防止溢出
snprintf(payload, sizeof(payload), "{\"current_fw_title\":\"%s\",\"current_fw_version\":\"%s\",\"fw_state\":\"FAILED\"}",FOTA_TITLE_DEFAULT,build_ver);
message.payloadlen = strlen(payload);
if ((rc = MQTTPublish(&mqtt_client, "v1/devices/me/telemetry", &message)) != 0){
printf("Return code from MQTT publish v1/devices/me/telemetry DOWNLOADED is %d\r\n", rc);
}
}
if(msg!=NULL){
if(msg->buf!=NULL){
free(msg->buf);
}
free(msg);
msg = NULL;
}
rc = MQTTDisconnect(&mqtt_client);
if(rc == SUCCESS)
printf("MQTT Disconnected by client\r\n");
else
printf("MQTT Disconnected failed by client\r\n");
NetworkDisconnect(&network);
MQTTClientDeinit(&mqtt_client);
mqtt_task_run_flag = 2;
exit:
if(readbuf){
free(readbuf);
}
if(recv){
cJSON_Delete(recv);
}
printf("========== mqtt test end ==========");
if(mqtt_task_run_flag==1)
mqtt_task_run_flag = 0;
ql_rtos_task_delete(NULL);
}
void app_fota_init(void)
{
char build_ver[128]={0};
memset(g_imei_buf,0,sizeof(g_imei_buf));
ql_dev_get_imei(g_imei_buf,sizeof(g_imei_buf));
printf("g_imei_buf:%s\r\n", g_imei_buf);
hal_os_get_build_ver(build_ver);
printf("\r\n\r\n************************************\r\nVERSION:%s\r\n************************************\r\n\r\n", build_ver);
ql_rtos_queue_create(&mqtt_data_task_msg_queue, sizeof(app_queue_msg), 1);
if(mqtt_task_run_flag==0){
if(mqtt_task_fota_check_flag==1)return;
mqtt_task_run_flag = 1;
ql_rtos_task_create(&mqtt_auth_task, 10*1024, 100, "mqtt_auth", MQTTEchoTask, NULL);
}
}