1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #ifndef __OTA_MQTT_C_H__
6 #define __OTA_MQTT_C_H__
7
8 #if (OTA_SIGNAL_CHANNEL) == 1
9
10 #include "linkkit/mqtt_api.h"
11 #include "ota_api.h"
12 #include "iotx_ota_internal.h"
13
14 /* OSC, OTA signal channel */
15
16 /* Specify the maximum characters of version */
17 #define OTA_MQTT_TOPIC_LEN (128)
18
19 typedef struct {
20 void *mqtt;
21 const char *product_key;
22 const char *device_name;
23 char topic_upgrade[OTA_MQTT_TOPIC_LEN];
24 char topic_request[OTA_MQTT_TOPIC_LEN];
25 char topic_config_get[OTA_MQTT_TOPIC_LEN];
26 char topic_config_push[OTA_MQTT_TOPIC_LEN];
27 ota_cb_fpt cb;
28 void *context;
29 } otamqtt_Struct_t, *otamqtt_Struct_pt;
30
31 /* Generate topic name according to @ota_topic_type, @product_key, @device_name
32 */
33 /* and then copy to @buf. */
34 /* 0, successful; -1, failed */
otamqtt_GenTopicName(char * buf,size_t buf_len,const char * ota_topic_type,const char * product_key,const char * device_name)35 static int otamqtt_GenTopicName(char *buf, size_t buf_len,
36 const char *ota_topic_type,
37 const char *product_key,
38 const char *device_name)
39 {
40 int ret;
41
42 ret = HAL_Snprintf(buf, buf_len, "/ota/device/%s/%s/%s", ota_topic_type,
43 product_key, device_name);
44
45 if (ret >= buf_len) {
46 return -1;
47 }
48
49 if (ret < 0) {
50 OTA_LOG_ERROR("HAL_Snprintf failed");
51 return -1;
52 }
53
54 return 0;
55 }
56
57 /* report progress of OTA */
otamqtt_Publish(otamqtt_Struct_pt handle,const char * topic_type,int qos,const char * msg)58 static int otamqtt_Publish(otamqtt_Struct_pt handle, const char *topic_type,
59 int qos, const char *msg)
60 {
61 int ret;
62 char topic_name[OTA_MQTT_TOPIC_LEN];
63 iotx_mqtt_topic_info_t topic_info;
64
65 memset(&topic_info, 0, sizeof(iotx_mqtt_topic_info_t));
66
67 if (0 == qos) {
68 topic_info.qos = IOTX_MQTT_QOS0;
69 } else {
70 topic_info.qos = IOTX_MQTT_QOS1;
71 }
72 topic_info.payload = (void *)msg;
73 topic_info.payload_len = strlen(msg);
74
75 /* inform OTA to topic: "/ota/device/progress/$(product_key)/$(device_name)"
76 */
77 ret = otamqtt_GenTopicName(topic_name, OTA_MQTT_TOPIC_LEN, topic_type,
78 handle->product_key, handle->device_name);
79 if (ret < 0) {
80 OTA_LOG_ERROR("generate topic name of info failed");
81 return -1;
82 }
83
84 ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &topic_info);
85 if (ret < 0) {
86 OTA_LOG_ERROR("publish failed");
87 return IOT_OTAE_OSC_FAILED;
88 }
89
90 return 0;
91 }
92
otamqtt_publish_full_topic(otamqtt_Struct_pt handle,const char * topic_name,iotx_mqtt_topic_info_pt topic_msg)93 static int otamqtt_publish_full_topic(otamqtt_Struct_pt handle,
94 const char *topic_name,
95 iotx_mqtt_topic_info_pt topic_msg)
96 {
97 if (IOT_MQTT_Publish(handle->mqtt, topic_name, topic_msg) < 0) {
98 OTA_LOG_ERROR("publish failed");
99 return IOT_OTAE_OSC_FAILED;
100 }
101
102 return 0;
103 }
104
105 /* decode JSON string to get firmware information, like firmware version, URL,
106 * file size, MD5. */
107 /* return NONE */
otamqtt_UpgrageCb(void * pcontext,void * pclient,iotx_mqtt_event_msg_pt msg)108 static void otamqtt_UpgrageCb(void *pcontext, void *pclient,
109 iotx_mqtt_event_msg_pt msg)
110 {
111 otamqtt_Struct_pt handle = (otamqtt_Struct_pt)pcontext;
112 iotx_mqtt_topic_info_pt topic_info = (iotx_mqtt_topic_info_pt)msg->msg;
113
114 OTA_LOG_DEBUG("topic=%.*s", topic_info->topic_len, topic_info->ptopic);
115 OTA_LOG_DEBUG("len=%u, topic_msg=%.*s", topic_info->payload_len,
116 topic_info->payload_len, (char *)topic_info->payload);
117
118 if (IOTX_MQTT_EVENT_PUBLISH_RECEIVED != msg->event_type) {
119 return;
120 }
121
122 if (NULL != strstr(topic_info->ptopic, "/ota/device/request")) {
123 OTA_LOG_DEBUG("receive device request");
124 /*if(NULL != HAL_strnstr(topic_info->payload, topic_info->payload_len,
125 "url", strlen("url")))*/
126 if (NULL != strstr(topic_info->payload, "url")) {
127 OTA_LOG_INFO("get request reply for new version image");
128 if (NULL != handle->cb) {
129 handle->cb(handle->context, topic_info->payload,
130 topic_info->payload_len,
131 IOTX_OTA_TOPIC_TYPE_DEVICE_REQUEST);
132 }
133 }
134 } else if (NULL != strstr(topic_info->ptopic, "/ota/device/upgrade")) {
135 OTA_LOG_DEBUG("receive device upgrade");
136 if (NULL != handle->cb) {
137 handle->cb(handle->context, topic_info->payload,
138 topic_info->payload_len,
139 IOTX_OTA_TOPIC_TYPE_DEVICE_UPGRATE);
140 }
141 } else if (NULL != strstr(topic_info->ptopic, "/thing/config/get_reply")) {
142 OTA_LOG_DEBUG("receive config get_reply");
143 if (NULL != handle->cb) {
144 handle->cb(handle->context, topic_info->payload,
145 topic_info->payload_len, IOTX_OTA_TOPIC_TYPE_CONFIG_GET);
146 }
147 } else if (NULL != strstr(topic_info->ptopic, "/thing/config/push")) {
148 OTA_LOG_DEBUG("receive config push");
149 if (NULL != handle->cb) {
150 if (0 != handle->cb(handle->context, topic_info->payload,
151 topic_info->payload_len,
152 IOTX_OTA_TOPIC_TYPE_CONFIG_PUSH)) {
153 /* fail, send fail response code:400 */
154 const char *pvalue;
155 uint32_t val_len;
156 char topic[OTA_MQTT_TOPIC_LEN] = { 0 };
157 char message[OTA_MQTT_TOPIC_LEN] = { 0 };
158 iotx_mqtt_topic_info_t message_info;
159
160 memset(&message_info, 0, sizeof(iotx_mqtt_topic_info_t));
161
162 pvalue =
163 otalib_JsonValueOf(topic_info->payload,
164 topic_info->payload_len, "id", &val_len);
165
166 HAL_Snprintf(topic, OTA_MQTT_TOPIC_LEN,
167 "/sys/%s/%s/thing/config/push_reply",
168 handle->product_key, handle->device_name);
169 HAL_Snprintf(message, OTA_MQTT_TOPIC_LEN,
170 "\"id\":%.*s,\"code\":\"%d\",\"data\":{}", val_len,
171 pvalue, 400);
172 message_info.qos = IOTX_MQTT_QOS0;
173 message_info.payload = (void *)message;
174 message_info.payload_len = strlen(message);
175
176 if (IOT_MQTT_Publish(handle->mqtt, topic, &message_info) < 0) {
177 OTA_LOG_ERROR("publish failed");
178 }
179 }
180 }
181 }
182 }
183
osc_Init(const char * product_key,const char * device_name,void * ch_signal,ota_cb_fpt cb,void * context)184 void *osc_Init(const char *product_key, const char *device_name,
185 void *ch_signal, ota_cb_fpt cb, void *context)
186 {
187 int ret;
188 otamqtt_Struct_pt h_osc = NULL;
189
190 h_osc = OTA_MALLOC(sizeof(otamqtt_Struct_t));
191 if (h_osc == NULL) {
192 OTA_LOG_ERROR("allocate for h_osc failed");
193 return NULL;
194 }
195
196 memset(h_osc, 0, sizeof(otamqtt_Struct_t));
197
198 /* subscribe the OTA topic:
199 * "/ota/device/request/$(product_key)/$(device_name)" */
200 ret = otamqtt_GenTopicName(h_osc->topic_request, OTA_MQTT_TOPIC_LEN,
201 "request", product_key, device_name);
202 if (ret < 0) {
203 OTA_LOG_ERROR("generate topic name of request failed");
204 goto do_exit;
205 }
206
207 #ifdef MQTT_AUTO_SUBSCRIBE
208 ret =
209 IOT_MQTT_Subscribe(ch_signal, h_osc->topic_request,
210 IOTX_MQTT_QOS3_SUB_LOCAL, otamqtt_UpgrageCb, h_osc);
211 #else
212 ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_request, IOTX_MQTT_QOS1,
213 otamqtt_UpgrageCb, h_osc);
214 #endif
215 if (ret < 0) {
216 OTA_LOG_ERROR("mqtt subscribe failed");
217 goto do_exit;
218 }
219
220 /* subscribe the OTA topic:
221 * "/ota/device/upgrade/$(product_key)/$(device_name)" */
222 ret = otamqtt_GenTopicName(h_osc->topic_upgrade, OTA_MQTT_TOPIC_LEN,
223 "upgrade", product_key, device_name);
224 if (ret < 0) {
225 OTA_LOG_ERROR("generate topic name of upgrade failed");
226 goto do_exit;
227 }
228
229 #ifdef MQTT_AUTO_SUBSCRIBE
230 ret =
231 IOT_MQTT_Subscribe(ch_signal, h_osc->topic_upgrade,
232 IOTX_MQTT_QOS3_SUB_LOCAL, otamqtt_UpgrageCb, h_osc);
233 #else
234 ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_upgrade, IOTX_MQTT_QOS1,
235 otamqtt_UpgrageCb, h_osc);
236 #endif
237 if (ret < 0) {
238 OTA_LOG_ERROR("mqtt subscribe failed");
239 goto do_exit;
240 }
241
242 /* subscribe the OTA topic:
243 * "/sys/{productKey}/{deviceName}/thing/config/get_reply" */
244 ret = HAL_Snprintf(h_osc->topic_config_get, OTA_MQTT_TOPIC_LEN,
245 "/sys/%s/%s/thing/config/get_reply", product_key,
246 device_name);
247 if (ret < 0) {
248 OTA_LOG_ERROR("generate topic name of config get failed");
249 goto do_exit;
250 }
251
252 #ifdef MQTT_AUTO_SUBSCRIBE
253 ret =
254 IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_get,
255 IOTX_MQTT_QOS3_SUB_LOCAL, otamqtt_UpgrageCb, h_osc);
256 #else
257 ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_get, IOTX_MQTT_QOS0,
258 otamqtt_UpgrageCb, h_osc);
259 #endif
260 if (ret < 0) {
261 OTA_LOG_ERROR("mqtt subscribe failed");
262 goto do_exit;
263 }
264
265 /* subscribe the OTA topic:
266 * "/sys/{productKey}/{deviceName}/thing/config/push" */
267 ret =
268 HAL_Snprintf(h_osc->topic_config_push, OTA_MQTT_TOPIC_LEN,
269 "/sys/%s/%s/thing/config/push", product_key, device_name);
270 if (ret < 0) {
271 OTA_LOG_ERROR("generate topic name of config get failed");
272 goto do_exit;
273 }
274
275 #ifdef MQTT_AUTO_SUBSCRIBE
276 ret =
277 IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_push,
278 IOTX_MQTT_QOS3_SUB_LOCAL, otamqtt_UpgrageCb, h_osc);
279 #else
280 ret = IOT_MQTT_Subscribe(ch_signal, h_osc->topic_config_push,
281 IOTX_MQTT_QOS0, otamqtt_UpgrageCb, h_osc);
282 #endif
283 if (ret < 0) {
284 OTA_LOG_ERROR("mqtt subscribe failed");
285 goto do_exit;
286 }
287
288 h_osc->mqtt = ch_signal;
289 h_osc->product_key = product_key;
290 h_osc->device_name = device_name;
291 h_osc->cb = cb;
292 h_osc->context = context;
293
294 return h_osc;
295
296 do_exit:
297 if (NULL != h_osc) {
298 OTA_FREE(h_osc);
299 }
300
301 return NULL;
302 }
303
osc_Deinit(void * handle)304 int osc_Deinit(void *handle)
305 {
306 if (NULL != handle) {
307 OTA_FREE(handle);
308 }
309
310 return 0;
311 }
312
313 /* report progress of OTA */
osc_ReportProgress(void * handle,const char * msg)314 int osc_ReportProgress(void *handle, const char *msg)
315 {
316 return otamqtt_Publish(handle, "progress", 0, msg);
317 }
318
319 /* report version of OTA firmware */
osc_ReportVersion(void * handle,const char * msg)320 int osc_ReportVersion(void *handle, const char *msg)
321 {
322 return otamqtt_Publish(handle, "inform", 1, msg);
323 }
324
325 /* request the OTA firmware pushed by user*/
osc_RequestImage(void * handle,const char * msg)326 int osc_RequestImage(void *handle, const char *msg)
327 {
328 return otamqtt_Publish(handle, "request", 1, msg);
329 }
330
331 /* request the config */
osc_RequestConfig(void * handle,const char * topic_name,iotx_mqtt_topic_info_pt topic_msg)332 int osc_RequestConfig(void *handle, const char *topic_name,
333 iotx_mqtt_topic_info_pt topic_msg)
334 {
335 return otamqtt_publish_full_topic(handle, topic_name, topic_msg);
336 }
337
338 #endif /* #if (OTA_SIGNAL_CHANNEL) == 1 */
339 #endif /* #ifndef __OTA_MQTT_C_H__ */
340