MCU SDK 移植

更新时间:2024-11-13 08:08:35下载pdf

MCU SDK 是根据涂鸦开发者平台定义的产品功能自动生成的 MCU 代码,能够协助您快速完成 MCU 程序的开发。本文为您介绍 Zigbee 通用方案移植 MCU SDK 的流程以及注意事项。

文件结构

在移植 MCU SDK 前,您需要了解其文件结构:

文件 说明
zigbee.h 提供通用宏的定义
system.h system.h 包含以下信息:
  • 函数声明:通用功能函数、队列处理函数、组帧函数
system.c system.c 包含以下信息:
  • 函数声明:队列处理函数
  • 函数定义:通用功能函数、队列处理函数、组帧函数
protocol.h protocol.h 包含以下信息:
  • 配置项:设备信息
  • DP ID 宏定义
  • 协议信息:帧字段、命令字等
  • 命令字相关信息:DP 数据类型、Zigbee 模组网络状态、网络参数等
  • 函数声明:帧接收函数、DP 处理函数
protocol.c protocol.c 包含以下信息:
  • 协议、命令字相关定义
  • 函数声明:帧接收处理函数(完整流程)、DP 消息处理函数
  • 函数定义:DP 处理函数、帧接收处理函数(完整流程)、帧发送函数、DP 消息处理函数
mcu_api.h mcu_api.h 包含以下信息:
  • 配置项:调试信息打印开关、串口及队列缓冲区尺寸、命令字相关信息等
  • 函数声明:串口服务函数、串口数据发送函数、MCU 唤醒 Zigbee 函数、帧接收处理函数(用户接口)、帧发送函数
mcu_api.c mcu_api.c 包含以下信息:
  • 函数定义:串口服务函数、串口数据发送函数

更多信息,参考 附录 - 文件详细说明

移植流程

完成移植流程后,用户可参考 使用流程 体验 MCU SDK。

  1. 下载 MCU SDK
  2. 编写 MCU 基础程序
  3. 使用 mcu_api.h
  4. 使用 mcu_api.c
  5. 使用 protocol.h
  6. 使用 protocol.c

第一步:下载 MCU SDK

下载 MCU SDK。具体步骤,参考 MCU 低代码开发

第二步:编写 MCU 基础程序

  1. 将 MCU SDK 文件夹中的 .c.h 文件分别添加到项目工程的源文件和头文件引用路径下。

  2. 项目工程 中需要使用 MCU SDK 接口的文件里,添加代码 #include "zigbee.h"

第三步:使用 mcu_api.h

  1. mcu_api.h 中,如果需要打印调试信息,使能宏 MCU_SDK_DEBUG。然后,把宏 PROJECT_PRINT_FUNC 替换为项目工程的调试信息打印函数(可能需要引用项目工程的头文件)。

    #ifndef MCU_SDK_DEBUG
    #define MCU_SDK_DEBUG                           1
    #endif
    
    #if MCU_SDK_DEBUG
    #include "xx_print.h"
    #define PRINT_DEBUG(fmt, ...)                   my_debug_print(fmt, ##__VA_ARGS__)
    #else
    #define PRINT_DEBUG(fmt, ...)
    #endif
    
  2. mcu_api.h 中,确认缓冲区尺寸,包括 UART_RX_BUF_LEN_LMTUART_TX_BUF_LEN_LMTUART_QUEUE_BUF_LEN_LMT

    • 串口接收缓冲区、串口发送缓冲区的尺寸要分别大于 DP 数据最长的 DP 消息长度,默认大小为 24 字节。
    • 接收队列缓冲区的尺寸,建议大于 260 字节,以应对 MCU OTA 升级。
    • 如果 RAM 紧张,则三个缓冲区的尺寸可以适当缩小。
    #define UART_RX_BUF_LEN_LMT                     256
    #define UART_TX_BUF_LEN_LMT                     256
    #define UART_QUEUE_BUF_LEN_LMT                  512
    
  3. mcu_api.h 中,修改 OTA 单包尺寸(OTA_PACKET_SIZE)以及 Zigbee 模组唤醒 MCU 时等待 MCU 的时间(ZG_WAIT_MCU_TIME_DEFAULT)。

    ///< OTA single packet payload length (UART command ID: 0x0c 0x0d 0x0e)
    #define OTA_PACKET_SIZE                         0x30            // max: 0x30
    
    ///< The waiting time after the Zigbee module starts to wake up the MCU (UART command ID: 0x2b)
    #if SLEEP_END_DEVICE
    #define ZG_WAIT_MCU_TIME_DEFAULT                10
    #endif
    
  4. 项目工程 的串口数据接收处理函数中,调用 uart_servive_rx_store() 函数处理接收的每个字节。

    int main(void)
    {
        ...
    
        // MCU 接收串口初始化
        recv_uart_init(recv_uart_callback);
    
        ...
    }
    
    void recv_uart_callback(uint8_t *buff, uint16_t len)
    {
        for (uint16_t i = 0; i < len; i++) {
            uart_servive_rx_store(buff[i]);
        }
    }
    
  5. 项目工程 的主循环或定时器中断(循环执行)中,调用 uart_service_parse() 函数。

    如果采用中断方式,则程序正常初始化完成后,建议不要关闭中断,因为关闭中断会导致串口数据接收丢失。如果必须关闭中断,则关闭中断时间必须短。禁止在中断内调用上报函数。

    int main(void)
    {
        ...
    
        while(1) {
            uart_service_parse();
        }
    
        ...
    }
    
  6. 项目工程 中实现 uart_send_byte() 函数,只需要在里面调用项目工程的串口单字节发送函数。

    int main(void)
    {
        ...
    
        ...
    }
    
    void uart_send_byte(unsigned char value)
    {
        my_uart_send_a_byte(value);
    }
    
  7. 对于低功耗设备,在 项目工程 中初始化低功耗唤醒 GPIO,并实现以下其中一个低功耗唤醒发送函数:

    • mcu_wakeup_zg_level_method() 函数,电平唤醒

    • mcu_wakeup_zg_pulse_method() 函数,脉冲唤醒

    具体实现方式,参考 低功耗唤醒

    int main(void)
    {
        ...
    
        // MCU 唤醒模组 GPIO 初始化
        // 模组唤醒 MCU GPIO 初始化
        wakeup_gpio_init();
    
        ...
    }
    
    void mcu_wakeup_zg_level_method(unsigned char *data, unsigned short data_len)
    {
        // 请根据串口协议的低功耗唤醒章节自行实现
    }
    
  8. 项目工程 中,必须实现串口协议的 所有 的帧接收处理函数(用户接口,mcu_recv_ 前缀),可以实现为空函数。

    void mcu_recv_factory_recovery_cb(void)
    {
        PRINT_DEBUG("factory recovery\r\n");
    }
    
    void mcu_recv_zg_nwk_status_notify_cb(unsigned char nwk_status)
    {
    }
    
    unsigned char mcu_recv_beacon_notify_cb(void)
    {
        return 1;
    }
    

