1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "iotx_dm_internal.h"
5 
6 #if defined(OTA_ENABLED) && !defined(BUILD_AOS)
7 
8 #ifdef INFRA_MEM_STATS
9 #include "linkkit/infra/infra_mem_stats.h"
10 #define DM_COTA_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "dm.cota")
11 #define DM_COTA_FREE(ptr)    LITE_free(ptr)
12 #else
13 #define DM_COTA_MALLOC(size) HAL_Malloc(size)
14 #define DM_COTA_FREE(ptr)      \
15     {                          \
16         HAL_Free((void *)ptr); \
17         ptr = NULL;            \
18     }
19 #endif
20 
21 static dm_cota_ctx_t g_dm_cota_ctx;
22 
dm_cota_get_ctx(void)23 dm_cota_ctx_t *dm_cota_get_ctx(void)
24 {
25     return &g_dm_cota_ctx;
26 }
27 
dm_cota_init(void)28 int dm_cota_init(void)
29 {
30     dm_cota_ctx_t *ctx = dm_cota_get_ctx();
31 
32     memset(ctx, 0, sizeof(dm_cota_ctx_t));
33 
34     return SUCCESS_RETURN;
35 }
36 
dm_cota_deinit(void)37 int dm_cota_deinit(void)
38 {
39     dm_cota_ctx_t *ctx = dm_cota_get_ctx();
40 
41     memset(ctx, 0, sizeof(dm_cota_ctx_t));
42 
43     return SUCCESS_RETURN;
44 }
45 
_dm_cota_send_new_config_to_user(void * ota_handle)46 static int _dm_cota_send_new_config_to_user(void *ota_handle)
47 {
48     int res = 0, message_len = 0;
49     char *message = NULL;
50     uint32_t config_size = 0;
51     char *config_id = NULL, *sign = NULL, *sign_method = NULL, *url = NULL,
52          *get_type = NULL;
53     const char *cota_new_config_fmt =
54         "{\"configId\":\"%s\",\"configSize\":%d,\"getType\":\"%s\",\"sign\":\"%"
55         "s\",\"signMethod\":\"%s\",\"url\":\"%s\"}";
56 
57     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_CONFIG_ID, (void *)&config_id, 1);
58     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_CONFIG_SIZE, &config_size, 4);
59     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_SIGN, (void *)&sign, 1);
60     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_SIGN_METHOD, (void *)&sign_method,
61                   1);
62     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_URL, (void *)&url, 1);
63     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_COTA_GETTYPE, (void *)&get_type, 1);
64 
65     if (config_id == NULL || sign == NULL || sign_method == NULL ||
66         url == NULL || get_type == NULL) {
67         res = FAIL_RETURN;
68         goto ERROR;
69     }
70 
71     message_len = strlen(cota_new_config_fmt) + strlen(config_id) +
72                   DM_UTILS_UINT32_STRLEN + strlen(get_type) + strlen(sign) +
73                   strlen(sign_method) + strlen(url) + 1;
74 
75     message = DM_malloc(message_len);
76     if (message == NULL) {
77         res = DM_MEMORY_NOT_ENOUGH;
78         goto ERROR;
79     }
80     memset(message, 0, message_len);
81     HAL_Snprintf(message, message_len, cota_new_config_fmt, config_id,
82                  config_size, get_type, sign, sign_method, url);
83 
84     dm_log_info("Send To User: %s", message);
85 
86     res = _dm_msg_send_to_user(IOTX_DM_EVENT_COTA_NEW_CONFIG, message);
87     if (res != SUCCESS_RETURN) {
88         if (message) {
89             DM_free(message);
90         }
91         res = FAIL_RETURN;
92         goto ERROR;
93     }
94 
95     res = SUCCESS_RETURN;
96 ERROR:
97     if (config_id) {
98         DM_COTA_FREE(config_id);
99     }
100     if (sign) {
101         DM_COTA_FREE(sign);
102     }
103     if (sign_method) {
104         DM_COTA_FREE(sign_method);
105     }
106     if (url) {
107         DM_COTA_FREE(url);
108     }
109     if (get_type) {
110         DM_COTA_FREE(get_type);
111     }
112 
113     return res;
114 }
115 
dm_cota_perform_sync(_OU_ char * output,_IN_ int output_len)116 int dm_cota_perform_sync(_OU_ char *output, _IN_ int output_len)
117 {
118     int res = 0, file_download = 0;
119     uint32_t file_size = 0, file_downloaded = 0;
120     uint32_t percent_pre = 0, percent_now = 0;
121     unsigned long long report_pre = 0, report_now = 0;
122     dm_cota_ctx_t *ctx = dm_cota_get_ctx();
123     void *ota_handle = NULL;
124     uint32_t ota_type = IOT_OTAT_NONE;
125 
126     if (output == NULL || output_len <= 0) {
127         return DM_INVALID_PARAMETER;
128     }
129 
130     /* Get Ota Handle */
131     res = dm_ota_get_ota_handle(&ota_handle);
132     if (res != SUCCESS_RETURN) {
133         return FAIL_RETURN;
134     }
135 
136     if (ota_handle == NULL) {
137         return FAIL_RETURN;
138     }
139     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4);
140 
141     if (ota_type != IOT_OTAT_COTA) {
142         return FAIL_RETURN;
143     }
144 
145     /* reset the size_fetched in ota_handle to be 0 */
146     IOT_OTA_Ioctl(ota_handle, IOT_OTAG_RESET_FETCHED_SIZE, ota_handle, 4);
147     /* Prepare Write Data To Storage */
148     HAL_Firmware_Persistence_Start();
149 
150     while (1) {
151         file_download = IOT_OTA_FetchYield(ota_handle, output, output_len, 1);
152         if (file_download < 0) {
153             IOT_OTA_ReportProgress(ota_handle, IOT_OTAP_FETCH_FAILED, NULL);
154             HAL_Firmware_Persistence_Stop();
155             ctx->is_report_new_config = 0;
156             return FAIL_RETURN;
157         }
158 
159         /* Write Config File Into Stroage */
160         HAL_Firmware_Persistence_Write(output, file_download);
161 
162         /* Get OTA information */
163         IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FETCHED_SIZE, &file_downloaded, 4);
164         IOT_OTA_Ioctl(ota_handle, IOT_OTAG_FILE_SIZE, &file_size, 4);
165 
166         /* Calculate Download Percent And Update Report Timestamp*/
167         percent_now = (file_downloaded * 100) / file_size;
168         report_now = HAL_UptimeMs();
169 
170         /* Report Download Process To Cloud */
171         if (report_now < report_pre) {
172             report_pre = report_now;
173         }
174         if ((((percent_now - percent_pre) > 5) &&
175              ((report_now - report_pre) > 50)) ||
176             (percent_now >= IOT_OTAP_FETCH_PERCENTAGE_MAX)) {
177             IOT_OTA_ReportProgress(ota_handle, percent_now, NULL);
178             percent_pre = percent_now;
179             report_pre = report_now;
180         }
181 
182         /* Check If OTA Finished */
183         if (IOT_OTA_IsFetchFinish(ota_handle)) {
184             uint32_t file_isvalid = 0;
185             IOT_OTA_Ioctl(ota_handle, IOT_OTAG_CHECK_CONFIG, &file_isvalid, 4);
186             if (file_isvalid == 0) {
187                 HAL_Firmware_Persistence_Stop();
188                 ctx->is_report_new_config = 0;
189                 return FAIL_RETURN;
190             } else {
191                 break;
192             }
193         }
194     }
195 
196     HAL_Firmware_Persistence_Stop();
197     ctx->is_report_new_config = 0;
198 
199     return SUCCESS_RETURN;
200 }
201 
dm_cota_get_config(const char * config_scope,const char * get_type,const char * attribute_keys)202 int dm_cota_get_config(const char *config_scope, const char *get_type,
203                        const char *attribute_keys)
204 {
205     int res = 0;
206     void *ota_handle = NULL;
207 
208     /* Get Ota Handle */
209     res = dm_ota_get_ota_handle(&ota_handle);
210     if (res != SUCCESS_RETURN) {
211         return FAIL_RETURN;
212     }
213 
214     return iotx_ota_get_config(ota_handle, config_scope, get_type,
215                                attribute_keys);
216 }
217 
dm_cota_status_check(void)218 int dm_cota_status_check(void)
219 {
220     int res = 0;
221     dm_cota_ctx_t *ctx = dm_cota_get_ctx();
222     void *ota_handle = NULL;
223 
224     /* Get Ota Handle */
225     res = dm_ota_get_ota_handle(&ota_handle);
226     if (res != SUCCESS_RETURN) {
227         return FAIL_RETURN;
228     }
229 
230     if (IOT_OTA_IsFetching(ota_handle)) {
231         uint32_t ota_type = IOT_OTAT_NONE;
232 
233         IOT_OTA_Ioctl(ota_handle, IOT_OTAG_OTA_TYPE, &ota_type, 4);
234 
235         if (ota_type == IOT_OTAT_COTA) {
236             /* Send New Config Information To User */
237             if (ctx->is_report_new_config == 0) {
238                 dm_log_debug("Cota Status Check");
239                 res = _dm_cota_send_new_config_to_user(ota_handle);
240                 if (res == SUCCESS_RETURN) {
241                     ctx->is_report_new_config = 1;
242                 }
243             }
244         }
245     }
246 
247     return SUCCESS_RETURN;
248 }
249 #endif
250