update qcloud sdk

1. iot-hub sdk update to 3.2.0
2. iot-explorer update to 3.1.1
This commit is contained in:
daishengdong
2020-05-07 11:11:04 +08:00
parent c8e39739d3
commit 3e631cd96a
594 changed files with 47287 additions and 44165 deletions

View File

@@ -0,0 +1,111 @@
set(INC_DIR ${PROJECT_SOURCE_DIR}/output/${BUILD_TYPE}/include)
set(LINK_DIR ${PROJECT_SOURCE_DIR}/output/${BUILD_TYPE}/lib/)
include_directories(${INC_DIR})
link_directories(${LINK_DIR})
if(FEATURE_AUTH_WITH_NOTLS)
set(link_lib
iot_sdk
iot_platform
)
else()
set(link_lib
iot_sdk
iot_platform
mbedtls
mbedx509
mbedcrypto
)
endif()
if (PLATFORM STREQUAL "linux" AND COMPILE_TOOLS STREQUAL "gcc")
set(lib -Wl,--start-group ${link_lib} -Wl,--end-group)
elseif (PLATFORM STREQUAL "windows" AND COMPILE_TOOLS STREQUAL "MSVC")
set(lib ${link_lib})
endif()
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/output/${BUILD_TYPE}/bin)
# MQTT
if(${FEATURE_MQTT_COMM_ENABLED} STREQUAL "ON")
file(GLOB src_mqtt_sample ${PROJECT_SOURCE_DIR}/samples/mqtt/mqtt_sample.c)
add_executable(mqtt_sample ${src_mqtt_sample})
target_link_libraries(mqtt_sample ${lib})
file(GLOB src_door_mqtt_sample ${PROJECT_SOURCE_DIR}/samples/scenarized/door_mqtt_sample.c)
add_executable(door_mqtt_sample ${src_door_mqtt_sample})
target_link_libraries(door_mqtt_sample ${lib})
endif()
# Multi-Thread Multi-Client sample
if (${FEATURE_MULTITHREAD_ENABLED} STREQUAL "ON")
file(GLOB src_multi_thread_mqtt_sample ${PROJECT_SOURCE_DIR}/samples/mqtt/multi_thread_mqtt_sample.c)
add_executable(multi_thread_mqtt_sample ${src_multi_thread_mqtt_sample})
target_link_libraries(multi_thread_mqtt_sample ${lib})
if (${FEATURE_DEBUG_DEV_INFO_USED} STREQUAL "OFF")
file(GLOB src_multi_client_mqtt_sample ${PROJECT_SOURCE_DIR}/samples/multi_client/multi_client_mqtt_sample.c)
add_executable(multi_client_mqtt_sample ${src_multi_client_mqtt_sample})
target_link_libraries(multi_client_mqtt_sample ${lib})
file(GLOB src_multi_client_shadow_sample ${PROJECT_SOURCE_DIR}/samples/multi_client/multi_client_shadow_sample.c)
add_executable(multi_client_shadow_sample ${src_multi_client_shadow_sample})
target_link_libraries(multi_client_shadow_sample ${lib})
endif()
endif()
# DYN_REG
if(${FEATURE_DEV_DYN_REG_ENABLED} STREQUAL "ON")
file(GLOB src_dynreg_dev_sample ${PROJECT_SOURCE_DIR}/samples/dynreg_dev/dynreg_dev_sample.c)
add_executable(dynreg_dev_sample ${src_dynreg_dev_sample})
target_link_libraries(dynreg_dev_sample ${lib})
endif()
# OTA MQTT
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON" AND ${FEATURE_OTA_SIGNAL_CHANNEL} STREQUAL "MQTT")
file(GLOB src_ota_mqtt_sample ${PROJECT_SOURCE_DIR}/samples/ota/ota_mqtt_sample.c)
add_executable(ota_mqtt_sample ${src_ota_mqtt_sample})
target_link_libraries(ota_mqtt_sample ${lib})
endif()
# SHADOW
if(${FEATURE_MQTT_DEVICE_SHADOW} STREQUAL "ON")
file(GLOB src_shadow_sample ${PROJECT_SOURCE_DIR}/samples/shadow/shadow_sample.c)
add_executable(shadow_sample ${src_shadow_sample})
target_link_libraries(shadow_sample ${lib})
file(GLOB src_aircond_shadow_sample ${PROJECT_SOURCE_DIR}/samples/scenarized/aircond_shadow_sample.c)
file(GLOB src_aircond_shadow_sample_v2 ${PROJECT_SOURCE_DIR}/samples/scenarized/aircond_shadow_sample_v2.c)
add_executable(aircond_shadow_sample ${src_aircond_shadow_sample})
add_executable(aircond_shadow_sample_v2 ${src_aircond_shadow_sample_v2})
target_link_libraries(aircond_shadow_sample ${lib})
target_link_libraries(aircond_shadow_sample_v2 ${lib})
endif()
# GATEWAY
if(${FEATURE_GATEWAY_ENABLED} STREQUAL "ON")
file(GLOB src_gateway_sample ${PROJECT_SOURCE_DIR}/samples/gateway/gateway_sample.c)
add_executable(gateway_sample ${src_gateway_sample})
target_link_libraries(gateway_sample ${lib})
endif()
# COAP
if(${FEATURE_COAP_COMM_ENABLED} STREQUAL "ON")
file(GLOB src_coap_sample ${PROJECT_SOURCE_DIR}/samples/coap/coap_sample.c)
add_executable(coap_sample ${src_coap_sample})
target_link_libraries(coap_sample ${lib})
file(GLOB src_door_coap_sample ${PROJECT_SOURCE_DIR}/samples/scenarized/door_coap_sample.c)
add_executable(door_coap_sample ${src_door_coap_sample})
target_link_libraries(door_coap_sample ${lib})
endif()
if(${FEATURE_OTA_COMM_ENABLED} STREQUAL "ON" AND ${FEATURE_OTA_SIGNAL_CHANNEL} STREQUAL "COAP")
file(GLOB src_ota_coap_sample ${PROJECT_SOURCE_DIR}/samples/ota/ota_coap_sample.c)
add_executable(ota_coap_sample ${src_ota_coap_sample})
target_link_libraries(ota_coap_sample ${lib})
endif()

View File

@@ -0,0 +1,158 @@
# Basic Settings
SHELL := /bin/bash
TOP_DIR ?= $(CURDIR)/../
SUBDIRS := directory-not-exist-actually
# Settings of input directory
SCRIPT_DIR := $(TOP_DIR)/tools/build_scripts
include $(TOP_DIR)/make.settings
include $(SCRIPT_DIR)/parse_make_settings.mk
# Makefile echo
ifeq ($(DEBUG_MAKEFILE),n)
Q := @
TOP_Q := @
else
Q :=
TOP_Q :=
endif
# Settings of output directory
SAMPLE_DIR := $(CURDIR)
FINAL_DIR := $(CURDIR)/../output/$(BUILD_TYPE)
IOT_LIB_DIR = $(FINAL_DIR)/lib
IOT_INC_CFLAGS = -I$(FINAL_DIR)/include -I$(FINAL_DIR)/include/exports
LDFLAGS := -Wl,--start-group $(IOT_LIB_DIR)/libiot_sdk.a
ifeq ($(FEATURE_AUTH_WITH_NOTLS),n)
LDFLAGS += $(IOT_LIB_DIR)/libmbedtls.a $(IOT_LIB_DIR)/libmbedx509.a $(IOT_LIB_DIR)/libmbedcrypto.a
endif
LDFLAGS += $(IOT_LIB_DIR)/libiot_platform.a -Wl,--end-group
CFLAGS += -Wall -Wno-error=sign-compare -Wno-error=format -Os -pthread -DFORCE_SSL_VERIFY
CFLAGS += ${IOT_INC_CFLAGS}
ifeq ($(FEATURE_AUTH_MODE),CERT)
CFLAGS += -DAUTH_MODE_CERT
endif
.PHONY: mqtt_sample ota_mqtt_sample ota_coap_sample shadow_sample coap_sample gateway_sample multi_thread_mqtt_sample dynreg_dev_sample multi_client
all: mqtt_sample ota_mqtt_sample ota_coap_sample shadow_sample coap_sample gateway_sample multi_thread_mqtt_sample dynreg_dev_sample multi_client
ifneq (,$(filter -DMQTT_COMM_ENABLED,$(CFLAGS)))
mqtt_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/mqtt/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/scenarized/door_$@.c $(LDFLAGS) -o door_$@
$(TOP_Q) \
mv door_$@ $(FINAL_DIR)/bin && \
mv $@ $(FINAL_DIR)/bin
# Multi-Thread Multi-Client sample
ifneq (,$(filter -DMULTITHREAD_ENABLED,$(CFLAGS)))
multi_thread_mqtt_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/mqtt/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
ifeq (,$(filter -DDEBUG_DEV_INFO_USED,$(CFLAGS)))
multi_client:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/multi_client/$@_mqtt_sample.c $(LDFLAGS) -o $@_mqtt_sample
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/multi_client/$@_shadow_sample.c $(LDFLAGS) -o $@_shadow_sample
$(TOP_Q) \
mv $@_mqtt_sample $(FINAL_DIR)/bin && \
mv $@_shadow_sample $(FINAL_DIR)/bin
endif
endif
ifneq (,$(filter -DDEV_DYN_REG_ENABLED,$(CFLAGS)))
dynreg_dev_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/dynreg_dev/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
endif
ifneq (,$(filter -DOTA_COMM_ENABLED,$(CFLAGS)))
ifneq (,$(filter -DOTA_MQTT_CHANNEL,$(CFLAGS)))
ota_mqtt_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/ota/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
endif
endif
ifneq (,$(filter -DMQTT_DEVICE_SHADOW,$(CFLAGS)))
shadow_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/shadow/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/scenarized/aircond_$@.c $(LDFLAGS) -o aircond_$@
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/scenarized/aircond_$@_v2.c $(LDFLAGS) -o aircond_$@_v2
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin && \
mv aircond_$@ $(FINAL_DIR)/bin && \
mv aircond_$@_v2 $(FINAL_DIR)/bin
endif
ifneq (,$(filter -DGATEWAY_ENABLED,$(CFLAGS)))
gateway_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/gateway/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
endif
endif
ifneq (,$(filter -DCOAP_COMM_ENABLED,$(CFLAGS)))
coap_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/coap/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/scenarized/door_$@.c $(LDFLAGS) -o door_$@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
$(TOP_Q) \
mv door_$@ $(FINAL_DIR)/bin
ifneq (,$(filter -DOTA_COMM_ENABLED,$(CFLAGS)))
ifneq (,$(filter -DOTA_COAP_CHANNEL,$(CFLAGS)))
ota_coap_sample:
$(TOP_Q) \
$(PLATFORM_CC) $(CFLAGS) $(SAMPLE_DIR)/ota/$@.c $(LDFLAGS) -o $@
$(TOP_Q) \
mv $@ $(FINAL_DIR)/bin
endif
endif
endif
clean:
rm -rf $(FINAL_DIR)/bin/*

View File

@@ -0,0 +1,195 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
void response_message_callback(void *coap_message, void *userContext)
{
int ret_code = IOT_COAP_GetMessageCode(coap_message);
switch (ret_code) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_RECEIVE_RESPCONTENT: {
char *payload = NULL;
int payload_len = 0;
int ret = -1;
ret = IOT_COAP_GetMessagePayload(coap_message, &payload, &payload_len);
if (ret == QCLOUD_RET_SUCCESS) {
Log_i("message received response, content: %s", payload);
} else {
Log_e("message received response, content error.");
}
}
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
default:
break;
}
}
void event_handler(void *pcontext, CoAPEventMessage *message)
{
switch (message->event_type) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_RECEIVE_RESPCONTENT:
Log_i("message received response, content: %s", IOT_COAP_GetMessageId(message->message));
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d",
(unsigned)(uintptr_t)message->message);
break;
default:
Log_e("unrecogonized event type: %d", message->event_type);
break;
}
}
static int _setup_connect_init_params(CoAPInitParams *initParams, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->event_handle.h_fp = event_handler;
initParams->max_retry_count = 3;
return QCLOUD_RET_SUCCESS;
}
int main(int argc, char **argv)
{
int rc = QCLOUD_RET_SUCCESS;
IOT_Log_Set_Level(eLOG_DEBUG);
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
return rc;
}
CoAPInitParams init_params = DEFAULT_COAPINIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *coap_client = IOT_COAP_Construct(&init_params);
if (coap_client == NULL) {
Log_e("COAP Client construct failed.");
return QCLOUD_ERR_FAILURE;
}
do {
SendMsgParams send_params = DEFAULT_SENDMSG_PARAMS;
send_params.pay_load = "{\"action\":\"hello world\"}";
send_params.pay_load_len = strlen("{\"action\":\"hello world\"}");
send_params.resp_callback = response_message_callback;
char topicName[128] = "";
sprintf(topicName, "%s/%s/data", device_info.product_id, device_info.device_name);
Log_i("topic name is %s", topicName);
rc = IOT_COAP_SendMessage(coap_client, topicName, &send_params);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
} else {
Log_d("client topic has been sent, msg_id: %d", rc);
}
if (!(argc >= 2 && !strcmp("loop", argv[1]))) {
HAL_SleepMs(1000);
}
rc = IOT_COAP_Yield(coap_client, 200);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("exit with error: %d", rc);
break;
}
if (argc >= 2)
HAL_SleepMs(1000);
} while (argc >= 2 && !strcmp("loop", argv[1]));
IOT_COAP_Destroy(&coap_client);
return QCLOUD_RET_SUCCESS;
}

View File

@@ -0,0 +1,105 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
#ifdef AUTH_MODE_CERT
/* NULL cert file */
#define QCLOUD_IOT_NULL_CERT_FILENAME "YOUR_DEVICE_NAME_cert.crt"
/* NULL key file */
#define QCLOUD_IOT_NULL_KEY_FILENAME "YOUR_DEVICE_NAME_private.key"
#else
/* NULL device secret */
#define QCLOUD_IOT_NULL_DEVICE_SECRET "YOUR_IOT_PSK"
#endif
int main(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "c:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file for DeviceInfo>] \n",
argv[0]);
return -1;
}
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
int ret;
DeviceInfo sDevInfo;
bool infoNullFlag = false;
memset((char *)&sDevInfo, 0, sizeof(DeviceInfo));
ret = HAL_GetDevInfo(&sDevInfo);
#ifdef AUTH_MODE_CERT
/* just demo the cert/key files are empty */
if (!strcmp(sDevInfo.dev_cert_file_name, QCLOUD_IOT_NULL_CERT_FILENAME) ||
!strcmp(sDevInfo.dev_key_file_name, QCLOUD_IOT_NULL_KEY_FILENAME)) {
Log_d("dev Cert not exist!");
infoNullFlag = true;
} else {
Log_d("dev Cert exist");
}
#else
/* just demo the PSK is empty */
if (!strcmp(sDevInfo.device_secret, QCLOUD_IOT_NULL_DEVICE_SECRET)) {
Log_d("dev psk not exist!");
infoNullFlag = true;
} else {
Log_d("dev psk exist");
}
#endif
/* device cert/key files or PSK is empty, do dynamic register to fetch */
if (infoNullFlag) {
if (QCLOUD_RET_SUCCESS == IOT_DynReg_Device(&sDevInfo)) {
ret = HAL_SetDevInfo(&sDevInfo);
if (QCLOUD_RET_SUCCESS != ret) {
Log_e("devices info save fail");
} else {
#ifdef AUTH_MODE_CERT
Log_d("dynamic register success, productID: %s, devName: %s, CertFile: %s, KeyFile: %s",
sDevInfo.product_id, sDevInfo.device_name, sDevInfo.dev_cert_file_name,
sDevInfo.dev_key_file_name);
#else
Log_d("dynamic register success,productID: %s, devName: %s, device_secret: %s", sDevInfo.product_id,
sDevInfo.device_name, sDevInfo.device_secret);
#endif
}
} else {
Log_e("%s dynamic register fail", sDevInfo.device_name);
}
}
return ret;
}

