system_mqtt.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub available.
  3. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  4. * Licensed under the MIT License (the "License"); you may not use this file except in
  5. * compliance with the License. You may obtain a copy of the License at
  6. * http://opensource.org/licenses/MIT
  7. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  8. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  9. * either express or implied. See the License for the specific language governing permissions and
  10. * limitations under the License.
  11. *
  12. */
  13. #include <string.h>
  14. #ifdef __cplusplus
  15. extern "C" {
  16. #endif
  17. #include "qcloud_iot_export.h"
  18. #include "qcloud_iot_import.h"
  19. #ifdef SYSTEM_COMM
  20. #include "qcloud_iot_export_system.h"
  21. #include "mqtt_client.h"
  22. #include "lite-utils.h"
  23. #include "qcloud_iot_device.h"
  24. #define RESOURCE_TIME_STR "time"
  25. typedef struct _sys_mqtt_state {
  26. bool topic_sub_ok;
  27. bool result_recv_ok;
  28. long time;
  29. char *ipList;
  30. } SysMQTTState;
  31. static SysMQTTState sg_sys_state = {
  32. .topic_sub_ok = false,
  33. .result_recv_ok = false,
  34. .time = 0,
  35. .ipList = NULL
  36. };
  37. static void _system_mqtt_message_callback(void *pClient, MQTTMessage *message, void *pUserData)
  38. {
  39. #define MAX_RECV_LEN (512)
  40. POINTER_SANITY_CHECK_RTN(message);
  41. static char rcv_buf[MAX_RECV_LEN + 1];
  42. size_t len = (message->payload_len > MAX_RECV_LEN)?MAX_RECV_LEN:(message->payload_len);
  43. if(message->payload_len > MAX_RECV_LEN) {
  44. Log_e("payload len oversize");
  45. }
  46. memcpy(rcv_buf, message->payload, len);
  47. rcv_buf[len] = '\0'; // jsmn_parse relies on a string
  48. SysMQTTState *state = (SysMQTTState *)pUserData;
  49. Log_d("Recv Msg Topic:%s, payload:%s", message->ptopic, rcv_buf);
  50. if(strstr(rcv_buf, RESOURCE_TIME_STR)) {
  51. char* time = LITE_json_value_of(RESOURCE_TIME_STR, rcv_buf);
  52. if (time) {
  53. state->time = atol(time);
  54. state->result_recv_ok = true;
  55. } else {
  56. state->result_recv_ok = false;
  57. }
  58. HAL_Free(time);
  59. }
  60. return;
  61. }
  62. static void _system_mqtt_sub_event_handler(void *pclient, MQTTEventType event_type, void *pUserData)
  63. {
  64. SysMQTTState *state = (SysMQTTState *)pUserData;
  65. switch(event_type) {
  66. case MQTT_EVENT_SUBCRIBE_SUCCESS:
  67. Log_d("mqtt sys topic subscribe success");
  68. state->topic_sub_ok = true;
  69. break;
  70. case MQTT_EVENT_SUBCRIBE_TIMEOUT:
  71. Log_i("mqtt sys topic subscribe timeout");
  72. state->topic_sub_ok = false;
  73. break;
  74. case MQTT_EVENT_SUBCRIBE_NACK:
  75. Log_i("mqtt sys topic subscribe NACK");
  76. state->topic_sub_ok = false;
  77. break;
  78. case MQTT_EVENT_UNSUBSCRIBE:
  79. Log_i("mqtt sys topic has been unsubscribed");
  80. state->topic_sub_ok = false;;
  81. break;
  82. case MQTT_EVENT_CLIENT_DESTROY:
  83. Log_i("mqtt client has been destroyed");
  84. state->topic_sub_ok = false;;
  85. break;
  86. default:
  87. return;
  88. }
  89. }
  90. static int _iot_resource_get_publish(void *pClient, DeviceInfo *dev_info, eSysResourcType eType)
  91. {
  92. POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
  93. POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
  94. Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
  95. char topic_name[128] = {0};
  96. char payload_content[128] = {0};
  97. HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/%s/%s", dev_info->product_id, dev_info->device_name);
  98. switch(eType) {
  99. case eRESOURCE_TIME:
  100. HAL_Snprintf(payload_content, sizeof(payload_content), "{\"type\": \"get\", \"resource\": [\"%s\"]}", RESOURCE_TIME_STR);
  101. break;
  102. case eRESOURCE_IP:
  103. break;
  104. default:
  105. Log_e("not supported resource type, %d", eType);
  106. return QCLOUD_ERR_INVAL;
  107. }
  108. PublishParams pub_params = DEFAULT_PUB_PARAMS;
  109. pub_params.qos = QOS0;
  110. pub_params.payload = payload_content;
  111. pub_params.payload_len = strlen(payload_content);
  112. return IOT_MQTT_Publish(mqtt_client, topic_name, &pub_params);
  113. }
  114. static int _iot_system_info_result_subscribe(void *pClient, DeviceInfo *dev_info)
  115. {
  116. POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
  117. POINTER_SANITY_CHECK(dev_info, QCLOUD_ERR_INVAL);
  118. char topic_name[128] = {0};
  119. int size = HAL_Snprintf(topic_name, sizeof(topic_name), "$sys/operation/result/%s/%s", dev_info->product_id, dev_info->device_name);
  120. if (size < 0 || size > sizeof(topic_name) - 1) {
  121. Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
  122. return QCLOUD_ERR_FAILURE;
  123. }
  124. SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
  125. sub_params.on_message_handler = _system_mqtt_message_callback;
  126. sub_params.on_sub_event_handler = _system_mqtt_sub_event_handler;
  127. sub_params.user_data = (void *)&sg_sys_state;
  128. sub_params.qos = QOS0;
  129. return IOT_MQTT_Subscribe(pClient, topic_name, &sub_params);
  130. }
  131. int IOT_Get_Sys_Resource(void* pClient, eSysResourcType eType, DeviceInfo *pDevInfo, void *usrArg)
  132. {
  133. #define SUB_RETRY_TIMES 3
  134. #define SYNC_TIMES 20
  135. int ret = 0;
  136. int cntSub = 0;
  137. int cntRev = 0;
  138. POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
  139. Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
  140. SysMQTTState *pSysState = &sg_sys_state;
  141. // subscribe sys topic: $sys/operation/get/${productid}/${devicename}
  142. // skip this if the subscription is done and valid
  143. if(!pSysState->topic_sub_ok) {
  144. for(cntSub = 0; cntSub < SUB_RETRY_TIMES; cntSub++) {
  145. ret = _iot_system_info_result_subscribe(mqtt_client, pDevInfo);
  146. if (ret < 0) {
  147. Log_w("_iot_system_info_result_subscribe failed: %d, cnt: %d", ret, cntSub);
  148. continue;
  149. }
  150. /* wait for sub ack */
  151. ret = qcloud_iot_mqtt_yield_mt(mqtt_client, 300);
  152. if(pSysState->topic_sub_ok) {
  153. break;
  154. }
  155. }
  156. }
  157. // return failure if subscribe failed
  158. if(!pSysState->topic_sub_ok) {
  159. Log_e("Subscribe sys topic failed!");
  160. return QCLOUD_ERR_FAILURE;
  161. }
  162. pSysState->result_recv_ok = false;
  163. // publish msg to get resource
  164. ret = _iot_resource_get_publish(mqtt_client, pDevInfo, eType);
  165. if (ret < 0) {
  166. Log_e("client publish sys topic failed :%d.", ret);
  167. return ret;
  168. }
  169. do {
  170. ret = qcloud_iot_mqtt_yield_mt(mqtt_client, 100);
  171. cntRev++;
  172. } while(!pSysState->result_recv_ok && cntRev < SYNC_TIMES);
  173. switch(eType) {
  174. case eRESOURCE_TIME:
  175. *((long *)usrArg) = pSysState->time;
  176. break;
  177. case eRESOURCE_IP:
  178. break;
  179. default:
  180. break;
  181. }
  182. if (pSysState->result_recv_ok) {
  183. ret = QCLOUD_RET_SUCCESS;
  184. } else {
  185. ret = QCLOUD_ERR_FAILURE;
  186. }
  187. return ret;
  188. #undef SUB_RETRY_TIMES
  189. #undef SYNC_TIMES
  190. }
  191. #ifdef __cplusplus
  192. }
  193. #endif
  194. #endif