blecfg_linksdk.c 23.7 KB
Newer Older
1
/*
2
 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3
 */
4 5 6 7

#include "blecfg_pub.h"

#include "aos/kv.h"
8 9 10 11 12

#include "aiot_state_api.h"
#include "aiot_sysdep_api.h"
#include "aiot_mqtt_api.h"
#include "aiot_dm_api.h"
13
#if (BOARD_HAAS100 == 1)
14 15
#include "led.h"
#include "cJSON.h"
16
#endif
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

/* 字符串长度限制 */
#define LIMIT_PRODUCT_KEY       32
#define LIMIT_DEVICE_NAME       64
#define LIMIT_DEVICE_SECRTE     64

typedef struct {
    BleCfg_link_cb link_cb;
    uint8_t product_key[LIMIT_PRODUCT_KEY];
    uint8_t device_name[LIMIT_DEVICE_NAME];
    uint8_t device_secret[LIMIT_DEVICE_SECRTE];
}device_info;

static device_info  s_device_info;

extern int BleCfg_linksdk_main(char *product_key, char *device_name, char *device_secret);

static void linksdk_thread(void *arg)
{
    device_info *dev_info = &s_device_info;

    printf("linksdk_thread start\r\n");
    BleCfg_linksdk_main(dev_info->product_key, dev_info->device_name, dev_info->device_secret);
}

static int32_t BleCfg_devinfo_kv_save(char *pk, char *dn, char *ds)
{
    int32_t ret;
    int len;
    char product_key[LIMIT_PRODUCT_KEY];
    char device_name[LIMIT_DEVICE_NAME];
    char device_secret[LIMIT_DEVICE_SECRTE];

    if ( pk == NULL || strlen(pk) >= LIMIT_PRODUCT_KEY
      || dn == NULL || strlen(dn) >= LIMIT_DEVICE_NAME
      || ds == NULL || strlen(ds) >= LIMIT_DEVICE_SECRTE ) {
        BLECFG_LOG_ERROR("[%s]: input para error!\r\n", __func__);
        return -1;
    }

    len = LIMIT_PRODUCT_KEY;
    ret = aos_kv_get("product_key", product_key, &len);
    if(ret){
        product_key[0] = 0;
    }

    len = LIMIT_DEVICE_NAME;
    ret = aos_kv_get("device_name", device_name, &len);
    if(ret){
        device_name[0] = 0;
    }

    len = LIMIT_DEVICE_SECRTE;
    ret = aos_kv_get("device_secret", device_secret, &len);
    if(ret){
        device_secret[0] = 0;
    }

    if ( strcmp(product_key, pk) == 0
      && strcmp(device_name, dn) == 0
      && strcmp(device_secret, ds) == 0) {
        BLECFG_LOG_INFO("[%s]: kv already saved.\r\n", __func__);
        return -1;
    }

    ret = aos_kv_set("product_key", pk, strlen(pk) + 1, 1);
    if ( ret ){
        BLECFG_LOG_ERROR("[%s]: set 'product_key' fail! ret = %d\r\n", __func__, ret);
        return ret;
    }

    ret = aos_kv_set("device_name", dn, strlen(dn) + 1, 1);
    if ( ret ) {
        BLECFG_LOG_ERROR("[%s]: set 'device_name' fail! ret = %d\r\n", __func__, ret);
        return ret;
    }

    ret = aos_kv_set("device_secret", ds, strlen(ds) + 1, 1);
    if ( ret ) {
        BLECFG_LOG_ERROR("[%s]: set 'device_secret' fail! ret = %d\r\n", __func__, ret);
        return ret;
    }

    return 0;
}