View File

@@ -0,0 +1,337 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "utils_getopt.h"
void _event_handler(void *client, void *context, MQTTEventMsg *msg)
{
MQTTMessage *mqtt_messge = (MQTTMessage *)msg->msg;
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
mqtt_messge->topic_len, mqtt_messge->ptopic, mqtt_messge->payload_len, mqtt_messge->payload);
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_NACK:
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
static void _message_handler(void *client, MQTTMessage *message, void *user_data)
{
if (message == NULL) {
return;
}
Log_i("Receive Message With topicName:%.*s, payload:%.*s", (int)message->topic_len, message->ptopic,
(int)message->payload_len, (char *)message->payload);
}
static int _setup_gw_init_params(GatewayInitParam *gw_init_params, GatewayDeviceInfo *gw_dev_info)
{
MQTTInitParams *init_params = &gw_init_params->init_param;
DeviceInfo * dev_info = &gw_dev_info->gw_info;
init_params->product_id = dev_info->product_id;
init_params->device_name = dev_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(init_params->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
dev_info->dev_cert_file_name);
HAL_Snprintf(init_params->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
dev_info->dev_key_file_name);
#else
HAL_Snprintf(init_params->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
dev_info->dev_cert_file_name);
HAL_Snprintf(init_params->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
dev_info->dev_key_file_name);
#endif
#else
init_params->device_secret = dev_info->device_secret;
#endif
init_params->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
init_params->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
init_params->auto_connect_enable = 1;
init_params->event_handle.h_fp = _event_handler;
init_params->event_handle.context = NULL;
return QCLOUD_RET_SUCCESS;
}
// subscribe subdev MQTT topic and wait for sub result
static int _subscribe_subdev_topic_wait_result(void *client, char *topic_keyword, QoS qos, GatewayParam *gw_info)
{
char topic_name[128] = {0};
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", gw_info->subdev_product_id,
gw_info->subdev_device_name, topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = qos;
sub_params.on_message_handler = _message_handler;
int rc = IOT_Gateway_Subscribe(client, topic_name, &sub_params);
if (rc < 0) {
Log_e("IOT_Gateway_Subscribe fail.");
return rc;
}
int wait_cnt = 10;
while (!IOT_Gateway_IsSubReady(client, topic_name) && (wait_cnt > 0)) {
// wait for subscription result
rc = IOT_Gateway_Yield(client, 1000);
if (rc) {
Log_e("MQTT error: %d", rc);
return rc;
}
wait_cnt--;
}
if (wait_cnt > 0) {
return QCLOUD_RET_SUCCESS;
} else {
Log_e("wait for subscribe result timeout!");
return QCLOUD_ERR_FAILURE;
}
}
// publish MQTT msg
static int _publish_subdev_msg(void *client, char *topic_keyword, QoS qos, GatewayParam *gw_info)
{
char topic_name[128] = {0};
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", gw_info->subdev_product_id,
gw_info->subdev_device_name, topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
static int test_count = 0;
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = qos;
char topic_content[128] = {0};
size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"gateway_test\", \"count\": \"%d\"}",
test_count++);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
pub_params.payload = topic_content;
pub_params.payload_len = strlen(topic_content);
return IOT_Gateway_Publish(client, topic_name, &pub_params);
}
static int sg_loop_count = 5;
static int parse_arguments(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "c:l:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
case 'l':
sg_loop_count = atoi(utils_optarg);
if (sg_loop_count > 10000)
sg_loop_count = 10000;
else if (sg_loop_count < 0)
sg_loop_count = 1;
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file for DeviceInfo>] \n"
" [-l <loop count>] \n",
argv[0]);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
int rc = QCLOUD_ERR_FAILURE;
void *client = NULL;
IOT_Log_Set_Level(eLOG_DEBUG);
// parse arguments for device info file and loop test;
rc = parse_arguments(argc, argv);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("parse arguments error, rc = %d", rc);
return rc;
}
GatewayDeviceInfo gw_dev_info;
rc = HAL_GetGwDevInfo((void *)&gw_dev_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("Get gateway dev info err,rc:%d", rc);
return rc;
}
GatewayInitParam init_params = DEFAULT_GATEWAY_INIT_PARAMS;
_setup_gw_init_params(&init_params, &gw_dev_info);
client = IOT_Gateway_Construct(&init_params);
if (client == NULL) {
Log_e("client constructed failed.");
return QCLOUD_ERR_FAILURE;
}
// make sub-device online
GatewayParam gw_param = DEFAULT_GATEWAY_PARAMS;
;
gw_param.product_id = gw_dev_info.gw_info.product_id;
gw_param.device_name = gw_dev_info.gw_info.device_name;
DeviceInfo *sub_dev_info;
sub_dev_info = gw_dev_info.sub_dev_info;
gw_param.subdev_product_id = sub_dev_info->product_id;
gw_param.subdev_device_name = sub_dev_info->device_name;
#if 0
// one GatewayParam only support one sub-device
// use more GatewayParam to add more sub-device
GatewayParam gw_param1 = DEFAULT_GATEWAY_PARAMS;;
gw_param1.product_id = gw_dev_info.gw_info.product_id;
gw_param1.device_name = gw_dev_info.gw_info.device_name;
gw_param1.subdev_product_id = "SUB-PRODUCT";
gw_param1.subdev_device_name = "SUB-DEVICE";
#endif
rc = IOT_Gateway_Subdev_Online(client, &gw_param);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("IOT_Gateway_Subdev_Online fail.");
return rc;
}
// gateway proxy loop for sub-device
// subscribe sub-device topic
rc = _subscribe_subdev_topic_wait_result(client, "data", QOS0, &gw_param);
if (rc) {
Log_e("Subdev Subscribe Topic Failed: %d", rc);
return rc;
}
do {
// publish msg to sub-device topic
rc = _publish_subdev_msg(client, "data", QOS1, &gw_param);
if (rc < 0) {
Log_e("IOT_Gateway_Publish fail.");
}
rc = IOT_Gateway_Yield(client, 200);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
HAL_SleepMs(1000);
} while (--sg_loop_count > 0);
// make sub-device offline
rc = IOT_Gateway_Subdev_Offline(client, &gw_param);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("IOT_Gateway_Subdev_Offline fail.");
return rc;
}
rc = IOT_Gateway_Destroy(client);
return rc;
}

View File

@@ -0,0 +1,356 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
// MQTT event callback
static void _mqtt_event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
MQTTMessage *mqtt_messge = (MQTTMessage *)msg->msg;
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
mqtt_messge->topic_len, mqtt_messge->ptopic, mqtt_messge->payload_len, mqtt_messge->payload);
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_NACK:
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(MQTTInitParams *initParams, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = _mqtt_event_handler;
initParams->event_handle.context = NULL;
return QCLOUD_RET_SUCCESS;
}
// publish MQTT msg
static int _publish_test_msg(void *client, char *topic_keyword, QoS qos)
{
char topic_name[128] = {0};
DeviceInfo *dev_info = IOT_MQTT_GetDeviceInfo(client);
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", dev_info->product_id, dev_info->device_name,
topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
static int test_count = 0;
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = qos;
char topic_content[128] = {0};
size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"publish_test\", \"count\": \"%d\"}",
test_count++);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
pub_params.payload = topic_content;
pub_params.payload_len = strlen(topic_content);
return IOT_MQTT_Publish(client, topic_name, &pub_params);
}
// callback when MQTT msg arrives
static void _on_message_callback(void *pClient, MQTTMessage *message, void *userData)
{
if (message == NULL) {
return;
}
Log_i("Receive Message With topicName:%.*s, payload:%.*s", (int)message->topic_len, message->ptopic,
(int)message->payload_len, (char *)message->payload);
}
// subscribe MQTT topic and wait for sub result
static int _subscribe_topic_wait_result(void *client, char *topic_keyword, QoS qos)
{
char topic_name[128] = {0};
DeviceInfo *dev_info = IOT_MQTT_GetDeviceInfo(client);
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", dev_info->product_id, dev_info->device_name,
topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = qos;
sub_params.on_message_handler = _on_message_callback;
int rc = IOT_MQTT_Subscribe(client, topic_name, &sub_params);
if (rc < 0) {
Log_e("MQTT subscribe FAILED: %d", rc);
return rc;
}
int wait_cnt = 10;
while (!IOT_MQTT_IsSubReady(client, topic_name) && (wait_cnt > 0)) {
// wait for subscription result
rc = IOT_MQTT_Yield(client, 1000);
if (rc) {
Log_e("MQTT error: %d", rc);
return rc;
}
wait_cnt--;
}
if (wait_cnt > 0) {
return QCLOUD_RET_SUCCESS;
} else {
Log_e("wait for subscribe result timeout!");
return QCLOUD_ERR_FAILURE;
}
}
#ifdef LOG_UPLOAD
// init log upload module
static int _init_log_upload(MQTTInitParams *init_params)
{
LogUploadInitParams log_init_params;
memset(&log_init_params, 0, sizeof(LogUploadInitParams));
log_init_params.product_id = init_params->product_id;
log_init_params.device_name = init_params->device_name;
#ifdef AUTH_MODE_CERT
log_init_params.sign_key = init_params->cert_file;
#else
log_init_params.sign_key = init_params->device_secret;
#endif
#if defined(__linux__) || defined(WIN32)
log_init_params.read_func = HAL_Log_Read;
log_init_params.save_func = HAL_Log_Save;
log_init_params.del_func = HAL_Log_Del;
log_init_params.get_size_func = HAL_Log_Get_Size;
#endif
return IOT_Log_Init_Uploader(&log_init_params);
}
#endif
static bool sg_loop_test = false;
static int parse_arguments(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "c:l")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
case 'l':
sg_loop_test = true;
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file for DeviceInfo>] \n"
" [-l ] loop test or not\n",
argv[0]);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
int rc;
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
// parse arguments for device info file and loop test;
rc = parse_arguments(argc, argv);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("parse arguments error, rc = %d", rc);
return rc;
}
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
return rc;
}
// init connection
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params error, rc = %d", rc);
return rc;
}
#ifdef LOG_UPLOAD
// _init_log_upload should be done after _setup_connect_init_params and before IOT_MQTT_Construct
rc = _init_log_upload(&init_params);
if (rc != QCLOUD_RET_SUCCESS)
Log_e("init log upload error, rc = %d", rc);
#endif
// create MQTT client and connect with server
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("MQTT Construct failed!");
IOT_Log_Upload(true);
return QCLOUD_ERR_FAILURE;
}
#ifdef SYSTEM_COMM
long time = 0;
// get system timestamp from server
rc = IOT_Get_SysTime(client, &time);
if (QCLOUD_RET_SUCCESS == rc) {
Log_i("system time is %ld", time);
} else {
Log_e("get system time failed!");
}
#endif
// subscribe normal topics and wait result
rc = _subscribe_topic_wait_result(client, "data", QOS0);
if (rc) {
Log_e("Client Subscribe Topic Failed: %d", rc);
IOT_Log_Upload(true);
return rc;
}
do {
rc = _publish_test_msg(client, "data", QOS1);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
}
rc = IOT_MQTT_Yield(client, 500);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
if (sg_loop_test)
HAL_SleepMs(1000);
} while (sg_loop_test);
rc = IOT_MQTT_Destroy(&client);
IOT_Log_Upload(true);
return rc;
}

