1. <track id="ob6no"><strike id="ob6no"><tt id="ob6no"></tt></strike></track>

      <track id="ob6no"></track>

      當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > BLE 數據接發流程

      BLE 數據接發流程 時間:2018-08-16      來源:未知

      BLE概述

      BLE分為兩部分:控制器和主機。對于4.0以前的藍牙,這兩部分是分開的。所有profile(用來定義設備或組件的角色)和應用都建構在GAP或GATT之上。下面由結構圖的底層組件開始介紹。

      協議梭的實現方式采用分層的思想,控制器部分包括物理層、鏈路層、主機控制接口層主機部分包括邏輯鏈路控制及自適應協議層、安全管理層、屬性協議層、通用訪問配置文件層、通用屬性配置文件層;上層可以調用下層提供的函數來實現需要的功能。

      PHY層:1Mbps自適應跳頻GFSK(高斯頻移鍵控),運行在免證的2.4GHz。

      LL層為RF控制器(射頻),控制設備處于準備(standby)、廣播、監聽/掃描(scan)、初始化、連接,這五種狀態中任一種。

      HCI層:為接口層,向上為主機提供軟件應用程序接口(API),對外為外部硬件控制接口,可以通過串口、SPI、USB來實現設備控制。

      L2CAP層:提供數據封裝服務

      SM層(加密);提供配對和密匙分發,實現安全連接和數據交換

      ATT層:負責數據檢索

      GATT層:出納負責處理向上與應用打交道,而GATT負責向下把檢索任務子進程交給ATT層去做,其關鍵工作是把為檢索工作提供合適的profile結構,而profile由檢索關鍵詞(characteristics)組成。

      GAP層:向上提供應用程序接口,向下管理各層的相應的功能,尤其是指示LL層的五種狀態切換,指導SM層做好加密工作。

      BLE 啟動流程

      在IAR 工程的左側有很多文件夾,如APP 、HAL、OSAL、 PROFILES等,如圖下圖所示, 這些文件夾下面包含了很多源代碼,這種實現方式與藍牙4.0 BLE 協議的分層思想是相對應的,盡量將實現某些功能的函數放在同一個文件夾下。

      圖 BLE 4.0 工程列表

      下面從main()函數入手,看看main函數都做啦哪些工作。下找到simpleBLECentral_Main.c文件中的main函數入口。代碼如下:

      int main(void)

      {

      /* Initialize hardware */

      HAL_BOARD_INIT();

      // Initialize board I/O

      InitBoard( OB_COLD );

      /* Initialze the HAL driver */

      HalDriverInit();

      /* Initialize NV system */

      osal_snv_init();

      /* Initialize LL */

      /* Initialize the operating system */

      osal_init_system();

      /* Enable interrupts */

      HAL_ENABLE_INTERRUPTS();

      // Final board initialization

      InitBoard( OB_READY );

      #if defined ( POWER_SAVING )

      osal_pwrmgr_device( PWRMGR_BATTERY );

      #endif

      /* Start OSAL */

      osal_start_system(); // No Return from here

      return 0;

      }

      在main函數中大部分是對CC2540的初始化和對無線網絡協議的配置。主要的就是osal_start_system()函數的處理,這是重點,只有執行這個函數,藍牙BLE的協議棧才是真正的運行。

      為下函數為任務啟動過程。實現不停的查看事件表,如果有事件發生就調用相應的事件處理函數。

      void osal_run_system( void )

      {

      uint8 idx = 0;

      #ifndef HAL_BOARD_CC2538

      osalTimeUpdate();

      #endif

      Hal_ProcessPoll();

      do {

      if (tasksEvents[idx]) // Task is highest priority that is ready.

      {

      break;

      }

      } while (++idx < tasksCnt);

      if (idx < tasksCnt)

      {

      uint16 events;

      halIntState_t intState;

      HAL_ENTER_CRITICAL_SECTION(intState);

      events = tasksEvents[idx];

      tasksEvents[idx] = 0; // Clear the Events for this task.

      HAL_EXIT_CRITICAL_SECTION(intState);

      activeTaskID = idx;

      events = (tasksArr[idx])( idx, events );

      activeTaskID = TASK_NO_TASK;

      HAL_ENTER_CRITICAL_SECTION(intState);

      tasksEvents[idx] |= events; // Add back unprocessed events to the current task.

      HAL_EXIT_CRITICAL_SECTION(intState);

      }

      #if defined( POWER_SAVING )

      else // Complete pass through all task events with no activity?

      {

      osal_pwrmgr_powerconserve(); // Put the processor/system into sleep

      }

      #endif

      /* Yield in case cooperative scheduling is being used. */

      #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)

      {

      osal_task_yield();

      }

      #endif

      }

      事件處理函數

      如果有事件調用SimpleBLEPeripheral_ProcessEvent()函數處理相應的消息事件。在simpleBLECentral.c文件中。

      uint16 SimpleBLECentral_ProcessEvent( uint8 task_id, uint16 events )

      {

      VOID task_id; // OSAL required parameter that isn't used in this function

      if ( events & 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 );

      }

      // return unprocessed events

      return (events ^ SYS_EVENT_MSG);

      }

      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 );

      }

      else

      {

      LCD_WRITE_STRING( "No Scan", HAL_LCD_LINE_1 );

      }

      return ( events ^ START_DEVICE_EVT );

      }

      if ( events & START_DISCOVERY_EVT )

      {

      simpleBLECentralStartDiscovery( );

      return ( events ^ START_DISCOVERY_EVT );

      }

      // Discard unknown events

      return 0;

      }

      接收數據

      本函數主要是處理無線的數據,如把接收到的數據打印到串口終端。打印函數如以下代碼中的紅色字體部分。注意紅色部分。

      static void simpleBLECentralProcessGATTMsg( gattMsgEvent_t *pMsg )

      {

      if ( simpleBLEState != BLE_STATE_CONNECTED )

      {

      // In case a GATT message came after a connection has dropped,

      // ignore the message

      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 );

      }

      simpleBLEProcedureInProgress = FALSE;

      }

      else if ( ( pMsg->method == ATT_WRITE_RSP ) ||

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

      ( pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ ) ) )

      {

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

      {

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

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

      }

      else

      {

      // After a succesful write, display the value that was written and increment value

      //LCD_WRITE_STRING_VALUE( "Write sent:", simpleBLECharVal++, 10, HAL_LCD_LINE_1 );

      simpleBLEChar6DoWrite = TRUE;

      }

      simpleBLEProcedureInProgress = FALSE;

      }

      else if ( simpleBLEDiscState != BLE_DISC_STATE_IDLE )

      {

      simpleBLEGATTDiscoveryEvent( pMsg );

      }

      else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ) //通知

      {

      if( pMsg->msg.handleValueNoti.handle == 0x0038) //CHAR7的通知 串口打印

      {

      if(pMsg->msg.handleValueNoti.value[0]>=15)

      {

      NPI_WriteTransport(&pMsg->msg.handleValueNoti.value[1],14 );

      NPI_WriteTransport("...\n",4 );

      }

      else

      {

      NPI_WriteTransport(&pMsg->msg.handleValueNoti.value[1],pMsg->msg.handleValueNoti.value[0] );

      }

      }

      }

      }

      發送數據

      從串口讀取數據存入buf[]緩沖區,然后調用協議棧函數GATT_WriteCharValue()發送出去。

      NpiSerialCallback()函數為串口回調函數,當串口有數據時就會調用此函數,并且同時會產生串口事件HAL_UART_RX_TIMEOUT。

      static void NpiSerialCallback( uint8 port, uint8 events )

      {

      (void)port;

      uint8 numBytes = 0;

      uint8 buf[128];

      if (events & HAL_UART_RX_TIMEOUT) //串口有數據

      {

      numBytes = NPI_RxBufLen(); //讀出串口緩沖區有多少字節

      if(numBytes)

      {

      if ( ( simpleBLEState == BLE_STATE_CONNECTED ) && ( simpleBLECharHd6 != 0 ) ) //已連接并獲取完CHAR6的Handle就寫CHAR6

      {

      if(simpleBLEChar6DoWrite) //寫入成功后再寫入

      {

      attWriteReq_t AttReq;

      if ( numBytes >= SIMPLEPROFILE_CHAR6_LEN ) buf[0] = SIMPLEPROFILE_CHAR6_LEN-1;

      else buf[0] = numBytes;

      NPI_ReadTransport(&buf[1],buf[0]); //從串口讀出數據

      AttReq.handle = simpleBLECharHd6;

      ttReq.len = SIMPLEPROFILE_CHAR6_LEN;

      AttReq.sig = 0;

      AttReq.cmd = 0;

      osal_memcpy(AttReq.value,buf,SIMPLEPROFILE_CHAR6_LEN);

      GATT_WriteCharValue( 0, &AttReq, simpleBLETaskId );

      simpleBLEChar6DoWrite = FALSE;

      }

      }

      else

      {

      NPI_WriteTransport("Not Ready\n", 10 );

      NPI_ReadTransport(buf,numBytes); //釋放串口數據

      }

      }

      }

      }

      BLE Central串口通信協議

      在上位機上顯示終端的實時信息,必須有相應的傳輸協議,協議里含有終端的相應信息。

      制定協議如下:

      ( 1 ) 串口打印數據協議信息:

      21 B 01 00 54 00 00 01 3E 14 EB

      21 協議頭’!’ B:BLE 01 00:模塊源節點地址 54:類型 00 00 01:數據/設備狀態 3E 14:父節點地址 EB:校驗

      如果第2數據類型為’B’,則代表所連接的設備是BLE。

      ( 2 ) 協調節點串口發送的信息:

      # C B f 00 01 01

      “# C”控制終端的協議頭 B:BLE 00 01:終端節點地址 01 控制命令(1:開/0:關)

      上一篇:BLE協議棧

      下一篇:BLE添加特征值

      熱點文章推薦
      華清學員就業榜單
      高薪學員經驗分享
      熱點新聞推薦
      前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2018 北京華清遠見科技發展有限公司 版權所有 ,京ICP備16055225號,京公海網安備11010802025203號
      操你啦,操你啦视频,操你啦影院,操你啦网站