第四步:使用 mcu_api.c

  1. mcu_api.c 中,对于低功耗设备,在 uart_send_frame() 函数中开启一个 MCU 唤醒发送函数(需要在项目工程中实现),并禁用另一个 MCU 唤醒发送函数。

    void uart_send_frame(unsigned short payload_len)
    {
    #if SLEEP_END_DEVICE
        mcu_wakeup_zg_level_method((unsigned char *)g_uart_tx_buf, payload_len + FRAME_LEN_WITHOUT_PAYLOAD);
        // mcu_wakeup_zg_pulse_method((unsigned char *)g_uart_tx_buf, payload_len + FRAME_LEN_WITHOUT_PAYLOAD);
    #else
        uart_send_bytes((unsigned char *)g_uart_tx_buf, payload_len + FRAME_LEN_WITHOUT_PAYLOAD);
    #endif
    }
    

第五步:使用 protocol.h

  1. protocol.h 中,确认设备信息。

    标识 说明 注意事项
    PRODUCT_KEY 产品 ID,即 PID 这是每个产品的唯一标识,可在 涂鸦开发者平台 的产品详情页面获取
    MCU_VER MCU 固件版本 关于 OTA 升级流程,参考 OTA 升级说明-平台配置
    SUPPORT_RECEIVE_BROADCAST_DATA MCU 是否需要区分群控消息
    • 0x00:不需要
    • 0x01:需要
    DEVICE_TYPE 设备类型
    • 0x00:标准功耗(非场景开关)
    • 0x01:低功耗
    • 0x02:标准功耗(场景开关)
    #define PRODUCT_KEY "ksubawat"    //在开发者平台创建产品后生成,16 位字符组成的产品唯一标识
    
    #define MCU_VER          "1.0.0"     // MAX 3.3.15,BIT 7~0,XX.XX.XXXX
    #define SUPPORT_RECEIVE_BROADCAST_DATA    1     // 0:不支持,1:支持
    #define DEVICE_TYPE     0     // 0:标准功耗设备(router),1:低功耗设备(sleep end device),2:场景开关(scene switch)
    #if (DEVICE_TYPE == 1)
    #define SLEEP_END_DEVICE     1     // 只有该设备类型才支持的命令:0x2b
    #elif (DEVICE_TYPE == 2)
    #define SCENE_SWITCH     1     // 只有该设备类型才支持的命令:0x0a,0x41,0x42 和 0x43,只有该设备类型不支持的命令:0x25,0x26 和 0x2a
    #endif
    
  2. protocol.h 中,确认 DP ID 宏(DPID_ 前缀)。

    #define DPID_TEMP_ROOM 101
    #define DPID_AIRCOND_SWITCH 102
    #define DPID_AIRCOND_TEMP_SET 103
    ...
    