View File

@@ -0,0 +1,488 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lite-utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
/*
* Notes for using SDK in multi-thread programing
* 1. IOT_MQTT_Yield, IOT_MQTT_Construct and IOT_MQTT_Destroy are NOT thread-safe, only calling them in the same thread
* 2. IOT_MQTT_Publish, IOT_MQTT_Subscribe and IOT_MQTT_Unsubscribe are thread-safe, and be executed in multi-threads
* simultaneously
* 3. IOT_MQTT_Yield is the only entry to read from socket and should not be hand up for long
* 4. Using IOT_MQTT_StartLoop to start a default thread for IOT_MQTT_Yield is recommended
*/
/*
* This sample test MQTT multi-thread performance for one device.
*/
#define MAX_PUB_THREAD_COUNT 5
#define PUBLISH_COUNT 10
#define THREAD_SLEEP_INTERVAL_MS 1000
#define RX_RECEIVE_PERCENTAGE 99.0f
#define MAX_SIZE_OF_TOPIC_CONTENT 100
// device info
static DeviceInfo sg_device_info;
static bool sg_sub_unsub_thread_quit;
static unsigned int sg_rx_count_array[MAX_PUB_THREAD_COUNT]
[PUBLISH_COUNT]; // record the times when msg from subscribed topic is received
static unsigned int sg_rx_msg_buf_too_big_count; // record the times when msg is oversize
static unsigned int sg_rx_unexpected_count; // record the times when unexpected msg is received
static unsigned int sg_republish_count; // record the times of re-publish
static char sg_pub_sub_test_topic[MAX_SIZE_OF_TOPIC_CONTENT]; // topic for sub/pub
typedef struct AppThreadData {
void *client;
int thread_id;
int thread_status;
} AppThreadData;
void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
MQTTMessage *mqtt_messge = (MQTTMessage *)msg->msg;
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
mqtt_messge->topic_len, mqtt_messge->ptopic, mqtt_messge->payload_len, mqtt_messge->payload);
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_NACK:
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
static int _setup_connect_init_params(MQTTInitParams *initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_device_info);
if (QCLOUD_RET_SUCCESS != ret) {
return ret;
}
initParams->device_name = sg_device_info.device_name;
initParams->product_id = sg_device_info.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_device_info.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_device_info.dev_key_file_name);
#else
initParams->device_secret = sg_device_info.device_secret;
#endif
memset(sg_pub_sub_test_topic, 0, MAX_SIZE_OF_TOPIC_CONTENT);
HAL_Snprintf(sg_pub_sub_test_topic, MAX_SIZE_OF_TOPIC_CONTENT, "%s/%s/data", sg_device_info.product_id,
sg_device_info.device_name);
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
static void _mqtt_message_handler(void *pClient, MQTTMessage *message, void *userData)
{
if (message == NULL) {
return;
}
if (MAX_SIZE_OF_TOPIC_CONTENT >= message->payload_len) {
/* parsing payload */
char tempBuf[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
unsigned int tempRow = 0, tempCol = 0;
char * temp = NULL;
HAL_Snprintf(tempBuf, message->payload_len + 1, "%s", (char *)message->payload);
Log_d("Message received : %s", tempBuf);
char *count_value = LITE_json_value_of("count", tempBuf);
if (count_value != NULL) {
tempCol = atoi(count_value);
HAL_Free(count_value);
} else {
Log_e("count value not found!");
sg_rx_unexpected_count++;
return;
}
char *action_value = LITE_json_value_of("action", tempBuf);
if (action_value != NULL) {
temp = strstr(action_value, "-");
if (NULL != temp) {
tempRow = atoi(temp + 1);
HAL_Free(action_value);
} else {
HAL_Free(action_value);
Log_e("invalid action value: %s", action_value);
sg_rx_unexpected_count++;
return;
}
} else {
Log_e("action value not found!");
sg_rx_unexpected_count++;
return;
}
if (((tempRow - 1) < MAX_PUB_THREAD_COUNT) && (tempCol < PUBLISH_COUNT)) {
sg_rx_count_array[tempRow - 1][tempCol]++;
} else {
Log_e(" Unexpected Thread : %d, Message : %d ", tempRow, tempCol);
sg_rx_unexpected_count++;
}
} else {
sg_rx_msg_buf_too_big_count++;
}
}
/**
* subscribe/unsubscribe test thread runner
* subscribed and unsubscribe
*/
static void _mqtt_sub_unsub_thread_runner(void *ptr)
{
int rc = QCLOUD_RET_SUCCESS;
void *pClient = ptr;
char testTopic[128];
HAL_Snprintf(testTopic, 128, "%s/%s/control", sg_device_info.product_id, sg_device_info.device_name);
while (QCLOUD_RET_SUCCESS == rc && false == sg_sub_unsub_thread_quit) {
do {
HAL_SleepMs(THREAD_SLEEP_INTERVAL_MS);
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = QOS1;
sub_params.on_message_handler = _mqtt_message_handler;
rc = IOT_MQTT_Subscribe(pClient, testTopic, &sub_params);
} while (QCLOUD_ERR_MQTT_NO_CONN == rc || QCLOUD_ERR_MQTT_REQUEST_TIMEOUT == rc);
if (rc < 0) {
Log_e("Subscribe failed. Ret : %d ", rc);
}
HAL_SleepMs(1000);
do {
HAL_SleepMs(THREAD_SLEEP_INTERVAL_MS);
rc = IOT_MQTT_Unsubscribe(pClient, testTopic);
} while (QCLOUD_ERR_MQTT_NO_CONN == rc || QCLOUD_ERR_MQTT_REQUEST_TIMEOUT == rc);
if (rc < 0) {
Log_e("Unsubscribe failed. Returned : %d ", rc);
}
}
}
/**
* do subscribe in the thread
*/
static int _mqtt_subscribe_to_test_topic(void *pClient)
{
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.on_message_handler = _mqtt_message_handler;
sub_params.qos = QOS1;
return IOT_MQTT_Subscribe(pClient, sg_pub_sub_test_topic, &sub_params);
}
/**
* do publish in the thread
* loop for PUBLISH_COUNT times
* If publish failed in 1st time, do it again
*/
static void _mqtt_publish_thread_runner(void *ptr)
{
int itr = 0;
char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
PublishParams params;
int rc = QCLOUD_RET_SUCCESS;
AppThreadData *thread_data = (AppThreadData *)ptr;
void * pClient = thread_data->client;
int thread_id = thread_data->thread_id;
for (itr = 0; itr < PUBLISH_COUNT; itr++) {
int size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"thread-%d\", \"count\": \"%d\"}",
thread_id, itr);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
}
params.payload = (void *)topic_content;
params.payload_len = strlen(topic_content);
params.qos = QOS1;
Log_d("Msg being published: %s", topic_content);
do {
rc = IOT_MQTT_Publish(pClient, sg_pub_sub_test_topic, &params);
HAL_SleepMs(THREAD_SLEEP_INTERVAL_MS);
} while (QCLOUD_ERR_MQTT_NO_CONN == rc || QCLOUD_ERR_MQTT_REQUEST_TIMEOUT == rc);
// 1st publish failed, re-publish and update sg_republish_count
if (rc < 0) {
Log_e("Failed attempt 1 Publishing Thread : %d, Msg : %d, cs : %d ", thread_id, itr, rc);
do {
rc = IOT_MQTT_Publish(pClient, sg_pub_sub_test_topic, &params);
HAL_SleepMs(THREAD_SLEEP_INTERVAL_MS);
} while (QCLOUD_ERR_MQTT_NO_CONN == rc);
sg_republish_count++;
if (rc < 0) {
Log_e("Failed attempt 2 Publishing Thread : %d, Msg : %d, cs : %d Second Attempt ", thread_id, itr, rc);
}
}
}
thread_data->thread_status = 1;
}
/**
* thread safety performance test
*/
static int _mqtt_multi_thread_test(void *client)
{
float percent_of_rx_msg = 0.0; // record the success percentage of every pub send and recv
int finished_thread_count = 0; // record the number of finished publish threads
int rx_msg_count = 0; // record the times of successfull subscribe
// thread data passed to publish thread
AppThreadData thread_data[MAX_PUB_THREAD_COUNT] = {0};
ThreadParams pub_thread_params[MAX_PUB_THREAD_COUNT] = {0};
int rc = QCLOUD_RET_SUCCESS;
int test_result = 0;
int i = 0, j = 0;
// init the global variables
sg_rx_msg_buf_too_big_count = 0;
sg_rx_unexpected_count = 0;
sg_republish_count = 0;
if (client == NULL) {
Log_e("MQTT client is invalid!");
return QCLOUD_ERR_FAILURE;
}
/* create a thread to test subscribe and unsubscribe another topic */
ThreadParams sub_thread_params = {0};
sub_thread_params.thread_func = _mqtt_sub_unsub_thread_runner;
sub_thread_params.user_arg = client;
rc = HAL_ThreadCreate(&sub_thread_params);
if (rc < 0) {
Log_e("Create Sub_unsub thread failed: %d", rc);
return rc;
}
/* subscribe the same test topic as publish threads */
rc = _mqtt_subscribe_to_test_topic(client);
if (rc < 0) {
Log_e("Client subscribe failed: %d", rc);
return rc;
}
/* setup the thread info for pub-threads */
for (j = 0; j < MAX_PUB_THREAD_COUNT; j++) {
thread_data[j].client = client;
// self defined thread ID: 1 - MAX_PUB_THREAD_COUNT
thread_data[j].thread_id = j + 1;
thread_data[j].thread_status = 0;
for (i = 0; i < PUBLISH_COUNT; i++) {
sg_rx_count_array[j][i] = 0;
}
}
/* create multi threads to test IOT_MQTT_Publish() */
for (i = 0; i < MAX_PUB_THREAD_COUNT; i++) {
pub_thread_params[i].thread_func = _mqtt_publish_thread_runner;
pub_thread_params[i].user_arg = (void *)&thread_data[i];
rc = HAL_ThreadCreate(&pub_thread_params[i]);
if (rc < 0) {
Log_e("Create publish thread(ID: %d) failed: %d", thread_data[i].thread_id, rc);
}
}
/* wait for all pub-threads to finish their jobs */
do {
finished_thread_count = 0;
for (i = 0; i < MAX_PUB_THREAD_COUNT; i++) {
finished_thread_count += thread_data[i].thread_status;
}
Log_i(">>>>>>>>Finished thread count : %d", finished_thread_count);
int exit_code;
if (!IOT_MQTT_GetLoopStatus(client, &exit_code))
Log_e("MQTT Loop thread quit with code: %d", exit_code);
HAL_SleepMs(1000);
} while (finished_thread_count < MAX_PUB_THREAD_COUNT);
Log_i("Publishing is finished");
sg_sub_unsub_thread_quit = true;
/* Allow time for sub_sunsub thread to exit */
HAL_SleepMs(1000);
/* all threads should have terminated gracefully at this point. If they haven't,
* which should not be possible, something below will fail. */
/* Calculating Test Results */
for (i = 0; i < PUBLISH_COUNT; i++) {
for (j = 0; j < MAX_PUB_THREAD_COUNT; j++) {
if (sg_rx_count_array[j][i] > 0) {
rx_msg_count++;
}
}
}
percent_of_rx_msg = (float)rx_msg_count * 100 / (PUBLISH_COUNT * MAX_PUB_THREAD_COUNT);
HAL_Printf("\n\nMQTT Multi-thread Test Result : \n");
HAL_Printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
if (RX_RECEIVE_PERCENTAGE <= percent_of_rx_msg && 0 == sg_rx_msg_buf_too_big_count && 0 == sg_rx_unexpected_count) {
// test success
HAL_Printf("Success! PercentOfRxMsg: %f %%\n", percent_of_rx_msg);
HAL_Printf("Published Messages: %d , Received Messages: %d \n", PUBLISH_COUNT * MAX_PUB_THREAD_COUNT,
rx_msg_count);
HAL_Printf("QoS 1 re publish count %u\n", sg_republish_count);
test_result = 0;
} else {
// test fail
HAL_Printf("\nFailure! PercentOfRxMsg: %f %%\n", percent_of_rx_msg);
HAL_Printf("Published Messages: %d , Received Messages: %d \n", PUBLISH_COUNT * MAX_PUB_THREAD_COUNT,
rx_msg_count);
HAL_Printf("\"Received message was too big than anything sent\" count: %u\n", sg_rx_msg_buf_too_big_count);
HAL_Printf("\"The number received is out of the range\" count: %u\n", sg_rx_unexpected_count);
test_result = -1;
}
HAL_Printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
return test_result;
}
int main(int argc, char **argv)
{
int rc;
// Init log level
IOT_Log_Set_Level(eLOG_DEBUG);
// Init connection
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
// MQTT client create and connect
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// Start the default loop thread to read and handle MQTT packet
rc = IOT_MQTT_StartLoop(client);
if (rc) {
Log_e("MQTT start loop failed: %d", rc);
rc = IOT_MQTT_Destroy(&client);
return rc;
}
// Start application
rc = _mqtt_multi_thread_test(client);
if (0 != rc) {
Log_e("MQTT multi-thread test FAILED! RC: %d", rc);
} else {
Log_i("MQTT multi-thread test SUCCESS");
}
// Finish and destroy
IOT_MQTT_StopLoop(client);
rc = IOT_MQTT_Destroy(&client);
return rc;
}

