1. 程式人生 > >BLE開發(TI CC254x)之一主多從方案(藍芽專案紀實)

BLE開發(TI CC254x)之一主多從方案(藍芽專案紀實)

近期一個BLE專案,整套方案做下來發現雖然需求特殊,但是根據這個專案可以衍生出BLE裝置一主多從的一般性方法。

專案的需求基本如下:

1.實現基於CC2541晶片的藍芽主機韌體程式碼,要求主機1拖4從機;

2.上電自動、同時連線4個BLE裝置;

3.身份識別需求:掃描繫結這4個唯一裝置,不允許自動連線其他BLE裝置

4.同時連線的情況下,讀取4個BLE裝置的通知型資料,並串列埠封包轉發。

這個專案的麻煩在於需求3,4的實現,需求2要求上電自動連線多個BLE裝置本來問題不大,但是需求3要求裝置繫結,於是最初考慮的方法是:

1.採取廣播包識別裝置UUID的方式,類似iBeacon廣播包中16個位元組的UUID,可以作為唯一身份識別;

2.讀取掃描應答包的裝置名作為唯一識別標準;

3.根據裝置的Mac地址作為裝置的身份識別。

iBeacon是蘋果推出的基於BLE4.0技術的應用層解決方案,主要利用BLE廣播包進行資訊的推送等服務,在長度受限的廣播包中定義了16個位元組的UUID,作為iBeacon裝置的唯一識別碼,這也是藍芽2.4G作為有源RFID的一個方案之一。應該來說,在廣播包裡存放身份ID是最佳方案,無需建立連線即可唯一識別裝置。

但是,這個專案的4個從機: 血壓、血氧、血糖、血脂裝置均為固定藍芽裝置,我無法修改其韌體程式碼,只能動主機程式碼。

好吧,既然不能動從機,只能主機去想辦法解決了。於是想到了方法2和3,方法2相比3實現起來要更麻煩,掃描應答包是從機對主機掃描的迴應包,裝置名存在於此包中,況且裝置名不一定唯一(雖然該專案的四個裝置名不同),考慮到一般性,決定採取Mac地址匹配的方法來進行裝置篩選和上電自動繫結

需求4的麻煩在於如果採用Mac來識別裝置並同時連線多個裝置後,如何分別開啟各裝置的通知,從而讀取各從機的通知型資料。答案是:依據連線時的handle,多從機時新建一個MulticonnHandle[]來儲存從機的連線handle,因此最終確定的方案如下:

上電自動掃描+Mac地址匹配+自動連線+開啟通知/斷開連線

從一般性來說,該方案可以適用於:需要識別繫結專屬BLE裝置(無密碼配對過程),並且一主多從通訊的情況。

首先宣告:CC2540/1晶片最多隻能同時連線3個BLE裝置,受晶片能力所限,官方解釋如下



所以本方案也最多隻能支援1拖3,要支援更多從機請選擇CC2640/CC2650晶片。

具體實現如下:(基於simpleBLECentral.eww工程)

1.加入上電自動掃描

在simpleBLECentral_ProcessEvent()函式的裝置啟動事件下加入掃描的程式碼:

uint16 SimpleBLECentral_ProcessEvent( uint8 task_id, uint16 events )
{
  
   ...

  //裝置啟動事件
  if ( events & START_DEVICE_EVT )
  {
    // Start the Device
    VOID GAPCentralRole_StartDevice( (gapCentralRoleCB_t *) &simpleBLERoleCB );

    // Register with bond manager after starting device
    GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );

    //裝置已啟動,進入上電自動掃描
    if ( !simpleBLEScanning & simpleBLEScanRes == 0 )
    {
      simpleBLEScanning = TRUE;
      simpleBLEScanRes = 0;
      GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
                                     DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                     DEFAULT_DISCOVERY_WHITE_LIST );   
      //LCD_WRITE_STRING( "Scanning...", HAL_LCD_LINE_1 );
      NPI_PrintString("Scanning...\n");
      
    }
    else
    {
      //LCD_WRITE_STRING( "No Scan", HAL_LCD_LINE_1 );
      NPI_PrintString("Scanning Canceled\n");
    }
    
    return ( events ^ START_DEVICE_EVT );
  }

  if ( events & START_DISCOVERY_EVT )
  {
    simpleBLECentralStartDiscovery( );
    
    return ( events ^ START_DISCOVERY_EVT );
  }
  
  // Discard unknown events
  return 0;
}