static int32_t BleCfg_devinfo_kv_load(char *pk, char *dn, char *ds)
{
    int32_t ret;
    int len;

    len = LIMIT_PRODUCT_KEY;
    ret = aos_kv_get("product_key", pk, &len);
    if(ret){
        //BLECFG_LOG_INFO("%s: product_key not find\r\n", __func__);
        return ret;
    }
    BLECFG_LOG_INFO("[%s]: product_key '%s'\r\n", __func__, pk);

    len = LIMIT_DEVICE_NAME;
    ret = aos_kv_get("device_name", dn, &len);
    if(ret){
        //BLECFG_LOG_INFO("%s: device_name not find\r\n", __func__);
        return ret;
    }
    BLECFG_LOG_INFO("[%s]: device_name '%s'\r\n", __func__, dn);

    len = LIMIT_DEVICE_SECRTE;
    ret = aos_kv_get("device_secret", ds, &len);
    if(ret){
        //BLECFG_LOG_INFO("%s: device_secret not find\r\n", __func__);
        return ret;
    }
    BLECFG_LOG_INFO("[%s]: device_secret '%s'\r\n", __func__, ds);

    return 0;
}

BLECFG_STATE BleCfg_dev_set(char *pk, char *dn, char *ds)
{
    device_info *dev_info = &s_device_info;

    if ( strlen(pk) + 1 >= sizeof(dev_info->product_key)
      || strlen(dn) + 1 >= sizeof(dev_info->device_name)
      || strlen(ds) + 1 >= sizeof(dev_info->device_secret)) {
        return BLECFG_COMMON_FAILED;
    }

    strncpy(dev_info->product_key, pk, sizeof(dev_info->product_key));
    strncpy(dev_info->device_name, dn, sizeof(dev_info->device_name));
    strncpy(dev_info->device_secret, ds, sizeof(dev_info->device_secret));

    return BLECFG_SUCCESS;
}

BLECFG_STATE BleCfg_dev_connect()
{
    int32_t ret;
    aos_task_t task_main;

    BLECFG_LOG_INFO("%s: Connecting cloud...", __func__);

    /* 配网流程结束,开启linkSDK连云流程 */
    ret = aos_task_create(&task_main, "linksdk_demo", linksdk_thread,
                          NULL, NULL, 6048, AOS_DEFAULT_APP_PRI, AOS_TASK_AUTORUN);
    if (ret < 0) {
        printf("create 'linksdk_demo' task failed, ret = %ld \r\n", ret);
    }

}

BLECFG_STATE BleCfg_dev_save()
{
    int32_t ret;
    device_info *dev_info = &s_device_info;

    ret = BleCfg_devinfo_kv_save(dev_info->product_key, dev_info->device_name, dev_info->device_secret);
    if ( ret != 0 ) {
        return BLECFG_COMMON_FAILED;
    }

    return BLECFG_SUCCESS;
}

BLECFG_STATE BleCfg_dev_restore()
{
    int32_t ret;
    device_info *dev_info = &s_device_info;

    ret = BleCfg_devinfo_kv_load(dev_info->product_key, dev_info->device_name, dev_info->device_secret);
    if ( ret != 0 ) {
        return BLECFG_COMMON_FAILED;
    }

    return BLECFG_SUCCESS;
}

/*
 * 这个例程演示了用SDK配置MQTT参数并建立连接, 之后创建2个线程
 *
 * + 一个线程用于保活长连接
 * + 一个线程用于接收消息, 并在有消息到达时进入默认的数据回调, 在连接状态变化时进入事件回调
 *
 * 接着演示了在MQTT连接上进行属性上报, 事件上报, 以及处理收到的属性设置, 服务调用, 取消这些代码段落的注释即可观察运行效果
 *
 * 需要用户关注或修改的部分, 已经用 TODO 在注释中标明
 *
 */
205 206 207 208 209 210 211 212 213

/* 位于portfiles/aiot_port文件夹下的系统适配函数集合 */
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;

/* 位于external/ali_ca_cert.c中的服务器证书 */
extern const char *ali_ca_cert;

static uint8_t g_mqtt_process_thread_running = 0;
static uint8_t g_mqtt_recv_thread_running = 0;
214 215

#if (BOARD_HAAS100 == 1)
216 217
static int32_t s_led_state[6];

