fota_http_demo.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. /*================================================================
  2. Copyright (c) 2021, Quectel Wireless Solutions Co., Ltd. All rights reserved.
  3. Quectel Wireless Solutions Proprietary and Confidential.
  4. =================================================================*/
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include "ql_type.h"
  9. #include "ql_api_osi.h"
  10. #include "ql_log.h"
  11. #include "ql_api_datacall.h"
  12. #include "ql_fs.h"
  13. #include "ql_power.h"
  14. #include "ql_api_dev.h"
  15. #include "ql_http_client.h"
  16. #include "ql_api_fota.h"
  17. #include "ql_app_feature_config.h"
  18. #ifdef QL_APP_FEATURE_SDMMC
  19. #include "ql_sdmmc.h"
  20. #endif
  21. #define QL_FOTA_HTTP_LOG_LEVEL QL_LOG_LEVEL_INFO
  22. #define QL_FOTA_HTTP_LOG(msg, ...) QL_LOG(QL_FOTA_HTTP_LOG_LEVEL, "ql_FOTA_http", msg, ##__VA_ARGS__)
  23. #define QL_FOTA_HTTP_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_FOTA_http", msg, ##__VA_ARGS__)
  24. #ifdef QL_APP_FEATURE_HTTP_FOTA
  25. #define TRY_DOWN_TIMES 10
  26. #define WRITE_TO_FILESIZE (1024*5)
  27. #define QL_VERSION_MAX 256
  28. #define HTTP_HEAD_RANGE_LENGTH_MAX 50
  29. #define HTTP_DLOAD_URL "http://49.235.127.120/output.pack"
  30. ql_task_t fota_http_task = NULL;
  31. ql_sem_t fota_http_semp = NULL;
  32. typedef enum
  33. {
  34. FOTA_HTTP_DOWN_INIT, //初始阶段
  35. FOTA_HTTP_DOWN_DOWNING, //下载中
  36. FOTA_HTTP_DOWN_INTR, //下载被中断
  37. FOTA_HTTP_DOWN_DOWNED, //下载完成
  38. FOTA_HTTP_DOWN_NOSPACE, //没有空间
  39. }e_fota_down_stage;
  40. typedef struct
  41. {
  42. bool is_show; //是否显示进度
  43. uint total_size; //文件总共大小
  44. uint dload_size; //已经下载大小
  45. uint file_size; //上次升级中断保存的文件大小
  46. }fota_http_progress_t;
  47. typedef struct
  48. {
  49. http_client_t http_cli; //和http交互创建的struct http_client_s类型的指针
  50. bool b_is_http_range; //是否发送http get range 报文
  51. int profile_idx; //cid
  52. uint8_t sim_id; //simid
  53. char fota_packname[QL_FOTA_PACK_NAME_MAX_LEN]; //下载到本地的升级文件的位置
  54. fota_http_progress_t http_progress; //http进度
  55. e_fota_down_stage e_stage; //http下载固件包的阶段
  56. QFILE fd; //写文件的文件描述符
  57. int i_save_size; //在一次下载的过程中,分为多次写入,保存的是上次的写入大小,用于控制满多少字节写一次
  58. uint last_precent; //下载最后一次百分比
  59. bool b_is_have_space; //存储空间是否可用
  60. int chunk_encode; //Transfer-Encoding:chunked 传输方式
  61. }fota_http_client_t;
  62. static int fota_http_get_fileszie(char *filename);
  63. static void fota_http_close_fd(fota_http_client_t* fota_http_cli_p);
  64. int fota_dload_file_clran(fota_http_client_t* fota_http_cli_p)
  65. {
  66. if ( fota_http_cli_p->fd < 0 )
  67. {
  68. QL_FOTA_HTTP_LOG("clran write file [%s] %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
  69. fota_http_cli_p->fd = -1;
  70. }
  71. else
  72. {
  73. ql_fclose(fota_http_cli_p->fd);
  74. ql_rtos_task_sleep_ms(10);
  75. }
  76. fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
  77. if(fota_http_cli_p->fd < 0)
  78. {
  79. QL_FOTA_HTTP_LOG("clran open write file [%s] failed %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
  80. return -1;
  81. }
  82. fota_http_cli_p->http_progress.file_size = 0;
  83. fota_http_cli_p->http_progress.dload_size = 0;
  84. fota_http_cli_p->http_progress.total_size = 0;
  85. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNING;
  86. fota_http_cli_p->i_save_size = 0;
  87. QL_FOTA_HTTP_LOG("clran write file [%s] open fd %d",fota_http_cli_p->fota_packname,fota_http_cli_p->fd);
  88. return 0;
  89. }
  90. static void fota_http_info_cfg(fota_http_client_t* fota_http_cli_p)
  91. {
  92. if ( fota_http_cli_p == NULL )
  93. {
  94. QL_FOTA_HTTP_LOG("fota_http_cli_p is null");
  95. return;
  96. }
  97. QL_FOTA_HTTP_LOG("init file name:[%s]",fota_http_cli_p->fota_packname);
  98. QL_FOTA_HTTP_LOG("init file stage:[%d]",fota_http_cli_p->e_stage);
  99. QL_FOTA_HTTP_LOG("init file download:[%d]",fota_http_cli_p->http_progress.dload_size);
  100. QL_FOTA_HTTP_LOG("init file file_size:[%d]",fota_http_cli_p->http_progress.file_size);
  101. QL_FOTA_HTTP_LOG("init file real file_size:[%d]",fota_http_get_fileszie(fota_http_cli_p->fota_packname));
  102. QL_FOTA_HTTP_LOG("init file is_show:[%d]",fota_http_cli_p->http_progress.is_show);
  103. QL_FOTA_HTTP_LOG("init file last_percent:[%d]",fota_http_cli_p->last_precent);
  104. QL_FOTA_HTTP_LOG("init file space:[%d]",fota_http_cli_p->b_is_have_space);
  105. }
  106. /***********************************************************
  107. * funcname :fota_http_event_cb
  108. * description :
  109. * http响应报文的回调函数,当http请求返回的时候调用
  110. * client [in] [http_client_t *] http句柄
  111. * event [in] [http_event_id_e] http事件类型
  112. * event_code [in] [http_error_code_e] http处理结果
  113. * argv [in] [void *] ql_httpc_news传进来的参数
  114. * infomation
  115. *
  116. ************************************************************/
  117. static void fota_http_event_cb(http_client_t *client, int event, int event_code, void *argv)
  118. {
  119. if ( argv == NULL )
  120. {
  121. QL_FOTA_HTTP_LOG("fota_http_event_cb argv is null");
  122. return;
  123. }
  124. fota_http_client_t* fota_http_cli_p = (fota_http_client_t*)argv;
  125. if (*client != fota_http_cli_p->http_cli)
  126. return;
  127. switch (event)
  128. {
  129. case HTTP_EVENT_SESSION_ESTABLISH: {
  130. if (event_code != QL_HTTP_OK)
  131. {
  132. QL_FOTA_HTTP_LOG("HTTP session create failed!!!!! ");
  133. //保存下载信息,如果不是无存储空间所致,设置为下载被中断状态
  134. if ( fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_NOSPACE && fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_DOWNED )
  135. {
  136. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INTR;
  137. }
  138. ql_rtos_semaphore_release(fota_http_semp);
  139. }
  140. }
  141. break;
  142. case HTTP_EVENT_RESPONE_STATE_LINE: {
  143. if (event_code == QL_HTTP_OK)
  144. {
  145. int resp_code = 0;
  146. int content_length = 0;
  147. int chunk_encode = 0;
  148. int accept_ranges = 0;
  149. char *location = NULL;
  150. ql_httpc_getinfo(client, HTTP_INFO_RESPONSE_CODE, &resp_code);
  151. ql_httpc_getinfo(client, HTTP_INFO_CHUNK_ENCODE, &chunk_encode);
  152. QL_FOTA_HTTP_LOG("response code:%d chunk_encode %d", resp_code,chunk_encode);
  153. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNING;
  154. if(resp_code == 200 || resp_code == 206)
  155. {
  156. if (chunk_encode == 0)
  157. {
  158. ql_httpc_getinfo(client, HTTP_INFO_ACCEPT_RANGES, &accept_ranges);
  159. ql_httpc_getinfo(client, HTTP_INFO_CONTENT_LEN, &content_length);
  160. if(accept_ranges == 1 && fota_http_cli_p->b_is_http_range == true)
  161. {
  162. fota_http_cli_p->http_progress.total_size += content_length;
  163. }
  164. else
  165. {
  166. if(fota_dload_file_clran(fota_http_cli_p) == 0)
  167. {
  168. fota_http_cli_p->http_progress.total_size = content_length;
  169. }
  170. else
  171. {
  172. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  173. }
  174. }
  175. QL_FOTA_HTTP_LOG("content_length:[%d] totalsize=[%d]",content_length ,fota_http_cli_p->http_progress.total_size);
  176. }
  177. else if (1 == chunk_encode)
  178. {
  179. QL_FOTA_HTTP_LOG("http chunk encode!");
  180. fota_http_cli_p->chunk_encode = 1;
  181. }
  182. }
  183. else
  184. {
  185. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  186. }
  187. //返回码416提示416 Requested Range Not Satisfiable
  188. if ( resp_code == 416 )
  189. {
  190. //发送已经最大了
  191. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  192. }
  193. if (resp_code >= 300 && resp_code < 400)
  194. {
  195. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  196. ql_httpc_getinfo(client, HTTP_INFO_LOCATION, &location);
  197. QL_FOTA_HTTP_LOG("redirect location:%s", location);
  198. free(location);
  199. }
  200. }
  201. }
  202. break;
  203. case HTTP_EVENT_SESSION_DISCONNECT: {
  204. if (event_code == QL_HTTP_OK)
  205. {
  206. //下载完成将配置文件设置为初始状态,只允许此种情况才能恢复为初始状态
  207. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  208. QL_FOTA_HTTP_LOG("===http transfer end!!!!");
  209. }
  210. else
  211. {
  212. //保存下载信息,如果不是无存储空间所致,设置为下载被中断状态
  213. if ( fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_NOSPACE && fota_http_cli_p->e_stage != FOTA_HTTP_DOWN_DOWNED )
  214. {
  215. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INTR;
  216. }
  217. QL_FOTA_HTTP_LOG("===http transfer occur exception!!!!!");
  218. }
  219. ql_rtos_semaphore_release(fota_http_semp);
  220. }
  221. break;
  222. }
  223. }
  224. /***********************************************************
  225. * funcname :fota_http_write_file
  226. * description :
  227. * 将收到的数据写入文件中
  228. ************************************************************/
  229. static int fota_http_write_file(fota_http_client_t* fota_cli_p ,char *data, int size, QFILE fd)
  230. {
  231. int ret = -1;
  232. uint temp=0;
  233. if(fota_cli_p->fd != fd)
  234. {
  235. QL_FOTA_HTTP_LOG("file fd error");
  236. fota_http_close_fd(fota_cli_p);
  237. return 0;
  238. }
  239. //写文件前休息1ms,以防永久阻塞
  240. ql_rtos_task_sleep_ms(1);
  241. QL_FOTA_HTTP_LOG("write [%d] size",size);
  242. ret = ql_fwrite(data, size,1,fd);
  243. QL_FOTA_HTTP_LOG("write ret=[%d]",ret);
  244. if (ret > 0)
  245. {
  246. fota_cli_p->http_progress.dload_size += (uint)ret;
  247. fota_cli_p->http_progress.file_size = ql_fsize(fd);
  248. if ( fota_cli_p->http_progress.is_show == true )
  249. {
  250. if (1 != fota_cli_p->chunk_encode)
  251. {
  252. //计算进度,如果开启进度显示,那么会计算本次进度和上次进度是否相同,进度不同才会展示进度
  253. temp = 100UL*fota_cli_p->http_progress.dload_size/fota_cli_p->http_progress.total_size;
  254. if ( fota_cli_p->last_precent != temp || temp == 100 )
  255. {
  256. fota_cli_p->last_precent = temp;
  257. 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 );
  258. }
  259. }
  260. else
  261. {
  262. QL_FOTA_HTTP_LOG("dload progress:=== file_size[%d] dload size[%d] ===", ql_fsize(fd), fota_cli_p->http_progress.dload_size);
  263. }
  264. }
  265. //保存文件,每一次满5k,保存一次写入的文件
  266. if ( (fota_cli_p->i_save_size <= fota_cli_p->http_progress.dload_size)
  267. || ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->i_save_size >= fota_cli_p->http_progress.total_size) ) )
  268. {
  269. //满WRITE_TO_FILESIZE个字节保存一次
  270. if ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->i_save_size >= fota_cli_p->http_progress.total_size) )
  271. {
  272. fota_cli_p->i_save_size = fota_cli_p->http_progress.total_size;
  273. }
  274. else
  275. {
  276. fota_cli_p->i_save_size=fota_cli_p->http_progress.dload_size+WRITE_TO_FILESIZE;
  277. }
  278. }
  279. if ( (1 != fota_cli_p->chunk_encode) && (fota_cli_p->http_progress.dload_size >= fota_cli_p->http_progress.total_size) )
  280. {
  281. fota_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  282. }
  283. if ( ret != size )
  284. {
  285. //关闭固件升级包的文件描述符
  286. fota_http_close_fd(fota_cli_p);
  287. }
  288. }
  289. else
  290. {
  291. QL_FOTA_HTTP_LOG("error: ret:%d",ret);
  292. //关闭固件升级包的文件描述符
  293. fota_http_close_fd(fota_cli_p);
  294. }
  295. return ret;
  296. }
  297. /***********************************************************
  298. * funcname :fota_http_write_response_data
  299. * description :
  300. * http响应报文,处理报文体的回调函数。
  301. * client [in] [int] http请求的句柄
  302. * argv [in] [void *] ql_httpc_setopt用HTTP_CLIENT_OPT_WRITE_DATA传递的参数
  303. * data [in ] [char *] http响应的报文体数据
  304. * size [in] [int] http响应报文体数据大小
  305. * end [in] [int] 1 表示当前为最后一包数据 0 非最后一包数据
  306. * 返回值: 实际处理的数据长度
  307. *
  308. ************************************************************/
  309. static int fota_http_write_response_data(http_client_t *client, void *argv, char *data, int size, unsigned char end)
  310. {
  311. int ret = -1;
  312. int write_size = size ;
  313. char * p_write_data= data;
  314. int i_deal_size = WRITE_TO_FILESIZE;
  315. int64 file_free_size=0;
  316. if ( argv == NULL )
  317. {
  318. QL_FOTA_HTTP_LOG("fota_http_write_response_data argv is invalied NULL ");
  319. return -2;
  320. }
  321. fota_http_client_t* fota_cli_p = (fota_http_client_t*)argv;
  322. if ( (fota_cli_p->e_stage == FOTA_HTTP_DOWN_DOWNED)
  323. || (fota_cli_p->chunk_encode == 1 && end == 1) )
  324. {
  325. fota_cli_p->e_stage = FOTA_HTTP_DOWN_DOWNED;
  326. //416提示资源已经超出长度,多余的314个字节的固件包数据不用写入文件。
  327. QL_FOTA_HTTP_LOG("go on dload file finished",fota_cli_p->fota_packname);
  328. //关闭本地固件升级包文件描述符
  329. fota_http_close_fd(fota_cli_p);
  330. return 0;
  331. }
  332. //获取当前剩余空间,如果不够直接不写文件
  333. file_free_size = ql_fs_free_size(fota_cli_p->fota_packname);
  334. if ( (1 != fota_cli_p->chunk_encode && file_free_size < (fota_cli_p->http_progress.total_size - fota_cli_p->http_progress.dload_size))
  335. || (1 == fota_cli_p->chunk_encode && file_free_size < size) )
  336. {
  337. if (1 != fota_cli_p->chunk_encode)
  338. {
  339. QL_FOTA_HTTP_LOG("free_space[%d] total_size [%d] dload_size[%d]",file_free_size,fota_cli_p->http_progress.total_size\
  340. ,fota_cli_p->http_progress.dload_size);
  341. }
  342. else
  343. {
  344. QL_FOTA_HTTP_LOG("free_space[%d] dload_size[%d]",file_free_size,fota_cli_p->http_progress.dload_size);
  345. }
  346. fota_cli_p->e_stage=FOTA_HTTP_DOWN_NOSPACE;
  347. fota_cli_p->b_is_have_space = false;
  348. QL_FOTA_HTTP_LOG("file free_size not enough");
  349. fota_http_close_fd(fota_cli_p);
  350. return 0;
  351. }
  352. if ( size <=0 )
  353. {
  354. QL_FOTA_HTTP_LOG("write 0 size to file [%s]",fota_cli_p->fota_packname);
  355. //关闭本地固件升级包文件描述符
  356. fota_http_close_fd(fota_cli_p);
  357. return -1;
  358. }
  359. //在这儿也可以添加一个缓存池,将数据先写入缓存池(需要判断数据量是否大于缓存池的情况),当缓存池满了在写入文件,
  360. //以防大量的小数据频繁写文件操作
  361. //每次写1k
  362. do {
  363. if ( write_size < i_deal_size )
  364. {
  365. i_deal_size = write_size;
  366. }
  367. ret = fota_http_write_file(fota_cli_p ,p_write_data, i_deal_size, fota_cli_p->fd);
  368. if ( ret < 0)
  369. {
  370. QL_FOTA_HTTP_LOG("write file error");
  371. return size-write_size;
  372. }
  373. write_size -= ret;
  374. p_write_data +=ret;
  375. }while(write_size > 0);
  376. return size-write_size;
  377. }
  378. int fota_http_init(fota_http_client_t* fota_http_cli_p)
  379. {
  380. QFILE fd = -1;
  381. ql_rtos_semaphore_create(&fota_http_semp, 0);
  382. //获取上次未完成下载信息
  383. memset(fota_http_cli_p,0x00,sizeof(fota_http_client_t));
  384. fota_http_cli_p->http_cli = 0; //http连接句柄
  385. fota_http_cli_p->profile_idx = 1; //cid
  386. fota_http_cli_p->sim_id = 0; //simid
  387. fota_http_cli_p->e_stage =FOTA_HTTP_DOWN_INIT;
  388. fota_http_cli_p->i_save_size = 0;
  389. memcpy(fota_http_cli_p->fota_packname,"UFS:fota.pack",strlen("UFS:fota.pack")); //默认升级包地址
  390. //存储空间开始默认为足够
  391. fota_http_cli_p->b_is_have_space = true;
  392. fota_http_cli_p->http_progress.is_show = true; //设置展示进度条
  393. fota_http_cli_p->last_precent = 0;
  394. fota_http_cli_p->chunk_encode = 0;
  395. fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
  396. if(fd < 0)
  397. {
  398. QL_FOTA_HTTP_LOG("init file name:[%s] ret: %d",fota_http_cli_p->fota_packname,fd);
  399. return -1;
  400. }
  401. ql_fclose(fd);
  402. QL_FOTA_HTTP_LOG("init file name:[%s]",fota_http_cli_p->fota_packname);
  403. QL_FOTA_HTTP_LOG("init file size:[%d]",fota_http_get_fileszie(fota_http_cli_p->fota_packname));
  404. QL_FOTA_HTTP_LOG("init file stage:[%d]",fota_http_cli_p->e_stage);
  405. return 0;
  406. }
  407. static void fota_http_release()
  408. {
  409. ql_rtos_semaphore_delete(fota_http_semp);
  410. //不设置成NULL 会导致restart
  411. fota_http_semp = NULL ;
  412. }
  413. static int fota_http_get_fileszie(char *filename)
  414. {
  415. int file_size= 0;
  416. QFILE fd = ql_fopen(filename,"rb");
  417. if ( fd < 0 )
  418. {
  419. QL_FOTA_HTTP_LOG("open file name:[%s] ret = %d",filename,fd);
  420. return -1;
  421. }
  422. file_size = ql_fsize(fd);
  423. ql_fclose(fd);
  424. return file_size;
  425. }
  426. /***********************************************************
  427. * funcname :fota_http_active
  428. * description :
  429. * 注册网络,拨号,初始化网络环境
  430. * return:
  431. * QL_DATACALL_SUCCESS -- sucess
  432. * other -- failed
  433. ************************************************************/
  434. static ql_datacall_errcode_e fota_http_active(uint8_t sim,int cid)
  435. {
  436. ql_datacall_errcode_e ret = QL_DATACALL_ACTIVE_FAIL_ERR;
  437. //判断网络是否正常
  438. if (ql_datacall_get_sim_profile_is_active(sim, cid) == false)
  439. {
  440. unsigned char num=0;
  441. for ( num = 0 ; num < 10 ; num++ )
  442. {
  443. if ( (ret = ql_network_register_wait(sim, 120)) == QL_DATACALL_SUCCESS )
  444. {
  445. //注网成功跳出循环
  446. break;
  447. }
  448. }
  449. if ( ret != QL_DATACALL_SUCCESS )
  450. {
  451. return ret;
  452. }
  453. //设置拨号同步
  454. if ( (ret = ql_set_data_call_asyn_mode(sim,cid,0)) != QL_DATACALL_SUCCESS )
  455. {
  456. return ret;
  457. }
  458. num=0;
  459. for ( num=0 ; num < 3 ; num++ )
  460. {
  461. if ( (ret = ql_start_data_call(sim, cid, QL_PDP_TYPE_IP, "uninet", NULL, NULL, 0)) == QL_DATACALL_SUCCESS )
  462. {
  463. //拨号成功跳出
  464. break;
  465. }
  466. }
  467. }
  468. return ret;
  469. }
  470. /********************************************************************
  471. * funcname :fota_http_get_fd
  472. * description :
  473. * 打开升级包文件描述符,用于写入http下载升级包数据,
  474. * 如果读取的上次保留的下载信息配置文件中的中断状态是初始状态、下载
  475. * 已完成状态、或者是由于存储空间不够导致的下载失败状态,则删除上级包
  476. * 重新下载重新覆盖写本地上次下载的升级包文件,其他的中断情况则启用追
  477. * 加的方式重新请求升级包,追加升级包文件。
  478. * fota_http_cli_p [in] [fota_http_client_t *] fota http客户端结构体
  479. * return:
  480. * 0 -- sucess
  481. * other -- failed
  482. **********************************************************************/
  483. static QFILE fota_http_get_fd(fota_http_client_t* fota_http_cli_p)
  484. {
  485. if ( fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_INIT || fota_http_cli_p->e_stage ==FOTA_HTTP_DOWN_DOWNED \
  486. ||fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_NOSPACE )
  487. {
  488. //已经完成、初始化、或者是没有空间导致的下载中断以覆盖写来打开文件
  489. fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "wb+");
  490. fota_http_cli_p->http_progress.file_size = 0;
  491. fota_http_cli_p->http_progress.dload_size = 0;
  492. fota_http_cli_p->http_progress.total_size = 0;
  493. fota_http_cli_p->e_stage = FOTA_HTTP_DOWN_INIT;
  494. fota_http_cli_p->i_save_size = 0;
  495. QL_FOTA_HTTP_LOG("over write file [%s]",fota_http_cli_p->fota_packname);
  496. }
  497. else
  498. {
  499. //其他的情况是追加方式打开文件
  500. fota_http_cli_p->fd = ql_fopen(fota_http_cli_p->fota_packname, "ab+");
  501. QL_FOTA_HTTP_LOG("add write file [%s]",fota_http_cli_p->fota_packname);
  502. }
  503. if ( fota_http_cli_p->fd < 0 )
  504. {
  505. QL_FOTA_HTTP_LOG("ql_fopen failed");
  506. }
  507. return fota_http_cli_p->fd;
  508. }
  509. /********************************************************************
  510. * funcname :fota_http_close_fd
  511. * description :
  512. * 关闭下载升级包的文件描述符
  513. * fota_http_cli_p [in] [fota_http_client_t *] fota http客户端结构体
  514. * return:
  515. * 0 -- sucess
  516. * other -- failed
  517. **********************************************************************/
  518. static void fota_http_close_fd(fota_http_client_t* fota_http_cli_p)
  519. {
  520. if ( fota_http_cli_p->fd > 0 )
  521. {
  522. ql_fclose(fota_http_cli_p->fd);
  523. fota_http_cli_p->fd = -1;
  524. }
  525. }
  526. /***********************************************************
  527. * funcname :fota_http_active
  528. * description :
  529. * 初始化http请求的网络环境,组建http请求报文,发起http请求
  530. * return:
  531. * 0 -- sucess
  532. * other -- failed
  533. ************************************************************/
  534. static int fota_http_evn_request(fota_http_client_t* fota_http_cli_p)
  535. {
  536. char dload_range[HTTP_HEAD_RANGE_LENGTH_MAX] = {0};
  537. http_method_e e_http_method;
  538. uint8_t sim = fota_http_cli_p->sim_id;
  539. int cid = fota_http_cli_p->profile_idx;
  540. //发送http请求前创建存储升级包文件的文件描述符,别忘关闭
  541. if ( fota_http_get_fd(fota_http_cli_p) < 0 )
  542. {
  543. QL_FOTA_HTTP_LOG("range_request http data done ,file_size[%d]",fota_http_cli_p->http_progress.file_size);
  544. return -1;
  545. }
  546. //注网拨号
  547. if ( QL_DATACALL_SUCCESS != fota_http_active(sim,cid) )
  548. {
  549. QL_FOTA_HTTP_LOG("http net is failed ");
  550. fota_http_close_fd(fota_http_cli_p);
  551. return -1;
  552. }
  553. //创建http请求句柄
  554. if (ql_httpc_new(&(fota_http_cli_p->http_cli), fota_http_event_cb, fota_http_cli_p) != QL_HTTP_OK)
  555. {
  556. QL_FOTA_HTTP_LOG("http create failed");
  557. ql_httpc_release(&(fota_http_cli_p->http_cli));
  558. fota_http_close_fd(fota_http_cli_p);
  559. return -2;
  560. }
  561. //设置http请求方式为HTTP_METHOD_GET
  562. e_http_method = HTTP_METHOD_GET;
  563. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_METHOD,e_http_method);
  564. //文件大小不为0,fota_http_get_fd已经限制了只有在下载被中断的情况下发生
  565. if ( fota_http_cli_p->b_is_http_range == true )
  566. {
  567. //设置使用断电续传功能,使用上次下载未完成的最后下载信息
  568. fota_http_cli_p->http_progress.dload_size = fota_http_cli_p->http_progress.file_size;
  569. sprintf(dload_range, "Range: bytes=%d-",fota_http_cli_p->http_progress.file_size);
  570. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_REQUEST_HEADER,dload_range);
  571. QL_FOTA_HTTP_LOG("Get http %s",dload_range);
  572. }
  573. else
  574. {
  575. //不设置范围下载字段
  576. }
  577. //设置url下载地址
  578. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_URL, HTTP_DLOAD_URL);
  579. //设置sim_id
  580. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_SIM_ID, fota_http_cli_p->sim_id);
  581. //设置cid
  582. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_PDPCID, fota_http_cli_p->profile_idx);
  583. //接收报体中的文件内容
  584. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_WRITE_FUNC, fota_http_write_response_data);
  585. //设置fota_http_write_response_data 第二参数为fota_http_cli
  586. ql_httpc_setopt(&(fota_http_cli_p->http_cli), HTTP_CLIENT_OPT_WRITE_DATA, fota_http_cli_p);
  587. //发送http请求
  588. if (ql_httpc_perform(&fota_http_cli_p->http_cli) == QL_HTTP_OK)
  589. {
  590. //阻塞等待信号量
  591. if ( ql_rtos_semaphore_wait(fota_http_semp, QL_WAIT_FOREVER) != QL_OSI_SUCCESS )
  592. {
  593. //获取信号量失败
  594. ql_httpc_release(&(fota_http_cli_p->http_cli));
  595. fota_http_close_fd(fota_http_cli_p);
  596. return -1;
  597. }
  598. QL_FOTA_HTTP_LOG("fota http dload size %d=====End,\n",fota_http_cli_p->http_progress.dload_size);
  599. ql_httpc_release(&(fota_http_cli_p->http_cli));
  600. fota_http_close_fd(fota_http_cli_p);
  601. return 0;
  602. }
  603. ql_httpc_release(&(fota_http_cli_p->http_cli));
  604. fota_http_close_fd(fota_http_cli_p);
  605. return -3;
  606. }
  607. /***********************************************************
  608. * funcname :fota_http_download_pacfile
  609. * description :
  610. * 下载升级包主体函数
  611. * return:
  612. * 0 -- sucess 下载成功并且校验成功
  613. *
  614. * other -- failed
  615. ************************************************************/
  616. static int fota_http_download_pacfile(fota_http_client_t* fota_http_cli_p)
  617. {
  618. fota_http_info_cfg(fota_http_cli_p);
  619. //初始化http网络环境,组http请求报文,发送http请求,阻塞到下载完成或异常
  620. if (fota_http_evn_request(fota_http_cli_p) != 0)
  621. {
  622. int file_size = fota_http_get_fileszie(fota_http_cli_p->fota_packname);
  623. QL_FOTA_HTTP_LOG("failed [%s] size[%d]",fota_http_cli_p->fota_packname,file_size);
  624. return -1;
  625. }
  626. fota_http_info_cfg(fota_http_cli_p);
  627. //校验下载完成文件是否有效
  628. if ( fota_http_cli_p->e_stage == FOTA_HTTP_DOWN_DOWNED )
  629. {
  630. ql_errcode_fota_e ret = ql_fota_image_verify(fota_http_cli_p->fota_packname);
  631. if ( ret != QL_FOTA_SUCCESS )
  632. {
  633. //下载完成校验不成功删除文件
  634. ql_remove(fota_http_cli_p->fota_packname);
  635. QL_FOTA_HTTP_LOG("[%s]package is invalid",fota_http_cli_p->fota_packname);
  636. return -3;
  637. }
  638. else
  639. {
  640. //校验成功
  641. QL_FOTA_HTTP_LOG("download is sucess ,system will reset power!");
  642. ql_rtos_task_sleep_s(5);
  643. ql_power_reset(RESET_NORMAL);
  644. }
  645. }
  646. return 0;
  647. }
  648. ql_fota_result_e fota_http_result_process(void)
  649. {
  650. ql_fota_result_e p_fota_result = 0;
  651. //获取升级结果
  652. if ( ql_fota_get_result(&p_fota_result) != QL_FOTA_SUCCESS )
  653. {
  654. QL_FOTA_HTTP_LOG("ql_fota_get_result failed ");
  655. return QL_FOTA_STATUS_INVALID;
  656. }
  657. if ( p_fota_result == QL_FOTA_FINISHED )
  658. {
  659. QL_FOTA_HTTP_LOG("update finished");
  660. ql_fota_file_reset(TRUE);
  661. return QL_FOTA_FINISHED;
  662. }
  663. else if(p_fota_result == QL_FOTA_READY)
  664. {
  665. QL_FOTA_HTTP_LOG("fota ready bigen power reset ");
  666. ql_rtos_task_sleep_s(5);
  667. ql_power_reset(RESET_NORMAL);
  668. }
  669. else if(p_fota_result == QL_FOTA_NOT_EXIST)
  670. {
  671. QL_FOTA_HTTP_LOG("fota file not exist");
  672. ql_fota_file_reset(TRUE);
  673. return QL_FOTA_NOT_EXIST;
  674. }
  675. QL_FOTA_HTTP_LOG("fota result status invalid");
  676. return QL_FOTA_STATUS_INVALID;
  677. }
  678. void fota_http_app_thread()
  679. {
  680. ql_rtos_task_sleep_s(5);
  681. #ifdef QL_APP_FEATURE_SDMMC
  682. QL_FOTA_HTTP_LOG("ql sdmmc mount : %d",ql_sdmmc_mount());
  683. #endif
  684. fota_http_client_t fota_http_cli;
  685. uint8 ui_down_times = TRY_DOWN_TIMES;
  686. char version_buf[QL_VERSION_MAX] = {0};
  687. //获取升级结果
  688. if(fota_http_result_process() == QL_FOTA_FINISHED)
  689. {
  690. goto exit;
  691. }
  692. ql_dev_get_firmware_version(version_buf, sizeof(version_buf));
  693. QL_FOTA_HTTP_LOG("current version: %s", version_buf);
  694. //下载前初始化
  695. if(fota_http_init(&fota_http_cli) != 0)
  696. {
  697. QL_FOTA_HTTP_LOG("fota http init failed");
  698. goto exit1;
  699. }
  700. //尝试下载最多十次
  701. while( ui_down_times-- )
  702. {
  703. QL_FOTA_HTTP_LOG("start [%d] times download fota packge",TRY_DOWN_TIMES-ui_down_times);
  704. if ( fota_http_download_pacfile(&fota_http_cli) == 0 )
  705. {
  706. //下载完成
  707. break;
  708. }
  709. if ( fota_http_cli.b_is_have_space != true )
  710. {
  711. //空间不够,删除文件
  712. ql_remove(fota_http_cli.fota_packname);
  713. QL_FOTA_HTTP_LOG("have no space");
  714. break;
  715. }
  716. //下载失败等待10s重新开始下载
  717. ql_rtos_task_sleep_s(5);
  718. }
  719. //下载失败等待10s重新开始下载
  720. exit1:
  721. fota_http_release();
  722. ql_rtos_task_sleep_s(5);
  723. exit:
  724. QL_FOTA_HTTP_LOG("exit ql_http_fota_demo");
  725. ql_rtos_task_delete(fota_http_task);
  726. }
  727. #endif
  728. void ql_fota_http_app_init()
  729. {
  730. #ifdef QL_APP_FEATURE_HTTP_FOTA
  731. QL_FOTA_HTTP_LOG("http fota demo support!");
  732. QlOSStatus err = QL_OSI_SUCCESS;
  733. err = ql_rtos_task_create(&fota_http_task, 4096*32, APP_PRIORITY_NORMAL, "QfotaHttp", fota_http_app_thread, NULL, 5);
  734. if (err != QL_OSI_SUCCESS)
  735. {
  736. QL_FOTA_HTTP_LOG("created task failed");
  737. }
  738. #else
  739. QL_FOTA_HTTP_LOG("http fota demo not support!");
  740. #endif
  741. }