2.實現Mac匹配演算法繫結多從機

(1)在全域性定義devMacList[MAX_DEVICE_NUM][B_ADDR_LEN]來預存指定裝置的Mac,並實現Mac匹配演算法。

預存Mac地址時需注意16進位制序列逆序儲存,主機掃描的裝置列表的Mac儲存在simpleDevList[].addr,如:(此處以兩個從機為例)

static uint8 devMacList[MAX_DEVICE_NUM][B_ADDR_LEN]={//預存Mac地址
  {0xB8,0x43,0xA2,0x21,0xF8,0x5C},//十六進位制序列逆序儲存!與掃描儲存的Mac地址對應,0x5CF821A243B8
  {0xAE,0x2D,0x42,0xBE,0x7C,0x08},
};
然後實現Mac匹配演算法,基本思路:迴圈提取simpleDevList[].addr的值,在devMacList中查詢Mac,若存在則記錄下標。
//Mac地址匹配演算法
//迴圈將simpleBLEDevList[i].addr的值提取,在devMacList中查詢匹配的mac,若存在則記錄對應的下標
 int findMacAddrMatching(int devMacRes[])
 {
        int k=0,num=0;
        int i=0,j=0;
        for(i=0;i<simpleBLEScanRes;i++)
        {
           for(j=0;j<MAX_DEVICE_NUM;j++)
           {
              if(isArrayEqual(simpleBLEDevList[i].addr,*(devMacList+j),B_ADDR_LEN,B_ADDR_LEN)==FALSE)
                  continue;//不相等匹配下一個
              devMacRes[j]=i;//按照預存Mac的順序儲存裝置下標,故自動連線時獲取的控制代碼MultiConnHandle[]也是固定順序,便於分別設定通知開關的控制代碼
              k++;
              break;//若相等記錄下標並跳出該層迴圈(mac唯一)
           }
        }
        //統計匹配到的mac裝置個數
       for(k=0;k<MAX_DEVICE_NUM;k++)
       {
          if(devMacRes[k]!=-1)
            num++;
       }
       return num;
 }
isArrayEqual()功能非常簡單,比較兩個陣列每個元素,完全相同返回真。但是在晶片上寫程式碼,一切都要自己造輪子。。
//陣列比較函式,兩個陣列完全相等返回TRUE,否則返回FALSE
static bool isArrayEqual(uint8 arr1[],uint8 arr2[],uint8 arr1_length,uint8 arr2_length)
{
  int i=0;
  if(arr1_length!=arr2_length)return FALSE;
  for(i=0;i<arr1_length;i++)
  {
      if(arr1[i]!=arr2[i])return FALSE;
  }
  return TRUE;
}
(2)實現Mac匹配演算法後,在simpleBLECentralEventCB()的GAP_DEVICE_DISCOVERY_EVENT下列印掃描到的裝置Mac資訊,並執行Mac匹配函式。
        //列印所有裝置Mac
        
        NPI_PrintString("device list:\n");    
        for(k=0;k<simpleBLEScanRes;k++)
        {
          NPI_PrintString((uint8*)bdAddr2Str( simpleBLEDevList[k].addr ));
          NPI_PrintString("\n");
        }      
        //執行Mac匹配演算法
        devMacNum=findMacAddrMatching(devMacResult);

測試發現,列印的Mac地址是所有掃描到的裝置,執行Mac匹配函式後4個專屬裝置在裝置列表裡的下標被成功儲存到devMacResult[]中。


3.加入自動連線功能