218
static void BleCfg_led_switch(uint32_t len, char *str)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
{
    int32_t led_id;
    int32_t led_state;
    cJSON *strCommand, *strLed;
    char *led_name[] = {NULL, "HaaS100_LED_1", "HaaS100_LED_2", "HaaS100_LED_3", "HaaS100_LED_4", "HaaS100_LED_5"};

    strCommand = cJSON_Parse(str);   //创建JSON解析对象,返回JSON格式是否正确
    if (!strCommand) {
        printf("JSON格式错误:%s\n\n", cJSON_GetErrorPtr()); //输出json格式错误信息
        return;
    }

    printf("JSON格式正确:\n%s\n\n",cJSON_Print(strCommand) );

    for (led_id = 1; led_id < 6; led_id++)
    {
        strLed = cJSON_GetObjectItem(strCommand, led_name[led_id]); //获取name键对应的值的信息
        if (strLed == NULL || strLed->type != cJSON_Number) {
            continue;
        }
        s_led_state[led_id] = strLed->valueint;
        if (strLed->valueint == 1) {
            led_switch(led_id, LED_ON);
        } else {
            led_switch(led_id, LED_OFF);
        }
        break;
    }

    cJSON_Delete(strCommand);//释放内存
}

251
static void BleCfg_led_init()
252 253 254 255 256 257 258 259 260
{
    memset(s_led_state, 0, sizeof(s_led_state));
    led_switch(1, LED_OFF);
    led_switch(2, LED_OFF);
    led_switch(3, LED_OFF);
    led_switch(4, LED_OFF);
    led_switch(5, LED_OFF);
}

261
static void BleCfg_led_update(void *dm_handle)
262 263 264 265 266 267 268 269 270 271 272 273
{
    aiot_dm_msg_t msg;

    memset(&msg, 0, sizeof(aiot_dm_msg_t));
    msg.type = AIOT_DMMSG_PROPERTY_POST;

    msg.data.property_post.params = "{\"LightSwitch\": 1}";
    aiot_dm_send(dm_handle, &msg);

    msg.data.property_post.params = s_led_state[1] == 1 ? "{\"HaaS100_LED_1\": 1}" : "{\"HaaS100_LED_1\": 0}";
    aiot_dm_send(dm_handle, &msg);

274
    msg.data.property_post.params = s_led_state[2] == 1 ? "{\"HaaS100_LED_2\": 1}" : "{\"HaaS100_LED_2\": 0}";
275 276
    aiot_dm_send(dm_handle, &msg);

277
    msg.data.property_post.params = s_led_state[3] == 1 ? "{\"HaaS100_LED_3\": 1}" : "{\"HaaS100_LED_3\": 0}";
278 279
    aiot_dm_send(dm_handle, &msg);

280
    msg.data.property_post.params = s_led_state[4] == 1 ? "{\"HaaS100_LED_4\": 1}" : "{\"HaaS100_LED_4\": 0}";
281 282
    aiot_dm_send(dm_handle, &msg);

283
    msg.data.property_post.params = s_led_state[5] == 1 ? "{\"HaaS100_LED_5\": 1}" : "{\"HaaS100_LED_5\": 0}";
284 285
    aiot_dm_send(dm_handle, &msg);
}
286
#endif
287 288 289 290 291 292 293 294 295 296

/* TODO: 如果要关闭日志, 就把这个函数实现为空, 如果要减少日志, 可根据code选择不打印
 *
 * 例如: [1577589489.033][LK-0317] mqtt_basic_demo&a13FN5TplKq
 *
 * 上面这条日志的code就是0317(十六进制), code值的定义见core/aiot_state_api.h
 *
 */

/* 日志回调函数, SDK的日志会从这里输出 */
297
int32_t BleCfg_state_logcb(int32_t code, char *message)
298 299 300 301 302 303
{
    printf("%s", message);
    return 0;
}

/* MQTT事件回调函数, 当网络连接/重连/断开时被触发, 事件定义见core/aiot_mqtt_api.h */
304
void BleCfg_mqtt_event_handler(void *handle, const aiot_mqtt_event_t *event, void *userdata)
305 306 307 308 309 310 311 312 313 314
{
    char *product_key;
    char *device_name;
    char *device_secret;
    int32_t res;

    switch (event->type) {
        /* SDK因为用户调用了aiot_mqtt_connect()接口, 与mqtt服务器建立连接已成功 */
        case AIOT_MQTTEVT_CONNECT: {
            printf("AIOT_MQTTEVT_CONNECT\n");
315 316
            if ( s_device_info.link_cb != NULL ){
                s_device_info.link_cb();
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
            }
            break;
        }

        /* SDK因为网络状况被动断连后, 自动发起重连已成功 */
        case AIOT_MQTTEVT_RECONNECT: {
            printf("AIOT_MQTTEVT_RECONNECT\n");
            break;
        }

        /* SDK因为网络的状况而被动断开了连接, network是底层读写失败, heartbeat是没有按预期得到服务端心跳应答 */
        case AIOT_MQTTEVT_DISCONNECT: {
            char *cause = (event->data.disconnect == AIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT) ? ("network disconnect") :
                          ("heartbeat disconnect");
            printf("AIOT_MQTTEVT_DISCONNECT: %s\n", cause);
            break;
        }

        default: {

        }
    }
}

