本文介绍如何在MCU侧添加AT连接程序,使用阿里云直连WiFi固件,实现快速入云与数据上报。

获取源码

我们为用户提供了通MCU对接模组的示例代码。在该示例代码中,用户可以了解如何使用模组完成,包括模组配置、联网、属性上报、处理服务等调用。

将示例加入AliOS Things3.0源码中

示例代码基于AliOS Things 3.0源码进行构建,用户下载源码后,需要将源码添加至AliOS Things 3.0源码中才能进行编译使用。

Step 1: 将以上文件解压后,放置于app/example目录下

mv wifi_at rel_3.0.0/app/example/

wifi_at_app的目录结构如下

.
├── aos.mk
├── atcmd_util.c
├── Config.in
├── README.md
├── include
│   ├── atcmd_config.h
│   └── atcmd_util.h
└── wifi_at.c

Step 2: 更新app/example/config.in

在app/example/Config.in的choice选项内添加,以上Config.in的source与配置

source "app/example/wifi_at/Config.in"
if AOS_APP_WIFI_AT_APP
    config AOS_BUILD_APP
        default "wifi_at_app"
endif

Step 3: 编译验证

以stm32f103rb-nucleo为目标版进行编译,命令如下

aos make wifi_at@stm32f103rb-nucleo -c config
aos make

示例介绍

示例入口为wifi_at.capplication_start函数,并在该函数内运行主逻辑。本节按照运行步骤进行介绍。

Step 1:配置MCU与模组

int application_start(int argc, char *argv[])
{
    ...
    /* 设置MCU log等级 */
    aos_set_log_level(AOS_LL_DEBUG);

    /* 初始化MCU AT设备驱动,例如UART参数、注册AT前缀处理回调 */
    at_device_init();

    /* 重置模组的连接 */
    at_device_reset();

    /* 等待模组断开 */
    aos_msleep(1000);

    /* 配置模组四元组信息 */
    at_device_config(DEMO_PRODUCT_KEY,
                     DEMO_DEVICE_NAME,
                     DEMO_DEVICE_SECRET,
                     DEMO_PRODUCT_SECRET);
    ...
}

Step 2:网络连接

int application_start(int argc, char *argv[])
{
    ...
    /*
    * 网络连接
    * 输入参数: WiFi AP的ssid, password
    * 如果ssid与password为空, 使用手机一键配网
    */
    do {
        ret = at_device_connect(NULL, NULL);
        if (ret >= 0) {
            break;
        }
        
        /* 循环等待网络连接 */
        LOGI(TAG, "AT device connect Cloud failed! retry...\n");
        aos_msleep(5000);
    } while (1);

    ...
}

Step 3:主业务循环

int application_start(int argc, char *argv[])
{
    ...
    /* 主循环 */
    while (1) {
        count++;

        if (count % 5 == 0) {
            memset(buffer, sizeof(buffer), 0);

            /* 可自行修改上报物模型的内容 */
            len = snprintf(buffer, sizeof(buffer), "{\"Counter\": %d}", count);

            /* 上报物模型 */
            user_send_property(buffer, len);
        }

        /* 处理来自云端消息 */
        user_process_cloud_msg();

        aos_msleep(1000);
    }
    ...
}

其中,user_send_property拼接AT指令并等待执行结果,其实现如下。

int user_send_property(const char *payload, int payload_len)
{
    int len = 0;
    char cmd_str[100] = { 0 };
    char *ptr = NULL;
    int pkid = -1;
    int devid = 0; /* master device default id */

    /*
     *  拼接AT指令,设置devid
     *  e.g. AT+IDMPP=0,
     */
    len = snprintf(cmd_str, sizeof(cmd_str),
                   "%s=%d,", "AT+IDMPP", devid);

    ptr = cmd_str + len;

    /*
     *  拼接AT指令,添加payload
     *  e.g. {"LightSwitch":1} ==> "{\"LightSwitch\":1}"
     */
    len += atcmd_add_slash_quote(ptr, sizeof(cmd_str) - len, payload, payload_len);

    /*
     *  发送AT指令,等待packet ID
     */
    pkid = atcmd_send_wait_ret_val(cmd_str, len, true, WAIT_PACKET_ID,
                                   SEND_WAIT_REPLY_TIMEOUT_MS);

    LOGI(TAG, "Sent Property Message ID: %d", pkid);

    return pkid;
}

Step 4:处理云端请求

云端下发的请求,首先由模组以AT字符串形式推送给MCU;MCU收到后,由在at_device_init()函数注册的回调at_response_callback进行预处理,并放入缓存队列中。用户在上述主循环中由函数user_process_cloud_msg进行处理。

void user_process_cloud_msg(void)
{
    ...

    /* 检查消息队列 */
    if(atcmd_tryfetch_msg(&req_msg) != 0) {
        return;
    }

    /* 根据消息类型进行分别处理 */
    switch(req_msg->type) {
        case SERV_SET_MSG:
            /* 
             * 用户在此添加业务处理,例如打开灯
             */

            /* 回复云端 */
            res =  user_answer_service(req_msg->dev_id, req_msg->serv_id, strlen(req_msg->serv_id),
                                       answer_payload, strlen(answer_payload), (void *)req_msg->msg_id);
            LOGI(TAG, "Answer Server ret: %d msg: %s", res, req_msg->payload);
            break;

        /* 添加更多消息处理 */
        /* case PROP_SET_MSG: */
        /* case OTA_INFO_MSG: */

        default:
            LOGI(TAG, "Unknown msg type");
            break;
    }

    /* 释放取出的消息 */
    aos_free(req_msg->payload);
    aos_free(req_msg);
}