在呼叫Mac匹配後,只需根據devMacResult[]中儲存的下標以此發起連線請求。

但是每次連線發起後都會進入到GAP_LINK_ESTABLISHED_EVENT事件處理中,為保證逐個連線成功,還加入了自動連線標誌進行調回處理。

示例程式碼如下:

        //自動連線     
            //連線第1個
            if(devMacNum > 0)
            {
                HalLedSet(HAL_LED_3, HAL_LED_MODE_ON );   //開LED3
           
                uint8 addrType;
                uint8 *peerAddr;
                
                simpleBLEScanIdx = devMacResult[0];
          
                // connect to current device in scan result 
                peerAddr = simpleBLEDevList[simpleBLEScanIdx].addr;
                addrType = simpleBLEDevList[simpleBLEScanIdx].addrType;
              
                simpleBLEState = BLE_STATE_CONNECTING;
                
                GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
                                              DEFAULT_LINK_WHITE_LIST,
                                              addrType, peerAddr );
   
                HalLedSet(HAL_LED_3, HAL_LED_MODE_OFF ); 
            }
            
              //連線第2個
      SECOND:
            if(devMacNum > 1)
            {
...
            }
連線3,4其他從機以此類推。在GAP_LINK_ESTABLISHED_EVENT事件中處理連線結果,重點是儲存連線的handle:
          MultiConnHandle[connHandle_num]=ppEvent->linkCmpl.connectionHandle;
          connHandle_num++;

儲存了連線handle的MulticonnHandle[]將作為後面斷開多從機連線和讀取多從機資料的依據。

示例程式碼如下:

        //自動連線標誌加1,開始連線下一個裝置
          autoConnectFlag++;
          if(autoConnectFlag==1)
            goto SECOND;
          else if(autoConnectFlag==2)
            goto THIRD;
  ...
          else if(autoConnectFlag==MAX_DEVICE_NUM)
            autoConnectFlag=0;//達到最大連線數後,結束上電連線任務

4.加入斷開連線功能

一主多從條件下,要斷開所有從機的連線,必須區分各個裝置,讀寫資料也是一樣,幸好連線事件中我們已儲存各從機的連線handle。

示例程式碼如下:

            if(connHandle_num==1)
              GAPCentralRole_TerminateLink( MultiConnHandle[0]);
            else if(connHandle_num==2)
              GAPCentralRole_TerminateLink( MultiConnHandle[1]);
            ...
             NPI_PrintString("Disconnecting...\n");

5.讀寫特徵值資料並處理

對於非通知型資料可以直接呼叫GATT_WriteCharValue和GATT_ReadCharValue讀寫資料,根據連線handle區分即可,如讀取第一個裝置的特徵值:

  	  if ( simpleBLEDoWrite )
          {
            // Do a write
            NPI_PrintString("Writing...\n");
            attWriteReq_t req;
            
            req.handle = simpleBLECharHdl;
            req.len = 1;
            req.value[0] = simpleBLECharVal;
            req.sig = 0;
            req.cmd = 0;
            status = GATT_WriteCharValue(MultiConnHandle[0], &req, simpleBLETaskId );      
          }
          else
          {
            // Do a read
            NPI_PrintString("Reading...\n");
            attReadReq_t req;
            
            req.handle = simpleBLECharHdl;
            status = GATT_ReadCharValue(MultiConnHandle[0], &req, simpleBLETaskId );
          }
          
          if ( status == SUCCESS )
          {
            simpleBLEProcedureInProgress = TRUE;
            simpleBLEDoWrite = !simpleBLEDoWrite;
          }
        }  
 
對於通知型資料,實際是往CCC標誌位寫0x0001開啟通知,多從機情況下只需依次開啟通知監聽即可,示例開啟一個裝置的通知,程式碼如下:
            attWriteReq_t req;
            
            req.handle = BLE_NotifyChar_Handle+1;
            req.len = 1;
            req.value[0] = 0x01;
            req.sig = 0;
            req.cmd = 0;
            status = GATT_WriteCharValue( MultiConnHandle[0], &req, simpleBLETaskId );  