/* 执行aiot_mqtt_process的线程, 包含心跳发送和QoS1消息重发 */
342
void *BleCfg_mqtt_process_thread(void *args)
343 344 345 346 347 348 349 350 351 352 353 354 355 356
{
    int32_t res = STATE_SUCCESS;

    while (g_mqtt_process_thread_running) {
        res = aiot_mqtt_process(args);
        if (res == STATE_USER_INPUT_EXEC_DISABLED) {
            break;
        }
        aos_msleep(1000);
    }
    return NULL;
}

/* 执行aiot_mqtt_recv的线程, 包含网络自动重连和从服务器收取MQTT消息 */
357
void *BleCfg_mqtt_recv_thread(void *args)
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
{
    int32_t res = STATE_SUCCESS;

    while (g_mqtt_recv_thread_running) {
        res = aiot_mqtt_recv(args);
        if (res < STATE_SUCCESS) {
            if (res == STATE_USER_INPUT_EXEC_DISABLED) {
                break;
            }
            aos_msleep(1000);
        }
    }
    return NULL;
}

/* 用户数据接收处理回调函数 */
374
static void BleCfg_dm_recv_handler(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
375
{
376
    printf("BleCfg_dm_recv_handler, type = %d\r\n", recv->type);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393

    switch (recv->type) {

        /* 属性上报, 事件上报, 获取期望属性值或者删除期望属性值的应答 */
        case AIOT_DMRECV_GENERIC_REPLY: {
            printf("msg_id = %d, code = %d, data = %.*s, message = %.*s\r\n",
                   recv->data.generic_reply.msg_id,
                   recv->data.generic_reply.code,
                   recv->data.generic_reply.data_len,
                   recv->data.generic_reply.data,
                   recv->data.generic_reply.message_len,
                   recv->data.generic_reply.message);
        }
        break;

        /* 属性设置 */
        case AIOT_DMRECV_PROPERTY_SET: {
K
kbfcy 已提交
394
            printf("msg_id = %lu, params = %.*s\r\n",
395 396 397 398
                   (unsigned long)recv->data.property_set.msg_id,
                   recv->data.property_set.params_len,
                   recv->data.property_set.params);

399
#if (BOARD_HAAS100 == 1)
400
            BleCfg_led_switch(recv->data.property_set.params_len, recv->data.property_set.params);
401 402 403 404 405 406 407 408 409 410 411 412 413
            {
                aiot_dm_msg_t msg;

                memset(&msg, 0, sizeof(aiot_dm_msg_t));
                msg.type = AIOT_DMMSG_PROPERTY_SET_REPLY;
                msg.data.property_set_reply.msg_id = recv->data.property_set.msg_id;
                msg.data.property_set_reply.code = 200;
                msg.data.property_set_reply.data = "{}";
                int32_t res = aiot_dm_send(dm_handle, &msg);
                if (res < 0) {
                    printf("aiot_dm_send failed\r\n");
                }
            }
414
            BleCfg_led_update(dm_handle);
415
#endif
416 417 418 419 420
        }
        break;

        /* 异步服务调用 */
        case AIOT_DMRECV_ASYNC_SERVICE_INVOKE: {
K
kbfcy 已提交
421
            printf("msg_id = %lu, service_id = %s, params = %.*s\r\n",
422 423 424 425 426 427 428 429 430 431
                   (unsigned long)recv->data.async_service_invoke.msg_id,
                   recv->data.async_service_invoke.service_id,
                   recv->data.async_service_invoke.params_len,
                   recv->data.async_service_invoke.params);

            /* TODO: 以下代码演示如何对来自云平台的异步服务调用进行应答, 用户可取消注释查看演示效果
             *
             * 注意: 如果用户在回调函数外进行应答, 需要自行保存msg_id, 因为回调函数入参在退出回调函数后将被SDK销毁, 不可以再访问到
             */

432

433 434 435 436 437 438 439 440 441 442 443 444 445 446
            {
                aiot_dm_msg_t msg;

                memset(&msg, 0, sizeof(aiot_dm_msg_t));
                msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY;
                msg.data.async_service_reply.msg_id = recv->data.async_service_invoke.msg_id;
                msg.data.async_service_reply.code = 200;
                msg.data.async_service_reply.service_id = "ToggleLightSwitch";
                msg.data.async_service_reply.data = "{\"dataA\": 20}";
                int32_t res = aiot_dm_send(dm_handle, &msg);
                if (res < 0) {
                    printf("aiot_dm_send failed\r\n");
                }
            }
447

448 449 450 451 452
        }
        break;

        /* 同步服务调用 */
        case AIOT_DMRECV_SYNC_SERVICE_INVOKE: {
K
kbfcy 已提交
453
            printf("msg_id = %lu, rrpc_id = %s, service_id = %s, params = %.*s\r\n",
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
                   (unsigned long)recv->data.sync_service_invoke.msg_id,
                   recv->data.sync_service_invoke.rrpc_id,
                   recv->data.sync_service_invoke.service_id,
                   recv->data.sync_service_invoke.params_len,
                   recv->data.sync_service_invoke.params);

            /* TODO: 以下代码演示如何对来自云平台的同步服务调用进行应答, 用户可取消注释查看演示效果
             *
             * 注意: 如果用户在回调函数外进行应答, 需要自行保存msg_id和rrpc_id字符串, 因为回调函数入参在退出回调函数后将被SDK销毁, 不可以再访问到
             */

            /*
            {
                aiot_dm_msg_t msg;

                memset(&msg, 0, sizeof(aiot_dm_msg_t));
                msg.type = AIOT_DMMSG_SYNC_SERVICE_REPLY;
                msg.data.sync_service_reply.rrpc_id = recv->data.sync_service_invoke.rrpc_id;
                msg.data.sync_service_reply.msg_id = recv->data.sync_service_invoke.msg_id;
                msg.data.sync_service_reply.code = 200;
                msg.data.sync_service_reply.service_id = "SetLightSwitchTimer";
                msg.data.sync_service_reply.data = "{}";
                int32_t res = aiot_dm_send(dm_handle, &msg);
                if (res < 0) {
                    printf("aiot_dm_send failed\r\n");
                }
            }
            */
        }
        break;

        /* 下行二进制数据 */
        case AIOT_DMRECV_RAW_DATA: {
            printf("raw data len = %d\r\n", recv->data.raw_data.data_len);
            /* TODO: 以下代码演示如何发送二进制格式数据, 若使用需要有相应的数据透传脚本部署在云端 */
            /*
            {
                aiot_dm_msg_t msg;
                uint8_t raw_data[] = {0x01, 0x02};

                memset(&msg, 0, sizeof(aiot_dm_msg_t));
                msg.type = AIOT_DMMSG_RAW_DATA;
                msg.data.raw_data.data = raw_data;
                msg.data.raw_data.data_len = sizeof(raw_data);
                aiot_dm_send(dm_handle, &msg);
            }
            */
        }
        break;

        /* 二进制格式的同步服务调用, 比单纯的二进制数据消息多了个rrpc_id */
        case AIOT_DMRECV_RAW_SYNC_SERVICE_INVOKE: {
            printf("raw sync service rrpc_id = %s, data_len = %d\r\n",
                   recv->data.raw_service_invoke.rrpc_id,
                   recv->data.raw_service_invoke.data_len);
        }
        break;

        default:
            break;
    }
}

/* 属性上报函数演示 */
518
int32_t BleCfg_send_property_post(void *dm_handle, char *params)
519 520 521 522 523 524 525 526 527 528 529
{
    aiot_dm_msg_t msg;

    memset(&msg, 0, sizeof(aiot_dm_msg_t));
    msg.type = AIOT_DMMSG_PROPERTY_POST;
    msg.data.property_post.params = params;

    return aiot_dm_send(dm_handle, &msg);
}

/* 事件上报函数演示 */
530
int32_t BleCfg_send_event_post(void *dm_handle, char *event_id, char *params)
531 532 533 534 535 536 537 538 539 540 541 542
{
    aiot_dm_msg_t msg;

    memset(&msg, 0, sizeof(aiot_dm_msg_t));
    msg.type = AIOT_DMMSG_EVENT_POST;
    msg.data.event_post.event_id = event_id;
    msg.data.event_post.params = params;

    return aiot_dm_send(dm_handle, &msg);
}

/* 演示了获取属性LightSwitch的期望值, 用户可将此函数加入到main函数中运行演示 */
543
int32_t BleCfg_send_get_desred_requset(void *dm_handle)
544 545 546 547 548 549 550 551 552 553 554
{
    aiot_dm_msg_t msg;

    memset(&msg, 0, sizeof(aiot_dm_msg_t));
    msg.type = AIOT_DMMSG_GET_DESIRED;
    msg.data.get_desired.params = "[\"LightSwitch\"]";

    return aiot_dm_send(dm_handle, &msg);
}

/* 演示了删除属性LightSwitch的期望值, 用户可将此函数加入到main函数中运行演示 */
555
int32_t BleCfg_send_delete_desred_requset(void *dm_handle)
556 557 558 559 560 561 562 563 564 565
{
    aiot_dm_msg_t msg;

    memset(&msg, 0, sizeof(aiot_dm_msg_t));
    msg.type = AIOT_DMMSG_DELETE_DESIRED;
    msg.data.get_desired.params = "{\"LightSwitch\":{}}";

    return aiot_dm_send(dm_handle, &msg);
}

566
int BleCfg_linksdk_main(char *product_key, char *device_name, char *device_secret)
567 568 569 570 571 572 573 574 575 576 577 578
{
    int32_t     res = STATE_SUCCESS;
    void       *dm_handle = NULL;
    void       *mqtt_handle = NULL;
    char       *url = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; /* 阿里云平台上海站点的域名后缀 */
    char        host[100] = {0}; /* 用这个数组拼接设备连接的云平台站点全地址, 规则是 ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com */
    uint16_t    port = 443;      /* 无论设备是否使用TLS连接阿里云平台, 目的端口都是443 */
    aiot_sysdep_network_cred_t cred; /* 安全凭据结构体, 如果要用TLS, 这个结构体中配置CA证书等参数 */

    /* 配置SDK的底层依赖 */
    aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
    /* 配置SDK的日志输出 */
579
    aiot_state_set_logcb(BleCfg_state_logcb);
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609

    /* 创建SDK的安全凭据, 用于建立TLS连接 */
    memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
    cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA;  /* 使用RSA证书校验MQTT服务端 */
    cred.max_tls_fragment = 16384; /* 最大的分片长度为16K, 其它可选值还有4K, 2K, 1K, 0.5K */
    cred.sni_enabled = 1;                               /* TLS建连时, 支持Server Name Indicator */
    cred.x509_server_cert = ali_ca_cert;                 /* 用来验证MQTT服务端的RSA根证书 */
    cred.x509_server_cert_len = strlen(ali_ca_cert);     /* 用来验证MQTT服务端的RSA根证书长度 */

    /* 创建1个MQTT客户端实例并内部初始化默认参数 */
    mqtt_handle = aiot_mqtt_init();
    if (mqtt_handle == NULL) {
        printf("aiot_mqtt_init failed\n");
        return -1;
    }

    snprintf(host, 100, "%s.%s", product_key, url);
    /* 配置MQTT服务器地址 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)host);
    /* 配置MQTT服务器端口 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port);
    /* 配置设备productKey */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key);
    /* 配置设备deviceName */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name);
    /* 配置设备deviceSecret */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret);
    /* 配置网络连接的安全凭据, 上面已经创建好了 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred);
    /* 配置MQTT事件回调函数 */
