1. 程式人生 > >藍芽4.0 BLE 資料傳輸 (二)

藍芽4.0 BLE 資料傳輸 (二)

轉載自:

https://blog.csdn.net/rfidunion/article/details/79711055

 

在第一部分我們瞭解了幾個專業詞彙,接下來我們再瞭解一下資料的傳送

一、資料傳送

在BLE協議棧中進行資料傳送分為兩個方面,一個事GATT的client主動向service傳送資料,另一個是GATT的service主動向client傳送資料

我們暫且簡單的分為主機向從機發送資料,從機主動向主機發送資料。

1、主機向從機發送資料

傳送可以呼叫GATT_WriteCharValue函式來實現,該函式會呼叫協議棧裡面與硬體相關的函式最終將資料通過天線傳送出去,這裡設計對射頻模組的操作,例如:打開發射機,調整發射機的發射功率等內容,這些部分協議棧都已經實現了,使用者不需要自己寫程式碼實現(這裡是廢話,可以忽略),只需掌握GATT_writeCharValue函式的使用方法即可。需要傳送的資料填充到value中,然後資料長度填充到len中,即:

首先我們得了解一下發送包的結構體

typedef struct

{

  uint16 handle;               //要寫入的屬性的控制代碼 (必須是第一個欄位)

  uint8 len;                   //資料長度

  uint8 value[ATT_MTU_SIZE-3]; //存資料的陣列

  uint8 sig;                   //身份驗證簽名狀態 (不包括 (0),有效的 (1),無效 (2))

  uint8 cmd;                   //標記命令

} attWriteReq_t;

我們再看下資料是怎麼傳送的:

藍芽4.0 <wbr>BLE <wbr> <wbr>資料傳輸 <wbr>(二)
GATT_WriteCharValue有三個引數,第一個為連線控制代碼,第二個引數就是我們要傳送的資料包,最後一個引數為時間的TASKID,只要滿足以上的傳送格式我們就可以把資料傳送出去了,是不是很簡單啊?

 

2、從機向主機發送資料

從機向主機發送資料,並不是用GATT_WriteCharValue這個函式,而至用另外的一種形式----notification,因此,我們需要呼叫GATT_Notification函式。在開發串列埠透傳等專案時,就需要在從機中主動向主機發送資料,需要該函式來實現。主要程式碼如下:

藍芽4.0 <wbr>BLE <wbr> <wbr>資料傳輸 <wbr>(二)
是不是感覺比Write的形式 更簡單?當然這個只能適用於從機主動傳送給主機。

二、資料接收

資料接收和資料傳送一樣,同樣分為兩個方面,即從機接收主機發來的資料和主機接收來自從機的資料。

1、主機接收來自從機的資料

與傳送資料相似,我們用GATT_ReadCharValue(傳遞的引數為連線控制代碼、關鍵詞控制代碼和自身任務的ID)這個函式來實現,同樣我們來看一下相關的結構體

typedef struct

{

  uint16 handle; //要讀取的屬性的控制代碼 (必須是第一個欄位)

} attReadReq_t;

 

具體例項如下:

attReadReq_t req;
        req.handle = simpleBLECharHdl;
        status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );

 

GATT應答了這個請求,返回值SUCCESS(0x00),向下告知BLE有生意了,該幹活了。於是BLE協議棧在下次建立連線時,傳送獲取資料指令個service,於是就把資料傳給了client,當client接收到資料時,BLE就會把資料打包成一個訊息(OSAL message), 通過出納GATT返回給了應用程式。訊息內包含GATT_MSG_EVENT和修改了的ATT_READ_RSP。應用程式接收到了從OSAL來的SYS_EVENT_MSG事件,就知道資料接收到了,應用程式接收訊息,拆包檢查,就可以取走訊息裡面的資料了,最後應用程式把包裝好的訊息給銷燬,這就是整資料傳送過程。

程式碼分析:

 

if ( events & SYS_EVENT_MSG ) //觸發SYS_EVENT_MSG事件

  {

    uint8 *pMsg;

 

    if ( (pMsg = osal_msg_receive( simpleBLETaskId )) != NULL )

    {

      simpleBLECentral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );//用於處理訊息

 

      // Release the OSAL message

      VOID osal_msg_deallocate( pMsg );//銷燬訊息資料

    }

 

進入simpleBLECentral_ProcessOSALMsg函式就會執行下面一句

    case GATT_MSG_EVENT:  

      simpleBLECentralProcessGATTMsg( (gattMsgEvent_t *) pMsg );//接收從機資料

      break;

 

進入simpleBLECentralProcessGATTMsg函式進行拆包分析資料

 

獲取從機訊息我們主要看下面幾句話

 

  if ( simpleBLEState != BLE_STATE_CONNECTED )   //以防GATT的訊息來了之後的連線已斷開,如果斷開連線就忽略該訊息

    return; 

  

  if ( ( pMsg->method == ATT_READ_RSP ) ||

       ( ( pMsg->method == ATT_ERROR_RSP ) &&

         ( pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ ) ) )   //判斷是不是讀資料

  {

    if ( pMsg->method == ATT_ERROR_RSP )//獲取錯誤資訊

    {

      uint8 status = pMsg->msg.errorRsp.errCode;

      

      LCD_WRITE_STRING_VALUE( "Read Error", status, 10, HAL_LCD_LINE_1 );

    }

    else

    {

      // After a successful read, display the read value

      uint8 valueRead = pMsg->msg.readRsp.value[0]; //取出訊息包中從機發送過來的資料

 

      LCD_WRITE_STRING_VALUE( "Read rsp:", valueRead, 10, HAL_LCD_LINE_1 );

    }

 2、從機接收主機發來的資料

當從機接收來自主機發來的資料後,從機會產生一個GATT Profile Callback呼叫,我們在這個callback中接收主機發送的資料。這個callback在從機初始化時向profile註冊。

藍芽4.0 <wbr>BLE <wbr> <wbr>資料傳輸 <wbr>(二)

藍芽4.0 <wbr>BLE <wbr> <wbr>資料傳輸 <wbr>(二)
到此為止,我們至少得理清這條線索:主機通過BLE提供的資料傳送介面傳送資料後,從機的協議棧接收到資料後,做相應處理,取得自己需要的資料即可。其他工作,都由BLE協議棧自動完成。

並且在這裡我們得清楚,用write和read來發送和獲取特徵值的方式方式只適用於主機,只主機主動發起的。而從機若想主動傳送資料給主機那麼我們就只能用notification的方式傳送。我們的主機一半作為GATT層的client,而從機一半作為service。

 

今天就到這裡,尼瑪部落格真難寫,真浪費時間,真的真的真的。。。。