feat: 移植腾讯云物联网开发平台 C SDK

This commit is contained in:
fancyxu
2022-07-01 11:06:09 +08:00
parent 2be1169b0b
commit 0acc079ed6
195 changed files with 36646 additions and 0 deletions

View File

@@ -0,0 +1,474 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file at_mqtt_cmd.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-19
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-19 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "at_module.h"
/**
* @brief AT Command for Iot Hub
* 1. network_register:
* AT+TCREGNET=?
* AT+TCREGNET?
* AT+TCREGNET=<module_type>,<action>[,<ssid>,<pw>][,<apn>]
* 2. device_info:
* AT+TCDEVINFOSET=?
* AT+TCDEVINFOSET?
* AT+TCDEVINFOSET=<tlsmode>,<productId>,<devicename>[,<devicesecret>][,<certname>]
* 3. cert:
* AT+TCCERTADD=?
* AT+TCCERTADD?
* AT+TCCERTADD=<cert_name>,<cert_size>
* AT+TCCERTCHECK=?
* AT+TCCERTCHECK?
* AT+TCCERTCHECK=<cert_name>
* AT+TCCERTDEL=?
* AT+TCCERTDEL?
* AT+TCCERTDEL=<cert_name>
* 4. dynamic register:
* AT+TCPRDINFOSET=?
* AT+TCPRDINFOSET?
* AT+TCPRDINFOSET=<tls_mode>,<product_ID>,<product_secret>,<device_name>
* AT+TCDEVREG=?
* AT+TCDEVREG
* 5. module info
* AT+TCMODULE
* AT+TCRESTORE=?
* 6. mqtt
* AT+TCMQTTCONN=?
* AT+TCMQTTCONN?
* AT+TCMQTTCONN=<tlsmode>,<cmdtimeout>,<keepalive>,<clean_session>,<reconnect>
* AT+TCMQTTDISCONN=?
* AT+TCMQTTDISCONN
* AT+TCMQTTPUB=?
* AT+TCMQTTPUB=<topic>,<qos>,<message>
* AT+TCMQTTPUBL=?
* AT+TCMQTTPUBL= <topic>,<qos>,<msg_length>
* AT+TCMQTTSUB=?
* AT+TCMQTTSUB?
* AT+TCMQTTSUB=<topic>,<qos>
* AT+TCMQTTUNSUB=?
* AT+TCMQTTUNSUB?
* AT+TCMQTTUNSUB=<topic>
* AT+TCMQTTSTATE=?
* AT+TCMQTTSTATE?
* 7. ota
* AT+TCOTASET=?
* AT+TCOTASET?
* AT+TCOTASET=<ctlstate>,<fw_ver>
* AT+TCFWINFO=?
* AT+TCFWINFO?
* AT+TCREADFWDATA=?
* AT+TCREADFWDATA=<len>
*
*/
/**
* @brief AT module cmd.
*
*/
typedef enum {
MODULE_CMD_SET_DEVICE_INFO, // AT+TCDEVINFOSET=<tlsmode>,<productId>,<devicename>[,<devicesecret>][,<certname>]
MODULE_CMD_CONNECT, // AT+TCMQTTCONN=<tlsmode>,<cmdtimeout>,<keepalive>,<clean_session>,<reconnect>
MODULE_CMD_DISCONNECT, // AT+TCMQTTDISCONN
MODULE_CMD_PUBLISH, // AT+TCMQTTPUB=<topic>,<qos>,<message>
MODULE_CMD_PUBLISHL, // AT+TCMQTTPUBL=<topic>,<qos>,<msg_length>
MODULE_CMD_SUBSCRIBE, // AT+TCMQTTSUB=<topic>,<qos>
MODULE_CMD_UNSUBSCRIBE, // AT+TCMQTTUNSUB=<topic>
MODULE_CMD_GET_CONNECT_STATUS, // AT+TCMQTTSTATE?
MODULE_CMD_SET_OTA_VERSION, // AT+TCOTASET=<ctlstate>,<fw_ver>
MODULE_CMD_GET_OTA_FW_INFO, // AT+TCFWINFO?
MODULE_CMD_READ_OTA_FW_DATA // AT+TCREADFWDATA=<len>
} ModuleCmd;
/**
* @brief Publish cmd params.
*
*/
typedef struct {
const char *topic_name;
const PublishParams *params;
} ModuleCmdPublishParams;
/**
* @brief Subscribe cmd params.
*
*/
typedef struct {
const char *topic_filter;
int qos;
} ModuleCmdSubscribeParams;
/**
* @brief Unsubscribe cmd params.
*
*/
typedef struct {
const char *topic_filter;
} ModuleCmdUnsubscribeParams;
/**
* @brief Set ota version to report.
*
*/
typedef struct {
/**
* @brief Control module report
* 0: off
* 1: only report mcu version
* 2: only report module version
* 3: report all
*/
QcloudIotOtaClsState cls_state;
const char *version; /* ota version */
} ModuleCmdSetOTAVersionParams;
/**
* @brief Read fw data.
*
*/
typedef struct {
void *fw_data_buf;
uint32_t *fw_data_len;
uint32_t timeout;
} ModuleCmdReadOTFwDataParams;
/**
* @brief Module cmd params.
*
*/
typedef struct {
const QcloudIotClient *client;
union {
ModuleCmdPublishParams publish_params;
ModuleCmdSubscribeParams subscribe_params;
ModuleCmdUnsubscribeParams unsubscribe_params;
ModuleCmdSetOTAVersionParams set_ota_version_params;
ModuleCmdReadOTFwDataParams read_ota_fw_data_params;
};
} ModuleCmdParams;
/**
* @brief Transfer '\"' and ','.
*
* @param[in,out] payload payload to transfer, reuse memory
* @return length of payload
*/
static int _transfer_payload(char *payload, char **payload_transferred)
{
char *tmp, *src = payload;
int count = 0;
char c = '\0';
// 1. calculate '\"' and '.'
while ((c = *src++) != '\0') {
if (c == '\"' || c == ',') {
count++;
}
}
// 2. malloc for payload
int tmp_len = src - payload + count;
tmp = HAL_Malloc(tmp_len);
if (!tmp) {
return 0;
}
memset(tmp, 0, tmp_len);
// 3. replace
for (src = payload, count = 0; (c = *src) != '\0'; src++) {
if (c == '\"' || c == ',') {
tmp[count++] = '\\';
}
tmp[count++] = c;
}
tmp[count] = '\0';
*payload_transferred = tmp;
return count;
}
/**
* @brief Send at cmd to at module.
*
* @param[in] cmd @see ModuleCmd
* @param[in] params @see ModuleCmdParams
* @return 0 for success
*/
static int _module_send_cmd(ModuleCmd cmd, ModuleCmdParams *params)
{
#define DEFAULT_TIMEOUT_MS 5000
int rc, len = 0;
char at_cmd[1250] = {0};
char at_resp[32] = {0};
char *payload_transferred = NULL;
const QcloudIotClient *client = params->client;
switch (cmd) {
case MODULE_CMD_SET_DEVICE_INFO:
strncpy(at_resp, "+TCDEVINFOSET:OK", sizeof(at_resp));
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCDEVINFOSET=%d,\"%s\",\"%s\",\"%s\"\r\n", client->tls_mode,
client->device_info->product_id, client->device_info->device_name,
client->device_info->device_secret);
break;
case MODULE_CMD_CONNECT:
strncpy(at_resp, "+TCMQTTCONN:OK", sizeof(at_resp));
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTCONN=%d,%d,%d,%d,%d\r\n", client->tls_mode,
client->command_timeout_ms, client->keep_alive_interval, client->clean_session,
client->auto_connect_enable);
break;
case MODULE_CMD_DISCONNECT:
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTDISCONN\r\n");
break;
case MODULE_CMD_PUBLISHL:
len = _transfer_payload(params->publish_params.params->payload, &payload_transferred);
if (!len) {
return QCLOUD_ERR_MALLOC;
}
strncpy(at_resp, ">", sizeof(at_resp));
HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTPUBL=\"%s\",%d,%d\r\n", params->publish_params.topic_name,
params->publish_params.params->qos, len);
rc = HAL_Module_SendAtCmdWaitResp(at_cmd, at_resp, client->command_timeout_ms);
if (rc) {
HAL_Free(payload_transferred);
return rc;
}
strncpy(at_resp, "+TCMQTTPUBL:OK", sizeof(at_resp));
rc = HAL_Module_SendAtData(payload_transferred, len);
HAL_Free(payload_transferred);
if (rc) {
return rc;
}
return HAL_Module_SendAtCmdWaitResp("\r\n", at_resp, client->command_timeout_ms);
case MODULE_CMD_PUBLISH:
strncpy(at_resp, "+TCMQTTPUB:OK", sizeof(at_resp));
len = _transfer_payload(params->publish_params.params->payload, &payload_transferred);
if (!len) {
return QCLOUD_ERR_MALLOC;
}
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTPUB=\"%s\",%d,\"%s\"\r\n",
params->publish_params.topic_name, params->publish_params.params->qos,
payload_transferred);
HAL_Free(payload_transferred);
break;
case MODULE_CMD_SUBSCRIBE:
strncpy(at_resp, "+TCMQTTSUB:OK", sizeof(at_resp));
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTSUB=\"%s\",%d\r\n",
params->subscribe_params.topic_filter, params->subscribe_params.qos);
break;
case MODULE_CMD_UNSUBSCRIBE:
strncpy(at_resp, "+TCMQTTUNSUB:OK", sizeof(at_resp));
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTUNSUB=\"%s\"\r\n",
params->subscribe_params.topic_filter);
break;
case MODULE_CMD_GET_CONNECT_STATUS:
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCMQTTSTATE?\r\n");
break;
case MODULE_CMD_SET_OTA_VERSION:
strncpy(at_resp, "+TCOTASET:OK", sizeof(at_resp));
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCOTASET=%d,\"%s\"\r\n",
params->set_ota_version_params.cls_state, params->set_ota_version_params.version);
break;
case MODULE_CMD_GET_OTA_FW_INFO:
len = HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCFWINFO?\r\n");
break;
case MODULE_CMD_READ_OTA_FW_DATA:
strncpy(at_resp, "+TCREADFWDATA:%u,", sizeof(at_resp));
HAL_Snprintf(at_cmd, sizeof(at_cmd), "AT+TCREADFWDATA=%d\r\n",
*(params->read_ota_fw_data_params.fw_data_len));
return HAL_Module_SendAtCmdWaitRespWithData(at_cmd, at_resp, params->read_ota_fw_data_params.fw_data_buf,
params->read_ota_fw_data_params.fw_data_len,
params->read_ota_fw_data_params.timeout);
default:
return QCLOUD_ERR_INVAL;
}
return len ? HAL_Module_SendAtCmdWaitResp(at_cmd, at_resp[0] ? at_resp : NULL,
client ? client->command_timeout_ms : DEFAULT_TIMEOUT_MS)
: QCLOUD_ERR_BUF_TOO_SHORT;
}
// ----------------------------------------------------------------------------
// device info
// ----------------------------------------------------------------------------
/**
* @brief Set device info.
*
* @param[in,out] client pointer to mqtt client
* @return 0 for success
*/
int module_device_info_set(const QcloudIotClient *client)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
return _module_send_cmd(MODULE_CMD_SET_DEVICE_INFO, &cmd_params);
}
// ----------------------------------------------------------------------------
// mqtt
// ----------------------------------------------------------------------------
/**
* @brief Connect mqtt server.
*
* @param[in,out] client pointer to mqtt client
* @return 0 for success
*/
int module_mqtt_connect(const QcloudIotClient *client)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
return _module_send_cmd(MODULE_CMD_CONNECT, &cmd_params);
}
/**
* @brief Disconnect mqtt server.
*
* @param[in,out] client pointer to mqtt client
* @return 0 for success
*/
int module_mqtt_disconnect(const QcloudIotClient *client)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
return _module_send_cmd(MODULE_CMD_DISCONNECT, &cmd_params);
}
/**
* @brief Publish mqtt message.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_name topic name to publish
* @param[in] params params for publish
* @return 0 for success
*/
int module_mqtt_publish(const QcloudIotClient *client, const char *topic_name, const PublishParams *params)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
cmd_params.publish_params.params = params;
cmd_params.publish_params.topic_name = topic_name;
return params->payload_len > MAX_PUB_SHORT_LEN ? _module_send_cmd(MODULE_CMD_PUBLISHL, &cmd_params)
: _module_send_cmd(MODULE_CMD_PUBLISH, &cmd_params);
}
/**
* @brief Subscribe mqtt topic.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to subscribe
* @param[in] qos max qos for subscribe
* @return 0 for success
*/
int module_mqtt_subscribe(const QcloudIotClient *client, const char *topic_filter, int qos)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
cmd_params.subscribe_params.topic_filter = topic_filter;
cmd_params.subscribe_params.qos = qos;
return _module_send_cmd(MODULE_CMD_SUBSCRIBE, &cmd_params);
}
/**
* @brief Unsubscribe mqtt topic.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to unsubscribe
* @return 0 for success
*/
int module_mqtt_unsubscribe(const QcloudIotClient *client, const char *topic_filter)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
cmd_params.unsubscribe_params.topic_filter = topic_filter;
return _module_send_cmd(MODULE_CMD_UNSUBSCRIBE, &cmd_params);
}
/**
* @brief Get mqtt connect state
*
* @param[in,out] client pointer to mqtt client
* @return 0 for success
*/
int module_mqtt_get_connect_state(const QcloudIotClient *client)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = client;
return _module_send_cmd(MODULE_CMD_GET_CONNECT_STATUS, &cmd_params);
}
// ----------------------------------------------------------------------------
// ota
// ----------------------------------------------------------------------------
/**
* @brief Set fw version and report.
*
* @param[in] cls_state 0: off;1: only report mcu version;2: only report module version;3: report all
* @param[in] version mcu fw version
* @return 0 for success
*/
int module_ota_set_fw_version(QcloudIotOtaClsState cls_state, const char *version)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = NULL;
cmd_params.set_ota_version_params.cls_state = cls_state;
cmd_params.set_ota_version_params.version = version;
return _module_send_cmd(MODULE_CMD_SET_OTA_VERSION, &cmd_params);
}
/**
* @brief Get fw info.
*
* @return 0 for success
*/
int module_ota_get_fw_info(void)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = NULL;
return _module_send_cmd(MODULE_CMD_GET_OTA_FW_INFO, &cmd_params);
}
/**
* @brief Read fw data.
*
* @param[out] fw_data_buf data buffer
* @param[out] fw_data_len data recv length
* @param[in] timeout read timeout
* @return 0 for success
*/
int module_ota_read_fw_data(void *fw_data_buf, uint32_t *fw_data_len, uint32_t timeout)
{
ModuleCmdParams cmd_params = {0};
cmd_params.client = NULL;
cmd_params.read_ota_fw_data_params.fw_data_buf = fw_data_buf;
cmd_params.read_ota_fw_data_params.fw_data_len = fw_data_len;
cmd_params.read_ota_fw_data_params.timeout = timeout;
return _module_send_cmd(MODULE_CMD_READ_OTA_FW_DATA, &cmd_params);
}