第六步:使用 protocol.c

  1. protocol.c 中,确认 DP 信息数组。

    const DOWNLOAD_CMD_S download_cmd[] =
    {
      {DPID_TEMP_ROOM, DP_TYPE_VALUE},
      {DPID_AIRCOND_SWITCH, DP_TYPE_BOOL},
      {DPID_AIRCOND_TEMP_SET, DP_TYPE_VALUE},
      ...
    };
    
  2. protocol.c 里的 mcu_rx_gw_check_dp 函数中,确认设备接收到网关查询 DP 命令后,设备上报 DP 的方式。

    • 如果希望触发联动,则使用 0x06 命令字。
    • 如果不希望触发联动,则使用 0x2c 命令字。
    static void mcu_rx_gw_check_dp(UART_FRAME_T *uart_frame)
    {
        ///< 1. 发送 0x28,不携带 payload
        ...
    
        ///< 2. DP 上报类型(是否触发联动)
        g_dp_send_type = DP_SEND_TYPE_REPORT_LINKAGE;       // 0x06
        // g_dp_send_type = DP_SEND_TYPE_REPORT_NOT_LINKAGE;   // 0x2c
    
        ///< 3. 上报 DP
        ...
    }
    
  3. protocol.c 中,完善 all_data_update() 函数,例如传入代表当前 DP 真实值的变量(该变量需要用户自行提供)。

    static void all_data_update(void)
    {
        mcu_dp_bool_update(DPID_AIRCOND_SWITCH,my_aircond_switch_value);
        mcu_dp_bool_update(DPID_AIRCOND_ECO,my_aircond_eco_value);
        ...
    }
    
  4. protocol.c 中,完善 specific_DP_update() 函数。只需要根据 DP ID,调用符合 DP 数据类型的 DP 上报函数。

    static void specific_dp_update(unsigned char dp_id)
    {
        switch (dp_id) {
            /** please refer the following example and 'all_data_update()'
             *
             *     case DPID_SCENE_1: {
             *         mcu_dp_enum_update(DPID_SCENE_1,当前场景 1); //枚举型数据上报
             *         break;
             *     }
             *
             *     case DPID_SCENE_2: {
             *         mcu_dp_enum_update(DPID_SCENE_2,当前场景 2); //枚举型数据上报
             *         break;
             *     }
             */
    
            case DPID_AIRCOND_SWITCH: {
                mcu_dp_bool_update(DPID_AIRCOND_SWITCH,my_aircond_switch_value);
                break;
            }
    
            case DPID_AIRCOND_ECO: {
                mcu_dp_bool_update(DPID_AIRCOND_ECO,my_aircond_eco_value);
                break;
            }
    
            default: {
                break;
            }
        }
    }
    
  5. protocol.c 中,查看 dp_msg_handle() 函数,并完善该函数使用的 DP 下发处理函数。DP_download_xxxxxx_handle() 格式,不同 DP 的函数内容稍有差异。

    static unsigned char dp_msg_handle(unsigned char dp_id, const unsigned char *value, unsigned short length)
    {
        unsigned char ret;
        if (NULL == value) {
            return ERROR;
        }
    
        switch (dp_id) {
            case DPID_AIRCOND_SWITCH:
                ret = dp_download_aircond_switch_handle(value,length);
            break;
    
            ...
    
            default :
                break;
        }
        return ret;
    }
    
    static unsigned char dp_download_aircond_switch_handle(const unsigned char value[], unsigned short length)
    {
        unsigned char ret;
        //0:off/1:on
        unsigned char aircond_switch;
    
        aircond_switch = mcu_get_dp_download_bool(value,length);
        if(aircond_switch == 0) {
            //bool off
            ...
            my_aircond_switch_off_handle();
            ...
        }else {
            //bool on
            my_aircond_switch_on_handle();
        }
    
        //There should be a report after processing the DP
        ret = mcu_dp_bool_update(DPID_AIRCOND_SWITCH,aircond_switch);
        if(ret == SUCCESS)
            return SUCCESS;
        else
            return ERROR;
    }
    

使用流程

移植成功后,用户只需要关心如下内容:

  1. 帧发送函数(mcu_tx_ 前缀)

    MCU 主动发送帧的接口。

    用户可直接调用这些函数,发送串口协议帧给烧录了通用对接固件的 Zigbee 模组。

    /*
    void mcu_tx_let_zigbee_reset(void)
    {
        unsigned short payload_len = 0;
        uart_framing_fill_payload_byte(&payload_len, 0x00);
        uart_framing_fill_protocol_field(UART_CMD_RESET_OR_JOIN, payload_len, NULL);
        uart_send_frame(payload_len);
    }
    */
    
    int main(void)
    {
        ...
        mcu_tx_let_zigbee_reset();
        ...
    }
    
  2. 帧接收处理函数(完整流程mcu_rx_ 前缀)

    MCU 接收到帧后 完整的处理流程。禁止用户修改。

    用户可结合 串口协议 相应命令的时序图,了解该命令的接收处理流程。

    static void mcu_rx_factory_recovery_notify(UART_FRAME_T *uart_frame)
    {
        if (NULL == uart_frame || NULL == uart_frame->frame_payload) {
            return;
        }
    
        ///< 1. 发送帧
        unsigned short payload_len = 0;
        uart_framing_fill_payload_byte(&payload_len, 0x01);
        uart_framing_fill_protocol_field(UART_CMD_FACTORY_RECOVERY, payload_len, &uart_frame->frame_seq);
        uart_send_frame(payload_len);
    
        ///< 2. 恢复出厂设置
        mcu_recv_factory_recovery_cb();
    }
    
  3. 帧接收处理函数(用户接口mcu_recv_ 前缀)

    MCU 接收到帧后 提供给用户进行处理的接口,需要用户实现。

    用户可查看这些函数被调用的位置,然后结合 串口协议 相应命令的时序图,确定这些函数的工作时点。

支持与帮助

  • 如果想详细了解通用对接串口协议,可参考 串口协议
  • 在开发过程遇到问题,您可以登录 TuyaOS 开发者论坛 MCU SDK 开发版块 进行咨询。

附录 - 文件详细说明

zigbee.h

功能

  • 提供通用宏的定义。

通用宏

  • 源代码

    #ifndef TRUE
    #define TRUE                    1
    #endif
    
    #ifndef FALSE
    #define FALSE                   0
    #endif
    
    #ifndef NULL
    #define NULL                    ((void *)0)
    #endif
    
    #ifndef SUCCESS
    #define SUCCESS                 1
    #endif
    
    #ifndef ERROR
    #define ERROR                   0
    #endif
    
    #ifndef INVALID
    #define INVALID                 0xFF
    #endif
    
    #ifndef ENABLE
    #define ENABLE                  1
    #endif
    
    #ifndef DISABLE
    #define DISABLE                 0
    #endif
    

system.h

功能

  • 函数声明:通用功能函数、队列处理函数、组帧函数。

