更新时间:2024-11-20 08:51:24下载pdf
智能设备的基础功能通常包括网络连接、设备控制、设备状态上报、OTA 等。此外,还会涉及到生产相关的烧录授权、产测等功能。本文讲解涂鸦 Zigbee SDK 运行逻辑以及如何使用 SDK 调用相关接口函数实现相应功能。
以下是 SDK 运行流程图和流程中主要用到的函数的说明,您可以参考理解 SDK 的完整运行流程,以便您更好的开发应用代码。
函数名称 | 函数作用 |
---|---|
dev_power_on_init |
这是硬件启动后的第一个函数,使用者至少需要实现 Zigbee 设备的创建,组网参数的设定。 |
dev_system_on_init |
这是系统启动后的第一个功能函数,使用者可以实现Zigbee 属性操作,硬件初始化,软件定时处理等初始化。 |
nwk_state_changed_callback |
实现 Zigbee 网络状态处理,当网络状态改变时调用此函数。 |
根据系统流程图,您首先要实现函数 dev_power_on_init
,这是硬件启动后的第一个函数。
您需要实现 Zigbee 设备的创建和设定 Zigbee 设备的参数。包括设备角色(路由器、终端设备)、加入设备网络、重新加入参数等。
CPU 和基本时钟在调用该函数之前被初始化。
/**
* @note (MUST) This is the first function after the hardware starts.
* The CPU and base clock are initialized before calling this function.
* You need to implement the creation of Zigbee devices and
* determine the parameters of Zigbee device behavior.
* Include device roles(router, end device), device networking(join),
* rejoin parameters, and more. Refer to the TUYA Zigbee SDK demo for details.
* @param none
* @return none
*/
void dev_power_on_init(void);
示例代码片段
void dev_power_on_init(void)
{
join_config_t cfg;
zg_dev_config_t zg_dev_config;
/**
根据标准的要求创建Zigbee设备(profile endpoint cluster attributes) 。
注册一个完整的 Zigbee 设备,包含描述 Zigbee 设备的 endpoint,cluster,attributes等。
*/
dev_register_zg_ep_infor((dev_description_t *)g_dev_des, EP_SUMS); //该函数必须要在 power_on_init 里面调用
memset(&zg_dev_config, 0, sizeof(zg_dev_config_t));
zg_dev_config.dev_type = ZG_ROUTER;
dev_register_zg_dev_config(&zg_dev_config); //配置 Zigbee 的设备角色,是路由还是 end device 和 join,rejoin 的参数
memset(&cfg, 0, sizeof(cfg));
cfg.auto_join_power_on_flag = TRUE;
cfg.auto_join_remote_leave_flag = TRUE;
cfg.join_timeout = ZIGBEE_JOIN_MAX_TIMEOUT; //配置上电和远程删除的组网策略
dev_zg_join_config(&cfg);
//TODO: others task
return;
}
Zigbee 设备创建和基础配置相关 API
API | 功能 | 限制 |
---|---|---|
dev_register_zg_ep_infor |
注册一个完整的 Zigbee 设备,包含描述 Zigbee 设备的 endpoint,cluster,attributes等 | 只能在 dev_power_on_init 里面调用制 |
dev_register_zg_dev_config |
配置 Zigbee 的设备角色,是路由还是 end device 和 join,rejoin 的参数 | 只能在 dev_power_on_init 里面调用制 |
dev_zg_join_config |
配置上电和远程删除的组网策略 | 只能在 dev_power_on_init 里面调用制 |
dev_system_on_init
是系统启动后的第一个函数。在调用这个函数之前,Zigbee 栈和一些基本的组件已启动。您可以使用除个别 API 之外的所有 API。可以实现 Zigbee 属性操作,硬件初始化,软件定时处理等初始化。
/**
* @note (MUST) This is the first function after the hardware starts.
* The CPU and base clock are initialized before calling this function.
* You need to implement the creation of Zigbee devices and
* determine the parameters of Zigbee device behavior.
* Include device roles(router, end device), device networking(join),
* rejoin parameters, and more. Refer to the TUYA Zigbee SDK demo for details.
* @param none
* @return none
*/
void dev_power_on_init(void);
示例代码片段
static void __uart_rx_callback(uint8_t *data, uint16_t len)
{
//TODO: 串口接收处理
}
static void __dev_evt_callback(uint8_t evt)
{
switch(evt) {
case EVT_LOCK_CANCEL: {
//TODO: 自定义事件处理
break;
}
default: {
break;
}
}
}
void dev_system_on_init(void)
{
user_uart_config_t *p_default_cfg = mf_test_uart_config();
user_uart_config_t uart_cfg;
memcpy(&uart_cfg, p_default_cfg, sizeof(user_uart_config_t));
uart_cfg.func = __uart_rx_callback;
user_uart_init(&uart_cfg); //单个串口配置,包含串口硬件参数和串口数据接收回调函数,
dev_timer_start_with_callback(EVT_LOCK_CANCEL, 1000, __dev_evt_callback);//启动某个延时执行事件并设置事件处理函数
dev_change_power(11, 19);//配置发送功率
return;
}
让设备进入搜索 Zigbee 网络的状态,如果设备已经加入网络,该函数会退网并立即搜网。
/**
* @description: join start delay timer hander, join now
* @param {none}
* @return: none
*/
void network_join_start_delay_timer_callback(void)
{
dev_zigbee_join_start(ZIGBEE_JOIN_MAX_TIMEOUT); //
}
当网络状态改变时调会用这个函数。建议在此函数处进行网络状态处理。
/**
* @note (MUST) This function is invoked when the network state changes.
* Handling network-related matters at this function is recommended.
* @param[in] {state} Refer to NET_EVT_T for more detal.
* @return none
*/
void nwk_state_changed_callback(NET_EVT_T state);
示例代码片段
void nwk_state_changed_callback(NET_EVT_T state)
{
switch(state) {
case NET_POWER_ON_LEAVE: {
//TODO: 上电无网络状态
break;
}
case NET_JOIN_START: {
//TODO: 组网开始
break;
}
case NET_JOIN_TIMEOUT: {
//TODO: 组网失败
break;
}
case NET_POWER_ON_ONLINE: {
//TODO: 上电有网络状态
break;
}
case NET_JOIN_OK: {
//TODO: 组网成功
break;
}
case NET_REJOIN_OK: {
//TODO: 重连成功
break;
}
case NET_LOST: {
//TODO: 和父节点丢失
break;
}
case NET_REMOTE_LEAVE: {
//TODO: 远程离网通知
break;
}
case NET_LOCAL_LEAVE: {
//TODO: 本地离网通知
break;
}
case NET_MF_TEST_LEAVE: {
//TODO: 产测离网通知
break;
}
default: {
break;
}
}
}
当网关或者 App 端有数据下发时,SDK 会自动找到下发数据处理的回调函数并执行,您需要完成回调函数的具体逻辑,实现解析接收到的数据并执行相关的命令。
您可以通过 dev_msg_recv_callback
来接收 Zigbee 网关的相关数据。以下为一个开关的数据接收示例:
/**
* @description: device receive message callback
* @param {*dev_msg} received message information
* @return: ZCL_CMD_RET_T
*/
ZCL_CMD_RET_T dev_msg_recv_callback(dev_msg_t *dev_msg)
{
ZCL_CMD_RET_T result = ZCL_CMD_RET_SUCCESS;
switch (dev_msg->cluster)
{
case CLUSTER_PRIVATE_TUYA_CLUSTER_ID: //private data processing
{
break;
}
case CLUSTER_ON_OFF_CLUSTER_ID: //0x0006 Zigbee ON OFF Cluster //standard data processin
{
attr_value_t *attr_list = dev_msg->data.attr_data.attr_value;
uint8_t attr_sums = dev_msg->data.attr_data.attr_value_sums;
uint8_t i;
for(i = 0; i < attr_sums; i++)
{
switch(attr_list[i].cmd)
{
case CMD_OFF_COMMAND_ID: //关命令
{
__dev_switch_op(dev_msg->endpoint, DEV_IO_OFF); //控制硬件接口
__dev_report_onoff_msg(dev_msg->endpoint, QOS_0);//上报网关设备开关状态
break;
}
case CMD_ON_COMMAND_ID: //开命令
{
__dev_switch_op(dev_msg->endpoint, DEV_IO_ON);
__dev_report_onoff_msg(dev_msg->endpoint, QOS_0);
break;
}
case CMD_TOGGLE_COMMAND_ID: //取反命令
{
__dev_switch_op(dev_msg->endpoint, (DEV_IO_ST_T)!g_relay_onoff_status[dev_msg->endpoint - 1]);
__dev_report_onoff_msg(dev_msg->endpoint,QOS_0);
break;
}
default:
{
break;
}
}
break;
}
}
default:
// Unrecognized cluster ID, error status will apply.
break;
}
return result
Zigbee Global 类的 Write 命令通过 dev_msg_write_attr_callback_ext
或者 dev_msg_write_attr_callback
来通知应用层。
void dev_msg_write_attr_callback(uint8_t endpoint, CLUSTER_ID_T cluster, uint16_t attr_id)
{
//TODO: 远程写属性成功后调用该函数
return;
}
void dev_msg_write_attr_callback_ext(
uint8_t endpoint,
CLUSTER_ID_T cluster,
uint16_t attr_id,
uint8_t mask,
uint16_t manufacturer_code,
uint8_t type,
uint8_t size,
uint8_t* value)
{
//TODO: 远程写属性成功后调用该函数,附带了原始数据参数
return;
}
设备状态改变时,根据设备状态对应的 DP,调用相应的上报接口函数,将设备状态同步到云端和 App。
static void __send_result_cb(SEND_ST_T st, dev_send_data_t *msg)
{
switch(st) {
case SEND_ST_OK: {
//TODO: 发送成功
break;
}
default: {
//TODO: 发送失败
break;
}
}
}
static void send_data_demo(void)
{
dev_send_data_t send_data;
memset(&send_data, 0, sizeof(dev_send_data_t));
send_data.zcl_id = 0; ///< 用户自定义 ID,发送成功失败回调会传回该参数
send_data.qos = QOS_1; ///< 如果没有收到ACK,会重传
send_data.direction = ZCL_DATA_DIRECTION_SERVER_TO_CLIENT;
send_data.command_id = CMD_REPORT_ATTRIBUTES_COMMAND_ID; ///< 通用上报属性的命令
send_data.addr.mode = SEND_MODE_GW; ///< 发送给网关
send_data.addr.type.gw.cluster_id = CLUSTER_ON_OFF_CLUSTER_ID; ///< 开关属性
send_data.addr.type.gw.src_ep = 1; ///< 设备 endpoint
send_data.delay_time = 0; ///< 延时发送时间
send_data.random_time = 0; ///< 随机发送时间范围
send_data.data.zg.attr_sum = 1; ///< 上报属性的个数
send_data.data.zg.attr[0].attr_id = ATTR_ON_OFF_ATTRIBUTE_ID; ///< 开光状态属性
send_data.data.zg.attr[0].type = ATTR_BOOLEAN_ATTRIBUTE_TYPE; ///< 属性数据类型
send_data.data.zg.attr[0].value_size = 1; ///< 属性数据长度
send_data.data.zg.attr[0].value[0] = 1; ///< 1代表开,0代表关状态
dev_zigbee_send_data(&send_data, __send_result_cb, 1000); ///< 发送,1000代表报文最大重传持续时间是1秒
}
Windows 下用 IAR 编译
Linux 下用GCC 编译
#./run.sh clean //清除编译输出的问题
#./run.sh build 0 //编译 release 版本
#./run.sh build 1 //编译 debug 版本(带串口打印信息)
将编译生成的生产文件烧录到芯片内,并使用涂鸦授权工具进行授权,即可验证代码功能。
不同芯片的烧录方式不同,需要参考具体芯片的烧录说明文档,授权通过串口通信,将授权信息写入到芯片特定 Flash 区域,此部分功能由涂鸦 SDK 自动完成,您无需关心具体的逻辑。
授权是产测中的其中一个测试项。涂鸦云模组烧录工具软件,以及 PCBA 产测软件都可以对模组进行授权。涂鸦云模组烧录工具进行烧录时,会自动对模组进行授权。只有对设备授权后,设备才能长期正常运行。
通过 J-Link 软件烧录的固件的设备,不能长期的运行,只能正常运行一周。固件开发好后,可以上传到涂鸦后台,进行云模组烧录工具进行授权。
产品在批量生产时,为提高生产效率,会用代码实现批量的自动化测试,通常称为产测。
SDK 底层已经对部分产测测试项进行过处理。例如,进入测试模式,读取 Mac,检测固件版本,写入 PID,读取 PID,进行 RF 测试,获取 RSSI 信号值,授权测试等。SDK中代码如下:
/**
* @description: device manufactury test callback, when device is in manufactury test model,
* sdk will use this callback to notify application the test item and test command;
* @param {cmd} manufactury test type
* @param {*args} manufactury test data
* @param {arg_len} manufactury test data length
* @return: none
*/
MF_TEST_RET_T dev_mf_test_callback(MF_TEST_CMD_T cmd, uint8_t *args, uint16_t arg_len)
{
switch(cmd)
{
case MF_TEST_LED_ON_ALL:
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_ON);
dev_led_stop_blink(LED_1_IO_INDEX, DEV_IO_ON);
break;
}
case MF_TEST_LED_OFF_ALL:
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_OFF);
dev_led_stop_blink(LED_1_IO_INDEX, DEV_IO_OFF);
break;
}
case MF_TEST_LED_BLINK_ALL:
{
dev_led_start_blink(NET_LED_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
dev_led_start_blink(LED_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
break;
}
case MF_TEST_RELAY_ON_ALL:
{
dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_ON);
break;
}
case MF_TEST_RELAY_OFF_ALL:
{
dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_OFF);
break;
}
case MF_TEST_RELAY_BLINK_ALL:
{
dev_led_start_blink(RELAY_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
break;
}
case MF_TEST_BUTTON:
{
g_work_st = DEV_WORK_ST_TEST;
return MF_TEST_DOING;
}
case MF_TRANSFER:
{
}
default :
{
break;
}
}
return MF_TEST_SUCCESS;
}
Zigbee 模组 SDK 自带 OTA 升级功能。工程开发编译完成后,会生成后缀为 .s37
的烧录固件以及后缀为 .bin
的 OTA 升级固件。
设备可以通过网关升级固件版本。如果 OTA 版本固件比当前版本低或者一致,就不能进行升级。高版本固件上传到涂鸦开发者平台,可以给要升级的设备配置白名单进行升级
对于 Router 节点(常供电设备),您不需要对 OTA 升级进行额外的开发。
对于 End device 节点(低功耗设备),因为低功耗设备长期进行休眠,关闭了接收 RF 数据能力,所以在移动应用上操作设备升级后,需要唤醒设备发送数据请求获取升级命令,并且设备需要在以下回调函数中处理相关逻辑:
// OTA 升级回调
void zg_ota_evt_callback(ZG_OTA_EVT_T evt)
{
switch(evt) {
case ZG_OTA_EVT_START: { //开始升级
zg_poll_interval_change( 250 ); // 配置数据请求间隔时间为 250ms,以加快升级。
zg_poll_start();
break;
}
default: {
zg_poll_interval_change( 1000 );
zg_poll_end(); // 升级完成后,停止数据请求,避免电量浪费。
break;
}
}
}
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