View File

@@ -0,0 +1,430 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
/*
* This sample test multi MQTT clients in multi-thread runtime.
* 3 MQTT clients run in each own thread
* psk/cert_device_info1/2/3.json for each device info are required
* data topic forward configuration is required
*/
#define MAX_MQTT_THREAD_COUNT 3
// record the status of all the threadss
static unsigned int sg_thread_status[MAX_MQTT_THREAD_COUNT];
#ifdef WIN32
#define OS_PATH ".\\"
#else
#define OS_PATH "./"
#endif
#ifdef AUTH_MODE_CERT
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {OS_PATH "cert_device_info1.json", OS_PATH "cert_device_info2.json",
OS_PATH "cert_device_info3.json"};
#else
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {OS_PATH "psk_device_info1.json", OS_PATH "psk_device_info2.json",
OS_PATH "psk_device_info3.json"};
#endif
// sample data structures
typedef struct AppThreadData {
int thread_id;
char * device_info_file;
bool sub_ready;
uint32_t msg_recv_cnt;
} AppThreadData;
static int sg_loop_cnt = 10;
// MQTT event callback
static void _mqtt_event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
MQTTMessage * mqtt_messge = (MQTTMessage *)msg->msg;
uintptr_t packet_id = (uintptr_t)msg->msg;
AppThreadData *app_data = (AppThreadData *)handle_context;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_PUBLISH_RECVEIVED:
Log_i("topic message arrived but without any related handle: topic=%.*s, topic_msg=%.*s",
mqtt_messge->topic_len, mqtt_messge->ptopic, mqtt_messge->payload_len, mqtt_messge->payload);
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_d("mqtt topic subscribe success");
app_data->sub_ready = true;
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("mqtt topic subscribe timeout");
app_data->sub_ready = false;
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("mqtt topic subscribe NACK");
app_data->sub_ready = false;
break;
case MQTT_EVENT_UNSUBCRIBE_SUCCESS:
Log_i("unsubscribe success, packet-id=%u", (unsigned int)packet_id);
app_data->sub_ready = false;
break;
case MQTT_EVENT_UNSUBCRIBE_TIMEOUT:
Log_i("unsubscribe timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_UNSUBCRIBE_NACK:
Log_i("unsubscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(MQTTInitParams *initParams, DeviceInfo *device_info, AppThreadData *app_data)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = _mqtt_event_handler;
initParams->event_handle.context = (void *)app_data;
return QCLOUD_RET_SUCCESS;
}
#define MAX_SIZE_OF_TOPIC_CONTENT 100
// publish MQTT msg
static int _publish_test_msg(void *client, char *topic_keyword, QoS qos, int count, int thread_id)
{
char topic_name[128] = {0};
DeviceInfo *dev_info = IOT_MQTT_GetDeviceInfo(client);
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", dev_info->product_id, dev_info->device_name,
topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = qos;
char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"text\": \"thread-%u\", \"count\": \"%d\"}", thread_id,
count);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
pub_params.payload = topic_content;
pub_params.payload_len = strlen(topic_content);
return IOT_MQTT_Publish(client, topic_name, &pub_params);
}
// callback when MQTT msg arrives
static void _on_message_callback(void *pClient, MQTTMessage *message, void *user_data)
{
if (message == NULL) {
return;
}
AppThreadData *app_data = (AppThreadData *)user_data;
app_data->msg_recv_cnt += 1;
Log_i("Thread-%d recv msg topic:%.*s, payload:%.*s", app_data->thread_id, (int)message->topic_len, message->ptopic,
(int)message->payload_len, (char *)message->payload);
}
// subscrib MQTT topic
static int _subscribe_topic_wait_result(void *client, char *topic_keyword, QoS qos, AppThreadData *app_data)
{
static char topic_name[128] = {0};
DeviceInfo *dev_info = IOT_MQTT_GetDeviceInfo(client);
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", dev_info->product_id, dev_info->device_name,
topic_keyword);
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = qos;
sub_params.on_message_handler = _on_message_callback;
sub_params.user_data = (void *)app_data;
int rc = IOT_MQTT_Subscribe(client, topic_name, &sub_params);
if (rc < 0) {
Log_e("MQTT subscribe failed: %d", rc);
return rc;
}
int wait_cnt = 10;
while (!app_data->sub_ready && (wait_cnt > 0)) {
// wait for subscription result
rc = IOT_MQTT_Yield(client, 1000);
if (rc) {
Log_e("MQTT error: %d", rc);
return rc;
}
wait_cnt--;
}
if (wait_cnt > 0) {
return QCLOUD_RET_SUCCESS;
} else {
Log_e("wait for subscribe result timeout!");
return QCLOUD_ERR_FAILURE;
}
}
static uint32_t _get_random_delay(void)
{
srand((unsigned)HAL_GetTimeMs());
/* range: 1000 - 5000 ms, in 10ms unit */
return (rand() % 400 + 100) * 10;
}
static void _mqtt_client_thread_runner(void *ptr)
{
int pub_cnt = 0;
void * client = NULL;
AppThreadData *app_data = (AppThreadData *)ptr;
int thread_id = app_data->thread_id;
DeviceInfo dev_info = {0};
if (HAL_GetDevInfoFromFile(app_data->device_info_file, (void *)&dev_info)) {
Log_e("invalid dev info file: %s", app_data->device_info_file);
goto thread_exit;
}
Log_i("Thread running. ID: %d; device file: %s", thread_id, app_data->device_info_file);
// init connection
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
int rc = _setup_connect_init_params(&init_params, &dev_info, app_data);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params error: %d", rc);
goto thread_exit;
}
// create MQTT client and connect with server
client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("MQTT Construct failed!");
goto thread_exit;
}
#ifdef SYSTEM_COMM
long time = 0;
// get system timestamp from server
rc = IOT_Get_SysTime(client, &time);
if (QCLOUD_RET_SUCCESS == rc) {
Log_i("system time is %ld", time);
} else {
Log_e("get system time failed!");
}
#endif
// subscribe topic first
rc = _subscribe_topic_wait_result(client, "data", QOS1, app_data);
if (rc < 0) {
Log_e("Client Subscribe Topic Failed: %d", rc);
goto thread_exit;
}
int test_count = 0;
do {
rc = _publish_test_msg(client, "data", QOS1, test_count, thread_id);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
} else {
pub_cnt++;
}
rc = IOT_MQTT_Yield(client, 1000);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
test_count++;
if (test_count < sg_loop_cnt)
HAL_SleepMs(_get_random_delay());
#ifdef SYSTEM_COMM
long time = 0;
// get system timestamp from server
rc = IOT_Get_SysTime(client, &time);
if (QCLOUD_RET_SUCCESS == rc) {
Log_i("system time is %ld", time);
} else {
Log_e("get system time failed!");
}
#endif
} while (test_count < sg_loop_cnt);
thread_exit:
if (client != NULL)
IOT_MQTT_Destroy(&client);
Log_i(">>>>>>>>>>Thread-%d totally pub %d msg and recv %d msg", thread_id, pub_cnt, app_data->msg_recv_cnt);
sg_thread_status[thread_id] = 1;
}
static int parse_arguments(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "l:")) != EOF) switch (c) {
case 'l':
sg_loop_cnt = atoi(utils_optarg);
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-l n] test loop count\n",
argv[0]);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
parse_arguments(argc, argv);
AppThreadData app_data[MAX_MQTT_THREAD_COUNT];
int i;
// init thread app data
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
sg_thread_status[i] = 0; // init thread status flag
app_data[i].device_info_file = device_info_file[i];
app_data[i].thread_id = i;
app_data[i].sub_ready = false;
app_data[i].msg_recv_cnt = 0;
}
int created_thread_cnt = 0;
/* create multi threads for multi mqtt client test */
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
sg_thread_status[i] = 0; // init thread status flag
ThreadParams thread_params = {0};
thread_params.thread_func = _mqtt_client_thread_runner;
thread_params.user_arg = &app_data[i];
int rc = HAL_ThreadCreate(&thread_params);
if (rc) {
Log_e("create mqtt thread fail: %d", rc);
} else {
created_thread_cnt++;
}
HAL_SleepMs(300);
}
Log_i("created %d mqtt threads", created_thread_cnt);
/* wait for all threads to finish their jobs */
int finished_created_thread_cnt;
do {
finished_created_thread_cnt = 0;
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
finished_created_thread_cnt += sg_thread_status[i];
}
Log_i(">>>>>>>>Finished thread count : %d", finished_created_thread_cnt);
HAL_SleepMs(1000);
} while (finished_created_thread_cnt < created_thread_cnt);
return 0;
}

View File