通用功能函数

  • 函数说明

    标识 说明 注意事项
    get_seq_num 生成 16 位序列号 用于发送串口协议帧给模组
    get_u8_checksum 计算 8 位校验和 用户计算串口协议帧的校验和
    my_strlen strlen 功能一致 -
    my_memset memset 功能一致 -
    my_memcpy memcpy 功能一致 -
    my_strcpy strcpy 功能一致 最后一个字节会被替换为 ‘\0’
    my_strcmp strcmp 功能一致 -
    my_strncmp strncmp 功能一致 -
    hex_to_bcd 16 进制数据转为 BCD 码 -
    int_to_byte 32 位数据转为 4 个 8 位数据 -
    byte_to_int 4 个 8 位数据转为 32 位数据 -
    ascii_to_hex ASCII 码转为 16 进制数据 -

队列处理函数

  • 函数说明

    标识 说明 注意事项
    queue_dequeue_byte 出队(单字节) 出队前,会进行空队检测
    TRUE:出队成功
    queue_enqueue_byte 入队(单字节) 入队前,会进行满队检测
    TRUE:入队成功

组帧函数

  • 函数说明

    标识 说明 注意事项
    uart_framing_fill_payload_byte 协议帧 payload 字段填充:单字节 -
    uart_framing_fill_payload_buff 协议帧 payload 字段填充:多字节 -
    uart_framing_fill_payload_add_group_id 协议帧 payload 字段填充:在 payload 字段的开头插入 group ID,2 字节 仅用于发送群组 DP 消息(串口协议命令字 0x43
    uart_framing_fill_protocol_field 协议帧其它字段填充 -

system.c

功能

  • 函数声明:队列处理函数。
  • 函数定义:通用功能函数、队列处理函数、组帧函数。

队列处理函数

  • 函数说明

    标识 说明 注意事项
    queue_is_empty 空队检测 TRUE:空队
    queue_is_full 满队检测 TRUE:满队

protocol.h

功能

  • 配置项:设备信息。
  • DP ID 宏定义。
  • 协议信息:帧字段、命令字等。
  • 命令字相关信息:DP 数据类型、Zigbee 模组网络状态、网络参数等。
  • 函数声明:帧接收函数、DP 处理函数。

配置项

  • 设备信息

    标识 说明 注意事项
    PRODUCT_KEY PID 只有前 8 位有效。
    用户需要检查是否为通用对接设备的 PID。
    MCU_VER MCU 固件版本(本地) MCU 会上报该固件号。
    MCU 接收到 OTA 升级通知后,会把 OTA 包中的版本号与该版本号进行比较。
    SUPPORT_RECEIVE_BROADCAST_DATA MCU 是否需要区分群控消息
    • 0:不需要
    • 1:需要
    Zigbee 模组会通过产品信息命令(命令字 0x01)获取该值。
    • Zigbee 模组接收到 群控 消息后,如果 MCU 需要区分群控消息,则 Zigbee 模组会通过 群控 DP 消息命令(命令字 0x2a)把该消息发送给 MCU。反之,Zigbee 模组会通过 DP 消息命令(命令字 0x04)把该消息发送给 MCU。
    • 如果 Zigbee 收到 单控 消息,则会直接通过 DP 消息命令(命令字 0x04)把该消息发送给 MCU。
    DEVICE_TYPE 设备类型
    • 0:标准功耗(非场景开关)
    • 1:低功耗
    • 2:标准功耗(场景开关)
    如需了解不同设备类型的命令支持情况,参考通用对接串口协议文档。
    SLEEP_END_DEVICE 设备类型标识:低功耗 -
    SCENE_SWITCH 设备类型标识:标准功耗(场景开关) -
    #define PRODUCT_KEY "ksubawat"    //在开发者平台创建产品后生成,16 位字符组成的产品唯一标识
    
    #define MCU_VER                                 "1.0.0"         // MAX 3.3.15,BIT 7~0,XX.XX.XXXX
    #define SUPPORT_RECEIVE_BROADCAST_DATA          1               // 0:不支持,1:支持
    #define DEVICE_TYPE                             0               // 0:标准功耗设备(router),1:低功耗设备(sleep end device),2:场景开关(scene switch)
    #if (DEVICE_TYPE == 1)
    #define SLEEP_END_DEVICE                        1               // 只有该设备类型才支持的命令:0x2b
    #elif (DEVICE_TYPE == 2)
    #define SCENE_SWITCH                            1               // 只有该设备类型才支持的命令:0x0a,0x41,0x42 和 0x43,只有该设备类型不支持的命令:0x25,0x26 和 0x2a
    #endif
    

DP ID

  • 示例

    #define DPID_TEMP_ROOM 101
    #define DPID_AIRCOND_SWITCH 102
    #define DPID_AIRCOND_TEMP_SET 103
    ...
    

协议信息

  • 帧字段 ID

    标识 说明 注意事项
    FRAME_FIELD_HDR_HIGH 帧头的高字节的序号 -
    FRAME_FIELD_HDR_LOW 帧头的低字节的序号 -
    FRAME_FIELD_PROT_VER 串口协议版本的序号 -
    FRAME_FIELD_SEQ_HIGH 帧序列号的高字节的序号 -
    FRAME_FIELD_SEQ_LOW 帧序列号的低字节的序号 -
    FRAME_FIELD_CMD_ID 帧命令字的序号 -
    FRAME_FIELD_PAYLOAD_LEN_HIGH 帧 payload 长度的高字节的序号 如无 payload,则长度高低字节都为 0
    FRAME_FIELD_SEQ_LOW 帧 payload 长度的低字节的序号 -
    FRAME_FIELD_PAYLOAD_START 帧 payload 的起始序号 -
    FRAME_LEN_WITHOUT_PAYLOAD 最小帧长 不携带 payload 时的帧长

    帧尾为校验和,因为 payload 长度可变,所以不使用序号来表示帧尾。

    #define FRAME_FIELD_HDR_HIGH                    0
    #define FRAME_FIELD_HDR_LOW                     1
    #define FRAME_FIELD_PROT_VER                    2
    #define FRAME_FIELD_SEQ_HIGH                    3
    #define FRAME_FIELD_SEQ_LOW                     4
    #define FRAME_FIELD_CMD_ID                      5
    #define FRAME_FIELD_PAYLOAD_LEN_HIGH            6
    #define FRAME_FIELD_PAYLOAD_LEN_LOW             7
    #define FRAME_FIELD_PAYLOAD_START               8
    
    #define FRAME_LEN_WITHOUT_PAYLOAD               9           // the shortest frame length (no payload)
    
  • 帧字段值

    标识 说明
    FRAME_VALUE_HDR_HIGH 帧头的高字节的值
    FRAME_VALUE_HDR_LOW 帧头的低字节的值
    FRAME_VALUE_HDR 帧头的值
    FRAME_VALUE_PROT_VER 串口协议版本的值

    帧头版本号 被用于识别通用对接串口协议帧。

    #define FRAME_VALUE_HDR_HIGH                    0x55
    #define FRAME_VALUE_HDR_LOW                     0xaa
    #define FRAME_VALUE_HDR                         0x55aa
    #define FRAME_VALUE_PROT_VER                    0x02
    
  • 命令字

    如果想详细了解,参考 串口协议

    #define UART_CMD_FACTORY_RECOVERY               0x00
    #define UART_CMD_PRODUCT_INFO                   0x01
    #define UART_CMD_ZG_NWK_STATUS_NOTIFY           0x02
    #define UART_CMD_RESET_OR_JOIN                  0x03
    #define UART_CMD_RX_DP                          0x04
    #define UART_CMD_RESPOND_DP                     0x05
    #define UART_CMD_REPORT_DP_LINKAGE              0x06
    #define UART_CMD_ZG_INFO                        0x07
    #define UART_CMD_RF_TEST                        0x08
    #define UART_CMD_SCENE_INFO                     0x0A
    #define UART_CMD_MCU_VER                        0x0B
    #define UART_CMD_OTA_NOTIFY                     0x0C
    #define UART_CMD_OTA_DATA                       0x0D
    #define UART_CMD_OTA_RESULT                     0x0E
    #define UART_CMD_ZG_NWK_STATUS_REQUEST          0x20
    #define UART_CMD_DOUBLE_DONGLE_DATA_NOTIFY      0x21
    #define UART_CMD_DOUBLE_DONGLE_REPORT           0x22
    #define UART_CMD_TIME_SYNC                      0x24
    #define UART_CMD_MCU_CHECK_GW_NWK_STAUTS        0x25
    #define UART_CMD_MCU_SET_ZG_NWK_PARAM           0x26
    #define UART_CMD_SEND_DP_BROADCAST              0x27
    #define UART_CMD_GW_CHECK_DP                    0x28
    #define UART_CMD_BEACON_TEST                    0x29
    #define UART_CMD_RX_DP_GROUP                    0x2A
    #define UART_CMD_ZG_WAIT_MCU_TIME               0x2B
    #define UART_CMD_REPORT_DP_NOT_LINKAGE          0x2C
    #define UART_CMD_CONFIG_ZG_GPIO                 0x36
    #define UART_CMD_READ_ZG_GPIO                   0x37
    #define UART_CMD_WRITE_ZG_GPIO                  0x38
    #define UART_CMD_ZG_GPIO_IRQ                    0x39
    #define UART_CMD_WEATHER_REQUEST                0x3A
    #define UART_CMD_WEATHER_RESPONSE               0x3B
    #define UART_CMD_SCENE_CONFIG                   0x41
    #define UART_CMD_SEND_CMD_GROUP                 0x42
    #define UART_CMD_SEND_DP_GROUP                  0x43
    

命令相关信息

  • DP 数据类型

    标识 说明 注意事项
    DP_TYPE_RAW 透传型 -
    DP_TYPE_BOOL 布尔型 -
    DP_TYPE_VALUE 数值型 -
    DP_TYPE_STRING 字符型 -
    DP_TYPE_ENUM 枚举型 -
    DP_TYPE_BITMAP 位图型 -
    DP_TYPE_FAULT 故障型 该类型的处理和 DP_TYPE_BITMAP 的处理完全一致
    #define DP_TYPE_RAW                             0x00
    #define DP_TYPE_BOOL                            0x01
    #define DP_TYPE_VALUE                           0x02
    #define DP_TYPE_STRING                          0x03
    #define DP_TYPE_ENUM                            0x04
    #define DP_TYPE_BITMAP                          0x05
    #define DP_TYPE_FAULT                           DP_TYPE_BITMAP
    
  • Zigbee 模组信息查询标识(命令字 0x07

    标识 说明
    ZG_INFO_TYPE_SW_VER MCU 想查询 Zigbee 模组的固件版本
    ZG_INFO_TYPE_AUTH MCU 想查询 Zigbee 模组的授权信息
    ZG_INFO_TYPE_MAC_ADDR MCU 想查询 Zigbee 模组的 MAC 地址
    #define ZG_INFO_TYPE_SW_VER                     0x01
    #define ZG_INFO_TYPE_AUTH                       0x02
    #define ZG_INFO_TYPE_MAC_ADDR                   0x03
    
  • Zigbee 模组网络参数(命令字 0x26

    标识 说明
    HEART_PERIOD_DEFAULT_SET MCU 想设置 Zigbee 模组的 心跳周期 为默认值
    JOIN_TIMEOUT_DEFAULT_SET MCU 想设置 Zigbee 模组的 JOIN 超时时长 为默认值
    REJOIN_INTERVAL_DEFAULT_SET MCU 想设置 Zigbee 模组的 每轮 REJOIN 的间隔 为默认值
    POLL_INTERVAL_DEFAULT_SET MCU 想设置 Zigbee 模组的 POLL 间隔 为默认值
    FAST_POLL_PERIOD_DEFAULT_SET MCU 想设置 Zigbee 模组的 上电 POLL 的时间 为默认值
    POLL_FAIL_TIMES_DEFAULT_SET MCU 想设置 Zigbee 模组的 POLL 最大失败次数 为默认值
    APP_DATA_TRIG_REJOIN_DEFAULT_SET MCU 想设置 Zigbee 模组的 数据触发 REJOIN 为默认值
    REJOIN_TRY_TIMES_DEFAULT_SET MCU 想设置 Zigbee 模组的 每轮 REJOIN 的尝试次数 为默认值
    RF_POWER_DEFAULT_SET MCU 想设置 Zigbee 模组的 发送功率 为默认值
    NWK_PARAM_DEFAULT_SET MCU 想设置 Zigbee 模组的 所有参数 为默认值
    #define HEART_PERIOD_DEFAULT_SET                0xfffe
    #define JOIN_TIMEOUT_DEFAULT_SET                0xfffe
    #define REJOIN_INTERVAL_DEFAULT_SET             0xfffe
    #define POLL_INTERVAL_DEFAULT_SET               0xfffe
    #define FAST_POLL_PERIOD_DEFAULT_SET            0xfffe
    #define POLL_FAIL_TIMES_DEFAULT_SET             0xfe
    #define APP_DATA_TRIG_REJOIN_DEFAULT_SET        0xfe
    #define REJOIN_TRY_TIMES_DEFAULT_SET            0xfe
    #define RF_POWER_DEFAULT_SET                    0xfe
    #define NWK_PARAM_DEFAULT_SET                   {HEART_PERIOD_DEFAULT_SET, JOIN_TIMEOUT_DEFAULT_SET, REJOIN_INTERVAL_DEFAULT_SET, POLL_INTERVAL_DEFAULT_SET, FAST_POLL_PERIOD_DEFAULT_SET, POLL_FAIL_TIMES_DEFAULT_SET, APP_DATA_TRIG_REJOIN_DEFAULT_SET, REJOIN_TRY_TIMES_DEFAULT_SET, RF_POWER_DEFAULT_SET}
    

命令相关数据类型

  • 模组网络状态(命令字 0x020x20

    标识 说明 注意事项
    ZG_NWK_STATUS_NOT_JOIN 未配网 -
    ZG_NWK_STATUS_JOINED 已配网 -
    ZG_NWK_STATUS_ERROR 网络状态异常 表示模组尚未收到 MCU 返回的产品信息
    ZG_NWK_STATUS_JOINING 正在配网 -
    typedef enum {
        ZG_NWK_STATUS_NOT_JOIN = 0,
        ZG_NWK_STATUS_JOINED,
        ZG_NWK_STATUS_ERROR,
        ZG_NWK_STATUS_JOINING,
    } ZG_NWK_STATUS_E;
    
  • 时间同步结构体(命令字 0x24

    标识 说明
    TIME_SYNC_CALENDAR_T 用于存放时间戳的转换结果
    typedef struct {
        unsigned short w_year;
        unsigned char w_month;
        unsigned char w_day;
        unsigned char hour;         // +8 for Beijing time
        unsigned char min;
        unsigned char sec;
    } TIME_SYNC_CALENDAR_T;
    
  • 网关联网状态(命令字 0x25

    标识 说明 注意事项
    GW_NWK_STATUS_OFFLINE 离线 网关未连接互联网
    GW_NWK_STATUS_ONLINE 在线 -
    GW_NWK_STATUS_RESPOND_TIMEOUT 网关回复超时 -
    typedef enum {
        GW_NWK_STATUS_OFFLINE = 0,
        GW_NWK_STATUS_ONLINE,
        GW_NWK_STATUS_RESPOND_TIMEOUT,
    } GW_NWK_STATUS_E;
    
  • Zigbee 模组网络参数结构体(命令字 0x26

    标识 说明
    NWK_PARAM_T 用于配置 Zigbee 模组的网络参数
    typedef struct {
        unsigned short heart_period;
        unsigned short join_timeout;
        unsigned short rejoin_interval;
        unsigned short poll_interval;
        unsigned short fast_poll_period;            // power on poll period
        unsigned char poll_fail_times;
        unsigned char app_data_trig_rejoin;
        unsigned char rejoin_try_times;
        unsigned char rf_power;
    } NWK_PARAM_T;
    
  • Zigbee 模组 GPIO(命令字 0x360x370x38

    标识 说明 注意事项
    MCU_CONFIG_GPIO_T 用于配置 Zigbee 模组的 GPIO 电平 -
    MCU_READ_GPIO_T 用于读 Zigbee 模组的 GPIO 电平 支持 input 或 output 模式的 GPIO
    MCU_WRITE_GPIO_T 用于写 Zigbee 模组的 GPIO 电平 仅支持 output 模式的 GPIO
    typedef struct {
        unsigned char port_num;
        unsigned char pin_num;
        unsigned char gpio_mode;
        unsigned char gpio_level;
    } MCU_CONFIG_GPIO_T;
    
    typedef struct {
        unsigned char port_num;
        unsigned char pin_num;
    } MCU_READ_GPIO_T;
    
    typedef struct {
        unsigned char port_num;
        unsigned char pin_num;
        unsigned char gpio_level;
    } MCU_WRITE_GPIO_T;
    
  • 天气/城市信息(命令字 0x3b

    标识 说明 注意事项
    WEATHER_INFO_T 用于处理模组返回的天气信息 需要结合协议文档,解析天气信息
    CITY_INFO_T 用于处理模组返回的城市信息 需要结合协议文档,解析城市信息
    typedef struct {
        unsigned char version;                  // 0x11
        unsigned char addr_type;
        unsigned char forecast_flag;            // 0x12
        unsigned char forecast_days;
        unsigned char real_time_weather_flag;   // 0x13
        unsigned char real_time_enable;
        unsigned char *weather_detail;
        unsigned char weather_detail_len;
    } WEATHER_INFO_T;
    
    typedef struct {
        unsigned char version;                  // 0x11
        unsigned char addr_type;
        unsigned char *city_detail;
        unsigned char city_detail_len;
    } CITY_INFO_T;
    
  • 群组标准命令(命令字 0x42

    标识 说明
    MCU_SEND_CMD_GROUP_T 用于发送群组标准命令给 Zigbee 模组
    #if SCENE_SWITCH
    typedef struct {
        unsigned short group_id;
        unsigned short cluster_id;
        unsigned char command_id;
        unsigned char *payload;
        unsigned char payload_len;
    } MCU_SEND_CMD_GROUP_T;
    #endif
    
  • DP 发送类型

    标识 说明 注意事项
    DP_SEND_TYPE_NOT_SEND 接收到 DP 消息后,不进行应答 MCU 接收到群控 DP 消息(命令字 0x2a)时,不需要进行应答
    DP_SEND_TYPE_RESPOND 接收到 DP 消息后,进行应答(命令字 0x05 MCU 接收到 DP 消息(命令字 0x04)时,需要进行应答
    DP_SEND_TYPE_REPORT_LINKAGE 上报 DP 消息,触发联动(命令字 0x06 -
    DP_SEND_TYPE_REPORT_NOT_LINKAGE 上报 DP 消息,不触发联动(命令字 0x2c -
    DP_SEND_TYPE_SEND_BROADCAST 发送广播 DP 消息(命令字 0x27 -
    DP_SEND_TYPE_SEND_GROUP 发送群组 DP 消息(命令字 0x43 -
    typedef enum {
        DP_SEND_TYPE_NOT_SEND,                      // Not send: when the MCU receives a broadcast DP message (UART command ID: 0x2a), it doesn't need to respond.
        DP_SEND_TYPE_RESPOND,                       // Respond to DP messages (UART command ID: 0x05): when the MCU receives a DP message (UART command ID: 0x04), it needs to respond to the Zigbee module.
        DP_SEND_TYPE_REPORT_LINKAGE,                // Report a DP message with linkage trigger (UART command ID: 0x06)
        DP_SEND_TYPE_REPORT_NOT_LINKAGE,            // Report a DP message without linkage trigger (UART command ID: 0x2c)
        DP_SEND_TYPE_SEND_BROADCAST,                // Send a DP message broadcast (UART command ID: 0x27)
        DP_SEND_TYPE_SEND_GROUP,                    // Send a DP message to a group (UART command ID: 0x43)
    } DP_SEND_TYPE_E;
    

帧接收函数

  • 函数说明

    标识 说明 注意事项
    frame_rx_handle 帧接收处理总接口 帧解析成功后,会进入该函数,然后根据命令字调用相应的帧接收处理函数(完整流程)

DP 处理函数

  • 函数说明

    标识 说明 注意事项
    dp_info_check 检查 DP ID、数据类型 -
    mcu_get_dp_download_bool

    mcu_get_dp_download_value
    获取 DP 数据值 -
    mcu_dp_raw_update

    mcu_dp_fault_update
    发送 DP 这些函数均通过 __dp_send_type_handle 发送 DP 消息

protocol.c

功能

  • 协议和命令字相关定义。
  • 函数声明:帧接收处理函数(完整流程)、DP 消息处理函数。
  • 函数定义:DP 处理函数、帧接收处理函数(完整流程)、帧发送函数、DP 消息处理函数。
  • 用户可以结合 串口协议 的时序图,对照 帧接收处理函数(完整流程)帧发送函数,了解串口协议 MCU 端的处理。
  • 用户可以结合 串口协议 帧收发情况,准确调用 帧发送函数

协议和命令相关定义

  • 源代码

    标识 说明 注意事项
    DOWNLOAD_CMD_S DP 消息数组的数据类型 包含 DP ID 和对应的 DP 数据类型
    UART_FRAME_T 串口协议帧的数据结构体(不完整) 不包含校验和,校验和的使用场合只有帧解析过程
    OTA_FW_INFO_T MCU 固件 OTA 升级信息 -
    typedef struct {
        unsigned char DP_id;
        unsigned char DP_type;
    } DOWNLOAD_CMD_S;
    
    typedef struct {
        unsigned short frame_hdr;
        unsigned char frame_ver;
        unsigned short frame_seq;
        unsigned char frame_cmd;
        unsigned short frame_payload_len;
        unsigned char *frame_payload;
    } UART_FRAME_T;
    
    typedef struct {
        unsigned char ota_pid[8];               // MCU PID
        unsigned char ota_fw_ver;               // new MCU fw version
        unsigned int ota_fw_size;               // MCU firmware total size
        unsigned int ota_current_offset;        // MCU firmware current offset
        unsigned int ota_expect_checksum;       // MCU firmware expective checksum
    } OTA_FW_INFO_T;
    

帧接收处理函数(完整流程)

  • 函数说明

    标识 说明 注意事项
    mcu_rx_factory_recovery_notify

    mcu_rx_scene_config
    mcu_rx_ 前缀
    各命令字的帧接收处理函数(完整流程)
    这些函数体现了帧接收处理的完整流程。对于需要用户处理的时点,均提供了用户接口(mcu_recv_ 前缀)

DP 消息处理函数

  • 函数说明

    标识 说明 注意事项
    __dp_send_type_handle 发送 DP (底层) 调用本函数前,需要先指定 g_dp_send_type 的值(即 DP 发送类型)。
    DP_download_xxxxxx_handle 特定 DP ID 的下发处理函数 这些函数由云平台生成,用户需要完善这些函数。
    DP_msg_handle 所有 DP ID 的下发处理总接口 -
    all_data_update 全 DP 上报函数 MCU 接收到网关查询 DP 命令(命令字 0x28)后,如果查询列表为空,则 MCU 需要上报所有 DP。用户需要完善该函数,例如使用代表 DP 真实值的变量。
    specific_DP_update 单 DP 上报函数 MCU 接收到网关查询 DP 命令(命令字 0x28)后,如果查询列表非空,则 MCU 需要上报列表包含的 DP。用户需要参考 all_data_update() 完善该函数,即根据不同的 DP ID,调用相应的 DP 值上报函数。

mcu_api.h

功能

  • 配置项:调试信息打印开关、串口及队列缓冲区的尺寸、命令相关信息等。
  • 函数声明:串口服务函数、串口数据发送函数、MCU 唤醒 Zigbee 函数、帧接收处理函数(用户接口)、帧发送函数。

用户可以结合 串口协议 的时序图,对照 帧接收处理函数(完整流程),了解 帧接收处理函数(用户接口) 的调用时点,从而准确处理帧接收数据。

配置项

  • 调试信息打印开关

    标识 说明 注意事项
    MCU_SDK_DEBUG 调试打印开关
    • 1:开启
    • 0:关闭
    PRINT_DEBUG(fmt, …) 调试打印的实现 用户需要把 PROJECT_PRINT_FUNC 替换为工程的调试信息打印函数
    #ifndef MCU_SDK_DEBUG
    #define MCU_SDK_DEBUG           1
    #endif
    
    #if MCU_SDK_DEBUG
    #define PRINT_DEBUG(fmt, ...)   PROJECT_PRINT_FUNC(fmt, ##__VA_ARGS__)
    #else
    #define PRINT_DEBUG(fmt, ...)
    #endif
    
  • 串口及队列缓冲区的尺寸

    标识 说明
    UART_RX_BUF_LEN_LMT 串口接收缓冲区的尺寸
    UART_TX_BUF_LEN_LMT 串口发送缓冲区的尺寸
    UART_QUEUE_BUF_LEN_LMT 队列缓冲区的尺寸

    MCU SDK 串口数据接收处理流程:

    1. MCU 接收到串口数据,数据入队(存放在队列缓冲区)。
    2. 主循环定时出队(存放在串口接收缓冲区),然后开始解析。
    3. 解析成功后,调用帧接收处理总接口。

    MCU SDK 串口数据发送流程:

    1. 填充 payload 字段(存放在串口发送缓冲区)。
    2. 填充其它字段(存放在串口发送缓冲区)。
    3. 发送帧。
    #define UART_RX_BUF_LEN_LMT                     256
    #define UART_TX_BUF_LEN_LMT                     256
    #define UART_QUEUE_BUF_LEN_LMT                  512
    
  • 命令相关信息

    标识 说明 注意事项
    OTA_PACKET_SIZE OTA 单包尺寸 在接收 OTA 升级数据时使用,最大值为 0x30
    ZG_WAIT_MCU_TIME_DEFAULT Zigbee 模组等待 MCU 退出休眠状态的时间 在 Zigbee 模组电平唤醒 MCU 或 MCU 脉冲唤醒 Zigbee 模组时使用。用户需要根据使用的 MCU 情况修改该值。
    ///< OTA single packet payload length (uart command id: 0x0c 0x0d 0x0e)
    #define OTA_PACKET_SIZE                         0x30            // max: 0x30
    
    ///< Zigbee module waits MCU time after Zigbee module starting wakeuping MCU (uart command id: 0x2b)
    #if SLEEP_END_DEVICE
    #define ZG_WAIT_MCU_TIME_DEFAULT                10
    #endif
    

串口服务函数

  • 函数说明

    标识 说明 注意事项
    uart_servive_rx_store 串口数据单字节接收处理函数 该函数会把串口接收到的每个字节数据入队。用户需要把该函数添加到工程的串口数据单字节接收处理函数中。
    uart_service_parse 帧解析函数 该函数会出队,然后解析出队的所有数据(含之前未解析成功的数据)。用户需要把该函数添加到工程里的主循环或定时器回调中。

串口数据发送函数

  • 函数说明

    标识 说明 注意事项
    uart_send_frame 帧发送函数 对于低功耗设备,用户需要在本函数中选择 MCU 唤醒 Zigbee 模组的方式,并在工程里实现对应的唤醒发送函数
    uart_send_bytes 串口多字节发送函数 -
    uart_send_byte 串口单字节发送函数 用户需要在工程里实现该函数,只需要在本函数里调用工程的串口数据单字节发送函数

MCU 唤醒 Zigbee 函数

  • 函数说明

    标识 说明
    mcu_wakeup_zg_level_method MCU 唤醒 Zigbee 模组函数,电平唤醒
    mcu_wakeup_zg_pulse_method MCU 唤醒 Zigbee 模组函数,脉冲唤醒

帧接收处理函数(用户接口)

  • 函数说明

    标识 说明
    mcu_recv_factory_recovery_cb

    mcu_recv_scene_config_cb
    mcu_recv_ 前缀,各命令字的帧接收处理函数(用户接口)

帧发送函数

  • 函数说明

    标识 说明
    mcu_tx_let_zigbee_reset

    mcu_tx_send_DP_group
    mcu_tx_ 前缀,各命令字的帧发送函数

mcu_api.c

功能

  • 函数定义:串口服务函数、串口数据发送函数。