ota_mqtt.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub
  3. available.
  4. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  5. * Licensed under the MIT License (the "License"); you may not use this file
  6. except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. * http://opensource.org/licenses/MIT
  9. * Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is
  11. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  12. KIND,
  13. * either express or implied. See the License for the specific language
  14. governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif
  21. #include "qcloud_iot_export.h"
  22. #include "qcloud_iot_import.h"
  23. #ifdef OTA_MQTT_CHANNEL
  24. #include <string.h>
  25. #include "ota_client.h"
  26. /* OSC, OTA signal channel */
  27. typedef struct {
  28. void *mqtt; // MQTT cient
  29. const char *product_id;
  30. const char *device_name;
  31. char topic_upgrade[OTA_MAX_TOPIC_LEN]; // OTA MQTT Topic
  32. OnOTAMessageCallback msg_callback;
  33. void *context;
  34. bool topic_ready;
  35. } OTA_MQTT_Struct_t;
  36. /* Generate topic name according to @OTATopicType, @productId, @deviceName */
  37. /* and then copy to @buf. */
  38. /* 0, successful; -1, failed */
  39. static int _otamqtt_gen_topic_name(char *buf, size_t bufLen, const char *OTATopicType, const char *productId,
  40. const char *deviceName)
  41. {
  42. IOT_FUNC_ENTRY;
  43. int ret;
  44. ret = HAL_Snprintf(buf, bufLen, "$ota/%s/%s/%s", OTATopicType, productId, deviceName);
  45. if (ret >= bufLen)
  46. IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
  47. if (ret < 0) {
  48. Log_e("HAL_Snprintf failed");
  49. IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
  50. }
  51. IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
  52. }
  53. /* report progress of OTA */
  54. static int _otamqtt_publish(OTA_MQTT_Struct_t *handle, const char *topicType, int qos, const char *msg)
  55. {
  56. IOT_FUNC_ENTRY;
  57. int ret;
  58. char topic_name[OTA_MAX_TOPIC_LEN];
  59. PublishParams pub_params = DEFAULT_PUB_PARAMS;
  60. if (0 == qos) {
  61. pub_params.qos = QOS0;
  62. } else {
  63. pub_params.qos = QOS1;
  64. }
  65. pub_params.payload = (void *)msg;
  66. pub_params.payload_len = strlen(msg);
  67. /* inform OTA to topic: "/ota/device/progress/$(product_id)/$(device_name)" */
  68. ret = _otamqtt_gen_topic_name(topic_name, OTA_MAX_TOPIC_LEN, topicType, handle->product_id, handle->device_name);
  69. if (ret < 0) {
  70. Log_e("generate topic name of info failed");
  71. IOT_FUNC_EXIT_RC(IOT_OTA_ERR_FAIL);
  72. }
  73. ret = IOT_MQTT_Publish(handle->mqtt, topic_name, &pub_params);
  74. if (ret < 0) {
  75. Log_e("publish to topic: %s failed", topic_name);
  76. IOT_FUNC_EXIT_RC(IOT_OTA_ERR_OSC_FAILED);
  77. }
  78. IOT_FUNC_EXIT_RC(ret);
  79. }
  80. /* callback after OTA topic is subscribed */
  81. /* Parse firmware info (version/URL/file size/MD5) from JSON text */
  82. static void _otamqtt_upgrage_cb(void *pClient, MQTTMessage *message, void *pcontext)
  83. {
  84. OTA_MQTT_Struct_t *handle = (OTA_MQTT_Struct_t *)pcontext;
  85. Log_d("topic=%.*s", message->topic_len, message->ptopic);
  86. Log_i("len=%u, topic_msg=%.*s", message->payload_len, message->payload_len, (char *)message->payload);
  87. if (NULL != handle->msg_callback) {
  88. handle->msg_callback(handle->context, message->payload, message->payload_len);
  89. }
  90. }
  91. static void _otamqtt_event_callback(void *pclient, MQTTEventType event_type, void *user_data)
  92. {
  93. OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)user_data;
  94. switch (event_type) {
  95. case MQTT_EVENT_SUBCRIBE_SUCCESS:
  96. Log_d("OTA topic subscribe success");
  97. h_osc->topic_ready = true;
  98. break;
  99. case MQTT_EVENT_SUBCRIBE_TIMEOUT:
  100. Log_i("OTA topic subscribe timeout");
  101. h_osc->topic_ready = false;
  102. break;
  103. case MQTT_EVENT_SUBCRIBE_NACK:
  104. Log_i("OTA topic subscribe NACK");
  105. h_osc->topic_ready = false;
  106. break;
  107. case MQTT_EVENT_UNSUBSCRIBE:
  108. Log_i("OTA topic has been unsubscribed");
  109. h_osc->topic_ready = false;
  110. ;
  111. break;
  112. case MQTT_EVENT_CLIENT_DESTROY:
  113. Log_i("mqtt client has been destroyed");
  114. h_osc->topic_ready = false;
  115. ;
  116. break;
  117. default:
  118. return;
  119. }
  120. }
  121. void *qcloud_osc_init(const char *productId, const char *deviceName, void *channel, OnOTAMessageCallback callback,
  122. void *context)
  123. {
  124. int ret;
  125. OTA_MQTT_Struct_t *h_osc = NULL;
  126. if (NULL == (h_osc = HAL_Malloc(sizeof(OTA_MQTT_Struct_t)))) {
  127. Log_e("allocate for h_osc failed");
  128. goto do_exit;
  129. }
  130. memset(h_osc, 0, sizeof(OTA_MQTT_Struct_t));
  131. /* subscribe the OTA topic: "$ota/update/$(product_id)/$(device_name)" */
  132. ret = _otamqtt_gen_topic_name(h_osc->topic_upgrade, OTA_MAX_TOPIC_LEN, "update", productId, deviceName);
  133. if (ret < 0) {
  134. Log_e("generate topic name of upgrade failed");
  135. goto do_exit;
  136. }
  137. SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
  138. sub_params.on_message_handler = _otamqtt_upgrage_cb;
  139. sub_params.on_sub_event_handler = _otamqtt_event_callback;
  140. sub_params.qos = QOS1;
  141. sub_params.user_data = h_osc;
  142. ret = IOT_MQTT_Subscribe(channel, h_osc->topic_upgrade, &sub_params);
  143. if (ret < 0) {
  144. Log_e("ota mqtt subscribe failed!");
  145. goto do_exit;
  146. }
  147. int wait_cnt = 10;
  148. while (!h_osc->topic_ready && (wait_cnt > 0)) {
  149. // wait for subscription result
  150. IOT_MQTT_Yield_MT(channel, 200);
  151. wait_cnt--;
  152. }
  153. if (wait_cnt == 0) {
  154. Log_e("ota mqtt subscribe timeout!");
  155. goto do_exit;
  156. }
  157. h_osc->mqtt = channel;
  158. h_osc->product_id = productId;
  159. h_osc->device_name = deviceName;
  160. h_osc->msg_callback = callback;
  161. h_osc->context = context;
  162. return h_osc;
  163. do_exit:
  164. if (NULL != h_osc) {
  165. HAL_Free(h_osc);
  166. }
  167. return NULL;
  168. }
  169. int qcloud_osc_deinit(void *handle)
  170. {
  171. IOT_FUNC_ENTRY;
  172. int ret = QCLOUD_RET_SUCCESS;
  173. if (NULL != handle) {
  174. OTA_MQTT_Struct_t *h_osc = (OTA_MQTT_Struct_t *)handle;
  175. ret = IOT_MQTT_Unsubscribe(h_osc->mqtt, h_osc->topic_upgrade);
  176. HAL_Free(handle);
  177. }
  178. IOT_FUNC_EXIT_RC(ret);
  179. }
  180. /* report progress of OTA */
  181. int qcloud_osc_report_progress(void *handle, const char *msg)
  182. {
  183. return _otamqtt_publish(handle, "report", QOS0, msg);
  184. }
  185. /* report version of OTA firmware */
  186. int qcloud_osc_report_version(void *handle, const char *msg)
  187. {
  188. return _otamqtt_publish(handle, "report", QOS1, msg);
  189. }
  190. /* report upgrade begin of OTA firmware */
  191. int qcloud_osc_report_upgrade_result(void *handle, const char *msg)
  192. {
  193. return _otamqtt_publish(handle, "report", QOS1, msg);
  194. }
  195. #endif
  196. #ifdef __cplusplus
  197. }
  198. #endif