@@ -0,0 +1,304 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
/*
* This sample test multi shadow clients in multi-thread runtime.
* 3 shadow clients run in each own thread
* psk/cert_device_info1/2/3.json for each device info are required
*/
#define MAX_MQTT_THREAD_COUNT 3
// record the status of all the threadss
static unsigned int sg_thread_status[MAX_MQTT_THREAD_COUNT];
#ifdef WIN32
#ifdef AUTH_MODE_CERT
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {".\\cert_device_info1.json", ".\\cert_device_info2.json",
".\\cert_device_info3.json"};
#else
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {".\\psk_device_info1.json", ".\\psk_device_info2.json",
".\\psk_device_info3.json"};
#endif
#else
#ifdef AUTH_MODE_CERT
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {"./cert_device_info1.json", "./cert_device_info2.json",
"./cert_device_info3.json"};
#else
char *device_info_file[MAX_MQTT_THREAD_COUNT] = {"./psk_device_info1.json", "./psk_device_info2.json",
"./psk_device_info3.json"};
#endif
#endif
// sample data structures
typedef struct SampleThreadData {
int thread_id;
char *device_info_file;
char *property_key;
} SampleThreadData;
static int sg_loop_cnt = 10;
void OnDeltaCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
{
Log_i("Thread recv delta str: %s", pJsonValueBuffer);
pProperty->delta_arrived = true;
}
void OnShadowUpdateCallback(void *pClient, Method method, RequestAck requestAck, const char *pJsonDocument,
void *pUserdata)
{
Log_i("Thread recv shadow update response ack: %d", requestAck);
}
static int _report_desire_null(void *handle, char *jsonBuffer, size_t sizeOfBuffer)
{
/* device data updated, desire should be set null */
int rc = IOT_Shadow_JSON_ConstructDesireAllNull(handle, jsonBuffer, sizeOfBuffer);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Shadow_Update(handle, jsonBuffer, sizeOfBuffer, OnShadowUpdateCallback, "desire_null",
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_d("shadow update(desired) success");
} else {
Log_e("shadow update(desired) failed, err: %d", rc);
}
} else {
Log_e("construct desire failed, err: %d", rc);
}
return rc;
}
static int _setup_connect_init_params(ShadowInitParams *initParams, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
return QCLOUD_RET_SUCCESS;
}
static uint32_t _get_random_delay(void)
{
srand((unsigned)HAL_GetTimeMs());
/* range: 1000 - 5000 ms, in 10ms unit */
return (rand() % 400 + 100) * 10;
}
static void _shadow_client_thread_runner(void *ptr)
{
int rc = QCLOUD_ERR_FAILURE;
void *shadow_client = NULL;
SampleThreadData *thread_data = (SampleThreadData *)ptr;
int thread_id = thread_data->thread_id;
DeviceInfo dev_info = {0};
if (HAL_GetDevInfoFromFile(thread_data->device_info_file, (void *)&dev_info)) {
Log_e("invalid dev info file: %s", thread_data->device_info_file);
goto thread_exit;
}
Log_i("Thread running. ID: %d; device: %s", thread_id, thread_data->device_info_file);
char shadow_json_buffer[200];
size_t shadow_json_buf_size = sizeof(shadow_json_buffer) / sizeof(shadow_json_buffer[0]);
DeviceProperty shadow_property;
int current_update_count = 0;
// init connection
ShadowInitParams init_params = DEFAULT_SHAWDOW_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &dev_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
goto thread_exit;
}
shadow_client = IOT_Shadow_Construct(&init_params);
if (shadow_client == NULL) {
Log_e("shadow client constructed failed.");
goto thread_exit;
}
// register delta property
shadow_property.key = thread_data->property_key;
shadow_property.data = &current_update_count;
shadow_property.type = JINT32;
rc = IOT_Shadow_Register_Property(shadow_client, &shadow_property, OnDeltaCallback);
if (rc != QCLOUD_RET_SUCCESS) {
rc = IOT_Shadow_Destroy(shadow_client);
Log_e("register device shadow property failed, err: %d", rc);
goto thread_exit;
}
// do get and sync operation before update
rc = IOT_Shadow_Get_Sync(shadow_client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("get device shadow failed, err: %d", rc);
goto thread_exit;
}
int loop_cnt = 0;
while (IOT_Shadow_IsConnected(shadow_client) || QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT == rc ||
QCLOUD_RET_MQTT_RECONNECTED == rc || QCLOUD_RET_SUCCESS == rc) {
rc = IOT_Shadow_Yield(shadow_client, 500);
if (QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT == rc) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
if (shadow_property.delta_arrived) {
_report_desire_null(shadow_client, shadow_json_buffer, shadow_json_buf_size);
shadow_property.delta_arrived = false;
}
IOT_Shadow_JSON_ConstructReport(shadow_client, shadow_json_buffer, shadow_json_buf_size, 1, &shadow_property);
rc = IOT_Shadow_Update(shadow_client, shadow_json_buffer, shadow_json_buf_size, OnShadowUpdateCallback, NULL,
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
current_update_count++;
if (loop_cnt++ >= sg_loop_cnt)
break;
// sleep for some time
HAL_SleepMs(_get_random_delay());
}
thread_exit:
if (shadow_client != NULL) {
IOT_Shadow_Destroy(shadow_client);
shadow_client = NULL;
}
sg_thread_status[thread_id] = 1;
}
static int parse_arguments(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "l:")) != EOF) switch (c) {
case 'l':
sg_loop_cnt = atoi(utils_optarg);
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-l n] test loop count\n",
argv[0]);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
parse_arguments(argc, argv);
SampleThreadData thread_data[MAX_MQTT_THREAD_COUNT];
char *property_key[MAX_MQTT_THREAD_COUNT] = {"update_count_1", "update_count_2", "update_count_3"};
int i;
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
sg_thread_status[i] = 0; // init thread status flag
thread_data[i].property_key = property_key[i];
thread_data[i].device_info_file = device_info_file[i];
thread_data[i].thread_id = i;
}
int created_thread_cnt = 0;
/* create multi threads for multi mqtt client test */
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
sg_thread_status[i] = 0; // init thread status flag
ThreadParams thread_params = {0};
thread_params.thread_func = _shadow_client_thread_runner;
thread_params.user_arg = &thread_data[i];
int rc = HAL_ThreadCreate(&thread_params);
if (rc) {
Log_e("create mqtt thread fail: %d", rc);
} else {
created_thread_cnt++;
}
HAL_SleepMs(300);
}
Log_i("created %d shadow threads", created_thread_cnt);
/* wait for all threads to finish their jobs */
int finished_created_thread_cnt;
do {
finished_created_thread_cnt = 0;
for (i = 0; i < MAX_MQTT_THREAD_COUNT; i++) {
finished_created_thread_cnt += sg_thread_status[i];
}
Log_i(">>>>>>>>Finished thread count : %d", finished_created_thread_cnt);
HAL_SleepMs(1000);
} while (finished_created_thread_cnt < created_thread_cnt);
return 0;
}

View File

@@ -0,0 +1,285 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#define OTA_BUF_LEN (5000)
static bool sg_pub_ack = false;
static int sg_packet_id = 0;
void response_message_callback(void *coap_message, void *userContext)
{
int ret_code = IOT_COAP_GetMessageCode(coap_message);
switch (ret_code) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_RECEIVE_RESPCONTENT: {
char *payload = NULL;
int payload_len = 0;
int ret = -1;
ret = IOT_COAP_GetMessagePayload(coap_message, &payload, &payload_len);
if (ret == QCLOUD_RET_SUCCESS) {
Log_i("message received response, content: %s", payload);
} else {
Log_e("message received response, content error.");
}
}
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d", IOT_COAP_GetMessageId(coap_message));
break;
default:
break;
}
}
void event_handler(void *pcontext, CoAPEventMessage *message)
{
switch (message->event_type) {
case COAP_EVENT_RECEIVE_ACK:
if (sg_packet_id == (unsigned)(uintptr_t)message->message) {
sg_pub_ack = true;
}
Log_i("message received ACK, msgid: %d", sg_packet_id);
break;
case COAP_EVENT_RECEIVE_RESPCONTENT:
Log_i("message received response, content: %s", IOT_COAP_GetMessageId(message->message));
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_SEPRESP_TIMEOUT:
Log_i("message received ACK but receive response timeout, msgid: %d",
(unsigned)(uintptr_t)message->message);
break;
default:
Log_e("unrecogonized event type: %d", message->event_type);
break;
}
}
static int _setup_connect_init_params(CoAPInitParams *initParams, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->event_handle.h_fp = event_handler;
initParams->max_retry_count = 3;
return QCLOUD_RET_SUCCESS;
}
int main(int argc, char **argv)
{
IOT_Log_Set_Level(eLOG_DEBUG);
int rc;
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
return rc;
}
CoAPInitParams init_params = DEFAULT_COAPINIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
return rc;
}
void *client = IOT_COAP_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
DeviceInfo *dev_info = IOT_COAP_GetDeviceInfo(client);
void * h_ota = IOT_OTA_Init(dev_info->product_id, dev_info->device_name, client);
if (NULL == h_ota) {
Log_e("initialize OTA failed");
return QCLOUD_ERR_FAILURE;
}
if (0 > IOT_OTA_ReportVersion(h_ota, "1.0.0")) {
Log_e("report OTA version failed");
return QCLOUD_ERR_FAILURE;
}
HAL_SleepMs(2000);
int ota_over = 0;
bool upgrade_fetch_success = true;
FILE *fp;
char buf_ota[OTA_BUF_LEN];
if (NULL == (fp = fopen("ota.bin", "wb+"))) {
Log_e("open file failed");
return QCLOUD_ERR_FAILURE;
}
do {
uint32_t firmware_valid;
Log_i("wait for ota upgrade command...");
IOT_COAP_Yield(client, 200);
if (IOT_OTA_IsFetching(h_ota)) {
char version[128], md5sum[33];
uint32_t len, size_downloaded, size_file;
do {
len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
if (len > 0) {
if (1 != fwrite(buf_ota, len, 1, fp)) {
Log_e("write data to file failed");
upgrade_fetch_success = false;
break;
}
} else if (len < 0) {
Log_e("download fail rc=%d", len);
upgrade_fetch_success = false;
break;
}
/* get OTA information */
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &size_downloaded, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &size_file, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_MD5SUM, md5sum, 33);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, version, 128);
IOT_COAP_Yield(client, 100);
} while (!IOT_OTA_IsFetchFinish(h_ota));
/* Must check MD5 match or not */
if (upgrade_fetch_success) {
IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
if (0 == firmware_valid) {
Log_e("The firmware is invalid");
upgrade_fetch_success = false;
} else {
Log_e("The firmware is valid");
upgrade_fetch_success = true;
}
}
ota_over = 1;
}
HAL_SleepMs(2000);
} while (!ota_over);
if (upgrade_fetch_success) {
/* begin execute OTA files, should report upgrade begin */
// sg_packet_id = IOT_OTA_ReportUpgradeBegin(h_ota);
// if (0 > sg_packet_id) {
// Log_e("report OTA begin failed error:%d", sg_packet_id);
// return QCLOUD_ERR_FAILURE;
// }
// while (!sg_pub_ack) {
// HAL_SleepMs(1000);
// IOT_COAP_Yield(client, 200);
// }
// sg_pub_ack = false;
/* if upgrade success */
/* after execute OTA files, should report upgrade result */
// sg_packet_id = IOT_OTA_ReportUpgradeSuccess(h_ota, "1.0.1");
// if (0 > sg_packet_id) {
// Log_e("report OTA result failed error:%d", sg_packet_id);
// return QCLOUD_ERR_FAILURE;
// }
// while (!sg_pub_ack) {
// HAL_SleepMs(1000);
// IOT_COAP_Yield(client, 200);
// }
// sg_pub_ack = false;
/* if upgrade fail */
// sg_packet_id = IOT_OTA_ReportUpgradeFail(h_ota, "1.0.1");
// if (0 > sg_packet_id) {
// Log_e("report OTA result failed error:%d", sg_packet_id);
// return QCLOUD_ERR_FAILURE;
// }
// while (!sg_pub_ack) {
// HAL_SleepMs(1000);
// IOT_COAP_Yield(client, 200);
// }
// sg_pub_ack = false;
}
IOT_OTA_Destroy(h_ota);
IOT_COAP_Destroy(&client);
return 0;
}

View File

