泰凌微8258入门教程 进阶篇⑤——Vendor Model 的使用和案例(自定义呼吸灯模型)

41 篇文章 304 订阅 ¥199.90 ¥99.00

一、前言

Bluetooth SIG Mesh Model已经制定得很详细了,详情看:MshMDLv1.0.1.pdf 这份文档

足以满足我们大部分的应用场景,但是总有一些私人定制类的需求。这时候就需要我们自定义Model。

二、演示

三、日志

  • Vendor On
[2021-04-17 22:53:09.236]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00c2,par_len:2,par:01 09 
[USER]:(USER)cb_vd_group_g_set par=01 09 
[USER]:(USER)cb_vd_group_g_get par=01 09 
[LIB]:(sdk)mesh tx NoAck,op:0xc4,src:0x0136,dst:0x0001,par_len:1 par:01 
[INFO]:(mesh)mesh_tx_access_key_get:print index part0,0,0  
  • Vendor Off
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00c2,par_len:2,par:00 0a 
[USER]:(USER)cb_vd_group_g_set par=00 0a 
[USER]:(USER)cb_vd_group_g_get par=00 0a 
[LIB]:(sdk)mesh tx NoAck,op:0xc4,src:0x0136,dst:0x0001,par_len:1 par:00 
[INFO]:(mesh)mesh_tx_access_key_get:print index part0,0,0  
  • Vendor On/Off Get
[2021-04-17 22:56:09.756]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00c1,par_len:0,par:
[USER]:(USER)cb_vd_group_g_get par=
[LIB]:(sdk)mesh tx NoAck,op:0xc4,src:0x0136,dst:0x0001,par_len:1 par:00 
[INFO]:(mesh)mesh_tx_access_key_get:print index part0,0,0  
  • Vendor On NO-ACK
[2021-04-17 22:56:55.442]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00c3,par_len:2,par:01 0d 
[USER]:(USER)cb_vd_group_g_set par=01 0d 

四、源码

去掉多余的#if和不必要的代码

  • 定义opcode操作码
#define VD_GROUP_G_GET				    0xC1
#define VD_GROUP_G_SET				    0xC2
#define VD_GROUP_G_SET_NOACK		    0xC3
#define VD_GROUP_G_STATUS		        0xC4
  • 定义 mesh_cmd_sig_func_t数组
  • 数组的主要作用是将操作码opcoderesp opcodecb回调函数关联起来。
typedef struct{
    u16 op;
    u16 status_cmd; // receive status message even though there is not server model        // u16 for align
    u32 model_id_tx;
    u32 model_id_rx;
    cb_cmd_sig2_t cb;
    u32 op_rsp;     // -1 for no rsp and ensure 4BYTE align
}mesh_cmd_sig_func_t;
mesh_cmd_sig_func_t mesh_cmd_vd_func[] = {	

    {VD_GROUP_G_SET, 0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_group_g_set, VD_GROUP_G_STATUS},
	{VD_GROUP_G_GET, 0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_group_g_get, VD_GROUP_G_STATUS},
	{VD_GROUP_G_SET_NOACK, 0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_group_g_set, STATUS_NONE},
    {VD_GROUP_G_STATUS, 1, VENDOR_MD_LIGHT_S, VENDOR_MD_LIGHT_C, cb_vd_group_g_status, STATUS_NONE},

};
  • 回调函数是我们主要实现业务代码的地方
