753 lines
26 KiB
C
753 lines
26 KiB
C
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include "ql_type.h"
|
||
#include "ql_api_osi.h"
|
||
#include "ql_log.h"
|
||
#include "ql_api_datacall.h"
|
||
#include "ql_fs.h"
|
||
#include "ql_power.h"
|
||
#include "ql_api_dev.h"
|
||
#include "ql_http_client.h"
|
||
#include "ql_api_fota.h"
|
||
#include "ql_app_feature_config.h"
|
||
|
||
typedef enum
|
||
{
|
||
FOTA_HTTP_DOWN_INIT, //初始阶段
|
||
FOTA_HTTP_DOWN_DOWNING, //下载中
|
||
FOTA_HTTP_DOWN_INTR, //下载被中断
|
||
FOTA_HTTP_DOWN_DOWNED, //下载完成
|
||
FOTA_HTTP_DOWN_NOSPACE, //没有空间
|
||
}e_fota_down_stage;
|
||
|
||
typedef struct
|
||
{
|
||
bool is_show; //是否显示进度
|
||
uint total_size; //文件总共大小
|
||
uint dload_size; //已经下载大小
|
||
uint file_size; //上次升级中断保存的文件大小
|
||
}fota_http_progress_t;
|
||
typedef struct
|
||
{
|
||
http_client_t http_cli; //和http交互创建的struct http_client_s类型的指针
|
||
bool b_is_http_range; //是否发送http get range 报文
|
||
int profile_idx; //cid
|
||
uint8_t sim_id; //simid
|
||
char fota_packname[QL_FOTA_PACK_NAME_MAX_LEN]; //下载到本地的升级文件的位置
|
||
fota_http_progress_t http_progress; //http进度
|
||
e_fota_down_stage e_stage; //http下载固件包的阶段
|
||
QFILE fd; //写文件的文件描述符
|
||
int i_save_size; //在一次下载的过程中,分为多次写入,保存的是上次的写入大小,用于控制满多少字节写一次
|
||
uint last_precent; //下载最后一次百分比
|
||
bool b_is_have_space; //存储空间是否可用
|
||
int chunk_encode; //Transfer-Encoding:chunked 传输方式
|
||
}fota_http_client_t;
|
||
|
||
#define TRY_DOWN_TIMES 10
|
||
#define QL_VERSION_MAX 256
|
||
#define HTTP_HEAD_RANGE_LENGTH_MAX 50
|
||
#define QL_FOTA_HTTP_LOG(msg, ...) QL_LOG(QL_LOG_LEVEL_INFO, "ql_FOTA_http", msg, ##__VA_ARGS__)
|
||
#define HTTP_DLOAD_URL "http://49.235.127.120/output.pack"
|
||
#define WRITE_TO_FILESIZE (1024*5)
|
||
|
||
ql_sem_t fota_http_semp = NULL;
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_event_cb
|
||
* description :
|
||
* http响应报文的回调函数,当http请求返回的时候调用
|
||
* client [in] [http_client_t *] http句柄
|
||
* event [in] [http_event_id_e] http事件类型
|
||
* event_code [in] [http_error_code_e] http处理结果
|
||
* argv [in] [void *] ql_httpc_news传进来的参数
|
||
* infomation
|
||
*
|
||
************************************************************/
|
||
|
||
int fota_dload_file_clran(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
if ( fota_http_cli_p->fd < 0 )
|
||
{
|
||
QL_FOTA_HTTP_LOG("clran write file [%s] %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
|
||
fota_http_cli_p->fd = -1;
|
||
}
|
||
else
|
||
{
|
||
ql_fclose(fota_http_cli_p->fd);
|
||
ql_rtos_task_sleep_ms(10);
|
||
}
|
||
fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
|
||
if(fota_http_cli_p->fd < 0)
|
||
{
|
||
QL_FOTA_HTTP_LOG("clran open write file [%s] failed %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
|
||
return -1;
|
||
}
|
||
fota_http_cli_p->http_progress.file_size = 0;
|
||
fota_http_cli_p->http_progress.dload_size = 0;
|
||
fota_http_cli_p->http_progress.total_size = 0;
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNING;
|
||
fota_http_cli_p->i_save_size = 0;
|
||
QL_FOTA_HTTP_LOG("clran write file [%s] open fd %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
|
||
return 0;
|
||
}
|
||
|
||
static void fota_http_event_cb(http_client_t *client, int event, int event_code, void *argv)
|
||
{
|
||
if ( argv == NULL )
|
||
{
|
||
QL_FOTA_HTTP_LOG("fota_http_event_cb argv is null");
|
||
return;
|
||
}
|
||
fota_http_client_t* fota_http_cli_p = (fota_http_client_t*)argv;
|
||
|
||
if (*client != fota_http_cli_p->http_cli)
|
||
return;
|
||
|
||
switch (event)
|
||
{
|
||
case HTTP_EVENT_SESSION_ESTABLISH: {
|
||
if (event_code != HTTP_SUCCESS)
|
||
{
|
||
QL_FOTA_HTTP_LOG("HTTP session create failed!!!!! ");
|
||
//保存下载信息,如果不是无存储空间所致,设置为下载被中断状态
|
||
if ( fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_NOSPACE && fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_DOWNED )
|
||
{
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INTR;
|
||
}
|
||
ql_rtos_semaphore_release(fota_http_semp);
|
||
}
|
||
}
|
||
break;
|
||
case HTTP_EVENT_RESPONE_STATE_LINE: {
|
||
if (event_code == HTTP_SUCCESS)
|
||
{
|
||
int resp_code = 0;
|
||
int content_length = 0;
|
||
int chunk_encode = 0;
|
||
int accept_ranges = 0;
|
||
char *location = NULL;
|
||
ql_httpc_getinfo(client, HTTP_INFO_RESPONSE_CODE, &resp_code);
|
||
ql_httpc_getinfo(client, HTTP_INFO_CHUNK_ENCODE, &chunk_encode);
|
||
QL_FOTA_HTTP_LOG("response code:%d chunk_encode %d", resp_code,chunk_encode);
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNING;
|
||
if(resp_code == 200 || resp_code == 206)
|
||
{
|
||
if (chunk_encode == 0)
|
||
{
|
||
ql_httpc_getinfo(client, HTTP_INFO_ACCEPT_RANGES, &accept_ranges);
|
||
ql_httpc_getinfo(client, HTTP_INFO_CONTENT_LEN, &content_length);
|
||
if(accept_ranges == 1 && fota_http_cli_p->b_is_http_range == true)
|
||
{
|
||
fota_http_cli_p->http_progress.total_size += content_length;
|
||
}
|
||
else
|
||
{
|
||
if(fota_dload_file_clran(fota_http_cli_p) == 0)
|
||
{
|
||
fota_http_cli_p->http_progress.total_size = content_length;
|
||
}
|
||
else
|
||
{
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
}
|
||
}
|
||
QL_FOTA_HTTP_LOG("content_length:[%d] totalsize=[%d]",content_length ,fota_http_cli_p->http_progress.total_size);
|
||
}
|
||
else if (1 == chunk_encode)
|
||
{
|
||
QL_FOTA_HTTP_LOG("http chunk encode!");
|
||
fota_http_cli_p->chunk_encode = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
}
|
||
//返回码416提示416 Requested Range Not Satisfiable
|
||
if ( resp_code == 416 )
|
||
{
|
||
//发送已经最大了
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
}
|
||
if (resp_code >= 300 && resp_code < 400)
|
||
{
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
ql_httpc_getinfo(client, HTTP_INFO_LOCATION, &location);
|
||
QL_FOTA_HTTP_LOG("redirect location:%s", location);
|
||
free(location);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case HTTP_EVENT_SESSION_DISCONNECT: {
|
||
if (event_code == HTTP_SUCCESS)
|
||
{
|
||
//下载完成将配置文件设置为初始状态,只允许此种情况才能恢复为初始状态
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
QL_FOTA_HTTP_LOG("===http transfer end!!!!");
|
||
}
|
||
else
|
||
{
|
||
//保存下载信息,如果不是无存储空间所致,设置为下载被中断状态
|
||
if ( fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_NOSPACE && fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_DOWNED )
|
||
{
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INTR;
|
||
}
|
||
QL_FOTA_HTTP_LOG("===http transfer occur exception!!!!!");
|
||
}
|
||
ql_rtos_semaphore_release(fota_http_semp);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void fota_http_release()
|
||
{
|
||
ql_rtos_semaphore_delete(fota_http_semp);
|
||
//不设置成NULL 会导致restart
|
||
fota_http_semp = NULL ;
|
||
}
|
||
|
||
ql_fota_result_e fota_http_result_process(void)
|
||
{
|
||
ql_fota_result_e p_fota_result = 0;
|
||
|
||
//获取升级结果
|
||
if ( ql_fota_get_result(&p_fota_result) != QL_FOTA_SUCCESS )
|
||
{
|
||
QL_FOTA_HTTP_LOG("ql_fota_get_result failed ");
|
||
return QL_FOTA_STATUS_INVALID;
|
||
}
|
||
|
||
if ( p_fota_result == QL_FOTA_FINISHED )
|
||
{
|
||
QL_FOTA_HTTP_LOG("update finished");
|
||
ql_fota_file_reset(TRUE);
|
||
return QL_FOTA_FINISHED;
|
||
}
|
||
else if(p_fota_result == QL_FOTA_READY)
|
||
{
|
||
QL_FOTA_HTTP_LOG("fota ready bigen power reset ");
|
||
ql_rtos_task_sleep_s(5);
|
||
ql_power_reset(RESET_NORMAL);
|
||
}
|
||
else if(p_fota_result == QL_FOTA_NOT_EXIST)
|
||
{
|
||
QL_FOTA_HTTP_LOG("fota file not exist");
|
||
ql_fota_file_reset(TRUE);
|
||
return QL_FOTA_NOT_EXIST;
|
||
}
|
||
QL_FOTA_HTTP_LOG("fota result status invalid");
|
||
return QL_FOTA_STATUS_INVALID;
|
||
}
|
||
|
||
static int fota_http_get_fileszie(char *filename)
|
||
{
|
||
int file_size= 0;
|
||
QFILE fd = ql_fopen(filename,"rb");
|
||
if ( fd < 0 )
|
||
{
|
||
QL_FOTA_HTTP_LOG("open file name:[%s] ret = %d",filename,fd);
|
||
return -1;
|
||
}
|
||
file_size = ql_fsize(fd);
|
||
ql_fclose(fd);
|
||
return file_size;
|
||
}
|
||
|
||
int fota_http_init(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
QFILE fd = -1;
|
||
ql_rtos_semaphore_create(&fota_http_semp, 0);
|
||
//获取上次未完成下载信息
|
||
memset(fota_http_cli_p,0x00,sizeof(fota_http_client_t));
|
||
|
||
fota_http_cli_p->http_cli = 0; //http连接句柄
|
||
fota_http_cli_p->profile_idx = 1; //cid
|
||
fota_http_cli_p->sim_id = 0; //simid
|
||
fota_http_cli_p->e_stage =FOTA_HTTP_DOWN_INIT;
|
||
fota_http_cli_p->i_save_size = 0;
|
||
memcpy(fota_http_cli_p->fota_packname,"UFS:fota.pack",strlen("UFS:fota.pack")); //默认升级包地址
|
||
|
||
//存储空间开始默认为足够
|
||
fota_http_cli_p->b_is_have_space = true;
|
||
fota_http_cli_p->http_progress.is_show = true; //设置展示进度条
|
||
fota_http_cli_p->last_precent = 0;
|
||
fota_http_cli_p->chunk_encode = 0;
|
||
fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
|
||
if(fd < 0)
|
||
{
|
||
QL_FOTA_HTTP_LOG("init file name:[%s] ret: %d",fota_http_cli_p->fota_packname,fd);
|
||
return -1;
|
||
}
|
||
ql_fclose(fd);
|
||
QL_FOTA_HTTP_LOG("init file name:[%s]",fota_http_cli_p->fota_packname);
|
||
QL_FOTA_HTTP_LOG("init file size:[%d]",fota_http_get_fileszie(fota_http_cli_p->fota_packname));
|
||
QL_FOTA_HTTP_LOG("init file stage:[%d]",fota_http_cli_p->e_stage);
|
||
return 0;
|
||
}
|
||
|
||
static void fota_http_info_cfg(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
if ( fota_http_cli_p == NULL )
|
||
{
|
||
QL_FOTA_HTTP_LOG("fota_http_cli_p is null");
|
||
return;
|
||
}
|
||
QL_FOTA_HTTP_LOG("init file name:[%s]",fota_http_cli_p->fota_packname);
|
||
QL_FOTA_HTTP_LOG("init file stage:[%d]",fota_http_cli_p->e_stage);
|
||
QL_FOTA_HTTP_LOG("init file download:[%d]",fota_http_cli_p->http_progress.dload_size);
|
||
QL_FOTA_HTTP_LOG("init file file_size:[%d]",fota_http_cli_p->http_progress.file_size);
|
||
QL_FOTA_HTTP_LOG("init file real file_size:[%d]",fota_http_get_fileszie(fota_http_cli_p->fota_packname));
|
||
QL_FOTA_HTTP_LOG("init file is_show:[%d]",fota_http_cli_p->http_progress.is_show);
|
||
QL_FOTA_HTTP_LOG("init file last_percent:[%d]",fota_http_cli_p->last_precent);
|
||
QL_FOTA_HTTP_LOG("init file space:[%d]",fota_http_cli_p->b_is_have_space);
|
||
}
|
||
|
||
/********************************************************************
|
||
* funcname :fota_http_get_fd
|
||
* description :
|
||
* 打开升级包文件描述符,用于写入http下载升级包数据,
|
||
* 如果读取的上次保留的下载信息配置文件中的中断状态是初始状态、下载
|
||
* 已完成状态、或者是由于存储空间不够导致的下载失败状态,则删除上级包
|
||
* 重新下载重新覆盖写本地上次下载的升级包文件,其他的中断情况则启用追
|
||
* 加的方式重新请求升级包,追加升级包文件。
|
||
* fota_http_cli_p [in] [fota_http_client_t *] fota http客户端结构体
|
||
* return:
|
||
* 0 -- sucess
|
||
* other -- failed
|
||
**********************************************************************/
|
||
static QFILE fota_http_get_fd(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
if ( fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_INIT || fota_http_cli_p->e_stage ==FOTA_HTTP_DOWN_DOWNED \
|
||
||fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_NOSPACE )
|
||
{
|
||
//已经完成、初始化、或者是没有空间导致的下载中断以覆盖写来打开文件
|
||
fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
|
||
fota_http_cli_p->http_progress.file_size = 0;
|
||
fota_http_cli_p->http_progress.dload_size = 0;
|
||
fota_http_cli_p->http_progress.total_size = 0;
|
||
fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INIT;
|
||
fota_http_cli_p->i_save_size = 0;
|
||
QL_FOTA_HTTP_LOG("over write file [%s]",fota_http_cli_p->fota_packname);
|
||
}
|
||
else
|
||
{
|
||
//其他的情况是追加方式打开文件
|
||
fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "ab+");
|
||
QL_FOTA_HTTP_LOG("add write file [%s]",fota_http_cli_p->fota_packname);
|
||
}
|
||
if ( fota_http_cli_p->fd < 0 )
|
||
{
|
||
QL_FOTA_HTTP_LOG("ql_fopen failed");
|
||
}
|
||
return fota_http_cli_p->fd;
|
||
}
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_active
|
||
* description :
|
||
* 注册网络,拨号,初始化网络环境
|
||
* return:
|
||
* QL_DATACALL_SUCCESS -- sucess
|
||
* other -- failed
|
||
************************************************************/
|
||
static ql_datacall_errcode_e fota_http_active(uint8_t sim,int cid)
|
||
{
|
||
ql_datacall_errcode_e ret = QL_DATACALL_ACTIVE_FAIL_ERR;
|
||
//判断网络是否正常
|
||
if (ql_datacall_get_sim_profile_is_active(sim, cid) == false)
|
||
{
|
||
unsigned char num=0;
|
||
|
||
for ( num = 0 ; num < 10 ; num++ )
|
||
{
|
||
if ( (ret = ql_network_register_wait(sim, 120)) == QL_DATACALL_SUCCESS )
|
||
{
|
||
//注网成功跳出循环
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( ret != QL_DATACALL_SUCCESS )
|
||
{
|
||
return ret;
|
||
}
|
||
//设置拨号同步
|
||
if ( (ret = ql_set_data_call_asyn_mode(sim,cid,0)) != QL_DATACALL_SUCCESS )
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
num=0;
|
||
for ( num=0 ; num < 3 ; num++ )
|
||
{
|
||
if ( (ret = ql_start_data_call(sim, cid, QL_PDP_TYPE_IP, "uninet", NULL, NULL, 0)) == QL_DATACALL_SUCCESS )
|
||
{
|
||
//拨号成功跳出
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/********************************************************************
|
||
* funcname :fota_http_close_fd
|
||
* description :
|
||
* 关闭下载升级包的文件描述符
|
||
* fota_http_cli_p [in] [fota_http_client_t *] fota http客户端结构体
|
||
* return:
|
||
* 0 -- sucess
|
||
* other -- failed
|
||
**********************************************************************/
|
||
|
||
static void fota_http_close_fd(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
if ( fota_http_cli_p->fd > 0 )
|
||
{
|
||
ql_fclose(fota_http_cli_p->fd);
|
||
fota_http_cli_p->fd = -1;
|
||
}
|
||
}
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_write_file
|
||
* description :
|
||
* 将收到的数据写入文件中
|
||
************************************************************/
|
||
|
||
static int fota_http_write_file(fota_http_client_t* fota_cli_p ,char *data, int size, QFILE fd)
|
||
{
|
||
int ret = -1;
|
||
uint temp=0;
|
||
if(fota_cli_p->fd != fd)
|
||
{
|
||
QL_FOTA_HTTP_LOG("file fd error");
|
||
fota_http_close_fd(fota_cli_p);
|
||
return 0;
|
||
}
|
||
//写文件前休息1ms,以防永久阻塞
|
||
ql_rtos_task_sleep_ms(1);
|
||
QL_FOTA_HTTP_LOG("write [%d] size",size);
|
||
ret = ql_fwrite(data, size,1,fd);
|
||
QL_FOTA_HTTP_LOG("write ret=[%d]",ret);
|
||
if (ret > 0)
|
||
{
|
||
fota_cli_p->http_progress.dload_size += (uint)ret;
|
||
fota_cli_p->http_progress.file_size = ql_fsize(fd);
|
||
if ( fota_cli_p->http_progress.is_show == true )
|
||
{
|
||
if (1 != fota_cli_p->chunk_encode)
|
||
{
|
||
//计算进度,如果开启进度显示,那么会计算本次进度和上次进度是否相同,进度不同才会展示进度
|
||
temp = 100UL*fota_cli_p->http_progress.dload_size/fota_cli_p->http_progress.total_size;
|
||
if ( fota_cli_p->last_precent != temp || temp == 100 )
|
||
{
|
||
fota_cli_p->last_precent = temp;
|
||
QL_FOTA_HTTP_LOG("dload progress:===[%u%%]===total size[%d] file_size[%d] dload size[%d]",temp,fota_cli_p->http_progress.total_size,ql_fsize(fd),fota_cli_p->http_progress.dload_size );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
QL_FOTA_HTTP_LOG("dload progress:=== file_size[%d] dload size[%d] ===", ql_fsize(fd), fota_cli_p->http_progress.dload_size);
|
||
}
|
||
}
|
||
|
||
//保存文件,每一次满5k,保存一次写入的文件
|
||
if ( (fota_cli_p->i_save_size <= fota_cli_p->http_progress.dload_size)
|
||
|| ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->i_save_size >= fota_cli_p->http_progress.total_size) ) )
|
||
{
|
||
//满WRITE_TO_FILESIZE个字节保存一次
|
||
if ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->i_save_size >= fota_cli_p->http_progress.total_size) )
|
||
{
|
||
fota_cli_p->i_save_size = fota_cli_p->http_progress.total_size;
|
||
}
|
||
else
|
||
{
|
||
fota_cli_p->i_save_size=fota_cli_p->http_progress.dload_size+WRITE_TO_FILESIZE;
|
||
}
|
||
}
|
||
if ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->http_progress.dload_size >= fota_cli_p->http_progress.total_size) )
|
||
{
|
||
fota_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
}
|
||
if ( ret != size )
|
||
{
|
||
//关闭固件升级包的文件描述符
|
||
fota_http_close_fd(fota_cli_p);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
QL_FOTA_HTTP_LOG("error: ret:%d",ret);
|
||
//关闭固件升级包的文件描述符
|
||
fota_http_close_fd(fota_cli_p);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_write_response_data
|
||
* description :
|
||
* http响应报文,处理报文体的回调函数。
|
||
* client [in] [int] http请求的句柄
|
||
* argv [in] [void *] ql_httpc_setopt用HTTP_CLIENT_OPT_WRITE_DATA传递的参数
|
||
* data [in ] [char *] http响应的报文体数据
|
||
* size [in] [int] http响应报文体数据大小
|
||
* end [in] [int] 1 表示当前为最后一包数据 0 非最后一包数据
|
||
* 返回值: 实际处理的数据长度
|
||
*
|
||
************************************************************/
|
||
static int fota_http_write_response_data(http_client_t *client, void *argv, char *data, int size, unsigned char end)
|
||
{
|
||
|
||
int ret = -1;
|
||
int write_size = size ;
|
||
char * p_write_data= data;
|
||
int i_deal_size = WRITE_TO_FILESIZE;
|
||
int64 file_free_size=0;
|
||
if ( argv == NULL )
|
||
{
|
||
QL_FOTA_HTTP_LOG("fota_http_write_response_data argv is invalied NULL ");
|
||
return -2;
|
||
}
|
||
fota_http_client_t* fota_cli_p = (fota_http_client_t*)argv;
|
||
|
||
if ( (fota_cli_p->e_stage == FOTA_HTTP_DOWN_DOWNED)
|
||
|| (fota_cli_p->chunk_encode == 1 && end == 1) )
|
||
{
|
||
fota_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
|
||
//416提示资源已经超出长度,多余的314个字节的固件包数据不用写入文件。
|
||
QL_FOTA_HTTP_LOG("go on dload file finished",fota_cli_p->fota_packname);
|
||
//关闭本地固件升级包文件描述符
|
||
fota_http_close_fd(fota_cli_p);
|
||
return 0;
|
||
}
|
||
|
||
//获取当前剩余空间,如果不够直接不写文件
|
||
file_free_size = ql_fs_free_size(fota_cli_p->fota_packname);
|
||
if ( (1 != fota_cli_p->chunk_encode && file_free_size < (fota_cli_p->http_progress.total_size - fota_cli_p->http_progress.dload_size))
|
||
|| (1 == fota_cli_p->chunk_encode && file_free_size < size) )
|
||
{
|
||
if (1 != fota_cli_p->chunk_encode)
|
||
{
|
||
QL_FOTA_HTTP_LOG("free_space[%d] total_size [%d] dload_size[%d]",file_free_size,fota_cli_p->http_progress.total_size\
|
||
,fota_cli_p->http_progress.dload_size);
|
||
}
|
||
else
|
||
{
|
||
QL_FOTA_HTTP_LOG("free_space[%d] dload_size[%d]",file_free_size,fota_cli_p->http_progress.dload_size);
|
||
}
|
||
fota_cli_p->e_stage=FOTA_HTTP_DOWN_NOSPACE;
|
||
fota_cli_p->b_is_have_space = false;
|
||
QL_FOTA_HTTP_LOG("file free_size not enough");
|
||
fota_http_close_fd(fota_cli_p);
|
||
return 0;
|
||
}
|
||
|
||
if ( size <=0 )
|
||
{
|
||
QL_FOTA_HTTP_LOG("write 0 size to file [%s]",fota_cli_p->fota_packname);
|
||
//关闭本地固件升级包文件描述符
|
||
fota_http_close_fd(fota_cli_p);
|
||
return -1;
|
||
}
|
||
//在这儿也可以添加一个缓存池,将数据先写入缓存池(需要判断数据量是否大于缓存池的情况),当缓存池满了在写入文件,
|
||
//以防大量的小数据频繁写文件操作
|
||
//每次写1k
|
||
do {
|
||
if ( write_size < i_deal_size )
|
||
{
|
||
i_deal_size = write_size;
|
||
}
|
||
ret = fota_http_write_file(fota_cli_p ,p_write_data, i_deal_size, fota_cli_p->fd);
|
||
if ( ret < 0)
|
||
{
|
||
QL_FOTA_HTTP_LOG("write file error");
|
||
return size-write_size;
|
||
}
|
||
write_size -= ret;
|
||
p_write_data +=ret;
|
||
}while(write_size > 0);
|
||
return size-write_size;
|
||
}
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_active
|
||
* description :
|
||
* 初始化http请求的网络环境,组建http请求报文,发起http请求
|
||
* return:
|
||
* 0 -- sucess
|
||
* other -- failed
|
||
************************************************************/
|
||
static int fota_http_evn_request(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
char dload_range[HTTP_HEAD_RANGE_LENGTH_MAX] = {0};
|
||
http_method_e e_http_method;
|
||
uint8_t sim = fota_http_cli_p->sim_id;
|
||
int cid = fota_http_cli_p->profile_idx;
|
||
//发送http请求前创建存储升级包文件的文件描述符,别忘关闭
|
||
if ( fota_http_get_fd(fota_http_cli_p) < 0 )
|
||
{
|
||
QL_FOTA_HTTP_LOG("range_request http data done ,file_size[%d]",fota_http_cli_p->http_progress.file_size);
|
||
return -1;
|
||
}
|
||
//注网拨号
|
||
if ( QL_DATACALL_SUCCESS != fota_http_active(sim,cid) )
|
||
{
|
||
QL_FOTA_HTTP_LOG("http net is failed ");
|
||
fota_http_close_fd(fota_http_cli_p);
|
||
return -1;
|
||
}
|
||
|
||
//创建http请求句柄
|
||
if (ql_httpc_new(&(fota_http_cli_p->http_cli), fota_http_event_cb, fota_http_cli_p) != HTTP_SUCCESS)
|
||
{
|
||
QL_FOTA_HTTP_LOG("http create failed");
|
||
ql_httpc_release(&(fota_http_cli_p->http_cli));
|
||
fota_http_close_fd(fota_http_cli_p);
|
||
return -2;
|
||
}
|
||
//设置http请求方式为HTTP_METHOD_GET
|
||
e_http_method = HTTP_METHOD_GET;
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_METHOD,e_http_method);
|
||
|
||
//文件大小不为0,fota_http_get_fd已经限制了只有在下载被中断的情况下发生
|
||
if ( fota_http_cli_p->b_is_http_range == true )
|
||
{
|
||
//设置使用断电续传功能,使用上次下载未完成的最后下载信息
|
||
fota_http_cli_p->http_progress.dload_size = fota_http_cli_p->http_progress.file_size;
|
||
sprintf(dload_range, "Range: bytes=%d-",fota_http_cli_p->http_progress.file_size);
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_REQUEST_HEADER,dload_range);
|
||
QL_FOTA_HTTP_LOG("Get http %s",dload_range);
|
||
}
|
||
else
|
||
{
|
||
//不设置范围下载字段
|
||
}
|
||
//设置url下载地址
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_URL, HTTP_DLOAD_URL);
|
||
//设置sim_id
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_SIM_ID, fota_http_cli_p->sim_id);
|
||
//设置cid
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_PDPCID, fota_http_cli_p->profile_idx);
|
||
//接收报体中的文件内容
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_WRITE_FUNC, fota_http_write_response_data);
|
||
//设置fota_http_write_response_data 第二参数为fota_http_cli
|
||
ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_WRITE_DATA, fota_http_cli_p);
|
||
//发送http请求
|
||
if (ql_httpc_perform(&fota_http_cli_p->http_cli) == HTTP_SUCCESS)
|
||
{
|
||
//阻塞等待信号量
|
||
if ( ql_rtos_semaphore_wait(fota_http_semp, QL_WAIT_FOREVER) != QL_OSI_SUCCESS )
|
||
{
|
||
//获取信号量失败
|
||
ql_httpc_release(&(fota_http_cli_p->http_cli));
|
||
fota_http_close_fd(fota_http_cli_p);
|
||
return -1;
|
||
}
|
||
QL_FOTA_HTTP_LOG("fota http dload size %d=====End,\n",fota_http_cli_p->http_progress.dload_size);
|
||
ql_httpc_release(&(fota_http_cli_p->http_cli));
|
||
fota_http_close_fd(fota_http_cli_p);
|
||
return 0;
|
||
}
|
||
ql_httpc_release(&(fota_http_cli_p->http_cli));
|
||
fota_http_close_fd(fota_http_cli_p);
|
||
return -3;
|
||
}
|
||
|
||
/***********************************************************
|
||
* funcname :fota_http_download_pacfile
|
||
* description :
|
||
* 下载升级包主体函数
|
||
* return:
|
||
* 0 -- sucess 下载成功并且校验成功
|
||
*
|
||
* other -- failed
|
||
************************************************************/
|
||
static int fota_http_download_pacfile(fota_http_client_t* fota_http_cli_p)
|
||
{
|
||
fota_http_info_cfg(fota_http_cli_p);
|
||
//初始化http网络环境,组http请求报文,发送http请求,阻塞到下载完成或异常
|
||
if (fota_http_evn_request(fota_http_cli_p) != 0)
|
||
{
|
||
int file_size = fota_http_get_fileszie(fota_http_cli_p->fota_packname);
|
||
QL_FOTA_HTTP_LOG("failed [%s] size[%d]",fota_http_cli_p->fota_packname,file_size);
|
||
return -1;
|
||
}
|
||
fota_http_info_cfg(fota_http_cli_p);
|
||
//校验下载完成文件是否有效
|
||
if ( fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_DOWNED )
|
||
{
|
||
ql_errcode_fota_e ret = ql_fota_image_verify(fota_http_cli_p->fota_packname);
|
||
if ( ret != QL_FOTA_SUCCESS )
|
||
{
|
||
//下载完成校验不成功删除文件
|
||
ql_remove(fota_http_cli_p->fota_packname);
|
||
QL_FOTA_HTTP_LOG("[%s]package is invalid",fota_http_cli_p->fota_packname);
|
||
return -3;
|
||
}
|
||
else
|
||
{
|
||
//校验成功
|
||
QL_FOTA_HTTP_LOG("download is sucess ,system will reset power!");
|
||
ql_rtos_task_sleep_s(5);
|
||
ql_power_reset(RESET_NORMAL);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
int AppImageUpgradeFotaEntry(osiEvent_t *waitevent){
|
||
fota_http_client_t fota_http_cli;
|
||
uint8 ui_down_times = TRY_DOWN_TIMES;
|
||
char version_buf[QL_VERSION_MAX] = {0};
|
||
|
||
//获取升级结果
|
||
if(fota_http_result_process() == QL_FOTA_FINISHED)
|
||
{
|
||
goto exit;
|
||
}
|
||
|
||
ql_dev_get_firmware_version(version_buf, sizeof(version_buf));
|
||
QL_LOG(QL_LOG_LEVEL_ERROR, "[uart1_modbus_master]:" ,"current version: %s", version_buf);
|
||
|
||
//下载前初始化
|
||
if(fota_http_init(&fota_http_cli) != 0)
|
||
{
|
||
QL_LOG(QL_LOG_LEVEL_ERROR, "[uart1_modbus_master]:" ,"fota http init failed");
|
||
goto exit1;
|
||
}
|
||
|
||
//尝试下载最多十次
|
||
while( ui_down_times-- )
|
||
{
|
||
QL_LOG(QL_LOG_LEVEL_ERROR, "[uart1_modbus_master]:" ,"start [%d] times download fota packge",TRY_DOWN_TIMES-ui_down_times);
|
||
if ( fota_http_download_pacfile(&fota_http_cli) == 0 )
|
||
{
|
||
//下载完成
|
||
return 0;
|
||
}
|
||
|
||
if ( fota_http_cli.b_is_have_space != true )
|
||
{
|
||
//空间不够,删除文件
|
||
ql_remove(fota_http_cli.fota_packname);
|
||
QL_LOG(QL_LOG_LEVEL_ERROR, "[uart1_modbus_master]:" ,"have no space\n");
|
||
break;
|
||
}
|
||
ql_rtos_task_sleep_s(1);
|
||
}
|
||
|
||
exit1:
|
||
fota_http_release();
|
||
ql_rtos_task_sleep_s(1);
|
||
return -1;
|
||
exit:
|
||
QL_LOG(QL_LOG_LEVEL_ERROR, "[uart1_modbus_master]:" ,"exit ql_http_fota_demo\n");
|
||
return 0 ;
|
||
}
|