@@ -0,0 +1,558 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lite-utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#define FW_RUNNING_VERSION "1.0.0"
#define KEY_VER "version"
#define KEY_SIZE "downloaded_size"
#define FW_VERSION_MAX_LEN 32
#define FW_FILE_PATH_MAX_LEN 128
#define OTA_BUF_LEN 5000
#define FW_INFO_FILE_DATA_LEN 128
typedef struct OTAContextData {
void *ota_handle;
void *mqtt_client;
char fw_file_path[FW_FILE_PATH_MAX_LEN];
char fw_info_file_path[FW_FILE_PATH_MAX_LEN];
// remote_version means version for the FW in the cloud and to be downloaded
char remote_version[FW_VERSION_MAX_LEN];
uint32_t fw_file_size;
// for resuming download
/* local_version means downloading but not running */
char local_version[FW_VERSION_MAX_LEN];
int downloaded_size;
// to make sure report is acked
bool report_pub_ack;
int report_packet_id;
} OTAContextData;
static void _event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
OTAContextData *ota_ctx = (OTAContextData *)handle_context;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
if (ota_ctx->report_packet_id == packet_id)
ota_ctx->report_pub_ack = true;
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
static int _setup_connect_init_params(MQTTInitParams *initParams, void *ota_ctx, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = _event_handler;
initParams->event_handle.context = ota_ctx;
return QCLOUD_RET_SUCCESS;
}
static void _wait_for_pub_ack(OTAContextData *ota_ctx, int packet_id)
{
int wait_cnt = 10;
ota_ctx->report_pub_ack = false;
ota_ctx->report_packet_id = packet_id;
while (!ota_ctx->report_pub_ack) {
HAL_SleepMs(500);
IOT_MQTT_Yield(ota_ctx->mqtt_client, 500);
if (wait_cnt-- == 0) {
Log_e("wait report pub ack timeout!");
break;
}
}
ota_ctx->report_pub_ack = false;
return;
}
/**********************************************************************************
* OTA file operations START
* these are platform-dependant functions
* POSIX FILE is used in this sample code
**********************************************************************************/
// calculate left MD5 for resuming download from break point
static int _cal_exist_fw_md5(OTAContextData *ota_ctx)
{
char buff[OTA_BUF_LEN];
size_t rlen, total_read = 0;
int ret = QCLOUD_RET_SUCCESS;
ret = IOT_OTA_ResetClientMD5(ota_ctx->ota_handle);
if (ret) {
Log_e("reset MD5 failed: %d", ret);
return QCLOUD_ERR_FAILURE;
}
FILE *fp = fopen(ota_ctx->fw_file_path, "ab+");
if (NULL == fp) {
Log_e("open file %s failed", ota_ctx->fw_file_path);
return QCLOUD_ERR_FAILURE;
}
// rewind(fp);
size_t size = ota_ctx->downloaded_size;
while ((size > 0) && (!feof(fp))) {
rlen = (size > OTA_BUF_LEN) ? OTA_BUF_LEN : size;
if (rlen != fread(buff, 1, rlen, fp)) {
Log_e("read data len not expected");
ret = QCLOUD_ERR_FAILURE;
break;
}
IOT_OTA_UpdateClientMd5(ota_ctx->ota_handle, buff, rlen);
size -= rlen;
total_read += rlen;
}
fclose(fp);
Log_d("total read: %d", total_read);
return ret;
}
/* update local firmware info for resuming download from break point */
static int _update_local_fw_info(OTAContextData *ota_ctx)
{
FILE *fp;
int wlen;
int ret = QCLOUD_RET_SUCCESS;
char data_buf[FW_INFO_FILE_DATA_LEN];
memset(data_buf, 0, sizeof(data_buf));
HAL_Snprintf(data_buf, sizeof(data_buf), "{\"%s\":\"%s\", \"%s\":%d}", KEY_VER, ota_ctx->remote_version, KEY_SIZE,
ota_ctx->downloaded_size);
fp = fopen(ota_ctx->fw_info_file_path, "w");
if (NULL == fp) {
Log_e("open file %s failed", ota_ctx->fw_info_file_path);
ret = QCLOUD_ERR_FAILURE;
goto exit;
}
wlen = fwrite(data_buf, 1, strlen(data_buf), fp);
if (wlen != strlen(data_buf)) {
Log_e("save version to file err");
ret = QCLOUD_ERR_FAILURE;
}
exit:
if (NULL != fp) {
fclose(fp);
}
return ret;
}
static int _get_local_fw_info(char *file_name, char *local_version)
{
int len;
int rlen;
char json_doc[FW_INFO_FILE_DATA_LEN] = {0};
FILE *fp = fopen(file_name, "r");
if (NULL == fp) {
Log_e("open file %s failed", file_name);
return 0;
}
fseek(fp, 0L, SEEK_END);
len = ftell(fp);
if (len > FW_INFO_FILE_DATA_LEN) {
Log_e("%s is too big, pls check", file_name);
fclose(fp);
return 0;
}
rewind(fp);
rlen = fread(json_doc, 1, len, fp);
if (len != rlen) {
Log_e("read data len (%d) less than needed (%d), %s", rlen, len, json_doc);
fclose(fp);
return 0;
}
char *version = LITE_json_value_of(KEY_VER, json_doc);
char *size = LITE_json_value_of(KEY_SIZE, json_doc);
if ((NULL == version) || (NULL == size)) {
if (version)
HAL_Free(version);
if (size)
HAL_Free(size);
fclose(fp);
return 0;
}
int local_size = atoi(size);
HAL_Free(size);
if (local_size <= 0) {
Log_w("local info offset invalid: %d", local_size);
HAL_Free(version);
local_size = 0;
}
strncpy(local_version, version, FW_VERSION_MAX_LEN);
HAL_Free(version);
fclose(fp);
return local_size;
}
/* get local firmware offset for resuming download from break point */
static int _update_fw_downloaded_size(OTAContextData *ota_ctx)
{
int local_size = _get_local_fw_info(ota_ctx->fw_info_file_path, ota_ctx->local_version);
if (local_size == 0) {
ota_ctx->downloaded_size = 0;
return 0;
}
if ((0 != strcmp(ota_ctx->local_version, ota_ctx->remote_version)) ||
(ota_ctx->downloaded_size > ota_ctx->fw_file_size)) {
ota_ctx->downloaded_size = 0;
return 0;
}
ota_ctx->downloaded_size = local_size;
Log_i("calc MD5 for resuming download from offset: %d", ota_ctx->downloaded_size);
int ret = _cal_exist_fw_md5(ota_ctx);
if (ret) {
Log_e("regen OTA MD5 error: %d", ret);
remove(ota_ctx->fw_info_file_path);
ota_ctx->downloaded_size = 0;
return 0;
}
Log_d("local MD5 update done!");
return local_size;
}
static int _delete_fw_info_file(char *file_name)
{
return remove(file_name);
}
static int _save_fw_data_to_file(char *file_name, uint32_t offset, char *buf, int len)
{
FILE *fp;
if (offset > 0) {
if (NULL == (fp = fopen(file_name, "ab+"))) {
Log_e("open file failed");
return QCLOUD_ERR_FAILURE;
}
} else {
if (NULL == (fp = fopen(file_name, "wb+"))) {
Log_e("open file failed");
return QCLOUD_ERR_FAILURE;
}
}
fseek(fp, offset, SEEK_SET);
if (1 != fwrite(buf, len, 1, fp)) {
Log_e("write data to file failed");
fclose(fp);
return QCLOUD_ERR_FAILURE;
}
fflush(fp);
fclose(fp);
return 0;
}
static char *_get_local_fw_running_version()
{
// asuming the version is inside the code and binary
// you can also get from a meta file
Log_i("FW running version: %s", FW_RUNNING_VERSION);
return FW_RUNNING_VERSION;
}
/**********************************************************************************
* OTA file operations END
**********************************************************************************/
// main OTA cycle
bool process_ota(OTAContextData *ota_ctx)
{
bool download_finished = false;
bool upgrade_fetch_success = true;
char buf_ota[OTA_BUF_LEN];
int rc;
void *h_ota = ota_ctx->ota_handle;
/* Must report version first */
if (0 > IOT_OTA_ReportVersion(h_ota, _get_local_fw_running_version())) {
Log_e("report OTA version failed");
return false;
}
do {
IOT_MQTT_Yield(ota_ctx->mqtt_client, 200);
Log_i("wait for ota upgrade command...");
// recv the upgrade cmd
if (IOT_OTA_IsFetching(h_ota)) {
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FILE_SIZE, &ota_ctx->fw_file_size, 4);
IOT_OTA_Ioctl(h_ota, IOT_OTAG_VERSION, ota_ctx->remote_version, FW_VERSION_MAX_LEN);
DeviceInfo *device_info = IOT_MQTT_GetDeviceInfo(ota_ctx->mqtt_client);
HAL_Snprintf(ota_ctx->fw_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s_%s.bin", device_info->client_id,
ota_ctx->remote_version);
HAL_Snprintf(ota_ctx->fw_info_file_path, FW_FILE_PATH_MAX_LEN, "./FW_%s.json", device_info->client_id);
/* check if pre-downloading finished or not */
/* if local FW downloaded size (ota_ctx->downloaded_size) is not zero, it will do resuming download */
_update_fw_downloaded_size(ota_ctx);
/*set offset and start http connect*/
rc = IOT_OTA_StartDownload(h_ota, ota_ctx->downloaded_size, ota_ctx->fw_file_size);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("OTA download start err,rc:%d", rc);
upgrade_fetch_success = false;
break;
}
// download and save the fw
do {
int len = IOT_OTA_FetchYield(h_ota, buf_ota, OTA_BUF_LEN, 1);
if (len > 0) {
rc = _save_fw_data_to_file(ota_ctx->fw_file_path, ota_ctx->downloaded_size, buf_ota, len);
if (rc) {
Log_e("write data to file failed");
upgrade_fetch_success = false;
break;
}
} else if (len < 0) {
Log_e("download fail rc=%d", len);
upgrade_fetch_success = false;
break;
}
/* get OTA information and update local info */
IOT_OTA_Ioctl(h_ota, IOT_OTAG_FETCHED_SIZE, &ota_ctx->downloaded_size, 4);
rc = _update_local_fw_info(ota_ctx);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("update local fw info err,rc:%d", rc);
}
// quit ota process as something wrong with mqtt
rc = IOT_MQTT_Yield(ota_ctx->mqtt_client, 100);
if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("MQTT error: %d", rc);
return false;
}
} while (!IOT_OTA_IsFetchFinish(h_ota));
/* Must check MD5 match or not */
if (upgrade_fetch_success) {
// download is finished, delete the fw info file
_delete_fw_info_file(ota_ctx->fw_info_file_path);
uint32_t firmware_valid;
IOT_OTA_Ioctl(h_ota, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
if (0 == firmware_valid) {
Log_e("The firmware is invalid");
upgrade_fetch_success = false;
} else {
Log_i("The firmware is valid");
upgrade_fetch_success = true;
}
}
download_finished = true;
}
if (!download_finished)
HAL_SleepMs(1000);
} while (!download_finished);
// do some post-download stuff for your need
// report result
int packet_id;
if (upgrade_fetch_success)
packet_id = IOT_OTA_ReportUpgradeSuccess(h_ota, NULL);
else
packet_id = IOT_OTA_ReportUpgradeFail(h_ota, NULL);
_wait_for_pub_ack(ota_ctx, packet_id);
return upgrade_fetch_success;
}
int main(int argc, char **argv)
{
int rc;
OTAContextData *ota_ctx = NULL;
void * mqtt_client = NULL;
void * h_ota = NULL;
IOT_Log_Set_Level(eLOG_DEBUG);
ota_ctx = (OTAContextData *)HAL_Malloc(sizeof(OTAContextData));
if (ota_ctx == NULL) {
Log_e("malloc failed");
goto exit;
}
memset(ota_ctx, 0, sizeof(OTAContextData));
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
goto exit;
}
// setup MQTT init params
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params, ota_ctx, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
// create MQTT mqtt_client and connect to server
mqtt_client = IOT_MQTT_Construct(&init_params);
if (mqtt_client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// init OTA handle
h_ota = IOT_OTA_Init(device_info.product_id, device_info.device_name, mqtt_client);
if (NULL == h_ota) {
Log_e("initialize OTA failed");
goto exit;
}
ota_ctx->ota_handle = h_ota;
ota_ctx->mqtt_client = mqtt_client;
bool ota_success;
do {
// mqtt should be ready first
rc = IOT_MQTT_Yield(mqtt_client, 500);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
// OTA process
ota_success = process_ota(ota_ctx);
if (!ota_success) {
Log_e("OTA failed! Do it again");
HAL_SleepMs(2000);
}
} while (!ota_success);
exit:
if (NULL != ota_ctx)
HAL_Free(ota_ctx);
if (NULL != h_ota)
IOT_OTA_Destroy(h_ota);
IOT_MQTT_Destroy(&mqtt_client);
return 0;
}

View File