View File

@@ -0,0 +1,407 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file at_module_mqtt_client.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-25 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "at_module.h"
/**
* @brief Init mqtt client.
*
* @param[in,out] client pointer to mqtt client
* @param[in] params mqtt init params, @see MQTTInitParams
* @return @see IotReturnCode
*
* @note
* 1. init device info.
* 2. init params.
* 3. set mqtt urc to at module.
* 4. set device info to at module.
*/
static int _qcloud_iot_mqtt_client_init(QcloudIotClient *client, const MQTTInitParams *params)
{
memset(client, 0x0, sizeof(QcloudIotClient));
client->device_info = params->device_info;
client->command_timeout_ms = params->command_timeout;
client->event_handle = params->event_handle;
client->default_subscribe = params->default_subscribe;
client->connect_state = MQTT_CONNECT_STATE_DISCONNECT;
client->tls_mode = TLS_MODE_TLS_PSK;
client->auto_connect_enable = params->auto_connect_enable;
client->clean_session = params->clean_session;
client->keep_alive_interval = params->keep_alive_interval > 690 ? 690 : params->keep_alive_interval;
client->lock_generic = HAL_MutexCreate();
if (!client->lock_generic) {
return QCLOUD_ERR_FAILURE;
}
// 1. detect module && close echo
int rc = HAL_Module_Init();
if (rc) {
Log_e("module init fail %d", rc);
return rc;
}
// 2. set urc function
rc = module_set_mqtt_urc();
if (rc) {
Log_e("set mqtt urc fail %d", rc);
return rc;
}
// 3. set device info
rc = module_device_info_set(client);
if (rc) {
Log_e("module init fail %d", rc);
return rc;
}
// 4. connect network
return HAL_Module_ConnectNetwork();
}
/**
* @brief Deinit mqtt client.
*
* @param[in,out] client pointer to mqtt client
*/
static void _qcloud_iot_mqtt_client_deinit(QcloudIotClient *client)
{
qcloud_iot_mqtt_sub_handle_array_clear(client);
HAL_MutexDestroy(client->lock_generic);
HAL_Module_Deinit();
Log_i("release mqtt client resources");
}
// ----------------------------------------------------------------------------
// API
// ----------------------------------------------------------------------------
/**
* @brief Only support one mqtt client when using at module.
*
*/
static QcloudIotClient *sg_mqtt_client;
/**
* @brief Get pointer to mqtt client.
*
* @return pointer to mqtt client.
*/
QcloudIotClient *qcloud_iot_get_mqtt_client(void)
{
return sg_mqtt_client;
}
/**
* @brief Create MQTT client and connect to MQTT server. Only one client supportted.
*
* @param[in] params MQTT init parameters
* @return a valid MQTT client handle when success, or NULL otherwise
*/
void *IOT_MQTT_Construct(const MQTTInitParams *params)
{
POINTER_SANITY_CHECK(params, NULL);
POINTER_SANITY_CHECK(params->device_info, NULL);
STRING_PTR_SANITY_CHECK(params->device_info->product_id, NULL);
STRING_PTR_SANITY_CHECK(params->device_info->device_name, NULL);
#ifdef AUTH_MODE_CERT
STRING_PTR_SANITY_CHECK(params->device_info->dev_cert_file_name, NULL);
STRING_PTR_SANITY_CHECK(params->device_info->dev_key_file_name, NULL);
#else
STRING_PTR_SANITY_CHECK(params->device_info->device_secret, NULL);
#endif
if (sg_mqtt_client) {
Log_e("only support one mqtt client in at module!");
return NULL;
}
int rc = 0;
QcloudIotClient *client = NULL;
// create and init MQTTClient
client = (QcloudIotClient *)HAL_Malloc(sizeof(QcloudIotClient));
if (!client) {
Log_e("malloc MQTTClient failed");
return NULL;
}
rc = _qcloud_iot_mqtt_client_init(client, params);
if (rc) {
Log_e("mqtt init failed: %d", rc);
goto exit;
}
if (!params->connect_when_construct) {
return client;
}
rc = IOT_MQTT_Connect(client);
if (rc) {
goto exit;
}
client->connect_state = MQTT_CONNECT_STATE_CONNECTED;
Log_i("mqtt connect with success");
sg_mqtt_client = client;
return client;
exit:
_qcloud_iot_mqtt_client_deinit(client);
HAL_Free(client);
return NULL;
}
/**
* @brief Connect Mqtt server if not connect.
*
* @param[in,out] client pointer to mqtt client pointer, should using the pointer of IOT_MQTT_Construct return.
* @return @see IotReturnCode
*/
int IOT_MQTT_Connect(void *client)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
int rc = 0;
QcloudIotTimer connect_timer;
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
if (mqtt_client->connect_state == MQTT_CONNECT_STATE_DISCONNECT) {
IOT_Timer_CountdownMs(&connect_timer, MAX_RECONNECT_WAIT_INTERVAL);
do { // wait for wifi config
rc = module_mqtt_connect(client);
if (rc) {
Log_e("mqtt connect with failed: %d", rc);
HAL_SleepMs(QCLOUD_IOT_MQTT_WAIT_ACK_TIMEOUT);
}
if (IOT_Timer_Expired(&connect_timer)) {
return QCLOUD_ERR_FAILURE;
}
} while (rc);
}
return QCLOUD_RET_SUCCESS;
}
/**
* @brief Close connection and destroy MQTT client.
*
* @param[in,out] client pointer to mqtt client pointer, should using the pointer of IOT_MQTT_Construct return.
* @return @see IotReturnCode
*/
int IOT_MQTT_Destroy(void **client)
{
POINTER_SANITY_CHECK(*client, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)(*client);
int rc = module_mqtt_disconnect(mqtt_client);
_qcloud_iot_mqtt_client_deinit(mqtt_client);
HAL_Free(*client);
*client = sg_mqtt_client = NULL;
Log_i("mqtt release!");
return rc;
}
/**
* @brief Check connection state.
*
* @param[in,out] client pointer to mqtt client
* @param[in] timeout_ms timeout value (unit: ms) for this operation
* @return QCLOUD_RET_SUCCESS when success, others @see IotReturnCode
*/
int IOT_MQTT_Yield(void *client, uint32_t timeout_ms)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
HAL_SleepMs(timeout_ms);
module_mqtt_get_connect_state(mqtt_client);
switch (mqtt_client->connect_state) {
case MQTT_CONNECT_STATE_CONNECTED:
return QCLOUD_RET_SUCCESS;
case MQTT_CONNECT_STATE_RECONNECTING:
return QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT;
case MQTT_CONNECT_STATE_RECONNECTED:
return QCLOUD_RET_MQTT_RECONNECTED;
case MQTT_CONNECT_STATE_DISCONNECT:
return QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT;
}
return QCLOUD_RET_SUCCESS;
}
/**
* @brief Publish MQTT message.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_name topic to publish
* @param[in] params @see PublishParams
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_MQTT_Publish(void *client, const char *topic_name, const PublishParams *params)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(params, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topic_name, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
if (strlen(topic_name) > MAX_SIZE_OF_CLOUD_TOPIC) {
return QCLOUD_ERR_MAX_TOPIC_LENGTH;
}
if (QOS2 == params->qos) {
Log_e("QoS2 is not supported currently");
return QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT;
}
return module_mqtt_publish(mqtt_client, topic_name, params);
}
/**
* @brief Subscribe MQTT topic.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to subscribe
* @param[in] params @see SubscribeParams
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_MQTT_Subscribe(void *client, const char *topic_filter, const SubscribeParams *params)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(params, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
if (strlen(topic_filter) > MAX_SIZE_OF_CLOUD_TOPIC) {
return QCLOUD_ERR_MAX_TOPIC_LENGTH;
}
if (QOS2 == params->qos) {
Log_e("QoS2 is not supported currently");
return QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT;
}
return qcloud_iot_mqtt_subscribe(mqtt_client, topic_filter, params);
}
/**
* @brief Unsubscribe MQTT topic.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to unsubscribe
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_MQTT_Unsubscribe(void *client, const char *topic_filter)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
if (strlen(topic_filter) > MAX_SIZE_OF_CLOUD_TOPIC) {
return QCLOUD_ERR_MAX_TOPIC_LENGTH;
}
return qcloud_iot_mqtt_unsubscribe(mqtt_client, topic_filter);
}
/**
* @brief Check if MQTT topic has been subscribed or not
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to subscribe
* @return true already subscribed
* @return false not ready
*/
bool IOT_MQTT_IsSubReady(void *client, const char *topic_filter)
{
POINTER_SANITY_CHECK(client, false);
STRING_PTR_SANITY_CHECK(topic_filter, false);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
return qcloud_iot_mqtt_is_sub_ready(mqtt_client, topic_filter);
}
/**
* @brief Get user data in subscribe.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to subscribe
* @return NULL or user data
*/
void *IOT_MQTT_GetSubUsrData(void *client, const char *topic_filter)
{
POINTER_SANITY_CHECK(client, NULL);
STRING_PTR_SANITY_CHECK(topic_filter, NULL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
return qcloud_iot_mqtt_get_subscribe_usr_data(mqtt_client, topic_filter);
}
/**
* @brief Subscribe and wait sub ready.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter to subscribe
* @param[in] params @see SubscribeParams
* @return @see IotReturnCode
*/
int IOT_MQTT_SubscribeSync(void *client, const char *topic_filter, const SubscribeParams *params)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(params, QCLOUD_ERR_INVAL);
STRING_PTR_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
return IOT_MQTT_Subscribe(client, topic_filter, params);
}
/**
* @brief Check if MQTT is connected.
*
* @param[in,out] client pointer to mqtt client
* @return true connected
* @return false no connected
*/
bool IOT_MQTT_IsConnected(void *client)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
module_mqtt_get_connect_state(mqtt_client);
return mqtt_client->connect_state != MQTT_CONNECT_STATE_DISCONNECT;
}
/**
* @brief Get device info using to connect mqtt server.
*
* @param[in,out] client pointer to mqtt client
* @return @see DeviceInfo
*/
DeviceInfo *IOT_MQTT_GetDeviceInfo(void *client)
{
POINTER_SANITY_CHECK(client, NULL);
QcloudIotClient *mqtt_client = (QcloudIotClient *)client;
return mqtt_client->device_info;
}

