sigmesh SDK转发beacon遥控器教程

蓝牙 BLE设备、蓝牙 MESH设备、蓝牙 Beacon设备、Sub-G设备等


Post Reply
tony
Posts: 30

背景:

beacon遥控器因其操作简单,可无需配网使用,搭配sigmesh设备取得了不错的反响,但是由于mesh设备一般都是大规模使用,beacon遥控器发出广播后只能控制附近的设备,无法控制远距离设备或遮挡设备。和app、网关比较体验较差。因此需要在设备端增加相应转发逻辑,可以使远距离设备受控。

拓扑结构:

Image
如图:遥控器要想控制目标灯具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; } }

全栈工程师修炼指南

Post Reply