610
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)BleCfg_mqtt_event_handler);
611 612 613 614 615 616 617 618 619 620

    /* 创建DATA-MODEL实例 */
    dm_handle = aiot_dm_init();
    if (dm_handle == NULL) {
        printf("aiot_dm_init failed");
        return -1;
    }
    /* 配置MQTT实例句柄 */
    aiot_dm_setopt(dm_handle, AIOT_DMOPT_MQTT_HANDLE, mqtt_handle);
    /* 配置消息接收处理回调函数 */
621
    aiot_dm_setopt(dm_handle, AIOT_DMOPT_RECV_HANDLER, (void *)BleCfg_dm_recv_handler);
622 623 624 625 626 627 628 629 630 631 632
    /* 与服务器建立MQTT连接 */
    res = aiot_mqtt_connect(mqtt_handle);
    if (res < STATE_SUCCESS) {
        /* 尝试建立连接失败, 销毁MQTT实例, 回收资源 */
        aiot_mqtt_deinit(&mqtt_handle);
        printf("aiot_mqtt_connect failed: -0x%04X\n", -res);
        return -1;
    }

    /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
    g_mqtt_process_thread_running = 1;
633 634
    res = aos_task_new("BleCfg_mqtt_process_thread", (void (*)(void *))BleCfg_mqtt_process_thread, mqtt_handle, 4096);
    // res = pthread_create(&g_mqtt_process_thread, NULL, BleCfg_mqtt_process_thread, mqtt_handle);