@@ -0,0 +1,292 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lite-utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
static DeviceInfo sg_devInfo;
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
#define ROOM_TEMPERATURE 32.0f
static float sg_desire_temperature = 20.0f;
static float sg_report_temperature = ROOM_TEMPERATURE;
static float sg_energy_consumption = 0.0f;
static bool sg_airconditioner_openned = false;
static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF;
#define MAX_RECV_LEN (512 + 1)
// compare float value
bool _is_value_equal(float left, float right)
{
if ((left < right + 0.01) && (left > right - 0.01))
return true;
else
return false;
}
// simulate room temperature change
static void _simulate_room_temperature(float *roomTemperature)
{
float delta_change = 0;
if (!sg_airconditioner_openned) {
if (!_is_value_equal(*roomTemperature, ROOM_TEMPERATURE)) {
delta_change = (*roomTemperature) > ROOM_TEMPERATURE ? -0.5 : 0.5;
}
} else {
sg_energy_consumption += 1;
if (!_is_value_equal(*roomTemperature, sg_desire_temperature)) {
delta_change = (*roomTemperature) > sg_desire_temperature ? -1.0 : 1.0;
}
}
*roomTemperature += delta_change;
}
// MQTT event callback
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// callback when MQTT msg arrives
static void on_message_callback(void *pClient, MQTTMessage *message, void *userData)
{
if (message == NULL)
return;
const char *topicName = message->ptopic;
size_t topicNameLen = message->topic_len;
if (topicName == NULL || topicNameLen == 0) {
return;
}
Log_i("Receive Message With topicName:%.*s, payload:%.*s", (int)topicNameLen, topicName, (int)message->payload_len,
(char *)message->payload);
static char cloud_rcv_buf[MAX_RECV_LEN + 1];
size_t len = (message->payload_len > MAX_RECV_LEN) ? MAX_RECV_LEN : (message->payload_len);
if (message->payload_len > MAX_RECV_LEN) {
Log_e("paload len exceed buffer size");
}
memcpy(cloud_rcv_buf, message->payload, len);
cloud_rcv_buf[len] = '\0'; // jsmn_parse relies on a string
char *value = LITE_json_value_of("action", cloud_rcv_buf);
if (value != NULL) {
if (strcmp(value, "come_home") == 0) {
sg_airconditioner_openned = true;
} else if (strcmp(value, "leave_home") == 0) {
sg_airconditioner_openned = false;
}
}
HAL_Free(value);
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(ShadowInitParams *initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if (QCLOUD_RET_SUCCESS != ret) {
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#endif
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
// subscrib MQTT topic
static int _register_subscribe_topics(void *client)
{
static char topic_name[128] = {0};
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", sg_devInfo.product_id, sg_devInfo.device_name,
"control");
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.on_message_handler = on_message_callback;
return IOT_Shadow_Subscribe(client, topic_name, &sub_params);
}
int main(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "c:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file for DeviceInfo>] \n",
argv[0]);
return -1;
}
int rc;
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
// init connection
ShadowInitParams init_params = DEFAULT_SHAWDOW_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_Shadow_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// register subscribe topics here
rc = _register_subscribe_topics(client);
if (rc < 0) {
Log_e("Client Subscribe Topic Failed: %d", rc);
return rc;
}
while (IOT_Shadow_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT ||
rc == QCLOUD_RET_MQTT_RECONNECTED) {
rc = IOT_Shadow_Yield(client, 200);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Exit loop caused of errCode: %d", rc);
}
if (sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_SUCCESS &&
sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_TIMEOUT &&
sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_NACK) {
Log_i("Wait for subscribe result. sg_subscribe_event_result = %d", sg_subscribe_event_result);
HAL_SleepMs(1000);
continue;
}
_simulate_room_temperature(&sg_report_temperature);
Log_i("airConditioner state: %s", sg_airconditioner_openned ? "open" : "close");
Log_i("currentTemperature: %f, energyConsumption: %f", sg_report_temperature, sg_energy_consumption);
HAL_SleepMs(1000);
}
rc = IOT_Shadow_Destroy(client);
return rc;
}

View File