View File

@@ -0,0 +1,114 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file at_module_mqtt_publish.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-25 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "at_module.h"
/**
* @brief Check if topic match
*
* @param[in] topic_filter topic name filter, wildcard is supported
* @param[in] topic_name topic name, no wildcard
* @param[in] topic_name_len length of topic name
* @return 1 for matched, 0 for no matched
*
* @note assume topic filter and name is in correct format;
* # can only be at end;
* + and # can only be next to separator.
*/
static uint8_t _is_topic_matched(char *topic_filter, const char *topic_name, uint16_t topic_name_len)
{
char *curf = topic_filter;
char *curn = (char *)topic_name;
char *curn_end = curn + topic_name_len;
while (*curf && curn < curn_end) {
if (*curn == '/' && *curf != '/')
break;
if (*curf != '+' && *curf != '#' && *curf != *curn)
break;
if (*curf == '+') { // skip until we meet the next separator, or end of string
char *nextpos = curn + 1;
while (nextpos < curn_end && *nextpos != '/') nextpos = ++curn + 1;
} else if (*curf == '#')
curn = curn_end - 1; // skip until end of string
curf++;
curn++;
};
return (curn == curn_end) && (*curf == '\0');
}
/**
* @brief Deliver message to subscribe message handler.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_name topic name, no wildcard
* @param[in] payload publish packet payload
* @param[in] payload_len payload length
*/
void qcloud_iot_deliver_message(QcloudIotClient *client, char *topic_name, char *payload, int payload_len)
{
int i;
MQTTMessage message = {
.qos = QOS0, // no use
.retain = 0,
.dup = 0,
.packet_id = 0,
.topic_name = topic_name,
.topic_len = strlen(topic_name),
.payload_str = payload,
.payload_len = payload_len,
};
HAL_MutexLock(client->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if (client->sub_handles[i].topic_filter &&
_is_topic_matched(client->sub_handles[i].topic_filter, message.topic_name, message.topic_len)) {
if (client->sub_handles[i].params.on_message_handler) {
HAL_MutexUnlock(client->lock_generic);
// if found, then handle it, then return
client->sub_handles[i].params.on_message_handler(client, &message,
client->sub_handles[i].params.user_data);
return;
}
}
}
HAL_MutexUnlock(client->lock_generic);
/* Message handler not found for topic */
/* May be we do not care change FAILURE use SUCCESS*/
Log_d("no matching any topic, call default handle function");
MQTTEventMsg msg;
if (client->event_handle.h_fp) {
msg.event_type = MQTT_EVENT_PUBLISH_RECEIVED;
msg.msg = &message;
client->event_handle.h_fp(client, client->event_handle.context, &msg);
}
}