通知開關的handle通常為characteristic的handle+1。

讀取到資料後,在simpleBLECentralProcessGATTMsg()中處理接收的資料,如資料的串列埠轉發等。

至此,完成BLE一主多從的通訊過程。

相關推薦

BLE開發TI CC254x之一方案專案紀實

近期一個BLE專案,整套方案做下來發現雖然需求特殊,但是根據這個專案可以衍生出BLE裝置一主多從的一般性方法。 專案的需求基本如下: 1.實現基於CC2541晶片的藍芽主機韌體程式碼,要求主機1拖4從機; 2.上電自動、同時連線4個BLE裝置; 3.身份識別需求:掃描繫結這

運維筆記36 mysql的一模型原始主從複製,基於GTID主從複製

概述: mysql的主從複製是十分經典的一個應用,但是主從之間總會有資料一致性(data consistency )的問題,一般情況從庫會落後主庫幾個小時,而且在傳統一主多從(mysql5.6之前)的模型中當master down掉後,我們不只是需要將一個sl

Mysql之一復制

一個 oca 正常 art 應用 必須 如果 1.4 emc MySQL主從復制簡介將master數據庫中的DDL和DML操作通過二進制日誌(BINLOG)傳輸到slave數據庫上,然後將這些日誌重新執行(重做);從而使得slave數據庫的數據與master數據庫保持一致。

MYSQL之一搭建方案

