Support OTA upgrade by MQTT

This commit is contained in:
wgzAIIT 2023-06-19 10:18:50 +08:00
parent dd43dd6d17
commit 87921c4212
7 changed files with 217 additions and 66 deletions

View File

@ -163,8 +163,8 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.serial_parity_mode = PARITY_NONE;
serial_cfg.serial_bit_order = STOP_BITS_1;
serial_cfg.serial_invert_mode = NRZ_NORMAL;
//serial receive timeout 10s
serial_cfg.serial_timeout = 10000;
//serial receive timeout 1s
serial_cfg.serial_timeout = 1000;
serial_cfg.is_ext_uart = 0;
#ifdef ADAPTER_EC200T_DRIVER_EXT_PORT
serial_cfg.is_ext_uart = 1;

View File

@ -293,6 +293,7 @@ int EntmSend(ATAgentType agent, const char *data, int len)
int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s)
{
struct timespec abstime;
uint32 real_recv_len = 0;
abstime.tv_sec = timeout_s;
if(buffer_len > ENTM_RECV_MAX){
@ -316,13 +317,14 @@ int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s)
printf("EntmRecv once len %d.\n", agent->entm_recv_len);
#endif
memcpy(rev_buffer, agent->entm_recv_buf, agent->entm_recv_len);
memset(agent->entm_recv_buf, 0, ENTM_RECV_MAX);
real_recv_len = agent->entm_recv_len;
agent->entm_recv_len = 0;
agent->read_len = 0;
PrivMutexAbandon(&agent->lock);
return buffer_len;
return real_recv_len;
}
static int GetCompleteATReply(ATAgentType agent)
@ -330,21 +332,22 @@ static int GetCompleteATReply(ATAgentType agent)
uint32_t read_len = 0;
char ch = 0, last_ch = 0;
bool is_full = false;
int res;
PrivMutexObtain(&agent->lock);
memset(agent->maintain_buffer, 0x00, agent->maintain_max);
agent->maintain_len = 0;
memset(agent->entm_recv_buf, 0x00, 256);
memset(agent->entm_recv_buf, 0x00, ENTM_RECV_MAX);
agent->entm_recv_len = 0;
PrivMutexAbandon(&agent->lock);
while (1) {
PrivRead(agent->fd, &ch, 1);
res = PrivRead(agent->fd, &ch, 1);
#ifdef CONNECTION_FRAMEWORK_DEBUG
if(ch != 0) {
if((res == 1) && (ch != 0)) {
printf(" %c (0x%x)\n", ch, ch);
}
#endif
@ -352,10 +355,9 @@ static int GetCompleteATReply(ATAgentType agent)
PrivMutexObtain(&agent->lock);
if (agent->receive_mode == ENTM_MODE) {
if (agent->entm_recv_len < ENTM_RECV_MAX) {
agent->entm_recv_buf[agent->entm_recv_len] = ch;
agent->entm_recv_len++;
if(agent->entm_recv_len < agent->read_len) {
if((res == 1) && (agent->entm_recv_len < agent->read_len)) {
agent->entm_recv_buf[agent->entm_recv_len] = ch;
agent->entm_recv_len++;
PrivMutexAbandon(&agent->lock);
continue;
} else {

View File

@ -560,6 +560,10 @@ KERNELPATHS +=-I$(KERNEL_ROOT)/tool/bootloader/flash \
-I$(KERNEL_ROOT)/tool/bootloader/ota #
endif
ifeq ($(CONFIG_TOOL_USING_MQTT), y)
KERNELPATHS +=-I$(KERNEL_ROOT)/tool/mqtt
endif
ifeq ($(CONFIG_FS_LWEXT4),y)
KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/blockdev/xiuos #
KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/include #

View File

@ -30,6 +30,10 @@
#include <adapter.h>
#endif
#ifdef OTA_BY_PLATFORM
#include "aliyun_mqtt.h"
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@ -124,34 +128,37 @@ static uint32_t calculate_crc32(uint32_t addr, uint32_t len)
* : cur_version:,new_version:
* : 0:,-1:
* : ,OTA传输而来的版本号也要保持这样三段式的形式
major.minor.patch,1.2.3
major.minor.patch,01.02.03
*******************************************************************************/
static int create_version(uint8_t* cur_version, uint8_t* new_version)
{
int major, minor, patch; //三段式版本号的各个部分
//解析当前版本号,版本号格式不对直接返回
if (sscanf(cur_version, "%d.%d.%d", &major, &minor, &patch) != 3) {
if (sscanf(cur_version, "%03d.%03d.%03d", &major, &minor, &patch) != 3) {
return -1;
}
//将当前版本号加1
patch++;
if(patch > MAX_PATCH) {
if(patch > 999)
{
minor++;
patch = 0;
if (minor > MAX_MINOR) {
if(minor > 999)
{
major++;
minor = 0;
patch = 0;
if (major > MAX_MAJOR) {
if(major > 999)
{
return -1;
}
}
}
//更新版本号
sprintf(new_version, "%d.%d.%d", major, minor, patch);
sprintf(new_version, "%03d.%03d.%03d", major, minor, patch);
return 0;
}
@ -690,8 +697,8 @@ try_again:
/*******************************************************************************
* : app_ota_by_4g
* : ota升级,,4g方式传输bin文件
* : adapter:Adapter指针,4G设备
* : 0:,-1:
* :
* :
*******************************************************************************/
static void app_ota_by_4g(void)
{
@ -731,6 +738,175 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHE
#ifdef OTA_BY_PLATFORM
#define FRAME_LEN 256 //每帧数据的数据包长度
static uint8_t MqttRxbuf[512];
static uint8_t FrameBuf[FRAME_LEN];
static OTA_TCB AliOTA;
/*******************************************************************************
* : PropertyVersion
* :
* :
* :
*******************************************************************************/
static void PropertyVersion(void)
{
uint8_t tempbuff[128];
ota_info_t ota_info;
memset(tempbuff,0,128);
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); //清空临时缓冲区
sprintf(tempbuff,"{\"id\": \"1\",\"params\": {\"version\": \"%s\"}}",ota_info.os.version);
MQTT_PublishDataQs1("/ota/device/inform/iv74JbFgzhv/D001",tempbuff,strlen(tempbuff)); //发送等级QS=1的PUBLISH报文
}
/*-------------------------------------------------*/
/*函数名OTA下载数据 */
/*参 数size本次下载量 */
/*参 数offset本次下载偏移量 */
/*返回值:无 */
/*-------------------------------------------------*/
void OTA_Download(int size, int offset)
{
uint8_t temp[256];
memset(temp,0,256);
sprintf(temp,"{\"id\": \"1\",\"params\": {\"fileInfo\":{\"streamId\":%d,\"fileId\":1},\"fileBlock\":{\"size\":%d,\"offset\":%d}}}",AliOTA.streamId,size,offset);
MQTT_PublishDataQs0("/sys/iv74JbFgzhv/D001/thing/file/download",temp,strlen(temp));
}
/*******************************************************************************
* : app_ota_by_platform
* : ota升级,,MQTT进行升级
* :
* :
*******************************************************************************/
static void app_ota_by_platform(void)
{
int datalen;
int ret = 0;
ota_info_t ota_info;
uint32_t flashdestination = DOWN_FLAH_ADDRESS;
mcuboot.flash_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
if((AdapterNetActive() == 0) && (MQTT_Connect() == 0))
{
KPrintf("Log in to aliyun mqtt successfully.\n");
MQTT_SubscribeTopic("/sys/iv74JbFgzhv/D001/thing/service/property/set"); //发送订阅Topic报文
MQTT_SubscribeTopic("/sys/iv74JbFgzhv/D001/thing/file/download_reply"); //发送订阅Topic报文
PropertyVersion();
}
while(1)
{
memset(MqttRxbuf,0,sizeof(MqttRxbuf));
datalen = MQTT_Recv(MqttRxbuf, 512);
if(datalen > 0 && (MqttRxbuf[0] == 0x30))
{
MQTT_DealPublishData(MqttRxbuf, datalen);
if(sscanf((char *)Aliyun_mqtt.cmdbuff,"/ota/device/upgrade/iv74JbFgzhv/D001{\"code\":\"1000\",\"data\":{\"size\":%d,\"streamId\":%d,\"sign\":\"%*32s\",\"dProtocol\":\"mqtt\",\"version\":\"%11s\"",&AliOTA.size,&AliOTA.streamId,AliOTA.version)==3)
{
KPrintf("ota file size:%d\r\n",AliOTA.size);
KPrintf("ota file id:%d\r\n",AliOTA.streamId);
KPrintf("ota file version:%s\r\n",AliOTA.version);
if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,AliOTA.size != kStatus_Success))
{
KPrintf("Failed to erase target fash!\n");
ret = -1;
break;
}
AliOTA.counter = (AliOTA.size%FRAME_LEN != 0)? (AliOTA.size/FRAME_LEN + 1):(AliOTA.size/FRAME_LEN);
AliOTA.num = 1; //下载次数,初始值为1
AliOTA.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
if(strstr((char *)Aliyun_mqtt.cmdbuff,"download_reply"))
{
memset(FrameBuf,0,sizeof(FrameBuf));
memcpy(FrameBuf, &MqttRxbuf[datalen-AliOTA.downlen-2], AliOTA.downlen);
if(mcuboot.op_flash_write(flashdestination,FrameBuf,AliOTA.downlen) != kStatus_Success)
{
KPrintf("current frame[%d] flash failed.\n",AliOTA.num-1);
ret = -1;
break;
}
else
{
KPrintf("current frame[%d] is written to flash 0x%x address successful.\n", AliOTA.num -1, flashdestination);
KPrintf("Current progress is %d/%d\r\n",AliOTA.num,AliOTA.counter);
flashdestination += AliOTA.downlen;
AliOTA.num++;
}
if(AliOTA.num < AliOTA.counter) //如果小于总下载次数
{
AliOTA.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else if(AliOTA.num == AliOTA.counter) //如果等于总下载次数,说明是最后一次下载
{
if(AliOTA.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍
{
AliOTA.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else
{
AliOTA.downlen = AliOTA.size%FRAME_LEN; //记录本次下载量
OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
}
else //下载完毕
{
ret = 0;
break;
}
}
}
}
if(0 == ret)
{
ota_info.down.size = AliOTA.size;
ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, AliOTA.size);
memset(ota_info.down.version,0,sizeof(ota_info.down.version));
create_version(ota_info.os.version, ota_info.down.version);
memset(ota_info.down.description,0,sizeof(ota_info.down.description));
strncpy(ota_info.down.description, "MQTT OTA bin.",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
mcuboot.flash_deinit();
KPrintf("ota file done,start reboot.\n");
MdelayKTask(2000);
mcuboot.op_reset();
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),aliyun, app_ota_by_platform, ota by 4g function);
#endif

View File

@ -23,11 +23,6 @@
#include "flash_ops.h"
#define MAX_MAJOR 99 //最大主版本号
#define MAX_MINOR 99 //最大次版本号
#define MAX_PATCH 99 //最大修订版本号
#define JUMP_FAILED_FLAG 0XABABABAB
#define JUMP_SUCCESS_FLAG 0XCDCDCDCD
#define STARTFLAG 0x1A2B //数据帧开始信号标记
@ -66,6 +61,7 @@ typedef struct {
} ota_info_t;
#ifdef OTA_BY_TCPSERVER
/*bin包传输过程中的数据帧相关的结构体*/
typedef struct
{
@ -87,7 +83,18 @@ typedef struct
ota_header_t header;
ota_frame_t frame;
} ota_data;
#endif
#ifdef OTA_BY_PLATFORM
typedef struct{
uint32_t size; //OTA固件大小
uint32_t streamId; //OTA固件下载时ID编号
uint32_t counter; //OTA总下载次数
uint32_t num; //OTA当前下载次数
uint32_t downlen; //OTA当前下载次数的下载量
uint8_t version[32]; //OTA下载时存储版本号的缓存区
}OTA_TCB;
#endif
void app_clear_jumpflag(void);
void ota_entry(void);

View File

@ -27,15 +27,14 @@
#include <adapter.h>
#include "aliyun_mqtt.h"
MQTT_TCB Aliyun_mqtt; //创建一个用于连接阿里云mqtt的结构体
static struct Adapter *adapter;
static MQTT_TCB Aliyun_mqtt; //创建一个用于连接阿里云mqtt的结构体
static const uint8_t parket_connetAck[] = {0x20,0x02,0x00,0x00}; //连接成功服务器回应报文
static const uint8_t parket_disconnet[] = {0xe0,0x00}; //客户端主动断开连接发送报文
static const uint8_t parket_heart[] = {0xc0,0x00}; //客户端发送保活心跳包
static const uint8_t parket_subAck[] = {0x90,0x03,0x00,0x0A,0x01}; //订阅成功服务器回应报文
static const uint8_t parket_unsubAck[] = {0xB0,0x02,0x00,0x0A}; //取消订阅成功服务器回应报文
static uint8_t mqtt_rxbuf[512];
static uint8_t mqtt_rxbuf[16];
/*******************************************************************************
@ -431,41 +430,3 @@ void MQTT_DealPublishData(uint8_t *data, uint16_t data_len)
memcpy(Aliyun_mqtt.cmdbuff, &data[cmdpos], cmdlen);
}
}
void testmqtt(void)
{
int ret = 0;
int len;
ret = AdapterNetActive();
if(ret == 0)
{
KPrintf("The network connection is successful.\n");
}
ret = MQTT_Connect();
if(ret == 0)
{
KPrintf("Log in to aliyun mqtt successfully.\n");
}
MdelayKTask(2000);
ret = MQTT_SubscribeTopic(TOPIC);
if(ret == 0)
{
KPrintf("mqtt sub successfully.\n");
}
while(1)
{
memset(mqtt_rxbuf,0,sizeof(mqtt_rxbuf));
len = MQTT_Recv(mqtt_rxbuf, 256);
if(len > 0 && (mqtt_rxbuf[0] == 0x30))
{
MQTT_DealPublishData(mqtt_rxbuf, len);
KPrintf("%s",Aliyun_mqtt.cmdbuff);
KPrintf("\r\n");
}
MdelayKTask(200);
MQTT_SendHeart();
}
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),mqtt, testmqtt, test mqtt);

View File

@ -29,7 +29,6 @@
#define PASSWORD "2e5e585ec5fc8665dd8bc1a17444fc8ffcb07ed515b220785883d478e49666e5"
#define SERVERIP "101.133.196.127"
#define SERVERPORT "1883"
#define TOPIC "/sys/iv74JbFgzhv/D001/thing/service/property/set"
#define PACK_SIZE 512 //存放报文数据缓冲区大小
#define CMD_SIZE 512 //保存推送的PUBLISH报文中的数据缓冲区大小
@ -44,6 +43,8 @@ typedef struct{
uint8_t cmdbuff[CMD_SIZE]; //保存推送的PUBLISH报文中的数据缓冲区
}MQTT_TCB;
extern MQTT_TCB Aliyun_mqtt; //外部变量声明
int AdapterNetActive(void);
int MQTT_Send(const uint8_t* buf, int buflen);
int MQTT_Recv(uint8_t* buf, int buflen);