View File

@@ -0,0 +1,255 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file at_module_mqtt_subscribe.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-25 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "at_module.h"
/**
* @brief Free topic_filter and user_data
*
* @param[in] handler subtopic handle
*/
static void _clear_sub_handle(SubTopicHandle *handler)
{
if (handler->topic_filter) {
HAL_Free(handler->topic_filter);
handler->topic_filter = NULL;
}
if (handler->params.user_data && handler->params.user_data_free) {
handler->params.user_data_free(handler->params.user_data);
handler->params.user_data = NULL;
}
}
/**
* @brief Remove sub handle when unsubscribe.
*
* @param[in,out] client pointer to mqtt_client
* @param[in] topic_filter topic to remove
* @return true topic exist
* @return false topic no exist
*/
static bool _remove_sub_handle_from_array(QcloudIotClient *client, const char *topic_filter)
{
int i;
bool topic_exists = false;
// remove from message handler array
HAL_MutexLock(client->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if ((client->sub_handles[i].topic_filter && !strcmp(client->sub_handles[i].topic_filter, topic_filter)) ||
strstr(topic_filter, "/#") || strstr(topic_filter, "/+")) {
// notify this event to topic subscriber
if (client->sub_handles[i].params.on_sub_event_handler) {
client->sub_handles[i].params.on_sub_event_handler(client, MQTT_EVENT_UNSUBSCRIBE,
client->sub_handles[i].params.user_data);
}
_clear_sub_handle(&client->sub_handles[i]);
// we don't want to break here, if the same topic is registered*with 2 callbacks.Unlikely scenario
topic_exists = true;
}
}
HAL_MutexUnlock(client->lock_generic);
return topic_exists;
}
/**
* @brief Add sub handle when subscribe.
*
* @param[in,out] client pointer to mqtt_client
* @param[in] sub_handle sub_handle to be add to array
* @return true topic exist
* @return false topic no exist
*/
static int _add_sub_handle_to_array(QcloudIotClient *client, const SubTopicHandle *sub_handle)
{
IOT_FUNC_ENTRY;
int i, i_free = -1;
HAL_MutexLock(client->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if (client->sub_handles[i].topic_filter) {
if (!strcmp(client->sub_handles[i].topic_filter, sub_handle->topic_filter)) {
i_free = i;
// free the memory before
_clear_sub_handle(&client->sub_handles[i]);
Log_w("Identical topic found: %s", sub_handle->topic_filter);
break;
}
} else {
i_free = i_free == -1 ? i : i_free;
}
}
if (-1 == i_free) {
Log_e("NO more @sub_handles space!");
HAL_MutexUnlock(client->lock_generic);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
}
client->sub_handles[i_free] = *sub_handle;
HAL_MutexUnlock(client->lock_generic);
IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
}
/**
* @brief Serialize and send subscribe packet.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic to subscribe
* @param[in] params subscribe params
* @return >=0 for packet id, < 0 for failed @see IotReturnCode
*/
int qcloud_iot_mqtt_subscribe(QcloudIotClient *client, const char *topic_filter, const SubscribeParams *params)
{
IOT_FUNC_ENTRY;
int rc, qos = params->qos;
char *topic_filter_stored;
SubTopicHandle sub_handle;
// topic filter should be valid in the whole sub life
topic_filter_stored = HAL_Malloc(strlen(topic_filter) + 1);
if (!topic_filter_stored) {
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MALLOC);
}
strncpy(topic_filter_stored, topic_filter, strlen(topic_filter) + 1);
sub_handle.topic_filter = topic_filter_stored;
sub_handle.params = *params;
sub_handle.status = client->default_subscribe ? SUB_ACK_RECEIVED : SUB_ACK_NOT_RECEIVED;
// add sub handle first to process
rc = _add_sub_handle_to_array(client, &sub_handle);
if (rc) {
goto exit;
}
if (client->default_subscribe) {
return 0;
}
rc = module_mqtt_subscribe(client, topic_filter, qos);
if (!rc) {
sub_handle.status = SUB_ACK_RECEIVED;
}
IOT_FUNC_EXIT_RC(rc);
exit:
_remove_sub_handle_from_array(client, topic_filter_stored);
IOT_FUNC_EXIT_RC(rc);
}
/**
* @brief Serialize and send unsubscribe packet.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic to unsubscribe
* @return >=0 packet id, < 0 for failed @see IotReturnCode
*/
int qcloud_iot_mqtt_unsubscribe(QcloudIotClient *client, const char *topic_filter)
{
IOT_FUNC_ENTRY;
SubTopicHandle sub_handle;
memset(&sub_handle, 0, sizeof(SubTopicHandle));
// remove from sub handle
if (!_remove_sub_handle_from_array(client, topic_filter)) {
Log_w("subscription does not exists: %s", topic_filter);
IOT_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_UNSUB_FAIL);
}
IOT_FUNC_EXIT_RC(module_mqtt_unsubscribe(client, topic_filter));
}
/**
* @brief Return if topic is sub ready.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter
* @return true for ready
* @return false for not ready
*/
bool qcloud_iot_mqtt_is_sub_ready(QcloudIotClient *client, const char *topic_filter)
{
IOT_FUNC_ENTRY;
int i = 0;
HAL_MutexLock(client->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if ((client->sub_handles[i].topic_filter && !strcmp(client->sub_handles[i].topic_filter, topic_filter)) ||
strstr(topic_filter, "/#") || strstr(topic_filter, "/+")) {
HAL_MutexUnlock(client->lock_generic);
return client->sub_handles[i].status == SUB_ACK_RECEIVED;
}
}
HAL_MutexUnlock(client->lock_generic);
IOT_FUNC_EXIT_RC(false);
}
/**
* @brief Get usr data, usr should handle lock/unlock usrdata itself in callback and caller.
*
* @param[in,out] client pointer to mqtt client
* @param[in] topic_filter topic filter
* @return NULL or user data
*/
void *qcloud_iot_mqtt_get_subscribe_usr_data(QcloudIotClient *client, const char *topic_filter)
{
IOT_FUNC_ENTRY;
int i = 0;
HAL_MutexLock(client->lock_generic);
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
if ((client->sub_handles[i].topic_filter && !strcmp(client->sub_handles[i].topic_filter, topic_filter)) ||
strstr(topic_filter, "/#") || strstr(topic_filter, "/+")) {
HAL_MutexUnlock(client->lock_generic);
return client->sub_handles[i].params.user_data;
}
}
HAL_MutexUnlock(client->lock_generic);
IOT_FUNC_EXIT_RC(NULL);
}
/**
* @brief Clear sub handle array.
*
* @param[in,out] client pointer to mqtt client
*/
void qcloud_iot_mqtt_sub_handle_array_clear(QcloudIotClient *client)
{
IOT_FUNC_ENTRY;
int i;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
/* notify this event to topic subscriber */
if (client->sub_handles[i].topic_filter && client->sub_handles[i].params.on_sub_event_handler) {
client->sub_handles[i].params.on_sub_event_handler(client, MQTT_EVENT_CLIENT_DESTROY,
client->sub_handles[i].params.user_data);
}
_clear_sub_handle(&client->sub_handles[i]);
}
IOT_FUNC_EXIT;
}

