fotax.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Copyright (C) 2019-2020 Alibaba Group Holding Limited
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <time.h>
  8. #include <cJSON.h>
  9. #include <yoc/fota.h>
  10. #include <ulog/ulog.h>
  11. #include <aos/kv.h>
  12. #include <yoc/sysinfo.h>
  13. #include <aos/version.h>
  14. #include "fotax.h"
  15. #define TAG "fotax"
  16. struct timespec diff_timespec(struct timespec start, struct timespec end)
  17. {
  18. struct timespec result;
  19. if (end.tv_nsec < start.tv_nsec)
  20. {
  21. result.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
  22. result.tv_sec = end.tv_sec - 1 - start.tv_sec;
  23. }
  24. else
  25. {
  26. result.tv_nsec = end.tv_nsec - start.tv_nsec;
  27. result.tv_sec = end.tv_sec - start.tv_sec;
  28. }
  29. return result;
  30. }
  31. static int fota_event_cb(void *arg, fota_event_e event)
  32. {
  33. static int data_offset;
  34. static struct timespec tv;
  35. fota_t *fota = (fota_t *)arg;
  36. fotax_t *fotax = (fotax_t *)fota->private;
  37. if (!fotax->fotax_event_cb) {
  38. LOGE(TAG, "fotax event callback is NULL.");
  39. return -1;
  40. }
  41. switch (event) {
  42. case FOTA_EVENT_START:
  43. LOGD(TAG, "FOTA START :%x", fota->status);
  44. break;
  45. case FOTA_EVENT_VERSION:
  46. {
  47. LOGD(TAG, "FOTA VERSION CHECK :%x", fota->status);
  48. data_offset = 0;
  49. memset(&tv, 0, sizeof(struct timespec));
  50. cJSON *root = cJSON_CreateObject();
  51. if (fota->error_code != FOTA_ERROR_NULL) {
  52. cJSON_AddNumberToObject(root, "code", 1);
  53. cJSON_AddStringToObject(root, "msg", "version check failed!");
  54. } else {
  55. cJSON_AddNumberToObject(root, "code", 0);
  56. cJSON_AddStringToObject(root, "curversion", fota->info.cur_version);
  57. cJSON_AddStringToObject(root, "newversion", fota->info.new_version);
  58. cJSON_AddNumberToObject(root, "timestamp", fota->info.timestamp);
  59. cJSON_AddStringToObject(root, "changelog", fota->info.changelog);
  60. cJSON_AddStringToObject(root, "local_changelog", fota->info.local_changelog);
  61. }
  62. char *out = cJSON_PrintUnformatted(root);
  63. cJSON_Delete(root);
  64. if (out != NULL) {
  65. fotax->fotax_event_cb(fotax, FOTAX_EVENT_VERSION, out);
  66. cJSON_free(out);
  67. } else {
  68. fotax->fotax_event_cb(fotax, FOTAX_EVENT_VERSION, "{\"code\": 1, \"msg\": \"(version)JSON print error!\"}");
  69. }
  70. break;
  71. }
  72. case FOTA_EVENT_PROGRESS:
  73. {
  74. LOGD(TAG, "FOTA PROGRESS :%x, %d, %d", fota->status, fota->offset, fota->total_size);
  75. int64_t cur_size = fota->offset;
  76. int64_t total_size = fota->total_size;
  77. int speed = 0; //kbps
  78. int percent = 0;
  79. if (total_size > 0) {
  80. percent = (int)(cur_size * 100 / total_size);
  81. }
  82. cJSON *root = cJSON_CreateObject();
  83. if (fota->error_code != FOTA_ERROR_NULL) {
  84. cJSON_AddNumberToObject(root, "code", 1);
  85. if (fota->error_code == FOTA_ERROR_VERIFY) {
  86. cJSON_AddStringToObject(root, "msg", "fota image verify failed!");
  87. } else {
  88. cJSON_AddStringToObject(root, "msg", "download failed!");
  89. }
  90. cJSON_AddNumberToObject(root, "total_size", total_size);
  91. cJSON_AddNumberToObject(root, "cur_size", cur_size);
  92. cJSON_AddNumberToObject(root, "percent", percent);
  93. } else {
  94. // current_size, total_size, percent, speed
  95. struct timespec now;
  96. clock_gettime(CLOCK_MONOTONIC, &now);
  97. if (tv.tv_sec > 0 && tv.tv_nsec > 0 && data_offset > 0) {
  98. struct timespec diff = diff_timespec(tv, now);
  99. int millisecond = diff.tv_sec * 1000 + diff.tv_nsec / 1000000;
  100. LOGD(TAG, "interval time: %d ms", millisecond);
  101. speed = ((fota->offset - data_offset) / 1024) * 1000 / millisecond;
  102. }
  103. cJSON_AddNumberToObject(root, "code", 0);
  104. cJSON_AddNumberToObject(root, "total_size", total_size);
  105. cJSON_AddNumberToObject(root, "cur_size", cur_size);
  106. cJSON_AddNumberToObject(root, "percent", percent);
  107. cJSON_AddNumberToObject(root, "speed", speed);
  108. tv.tv_sec = now.tv_sec;
  109. tv.tv_nsec = now.tv_nsec;
  110. data_offset = fota->offset;
  111. }
  112. char *out = cJSON_PrintUnformatted(root);
  113. cJSON_Delete(root);
  114. if (out != NULL) {
  115. fotax->fotax_event_cb(fotax, FOTAX_EVENT_DOWNLOAD, out);
  116. cJSON_free(out);
  117. } else {
  118. fotax->fotax_event_cb(fotax, FOTAX_EVENT_DOWNLOAD, "{\"code\": 1, \"msg\": \"(download)JSON print error!\"}");
  119. }
  120. break;
  121. }
  122. case FOTA_EVENT_FAIL:
  123. LOGD(TAG, "FOTA FAIL :%x, %d", fota->status, fota->error_code);
  124. break;
  125. case FOTA_EVENT_VERIFY:
  126. LOGD(TAG, "FOTA VERIFY :%x", fota->status);
  127. break;
  128. case FOTA_EVENT_FINISH:
  129. LOGD(TAG, "FOTA FINISH :%x", fota->status);
  130. fotax->fotax_event_cb(fotax, FOTAX_EVENT_END, "{\"code\": 0, \"msg\": \"fota finish\"}");
  131. break;
  132. case FOTA_EVENT_RESTART:
  133. LOGD(TAG, "FOTA RESTART :%x", fota->status);
  134. fotax->fotax_event_cb(fotax, FOTAX_EVENT_RESTART, "{\"code\": 0, \"msg\": \"fota restart event\"}");
  135. break;
  136. case FOTA_EVENT_QUIT:
  137. LOGD(TAG, "FOTA QUIT :%x", fota->status);
  138. break;
  139. default:
  140. break;
  141. }
  142. return 0;
  143. }
  144. int fotax_start(fotax_t *fotax)
  145. {
  146. int ret;
  147. char to_buf[32];
  148. char cloud_buf[32];
  149. char *cloud = "cop";
  150. char *to = "flash://misc";
  151. int read_timeoutms; /*!< read timeout, millisecond */
  152. int write_timeoutms; /*!< write timeout, millisecond */
  153. int retry_count; /*!< when download abort, it will retry to download again in retry_count times */
  154. int sleep_time; /*!< the sleep time for auto-check task */
  155. int auto_check_en; /*!< whether check version automatic */
  156. fota_config_t config;
  157. if (fotax == NULL) {
  158. LOGE(TAG, "fotax start args e");
  159. return -EINVAL;
  160. }
  161. if (fotax->state != 0) {
  162. LOGE(TAG, "fotax already started.");
  163. return -1;
  164. }
  165. fotax->fota_handle = NULL;
  166. LOGD(TAG, "%s, %d", __func__, __LINE__);
  167. if (fotax->register_ops && fotax->register_ops->fota_register_cloud) {
  168. ret = fotax->register_ops->fota_register_cloud();
  169. } else {
  170. ret = fota_register_cop();
  171. if (ret != 0) {
  172. return -1;
  173. }
  174. ret = netio_register_http();
  175. }
  176. if (ret != 0) {
  177. return -1;
  178. }
  179. if (fotax->register_ops && fotax->register_ops->netio_register_from) {
  180. ret = fotax->register_ops->netio_register_from(fotax->register_ops->cert);
  181. } else {
  182. ret = netio_register_httpc(NULL);
  183. }
  184. if (ret != 0) {
  185. return -1;
  186. }
  187. if (fotax->register_ops && fotax->register_ops->netio_register_to) {
  188. ret = fotax->register_ops->netio_register_to();
  189. } else {
  190. ret = netio_register_flash();
  191. }
  192. if (ret != 0) {
  193. return -1;
  194. }
  195. memset(cloud_buf, 0 ,sizeof(cloud_buf));
  196. ret = aos_kv_getstring(KV_FOTA_CLOUD_PLATFORM, cloud_buf, sizeof(cloud_buf));
  197. if (ret >= 0) {
  198. cloud = cloud_buf;
  199. }
  200. LOGD(TAG, "cloud: %s", cloud);
  201. memset(to_buf, 0, sizeof(to_buf));
  202. ret = aos_kv_getstring(KV_FOTA_TO_URL, to_buf, sizeof(to_buf));
  203. if (ret >= 0) {
  204. to = to_buf;
  205. }
  206. LOGD(TAG, "to: %s", to);
  207. fotax->fota_handle = fota_open(cloud, to, fota_event_cb);
  208. if (fotax->fota_handle == NULL) {
  209. return -1;
  210. }
  211. ((fota_t *)(fotax->fota_handle))->private = fotax;
  212. if (aos_kv_getint(KV_FOTA_READ_TIMEOUTMS, &read_timeoutms) < 0) {
  213. read_timeoutms = 3000;
  214. }
  215. if (aos_kv_getint(KV_FOTA_WRITE_TIMEOUTMS, &write_timeoutms) < 0) {
  216. write_timeoutms = 3000;
  217. }
  218. if (aos_kv_getint(KV_FOTA_RETRY_COUNT, &retry_count) < 0) {
  219. retry_count = 0;
  220. }
  221. if (aos_kv_getint(KV_FOTA_AUTO_CHECK, &auto_check_en) < 0) {
  222. auto_check_en = 0;
  223. }
  224. if (aos_kv_getint(KV_FOTA_SLEEP_TIMEMS, &sleep_time) < 0) {
  225. sleep_time = 30000;
  226. }
  227. config.read_timeoutms = read_timeoutms;
  228. config.write_timeoutms = write_timeoutms;
  229. config.retry_count = retry_count;
  230. config.auto_check_en = auto_check_en;
  231. config.sleep_time = sleep_time;
  232. LOGD(TAG, "read_timeoutms: %d", read_timeoutms);
  233. LOGD(TAG, "write_timeoutms: %d", write_timeoutms);
  234. LOGD(TAG, "retry_count: %d", retry_count);
  235. LOGD(TAG, "auto_check_en: %d", auto_check_en);
  236. LOGD(TAG, "sleep_time: %d", sleep_time);
  237. fota_config(fotax->fota_handle, &config);
  238. ret = fota_start(fotax->fota_handle);
  239. fotax->state = FOTAX_INIT;
  240. return ret;
  241. }
  242. int fotax_stop(fotax_t *fotax)
  243. {
  244. if (fotax == NULL || fotax->fota_handle == NULL) {
  245. LOGE(TAG, "fotax stop args e");
  246. return -EINVAL;
  247. }
  248. LOGD(TAG, "%s, %d", __func__, __LINE__);
  249. fota_stop(fotax->fota_handle);
  250. fota_close(fotax->fota_handle);
  251. fotax->state = 0;
  252. fotax->fota_handle = NULL;
  253. LOGD(TAG, "fotax stop finish. %s, %d", __func__, __LINE__);
  254. return 0;
  255. }
  256. int fotax_get_state(fotax_t *fotax)
  257. {
  258. int state;
  259. if (fotax == NULL || fotax->fota_handle == NULL) {
  260. LOGE(TAG, "fotax get state args e");
  261. return -EINVAL;
  262. }
  263. state = fota_get_status(fotax->fota_handle);
  264. LOGD(TAG, "%s, %d, state:%d", __func__, __LINE__, state);
  265. return state;
  266. }
  267. int fotax_version_check(fotax_t *fotax)
  268. {
  269. char *device_id, *model, *app_version, *changelog;
  270. if (fotax == NULL || fotax->fota_handle == NULL) {
  271. LOGE(TAG, "fotax version check args e");
  272. return -EINVAL;
  273. }
  274. device_id = aos_get_device_id();
  275. app_version = aos_get_app_version();
  276. model = (char *)aos_get_product_model();
  277. changelog = aos_get_changelog();
  278. cJSON *root = cJSON_CreateObject();
  279. cJSON_AddNumberToObject(root, "code", 0);
  280. cJSON_AddStringToObject(root, "curversion", app_version ? app_version : "null");
  281. cJSON_AddStringToObject(root, "deviceid", device_id ? device_id : "null");
  282. cJSON_AddStringToObject(root, "model", model ? model : "null");
  283. cJSON_AddStringToObject(root, "local_changelog", changelog ? changelog : "null");
  284. char *out = cJSON_PrintUnformatted(root);
  285. cJSON_Delete(root);
  286. if (out != NULL) {
  287. if (fotax->fotax_event_cb) {
  288. fotax->fotax_event_cb(fotax, FOTAX_EVENT_VERSION, out);
  289. }
  290. cJSON_free(out);
  291. } else {
  292. fotax->fotax_event_cb(fotax, FOTAX_EVENT_VERSION, "{\"code\": 1, \"msg\": \"(version)JSON print error!\"}");
  293. }
  294. LOGD(TAG, "%s, %d", __func__, __LINE__);
  295. fota_do_check(fotax->fota_handle);
  296. return 0;
  297. }
  298. int fotax_download(fotax_t *fotax)
  299. {
  300. if (fotax == NULL || fotax->fota_handle == NULL) {
  301. LOGE(TAG, "fotax download args e");
  302. return -EINVAL;
  303. }
  304. LOGD(TAG, "%s, %d", __func__, __LINE__);
  305. fotax->state = FOTAX_DOWNLOAD;
  306. return fota_download(fotax->fota_handle);
  307. }
  308. int fotax_restart(fotax_t *fotax, int delay_ms)
  309. {
  310. if (fotax == NULL || fotax->fota_handle == NULL) {
  311. LOGE(TAG, "fotax restart e");
  312. return -EINVAL;
  313. }
  314. LOGD(TAG, "%s, %d", __func__, __LINE__);
  315. return fota_restart(fotax->fota_handle, delay_ms);
  316. }
  317. int64_t fotax_get_size(fotax_t *fotax, const char *name)
  318. {
  319. if (fotax == NULL || fotax->fota_handle == NULL) {
  320. LOGE(TAG, "fotax get size e");
  321. return -EINVAL;
  322. }
  323. LOGD(TAG, "%s, %d", __func__, __LINE__);
  324. return fota_get_size(fotax->fota_handle, name);
  325. }