635
    if (res != 0) {
636
        printf("create BleCfg_mqtt_process_thread failed: %d\n", res);
637 638 639 640 641
        return -1;
    }

    /* 创建一个单独的线程用于执行aiot_mqtt_recv, 它会循环收取服务器下发的MQTT消息, 并在断线时自动重连 */
    g_mqtt_recv_thread_running = 1;
642 643
    res = aos_task_new("BleCfg_mqtt_recv_thread", (void (*)(void *))BleCfg_mqtt_recv_thread, mqtt_handle, 4096);
    // res = pthread_create(&g_mqtt_recv_thread, NULL, BleCfg_mqtt_recv_thread, mqtt_handle);
644
    if (res != 0) {
645
        printf("create BleCfg_mqtt_recv_thread failed: %d\n", res);
646 647 648
        return -1;
    }

649
#if (BOARD_HAAS100 == 1)
650
    BleCfg_led_update(mqtt_handle);
651
#endif
652 653 654 655

    /* 主循环进入休眠 */
    while (1) {
        /* TODO: 以下代码演示了简单的属性上报和事件上报, 用户可取消注释观察演示效果 */
656 657
        //BleCfg_send_property_post(dm_handle, s_led_state[1] == 1 "{\"HaaS100_LED_1\": 1}" ?: "{\"HaaS100_LED_1\": 0}");
        //BleCfg_send_event_post(dm_handle, "Error", "{\"ErrorCode\": 0}");
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
        aos_msleep(10000);
    }

    /* 断开MQTT连接, 一般不会运行到这里 */
    res = aiot_mqtt_disconnect(mqtt_handle);
    if (res < STATE_SUCCESS) {
        aiot_mqtt_deinit(&mqtt_handle);
        printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
        return -1;
    }

    /* 销毁DATA-MODEL实例, 一般不会运行到这里 */
    res = aiot_dm_deinit(&dm_handle);
    if (res < STATE_SUCCESS) {
        printf("aiot_dm_deinit failed: -0x%04X\n", -res);
        return -1;
    }

    /* 销毁MQTT实例, 一般不会运行到这里 */
    res = aiot_mqtt_deinit(&mqtt_handle);
    if (res < STATE_SUCCESS) {
        printf("aiot_mqtt_deinit failed: -0x%04X\n", -res);
        return -1;
    }

    g_mqtt_process_thread_running = 0;
    g_mqtt_recv_thread_running = 0;

    return 0;
}

689
BLECFG_STATE BleCfg_linksdk_init(BleCfg_link_cb link_callback)
690
{
691
    memset(&s_device_info, 0, sizeof(s_device_info));
692

693
    s_device_info.link_cb = link_callback;
694

695
#if (BOARD_HAAS100 == 1)
696
    BleCfg_led_init();
697 698
#endif

699
    return BLECFG_SUCCESS;
700
}
701 702