@@ -0,0 +1,449 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lite-utils.h"
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
static DeviceInfo sg_devInfo;
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
#define ROOM_TEMPERATURE 32.0f
#define MAX_RECV_LEN (512 + 1)
static float sg_desire_temperature = 20.0f;
static float sg_report_temperature = ROOM_TEMPERATURE;
static float sg_energy_consumption = 0.0f;
static bool sg_airconditioner_openned = false;
static DeviceProperty sg_energy_consumption_prop;
static DeviceProperty sg_temperature_desire_prop;
static bool sg_message_arrived_on_delta = false;
static MQTTEventType sg_subscribe_event_result = MQTT_EVENT_UNDEF;
static bool sg_finish_shadow_get = false;
char sg_document_buffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
size_t sg_document_buffersize = sizeof(sg_document_buffer) / sizeof(sg_document_buffer[0]);
static int _register_config_shadow_property(void *client);
static int _register_subscribe_topics(void *client);
// compare float value
bool _is_value_equal(float left, float right)
{
if ((left < right + 0.01) && (left > right - 0.01))
return true;
else
return false;
}
// simulate room temperature change
static void _simulate_room_temperature(float *roomTemperature)
{
float delta_change = 0;
if (!sg_airconditioner_openned) {
if (!_is_value_equal(*roomTemperature, ROOM_TEMPERATURE)) {
delta_change = (*roomTemperature) > ROOM_TEMPERATURE ? -0.5 : 0.5;
}
} else {
sg_energy_consumption += 1;
if (!_is_value_equal(*roomTemperature, sg_desire_temperature)) {
delta_change = (*roomTemperature) > sg_desire_temperature ? -1.0 : 1.0;
}
}
*roomTemperature += delta_change;
}
// callback for request response arrives
static void on_request_handler(void *pClient, Method method, RequestAck status, const char *jsonDoc, void *userData)
{
char *shadow_status = NULL;
char *shadow_method = NULL;
if (status == ACK_TIMEOUT) {
shadow_status = "ACK_TIMEOUT";
} else if (status == ACK_ACCEPTED) {
shadow_status = "ACK_ACCEPTED";
} else if (status == ACK_REJECTED) {
shadow_status = "ACK_REJECTED";
}
if (method == GET) {
shadow_method = "GET";
} else if (method == UPDATE) {
shadow_method = "UPDATE";
}
Log_i("Method=%s|Ack=%s", shadow_method, shadow_status);
Log_i("received jsonString=%s", jsonDoc);
if (status == ACK_ACCEPTED && method == UPDATE) {
if (sg_message_arrived_on_delta)
sg_message_arrived_on_delta = false;
Log_i("Update Shadow Success");
} else if (status == ACK_ACCEPTED && method == GET) {
Log_i("Get Shadow Document Success");
sg_finish_shadow_get = true;
} else if (status == ACK_TIMEOUT && method == UPDATE) {
Log_e("Update Shadow Fail!");
exit(1);
}
}
// callback when MQTT msg arrives
static void on_message_callback(void *pClient, MQTTMessage *message, void *userData)
{
if (message == NULL)
return;
const char *topicName = message->ptopic;
uint16_t topicNameLen = message->topic_len;
if (topicName == NULL || topicNameLen == 0) {
return;
}
Log_i("Receive Message With topicName:%.*s, payload:%.*s", (int)topicNameLen, topicName, (int)message->payload_len,
(char *)message->payload);
static char cloud_rcv_buf[MAX_RECV_LEN + 1];
size_t len = (message->payload_len > MAX_RECV_LEN) ? MAX_RECV_LEN : (message->payload_len);
if (message->payload_len > MAX_RECV_LEN) {
Log_e("paload len exceed buffer size");
}
memcpy(cloud_rcv_buf, message->payload, len);
cloud_rcv_buf[len] = '\0'; // jsmn_parse relies on a string
char *value = LITE_json_value_of("action", cloud_rcv_buf);
if (value != NULL) {
if (strcmp(value, "come_home") == 0) {
sg_airconditioner_openned = true;
} else if (strcmp(value, "leave_home") == 0) {
sg_airconditioner_openned = false;
}
}
HAL_Free(value);
}
// callback for delta msg
static void on_temperature_actuate_callback(void *pClient, const char *jsonResponse, uint32_t responseLen,
DeviceProperty *context)
{
Log_i("actuate callback jsonString=%s|dataLen=%u", jsonResponse, responseLen);
if (context != NULL) {
Log_i("modify desire temperature to: %f", *(float *)context->data);
sg_message_arrived_on_delta = true;
}
}
// MQTT event callback
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
sg_subscribe_event_result = msg->event_type;
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// report energy consumption
static int _do_report_energy_consumption(void *client)
{
int rc = IOT_Shadow_JSON_ConstructReport(client, sg_document_buffer, sg_document_buffersize, 1,
&sg_energy_consumption_prop);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("shadow construct report failed: %d", rc);
return rc;
}
Log_i("Update Shadow: %s", sg_document_buffer);
rc = IOT_Shadow_Update(client, sg_document_buffer, sg_document_buffersize, on_request_handler, NULL,
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_i("Update Shadow Failed: %d", rc);
return rc;
}
return rc;
}
static int _do_report_temperature_desire(void *client)
{
/*
* report desire as null if recv delta or desire msg, otherwise server will keep desire record
*/
int rc;
rc = IOT_Shadow_JSON_ConstructReportAndDesireAllNull(client, sg_document_buffer, sg_document_buffersize, 1,
&sg_temperature_desire_prop);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("shadow construct report failed: %d", rc);
return rc;
}
Log_i("update desire temperature: %s", sg_document_buffer);
rc = IOT_Shadow_Update(client, sg_document_buffer, sg_document_buffersize, on_request_handler, NULL,
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_i("Update Shadow Failed: %d", rc);
return rc;
} else {
Log_i("Update Shadow Success");
}
return rc;
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(ShadowInitParams *initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if (QCLOUD_RET_SUCCESS != ret) {
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#endif
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
// setup shadow properties
static void _setup_shadow_data()
{
// s_temperatureReportProp: device ---> shadow <---> app
sg_energy_consumption_prop.key = "energyConsumption";
sg_energy_consumption_prop.data = &sg_energy_consumption;
sg_energy_consumption_prop.type = JFLOAT;
// s_temperatureDesireProp: app ---> shadow ---> device
sg_temperature_desire_prop.key = "temperatureDesire";
sg_temperature_desire_prop.data = &sg_desire_temperature;
sg_temperature_desire_prop.type = JFLOAT;
}
// register properties
static int _register_config_shadow_property(void *client)
{
return IOT_Shadow_Register_Property(client, &sg_temperature_desire_prop, on_temperature_actuate_callback);
}
// subscrib MQTT topic
static int _register_subscribe_topics(void *client)
{
static char topic_name[128] = {0};
int size = HAL_Snprintf(topic_name, sizeof(topic_name), "%s/%s/%s", sg_devInfo.product_id, sg_devInfo.device_name,
"control");
if (size < 0 || size > sizeof(topic_name) - 1) {
Log_e("topic content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
return QCLOUD_ERR_FAILURE;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.qos = QOS1;
sub_params.on_message_handler = on_message_callback;
return IOT_Shadow_Subscribe(client, topic_name, &sub_params);
}
int main(int argc, char **argv)
{
int c;
while ((c = utils_getopt(argc, argv, "c:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
default:
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file for DeviceInfo>] \n",
argv[0]);
return -1;
}
int rc;
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
// init connection
ShadowInitParams init_params = DEFAULT_SHAWDOW_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_Shadow_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// init shadow data
_setup_shadow_data();
// register config shadow propertys here
rc = _register_config_shadow_property(client);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("Cloud Device Register Delta Success");
} else {
Log_e("Cloud Device Register Delta Failed: %d", rc);
return rc;
}
// pull shadow document and update local shadow version
IOT_Shadow_Get(client, on_request_handler, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
while (sg_finish_shadow_get == false) {
Log_i("Wait for Shadow Get Result");
IOT_Shadow_Yield(client, 200);
HAL_SleepMs(1000);
}
// register subscribe topics here
rc = _register_subscribe_topics(client);
if (rc < 0) {
Log_e("Client Subscribe Topic Failed: %d", rc);
return rc;
}
while (IOT_Shadow_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT ||
rc == QCLOUD_RET_MQTT_RECONNECTED) {
rc = IOT_Shadow_Yield(client, 200);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Exit loop caused of errCode: %d", rc);
}
if (sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_SUCCESS &&
sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_TIMEOUT &&
sg_subscribe_event_result != MQTT_EVENT_SUBCRIBE_NACK) {
Log_i("Wait for subscribe result, sg_subscribe_event_result = %d", sg_subscribe_event_result);
HAL_SleepMs(1000);
continue;
}
_simulate_room_temperature(&sg_report_temperature);
Log_i("airConditioner state: %s", sg_airconditioner_openned ? "open" : "close");
Log_i("currentTemperature: %f, energyConsumption: %f", sg_report_temperature, sg_energy_consumption);
if (sg_message_arrived_on_delta)
_do_report_temperature_desire(client);
if (sg_message_arrived_on_delta == false)
_do_report_energy_consumption(client);
HAL_SleepMs(3000);
}
rc = IOT_Shadow_Destroy(client);
return rc;
}

View File

@@ -0,0 +1,194 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
#define MAX_SIZE_OF_TOPIC_CONTENT 100
#define PROGRAM_NAME "door_coap_sample"
void printUsage()
{
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file of DeviceInfo>] \n"
" [-t <target device name>]\n"
" [-a <action: come_home or leave_home>]\n",
PROGRAM_NAME);
}
void event_handler(void *pcontext, CoAPEventMessage *message)
{
switch (message->event_type) {
case COAP_EVENT_RECEIVE_ACK:
Log_i("message received ACK, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_RECEIVE_RESPCONTENT: /* not supported currently */
break;
case COAP_EVENT_UNAUTHORIZED:
Log_i("coap client auth token expired or invalid, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_FORBIDDEN:
Log_i("coap URI is invalid for this device, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_INTERNAL_SERVER_ERROR:
Log_i("coap server internal error, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_ACK_TIMEOUT:
Log_i("message receive ACK timeout, msgid: %d", (unsigned)(uintptr_t)message->message);
break;
case COAP_EVENT_SEPRESP_TIMEOUT: /* not supported currently */
break;
default:
Log_e("unrecogonized event type: %d", message->event_type);
break;
}
}
static int _setup_connect_init_params(CoAPInitParams *initParams, DeviceInfo *device_info)
{
initParams->product_id = device_info->product_id;
initParams->device_name = device_info->device_name;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
device_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
device_info->dev_key_file_name);
#endif
#else
initParams->device_secret = device_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->event_handle.h_fp = event_handler;
initParams->max_retry_count = 3;
return QCLOUD_RET_SUCCESS;
}
int main(int argc, char **argv)
{
int c;
char action[16] = {0};
char target_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = {0};
while ((c = utils_getopt(argc, argv, "c:t:a:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
case 't':
strncpy(target_device_name, utils_optarg, MAX_SIZE_OF_DEVICE_NAME);
break;
case 'a':
strncpy(action, utils_optarg, sizeof(action) - 1);
break;
default:
printUsage();
return -1;
}
int rc = QCLOUD_RET_SUCCESS;
IOT_Log_Set_Level(eLOG_DEBUG);
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
return rc;
}
CoAPInitParams init_params = DEFAULT_COAPINIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *coap_client = IOT_COAP_Construct(&init_params);
if (coap_client == NULL) {
Log_e("COAP Client construct failed.");
return QCLOUD_ERR_FAILURE;
} else {
Log_e("%p", coap_client);
}
if (strcmp(action, "come_home") == 0 || strcmp(action, "leave_home") == 0) {
char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
SendMsgParams send_params = DEFAULT_SENDMSG_PARAMS;
int size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"%s\", \"targetDevice\": \"%s\"}",
action, target_device_name);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
send_params.pay_load = topic_content;
send_params.pay_load_len = strlen(topic_content);
char topicName[128] = "";
sprintf(topicName, "%s/%s/event", device_info.product_id, device_info.device_name);
Log_i("topic name is %s", topicName);
rc = IOT_COAP_SendMessage(coap_client, topicName, &send_params);
if (rc < 0) {
Log_e("client publish topic failed :%d.", rc);
} else {
Log_d("client topic has been sent, msg_id: %d", rc);
}
rc = IOT_COAP_Yield(coap_client, 200);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("exit with error: %d", rc);
}
} else {
printUsage();
return -2;
}
IOT_COAP_Destroy(&coap_client);
return QCLOUD_RET_SUCCESS;
}

View File

@@ -0,0 +1,237 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"
#define MAX_SIZE_OF_TOPIC_CONTENT 100
static DeviceInfo sg_devInfo;
static bool sg_has_rev_ack = false;
#define PROGRAM_NAME "door_mqtt_sample"
void printUsage()
{
HAL_Printf(
"usage: %s [options]\n"
" [-c <config file of DeviceInfo>] \n"
" [-t <target device name>]\n"
" [-a <action: come_home or leave_home>]\n",
PROGRAM_NAME);
}
static void event_handler(void *pclient, void *handle_context, MQTTEventMsg *msg)
{
uintptr_t packet_id = (uintptr_t)msg->msg;
sg_has_rev_ack = true;
switch (msg->event_type) {
case MQTT_EVENT_UNDEF:
Log_i("undefined event occur.");
break;
case MQTT_EVENT_DISCONNECT:
Log_i("MQTT disconnect.");
break;
case MQTT_EVENT_RECONNECT:
Log_i("MQTT reconnect.");
break;
case MQTT_EVENT_SUBCRIBE_SUCCESS:
Log_i("subscribe success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
Log_i("subscribe wait ack timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_SUBCRIBE_NACK:
Log_i("subscribe nack, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_SUCCESS:
Log_i("publish success, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_TIMEOUT:
Log_i("publish timeout, packet-id=%u", (unsigned int)packet_id);
break;
case MQTT_EVENT_PUBLISH_NACK:
Log_i("publish nack, packet-id=%u", (unsigned int)packet_id);
break;
default:
Log_i("Should NOT arrive here.");
break;
}
}
// Setup MQTT construct parameters
static int _setup_connect_init_params(MQTTInitParams *initParams)
{
int ret;
ret = HAL_GetDevInfo((void *)&sg_devInfo);
if (QCLOUD_RET_SUCCESS != ret) {
return ret;
}
initParams->device_name = sg_devInfo.device_name;
initParams->product_id = sg_devInfo.product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
sg_devInfo.dev_key_file_name);
#endif
#else
initParams->device_secret = sg_devInfo.device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
initParams->event_handle.h_fp = event_handler;
return QCLOUD_RET_SUCCESS;
}
// publish MQTT msg
static int _publish_msg(void *client, char *action, char *targetDeviceName)
{
if (NULL == action || NULL == targetDeviceName)
return -1;
char topic_name[128] = {0};
sprintf(topic_name, "%s/%s/%s", sg_devInfo.product_id, sg_devInfo.device_name, "event");
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = QOS1;
char topic_content[MAX_SIZE_OF_TOPIC_CONTENT + 1] = {0};
if (strcmp(action, "come_home") == 0 || strcmp(action, "leave_home") == 0) {
int size = HAL_Snprintf(topic_content, sizeof(topic_content), "{\"action\": \"%s\", \"targetDevice\": \"%s\"}",
action, targetDeviceName);
if (size < 0 || size > sizeof(topic_content) - 1) {
Log_e("payload content length not enough! content size:%d buf size:%d", size, (int)sizeof(topic_content));
return -3;
}
pub_params.payload = topic_content;
pub_params.payload_len = strlen(topic_content);
} else {
printUsage();
return -2;
}
int rc = IOT_MQTT_Publish(client, topic_name, &pub_params);
if (rc < 0) {
Log_e("Client publish Topic:%s Failed :%d with content: %s", topic_name, rc, (char *)pub_params.payload);
return rc;
}
return 0;
}
int main(int argc, char **argv)
{
int c;
char action[16] = {0};
char target_device_name[MAX_SIZE_OF_DEVICE_NAME + 1] = {0};
while ((c = utils_getopt(argc, argv, "c:t:a:")) != EOF) switch (c) {
case 'c':
if (HAL_SetDevInfoFile(utils_optarg))
return -1;
break;
case 't':
strncpy(target_device_name, utils_optarg, MAX_SIZE_OF_DEVICE_NAME);
break;
case 'a':
strncpy(action, utils_optarg, sizeof(action) - 1);
break;
default:
printUsage();
return -1;
}
// init log level
IOT_Log_Set_Level(eLOG_DEBUG);
int rc;
// init connection
MQTTInitParams init_params = DEFAULT_MQTTINIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
void *client = IOT_MQTT_Construct(&init_params);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return QCLOUD_ERR_FAILURE;
}
// publish msg
rc = _publish_msg(client, action, target_device_name);
if (rc < 0) {
Log_e("Demo publish fail rc=%d", rc);
}
while (IOT_MQTT_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT ||
rc == QCLOUD_RET_MQTT_RECONNECTED) {
if (false != sg_has_rev_ack)
break;
Log_i("Wait for publish ack");
rc = IOT_MQTT_Yield(client, 200);
HAL_SleepMs(1000);
}
rc = IOT_MQTT_Destroy(&client);
return rc;
}

View File

@@ -0,0 +1,186 @@
/*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright (C) 2018-2020 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.
*
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qcloud_iot_export.h"
void OnDeltaCallback(void *pClient, const char *pJsonValueBuffer, uint32_t valueLength, DeviceProperty *pProperty)
{
Log_i(">>>>> Delta str: %s", pJsonValueBuffer);
pProperty->delta_arrived = true;
}
void OnShadowUpdateCallback(void *pClient, Method method, RequestAck requestAck, const char *pJsonDocument,
void *pUserdata)
{
Log_i("recv shadow update response, response ack: %d", requestAck);
}
static int _report_desire_null(void *handle, char *jsonBuffer, size_t sizeOfBuffer)
{
/* device data updated, desire should be set null */
int rc = IOT_Shadow_JSON_ConstructDesireAllNull(handle, jsonBuffer, sizeOfBuffer);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Shadow_Update(handle, jsonBuffer, sizeOfBuffer, OnShadowUpdateCallback, "desire_null",
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_d("shadow update(desired) success");
} else {
Log_e("shadow update(desired) failed, err: %d", rc);
}
} else {
Log_e("construct desire failed, err: %d", rc);
}
return rc;
}
static int _setup_connect_init_params(ShadowInitParams *initParams, DeviceInfo *dev_info)
{
initParams->device_name = dev_info->device_name;
initParams->product_id = dev_info->product_id;
#ifdef AUTH_MODE_CERT
char certs_dir[16] = "certs";
char current_path[128];
char *cwd = getcwd(current_path, sizeof(current_path));
if (cwd == NULL) {
Log_e("getcwd return NULL");
return QCLOUD_ERR_FAILURE;
}
#ifdef WIN32
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
dev_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s\\%s\\%s", current_path, certs_dir,
dev_info->dev_key_file_name);
#else
HAL_Snprintf(initParams->cert_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
dev_info->dev_cert_file_name);
HAL_Snprintf(initParams->key_file, FILE_PATH_MAX_LEN, "%s/%s/%s", current_path, certs_dir,
dev_info->dev_key_file_name);
#endif
#else
initParams->device_secret = dev_info->device_secret;
#endif
initParams->command_timeout = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
initParams->keep_alive_interval_ms = QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL;
initParams->auto_connect_enable = 1;
return QCLOUD_RET_SUCCESS;
}
int demo_device_shadow()
{
int rc = QCLOUD_ERR_FAILURE;
void *shadow_client = NULL;
char shadow_json_buffer[200];
size_t shadow_json_buf_size = sizeof(shadow_json_buffer) / sizeof(shadow_json_buffer[0]);
DeviceProperty shadow_property;
int current_update_count = 0;
DeviceInfo device_info = {0};
rc = HAL_GetDevInfo((void *)&device_info);
if (QCLOUD_RET_SUCCESS != rc) {
Log_e("get device info failed: %d", rc);
return rc;
}
// init connection
ShadowInitParams init_params = DEFAULT_SHAWDOW_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params, &device_info);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return rc;
}
shadow_client = IOT_Shadow_Construct(&init_params);
if (shadow_client == NULL) {
Log_e("shadow client constructed failed.");
return QCLOUD_ERR_FAILURE;
}
// register delta property
shadow_property.key = "updateCount";
shadow_property.data = &current_update_count;
shadow_property.type = JINT32;
rc = IOT_Shadow_Register_Property(shadow_client, &shadow_property, OnDeltaCallback);
if (rc != QCLOUD_RET_SUCCESS) {
rc = IOT_Shadow_Destroy(shadow_client);
Log_e("register device shadow property failed, err: %d", rc);
return rc;
}
// do get and sync operation before update
rc = IOT_Shadow_Get_Sync(shadow_client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("get device shadow failed, err: %d", rc);
return rc;
}
while (IOT_Shadow_IsConnected(shadow_client) || QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT == rc ||
QCLOUD_RET_MQTT_RECONNECTED == rc || QCLOUD_RET_SUCCESS == rc) {
rc = IOT_Shadow_Yield(shadow_client, 500);
if (QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT == rc) {
HAL_SleepMs(1000);
continue;
} else if (rc != QCLOUD_RET_SUCCESS && rc != QCLOUD_RET_MQTT_RECONNECTED) {
Log_e("exit with error: %d", rc);
break;
}
if (shadow_property.delta_arrived) {
_report_desire_null(shadow_client, shadow_json_buffer, shadow_json_buf_size);
shadow_property.delta_arrived = false;
}
IOT_Shadow_JSON_ConstructReport(shadow_client, shadow_json_buffer, shadow_json_buf_size, 1, &shadow_property);
rc = IOT_Shadow_Update(shadow_client, shadow_json_buffer, shadow_json_buf_size, OnShadowUpdateCallback, NULL,
QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
current_update_count++;
// sleep for some time
HAL_SleepMs(3000);
}
Log_e("loop exit with error: %d", rc);
rc = IOT_Shadow_Destroy(shadow_client);
shadow_client = NULL;
return rc;
}
int main()
{
IOT_Log_Set_Level(eLOG_DEBUG);
demo_device_shadow();
return 0;
}