原理 方案 環境 虛擬機器兩臺:192.168.153.11/12 系統:Centos6.7x64位(磁力下載) 資料版本:mysql-5.5.60-linux-glibc2.12-x86_64.tar.gz(可以通過迅雷或者shell命令wget在li

BLE開發TI CC254x之串列埠收發

基於CC254x藍芽協議棧的串列埠收發非常簡單,現總結成5個步驟: 1.修改NPI下npi.c中的初始化函式 只需修改配置UART的兩個引數:波特率和流控制。 使用兩線的串列埠通訊時必須關閉流控制,

mysql之 mysql 5.6不停機雙搭建活躍雙基於日誌點復制

stat 5.6 create 文件夾 eat ima send spec tar 環境說明:版本 version 5.6.25-log 主1庫ip: 10.219.24.25主2庫ip: 10.219.24.22從1庫ip:10.219.24.26os 版本: cento

EF通用數據層封裝類支持讀寫分離,一

dto cte 功能 pes getc mes 工廠 好的 靈活 淺談orm 記得四年前在學校第一次接觸到 Ling to Sql,那時候瞬間發現不用手寫sql語句是多麽的方便,後面慢慢的接觸了許多orm框架,像 EF,Dapper,Hibernate,ServiceSta

MySQL主從MySQL proxy Lua讀寫分離設置,一同步配置,分庫分表方案

否則 count user username 2個 ons 基礎 zxvf 路徑 Mysql Proxy Lua讀寫分離設置一.讀寫分離說明讀寫分離(Read/Write Splitting),基本的原理是讓主數據庫處理事務性增、改、刪操作(INSERT、UPDATE、DE

搭建MySQL一————VMware Workstation 虛擬機nat網絡配置

VMware Workstation 虛擬機 虛擬網絡 nat連接 運行 VMware Workstation Pro 在桌面找到該圖標,雙擊運行即可,如果沒有安裝請下載安裝。流程編輯 ==》虛擬網絡編輯器 ==》 VMnet0 如果沒有 添加網絡 最後設置完後,點擊確定即可。 配置虛

【k8s安裝】使用kubeasz安裝k8s集群簡單快捷

bec 改變 路徑 介紹 tps 進行 github 自帶 如果 使用kubeasz安裝多主多從k8s集群 一、項目介紹 kubeasz為github上開源的一個用於安裝k8s集群的項目,目前很多方法安裝k8s,但是多是單master多node的安裝方式,但是kubeasz

Android開發之經典2.0開發全記錄

前言部分 最近因為需要開始藍芽相關開發,所以在網上搜索了很多內容,並且結合自己的開發過程做了一個總結,先儲備上,也許可能幫到正在做藍芽開發的同學。 藍芽很早就是android裝置上基本通訊功能了,只是以前的沒有那麼多藍芽裝置,現在藍芽裝置種類繁多,所以經常會有人遇到藍芽相關的開發

人工智慧2- 學習成成分分析PCA進行降維

一.為什麼要進行降維?     在進行分類的時候我們需要大量的特徵來提高分類器的準確度,但是分類器的效能隨著隨著維度的增加,逐步上升,達到某點其效能便逐漸下降。    為了避免效能下降的情況,我們要進行降低維度的處理。  &nb

Setting up replication主從複製

mysql資料庫安裝參考再次不在詳述,本文采用的是mysql8.0.12 介紹 主從複製涉及單個主伺服器和多個從伺服器,結構圖如下,所有的主從複製都是基於binary log 開啟主從複製有以下幾步 在Master伺服器上開啟binary logging 在

Mysql叢集和一之後如何分庫分表的方案實現

4-3、使用MyCat配置橫向拆分 之前文章中我們介紹瞭如何使用MyCat進行讀寫分離,類似的關係型資料庫的讀寫分離儲存方案可以在保持上層業務系統透明度的基礎上滿足70%業務系統的資料承載規模要求和效能要求。比起單純使用LVS + Replicaion的讀寫分離方案而言最大的優勢在於更能增加對上層業務系

oracle叢集RAC備資料同步DataGuard思路

Oracle主備庫資料同步使用DataGuard。Data Guard 是Oracle的遠端複製技術,它有物理和邏輯之分,但是總的來說,它需要在異地有一套獨立的系統,這是兩套硬體配置可以不同的系統,但是這兩套系統的軟體結構保持一致,包括軟體的版本,目錄儲存結構,以及資料的

EF通用資料層封裝類支援讀寫分離,一

原文: EF通用資料層封裝類(支援讀寫分離,一主多從) 淺談orm   記得四年前在學校第一次接觸到 Ling to Sql,那時候瞬間發現不用手寫sql語句是多麼的方便,後面慢慢的接觸了許多orm框架,像 EF,Dapper,Hibernate,ServiceStack.OrmLite 等。當

Mysql叢集和一方案實現

4、改進方式三:MyCat資料庫中介軟體 在上文中我們介紹了MySQL讀寫分離叢集的持續優化方式。按照這樣的方式,叢集中負責讀寫分離的MySQL節點基本上能夠分別實現真對上層業務系統訪問的透明化。這樣的MySQL叢集方式已經可以承載讀者遇到的大部分業務系統的結構化資料規模,但整個叢集方案還有一些明顯的問

使用spring實現讀寫分離mysql主從複製五:一的實現

很多實際使用場景下都是採用“一主多從”的架構的,使用輪詢演算法實現,目前只需要修改DynamicDataSource即可。   1.1. 實現 import java.lang.reflect.Field; import java.util.ArrayList; impo

bluetooth開發------Bluez執行環境的建立與的初始化

bluez已經移植完成,下一步就是如何建立bluez執行的系統環境。 其實整個過程分為兩個部分: 1、準備dbus 和bluetoothd 所需要的庫檔案,一般這些庫都屬於公共庫,名字就不列舉了,一般執行不成功就是缺少這些庫,這部分自己解決吧。 2、晒一晒我的初始化指

Spring AOP實現Mysql資料庫主從切換

設定資料庫主從切換的原因:資料庫中經常發生的是“讀多寫少”,這樣讀操作對資料庫壓力比較大,通過採用資料庫叢集方案,  一個數據庫是主庫,負責寫;其他為從庫,負責讀,從而實現讀寫分離增大資料庫的容錯率。  那麼,對資料庫的要求是:  1. 讀庫和寫庫的資料一致;  2. 寫資料