View File

@@ -0,0 +1,116 @@
/**
* @file at_module_ota.c
* @author {hubert} ({hubertxxu@tencent.com})
* @brief
* @version 1.0
* @date 2022-06-07
*
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @par Change Log:
* <table>
* Date Version Author Description
* 2022-06-07 1.0 hubertxxu first commit
* </table>
*/
#include "at_module.h"
/**
* @brief OTA info handle.
*
*/
static QcloudIotOtaFwInfo sg_iot_ota_info_handle;
/**
* @brief Get ota info handle.
*
* @return @see QcloudIotOtaFwInfo
*/
QcloudIotOtaFwInfo *qcloud_iot_get_ota_info_handle(void)
{
return &sg_iot_ota_info_handle;
}
/**
* @brief Init ota && report mcu & at version.
*
* @param[in] version mcu version.
* @return 0 for success
*/
int IOT_OTA_Init(const char *version)
{
sg_iot_ota_info_handle.get_fw_info_sem = HAL_SemaphoreCreate();
if (!sg_iot_ota_info_handle.get_fw_info_sem) {
Log_e("create sem fail.");
return QCLOUD_ERR_FAILURE;
}
module_set_ota_urc();
// TODO: get at module version and change cls state.
return module_ota_set_fw_version(IOT_OTA_CLS_STATE_REPORT_MCU, version);
}
/**
* @brief Deinit ota.
*
*/
void IOT_OTA_Deinit(void)
{
HAL_SemaphoreDestroy(sg_iot_ota_info_handle.get_fw_info_sem);
}
/**
* @brief Read fw info from at module.
*
* @param[out] version mcu fw version
* @param[out] fw_size mcu fw size
* @param[out] md5 mcu fw md5
* @param[in] timeout_ms timeout
* @return 0 for success
*/
int IOT_OTA_ReadFwInfo(char **version, uint32_t *fw_size, char **md5, uint32_t timeout_ms)
{
int rc = 0;
rc = module_ota_get_fw_info();
if (rc) {
return rc;
}
rc = HAL_SemaphoreWait(sg_iot_ota_info_handle.get_fw_info_sem, timeout_ms);
if (rc) {
*version = NULL;
*fw_size = 0;
*md5 = NULL;
return QCLOUD_ERR_FAILURE;
}
*version = sg_iot_ota_info_handle.version;
*fw_size = sg_iot_ota_info_handle.fw_size;
*md5 = sg_iot_ota_info_handle.md5;
return QCLOUD_RET_SUCCESS;
}
/**
* @brief Read fw data from at module.
*
* @param[out] fw_data fw data
* @param[out] fw_data_len fw data length
* @param[in] timeout_ms timeout
* @return 0 for success
*/
int IOT_OTA_ReadFWData(uint8_t *fw_data, uint32_t *fw_data_len, uint32_t timeout_ms)
{
return module_ota_read_fw_data(fw_data, fw_data_len, timeout_ms);
}