// --------- vendor sub op code end  --------
int cb_vd_group_g_get(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{
    u8 sub_op = 0;
	LOG_USER_MSG_INFO(par, par_len, "cb_vd_group_g_get par=", 0);
    if(par_len){    // compatible with legacy version that is no par.
        sub_op = par[0];
    }
    
    model_g_light_s_t *p_model = (model_g_light_s_t *)cb_par->model;
    cb_vd_group_g_sub_tx_st p_cb = (cb_vd_group_g_sub_tx_st)search_vd_group_g_func(sub_op, SEARCH_VD_GROUP_G_FUNC_TYPE_TX_ST);
    if(p_cb){
        return p_cb(cb_par->model_idx, sub_op, p_model->com.ele_adr, cb_par->adr_src, 0, 0);
    }else{
        return -1;
    }
}

int cb_vd_group_g_set(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{
    int err = -1;
	int pub_flag = 0;
	LOG_USER_MSG_INFO(par, par_len, "cb_vd_group_g_set par=", 0);
    //model_g_light_s_t *p_model = (model_g_light_s_t *)cb_par->model;
    vd_group_g_set_t *p_set = (vd_group_g_set_t *)par;
    u8 sub_op = p_set->sub_op;

    if(!cb_par->retransaction){
        cb_vd_group_g_sub_set p_cb_set = (cb_vd_group_g_sub_set)search_vd_group_g_func(sub_op, SEARCH_VD_GROUP_G_FUNC_TYPE_SET);
        if(p_cb_set){
            pub_flag = p_cb_set(par, par_len, cb_par);
        }else{
            return -1;
        }
    }

    if(VD_GROUP_G_SET_NOACK != cb_par->op){
        err = cb_vd_group_g_get(par, par_len, cb_par);
    }else{
        err = 0;
    }

    if(!err && pub_flag){
        if(is_vd_onoff_op(sub_op)){ // only onoff need publish now
            model_pub_check_set(ST_G_LEVEL_SET_PUB_NOW, cb_par->model, 1);
        }
    }
    
    return err;
}

五、自定义Model(呼吸灯)

  • 了解了Vendor Model的流程,现在开始我们自定义的模型开发之旅
  • 我们选择做一个呼吸灯的模型
    • 可以查询当前呼吸灯的状态
    • 设置呼吸灯开始呼吸和停止呼吸

5.1 定义操作码opcode

    • vendor\common\vendor_model.h
  • 定义4个opcode,分别是
    • 查询呼吸灯
    • 设置呼吸灯
    • 不需要ACK的设置呼吸灯
    • 呼吸灯当前的状态(应答)
#define VD_BREATH_G_GET			        0xF0
#define VD_BREATH_G_SET			        0xF1
#define VD_BREATH_G_SET_NOACK	        0xF2
#define VD_BREATH_G_STATUS		        0xF3

5.2 定义操作数组 mesh_cmd_sig_func_t

  • vendor\common\vendor_model.c
mesh_cmd_sig_func_t mesh_cmd_vd_func[] = {

    {VD_BREATH_G_SET, 		0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_breath_g_set, 	VD_BREATH_G_STATUS},
	{VD_BREATH_G_GET, 		0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_breath_g_get, 	VD_BREATH_G_STATUS},
	{VD_BREATH_G_SET_NOACK, 0, VENDOR_MD_LIGHT_C, VENDOR_MD_LIGHT_S, cb_vd_breath_g_set, 	STATUS_NONE},
    {VD_BREATH_G_STATUS, 	1, VENDOR_MD_LIGHT_S, VENDOR_MD_LIGHT_C, cb_vd_scence_g_status, STATUS_NONE},

}

5.3 定义回调函数cb

  • vendor\common\vendor_model.c
// --------- vendor sub op code end  --------
int cb_vd_breath_g_get(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{ 
	LOG_USER_MSG_INFO(par, par_len,"cb_vd_breath_g_get par=", 0);

	return 0;
}

int cb_vd_breath_g_set(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{ 
	LOG_USER_MSG_INFO(par, par_len, "cb_vd_breath_g_set par=", 0);
	if(par[0]==0x01){
		LOG_USER_MSG_INFO(0, 0, "kangweijian start breath", 0);
	}else{
		LOG_USER_MSG_INFO(0, 0, "kangweijian stop breath", 0);
	}	
	return 0;
}

5.4 测试

在这里插入图片描述


2021-04-17 23:30:07.385]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:01 
[USER]:(USER)cb_vd_breath_g_set par=01 
[USER]:(USER)kangweijian start breath

[2021-04-17 23:30:08.651]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:01 
[USER]:(USER)cb_vd_breath_g_set par=01 
[USER]:(USER)kangweijian start breath

[2021-04-17 23:30:09.970]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:01 
[USER]:(USER)cb_vd_breath_g_set par=01 
[USER]:(USER)kangweijian start breath

[2021-04-17 23:30:28.429]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:00 
[USER]:(USER)cb_vd_breath_g_set par=00 
[USER]:(USER)kangweijian stop breath

[2021-04-17 23:30:29.690]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:00 
[USER]:(USER)cb_vd_breath_g_set par=00 
[USER]:(USER)kangweijian stop breath

[2021-04-17 23:30:31.016]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:00 
[USER]:(USER)cb_vd_breath_g_set par=00 
[USER]:(USER)kangweijian stop breath

现在出现了一个问题,为什么会连续发三次吗,间隔1s左右。是分包吗,看着不像。最后深究发现,是因为App下发后,设备没有应答!

5.5 增加应答rsp

  • 主要是增加了mesh_tx_cmd_rsp应答函数
  • 最后测试,有了应答,命令就只下发一次
  • vendor\common\vendor_model.c
int cb_vd_breath_g_get(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{ 
	LOG_USER_MSG_INFO(par, par_len,"cb_vd_breath_g_get par=", 0);

    model_g_light_s_t *p_model = (model_g_light_s_t *)cb_par->model;
	u8 rsp = 00;
    return mesh_tx_cmd_rsp(VD_BREATH_G_STATUS, (u8 *)&rsp, sizeof(rsp), p_model->com.ele_adr, cb_par->adr_src, 0, 0);
}

int cb_vd_breath_g_set(u8 *par, int par_len, mesh_cb_fun_par_t *cb_par)
{ 
	LOG_USER_MSG_INFO(par, par_len, "cb_vd_breath_g_set par=", 0);
	if(par[0]==0x01){
		LOG_USER_MSG_INFO(0, 0, "kangweijian start breath", 0);
	}else{
		LOG_USER_MSG_INFO(0, 0, "kangweijian stop breath", 0);
	}	
	if(VD_GROUP_G_SET_NOACK != cb_par->op){
        return cb_vd_breath_g_get(par, par_len, cb_par);
    }else{
        return 0;
    }
}
  • 日志Log
[2021-04-17 23:50:06.776]
RX:[LIB]:(sdk)rcv access layer,retransaction:0,ttl:10,src:0x0001,dst:0xffff op:0x00f1,par_len:1,par:01 
[USER]:(USER)cb_vd_breath_g_set par=01 
[USER]:(USER)kangweijian start breath
[USER]:(USER)cb_vd_breath_g_get par=01 

六、呼吸灯的具体实现

呼吸灯的具体实现,详情见下一篇博文:泰凌微8258入门教程 进阶篇⑥——proc_led指示灯处理函数和呼吸灯实现

觉得好,就一键三连呗(点赞+收藏+关注)

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小康师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值