背景:
beacon遥控器因其操作简单,可无需配网使用,搭配sigmesh设备取得了不错的反响,但是由于mesh设备一般都是大规模使用,beacon遥控器发出广播后只能控制附近的设备,无法控制远距离设备或遮挡设备。和app、网关比较体验较差。因此需要在设备端增加相应转发逻辑,可以使远距离设备受控。
拓扑结构:
如图:遥控器要想控制目标灯具F,由于距离太远需要中间的设备转发遥控器的消息才能实现。灯具A、B、C、D、E、F、都具有转发能力,A灯具接收到遥控器广播后向周围转发,B、C、D都收到命令并且向周围转发,其中C、D的转发消息被E接收,E向周围抓发命令。目标灯具收到控制命令,开始执行相应动作。
beacon广播接收过滤
- 1.接收空中广播包,将接口插入sdk接口
- 2.过滤广播包,将符合遥控器数据的广播数据进行下一步处理
- 3.防重放和缓存
a:可以防止重复的数据触发设备重复转发数据。
b:设备都在转发时,可以防止设备之间同一条消息的无限转发 - 4.将通过过滤的广播设置如发送接口
以下为程序示例
- 1.插入sdk广播接口
Code: Select all
VOID app_ble_data_recv(TAL_BLE_EVT_PARAMS_T *p_event){ switch(p_event->type) { case TAL_BLE_EVT_PERIPHERAL_CONNECT: break; case TAL_BLE_EVT_DISCONNECT: break; case TAL_BLE_EVT_ADV_REPORT: beacon_data_proc(p_event->ble_event.adv_report.p_data, p_event->ble_event.adv_report.data_len, p_event->ble_event.adv_report.peer_addr.addr, p_event->ble_event.adv_report.rssi); break; case TAL_BLE_EVT_WRITE_REQ: break; default: break; } }
- 2.过滤、防重、调用发送接口
Code: Select all
#define CASHE_NUM_MAX 20 #pragma pack(1) typedef struct { UINT8_T mac[6]; UINT32_T sn;//收包序号 } BLE_RMT_CASHE_INFO; #pragma pack() UINT8_T idx = 0; BLE_RMT_CASHE_INFO remote_data_cashe[CASHE_NUM_MAX]; OPERATE_RET beacon_data_proc(UINT8_T *adv_data, UINT8_T adv_len, UINT8_T *mac, INT32_T rssi) { OPERATE_RET op_ret = OPRT_OK; if(adv_len!=31) { return OPRT_INVALID_PARM; } if((adv_data[0] != 0x02)||(adv_data[1] != 0x01)||(adv_data[2] != 0x06) ) { return OPRT_INVALID_PARM; } if((adv_data[3] != 0x03)||(adv_data[4] != 0x02)||(adv_data[5] != 0x50)||(adv_data[6] != 0xfd) ) { return OPRT_INVALID_PARM; }
if((adv_data[7] != 0x17)||(adv_data[8] != 0x16)||(adv_data[9] != 0x50)||(adv_data[10] != 0xfd) ) { return OPRT_INVALID_PARM; } if((adv_data[11] != 0x40)||(adv_data[12] != 0x80)||(adv_data[13] != 0x80)) { return OPRT_INVALID_PARM; } for (UINT8_T cashe_idx = 0; cashe_idx < CASHE_NUM_MAX; cashe_idx++) { if (0 == memcmp(&remote_data_cashe[cashe_idx].mac, mac, 6)) { if(0 == memcmp(&remote_data_cashe[cashe_idx].sn, &adv_data[14], 4)) { return OPRT_INVALID_PARM; } else{ memcpy(&remote_data_cashe[cashe_idx].sn, &adv_data[14], 4); break; } } if(cashe_idx == (CASHE_NUM_MAX-1)) { if(idx>=CASHE_NUM_MAX) { idx = 0; } memcpy(&remote_data_cashe[idx].mac, mac, 6); memcpy(&remote_data_cashe[idx].sn, &adv_data[14], 4); idx++; } } app_ble_data_adv_send_set_mac(mac); app_ble_data_adv_send_start(adv_data,adv_len); return OPRT_OK; }广播发送
1.初始换注册广播发送回调
Code: Select all
OPERATE_RET tuya_init_last(VOID_T) { tuya_ble_advertise_send_cb_init(app_ble_data_adv_send); }
2.通过校验的广播数据通过注册到底层的函数发送出去,可以设置发送的广播数量,目前示例转发一包数据。
Code: Select all
UINT8_T __adv_data_send_start = 0; UINT8_T __adv_data[31]; UINT8_T __adv_data_len; UINT8_T __adv_mac_is_default = 1; UINT8_T __adv_mac[6]; UINT8_T local_mac[6];//12 VOID_T app_ble_data_adv_send_set_mac(UINT8_T *mac) { if(mac == NULL){//use node default mac __adv_mac_is_default = 1; }else{//use new mac send adv memcpy(__adv_mac,mac,6); __adv_mac_is_default = 0; } } VOID app_ble_data_adv_send_start(UINT8_T *adv_data, UINT8_T adv_len) { __adv_data_send_start = 0; memcpy(__adv_data,adv_data,adv_len); __adv_data_len = adv_len; __adv_data_send_start = 1; } INT32_T app_ble_data_adv_send(rf_packet_adv_t *par) { if(__adv_data_send_start == 1){ __adv_data_send_start = 0; if(__adv_mac_is_default == 0){ for(UINT8_T i=0;i<6;i++){ par->advA[i] = __adv_mac[i]; } }else{ for(UINT8_T i=0;i<6;i++){ par->advA[i] = local_mac[i]; }
} memcpy(par->data, __adv_data, __adv_data_len); par->header.type = 2;//LL_TYPE_ADV_NONCONN_IND; par->rf_len = __adv_data_len + 6; par->dma_len = par->rf_len + 2; return 1; }else{ return 0; } }