View File

@@ -0,0 +1,230 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file at_module_urc.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-04-24
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-04-24 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "at_module.h"
/**
* @brief URC for iot hub
* 1. urc for at command
* +TCMQTTRCVPUB
* +TCMQTTDISCON
* +TCMQTTRECONNECTING
* +TCMQTTRECONNECTED
* +TCOTASTATUS
* 2. urc cmd response
* +TCMQTTSTATE
* 3. urc for ota
* +TCREADFWDATA
* +TCFWINFO
* +TCOTASTATUS
*
*/
// ----------------------------------------------------------------------------
// mqtt urc handle
// ----------------------------------------------------------------------------
/**
* @brief Discconect by mqtt server.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_mqtt_disconnect_handle(const char *data, size_t data_len)
{
// +TCMQTTSTATE:-3
int error_code = 0;
QcloudIotClient *mqtt_client = qcloud_iot_get_mqtt_client();
if (!mqtt_client) {
return;
}
mqtt_client->connect_state = MQTT_CONNECT_STATE_DISCONNECT;
sscanf(data, "+TCMQTTDISCON,%d", &error_code);
Log_e("disconnect %d", error_code);
}
/**
* @brief Reconnecting.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_mqtt_reconnect_handle(const char *data, size_t data_len)
{
// +TCMQTTRECONNECTING
QcloudIotClient *mqtt_client = qcloud_iot_get_mqtt_client();
if (!mqtt_client) {
return;
}
mqtt_client->connect_state = MQTT_CONNECT_STATE_RECONNECTING;
}
/**
* @brief Reconnected.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_mqtt_reconnected_handle(const char *data, size_t data_len)
{
// +TCMQTTRECONNECTED
QcloudIotClient *mqtt_client = qcloud_iot_get_mqtt_client();
if (!mqtt_client) {
return;
}
mqtt_client->connect_state = MQTT_CONNECT_STATE_RECONNECTED;
}
/**
* @brief Connect state.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_mqtt_state_handle(const char *data, size_t data_len)
{
// +TCMQTTSTATE:1
int connect_state = 1;
QcloudIotClient *mqtt_client = qcloud_iot_get_mqtt_client();
if (!mqtt_client) {
return;
}
sscanf(data, "+TCMQTTSTATE:%d", &connect_state);
Log_d("mqtt state %d", connect_state);
if (connect_state) {
mqtt_client->connect_state = MQTT_CONNECT_STATE_CONNECTED;
}
}
/**
* @brief Recv publish packet.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_mqtt_publish_handle(const char *data, size_t data_len)
{
// +TCMQTTRCVPUB:"$thing/down/property/Q5NNWVC2Z8/test1",81,"{"method":"report_reply","clientToken":"property-69","code":0,"status":"success"}"
QcloudIotClient *mqtt_client = qcloud_iot_get_mqtt_client();
if (!mqtt_client) {
return;
}
char *head, *topic_name, *payload;
char *src = (char *)data;
src[data_len - 1] = '\0';
head = strtok((char *)data, "\"");
if (!head) {
return;
}
topic_name = strtok(NULL, "\"");
if (!topic_name) {
return;
}
strtok(NULL, "\"");
payload = strtok(NULL, "");
if (!payload) {
return;
}
qcloud_iot_deliver_message(mqtt_client, topic_name, payload, strlen(payload));
}
// ----------------------------------------------------------------------------
// ota urc handle
// ----------------------------------------------------------------------------
static void _delete_char(char *str, char ch)
{
char *p;
for (p = str; *p != '\0'; p++)
if (*p != ch)
*str++ = *p;
*str = '\0';
}
/**
* @brief Recv fw info.
*
* @param[in] data data recv from at module
* @param[in] data_len data len
*/
static void _urc_ota_fw_info_handle(const char *data, size_t data_len)
{
// +TCFWINFO:"1.2.0",17300,"a2aa3c261ebfc1322edafd37edb6b183",262144
QcloudIotOtaFwInfo *ota_info = qcloud_iot_get_ota_info_handle();
_delete_char((char *)data, '"');
sscanf((char *)data, "+TCFWINFO:%[^,],%u,%[^,],%u", ota_info->version, &(ota_info->fw_size), ota_info->md5,
&ota_info->fw_max_size);
HAL_SemaphorePost(ota_info->get_fw_info_sem);
}
static void _urc_ota_state_handle(const char *data, size_t data_len)
{
// Todo
}
// ----------------------------------------------------------------------------
// API
// ----------------------------------------------------------------------------
/**
* @brief Set mqtt urc to at module.
*
* @return 0 means successful.
*/
int module_set_mqtt_urc(void)
{
int rc;
rc = HAL_Module_SetUrc("+TCMQTTRCVPUB", _urc_mqtt_publish_handle);
rc |= HAL_Module_SetUrc("+TCMQTTDISCON", _urc_mqtt_disconnect_handle);
rc |= HAL_Module_SetUrc("+TCMQTTRECONNECTING", _urc_mqtt_reconnect_handle);
rc |= HAL_Module_SetUrc("+TCMQTTRECONNECTED", _urc_mqtt_reconnected_handle);
rc |= HAL_Module_SetUrc("+TCMQTTSTATE", _urc_mqtt_state_handle);
return rc;
}
/**
* @brief Set ota urc to at module.
*
* @return 0 means successful.
*/
int module_set_ota_urc(void)
{
int rc;
rc = HAL_Module_SetUrc("+TCFWINFO", _urc_ota_fw_info_handle);
rc |= HAL_Module_SetUrc("+TCOTASTATUS", _urc_ota_state_handle);
return rc;
}