CC2541 BLE源码阅读知识积累之外设从机Peripheral工作模式

来源:互联网 发布:阿里巴巴代销传淘宝 编辑:程序博客网 时间:2024/06/05 03:37

转自:http://blog.csdn.net/zhjr1220/article/details/9416761

阅读的源代码:核心主要是位于BLE/project/SimpleBLEPeripheral部分

阅读的参考文档:TI_BLE_Software_Developer's_Guide.pdf,BLE_CC2540_DeepDive_Training_2011.pdf,TI_BLE_Sample_Applications_Guide.pdf,SIG的Core_V4.0.pdf

 

在BLE的源码架构中,感觉是好复杂,还好TI对协议栈不开源,不然就得累死。能力有限只能把整个架构从最简单的主从工作模式入手。

1.BLE中主从机建立连接,到配对和绑定的过程如下图。


正如上图所示,最简单一次蓝牙通信需要以上相关步骤,包括discovery device,connect,pairing,bond等4个主要部分。

 

2.BLE中的GAP和GATT

初始接触,感觉十分的抽象,到现在为止,GAP个人认为就是监控上图中的交互状态,比如从广播变成连接,到配对等。

GATT通俗理解为用于主从机之间的客户端和服务器端的数据交互,以Attribute Table来体现。

GAP Role Profile:在GAP剧本里所处的4个角色:广播Advertise,主机central,从机Peripheral,观察者Observer。

GATT Attribute:通用属性配置文件。

 

3.SimpleBLEPeripheral_Init函数解析。

无论是在主机还是从机,任何的蓝牙都将这部分内容作为自己的APPlication,在init中都会完成Bluetooth的GAP,GATT,SM等相关初始化。

void SimpleBLEPeripheral_Init( uint8 task_id )
{
  simpleBLEPeripheral_TaskID = task_id;

  // Setup the GAP Peripheral Role Profile  //GAP外设剧本
  {

    #if defined( CC2540_MINIDK )
      // For the CC2540DK-MINI keyfob, device doesn't start advertising until button is pressed
      uint8 initial_advertising_enable = FALSE;
    #else
      // For other hardware platforms, device starts advertising upon initialization
      uint8 initial_advertising_enable = TRUE;//广播使能
    #endif

    // By setting this to zero, the device will go into the waiting state after
    // being discoverable for 30.72 second, and will not being advertising again
    // until the enabler is set back to TRUE
    uint16 gapRole_AdvertOffTime = 0;

    uint8 enable_update_request = DEFAULT_ENABLE_UPDATE_REQUEST;//使能请求更新
    uint16 desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL; //最小连接间隔0.1ms
    uint16 desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;  //最大连接间隔 1ms
    uint16 desired_slave_latency = DEFAULT_DESIRED_SLAVE_LATENCY;//0
    uint16 desired_conn_timeout = DEFAULT_DESIRED_CONN_TIMEOUT;//10s,定义该参数表示在该时间段内建立的连接不成功

    // Set the GAP Role Parameters
    GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable );
    GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime );

    GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );//当主机扫描到广播后会发出扫描请求,从机就发回该数据到主机
    GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );//广播参数

    GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &enable_update_request );
    GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
    GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );
    GAPRole_SetParameter( GAPROLE_SLAVE_LATENCY, sizeof( uint16 ), &desired_slave_latency );
    GAPRole_SetParameter( GAPROLE_TIMEOUT_MULTIPLIER, sizeof( uint16 ), &desired_conn_timeout );
  }

  // Set the GAP Characteristics, Set GAP GATT Server parameter
  GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );//GAP GATT服务器参数设置

  // Set advertising interval
  {
    uint16 advInt = DEFAULT_ADVERTISING_INTERVAL;

    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_LIM_DISC_ADV_INT_MAX, advInt );
    GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, advInt );
    GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, advInt );
  }

  // Setup the GAP Bond Manager   //GAP 绑定管理器设置
  {
    uint32 passkey = 0; // passkey "000000",密钥
    uint8 pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;//配对模式,配置成等待主机的配对请求
    uint8 mitm = TRUE;
    uint8 ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    uint8 bonding = TRUE;
    GAPBondMgr_SetParameter( GAPBOND_DEFAULT_PASSCODE, sizeof ( uint32 ), &passkey );
    GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof ( uint8 ), &pairMode );
    GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof ( uint8 ), &mitm );
    GAPBondMgr_SetParameter( GAPBOND_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap );
    GAPBondMgr_SetParameter( GAPBOND_BONDING_ENABLED, sizeof ( uint8 ), &bonding );
  }

  // Initialize GATT attributes
  GGS_AddService( GATT_ALL_SERVICES );            // GAP
  GATTServApp_AddService( GATT_ALL_SERVICES );    // GATT attributes
  DevInfo_AddService();                           // Device Information Service
  SimpleProfile_AddService( GATT_ALL_SERVICES );  // Simple GATT Profile
#if defined FEATURE_OAD
  VOID OADTarget_AddService();                    // OAD Profile
#endif

  // Setup the SimpleProfile Characteristic Values,对相关数值做初始化
  {
    uint8 charValue1 = 1;
    uint8 charValue2 = 2;
    uint8 charValue3 = 3;
    uint8 charValue4 = 4;
    uint8 charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };
    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR1, sizeof ( uint8 ), &charValue1 );
    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR2, sizeof ( uint8 ), &charValue2 );
    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR3, sizeof ( uint8 ), &charValue3 );
    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, sizeof ( uint8 ), &charValue4 );
    SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN, charValue5 );
  }


#if defined( CC2540_MINIDK )

  SK_AddService( GATT_ALL_SERVICES ); // Simple Keys Profile

  // Register for all key events - This app will handle all key events
  RegisterForKeys( simpleBLEPeripheral_TaskID );//注册按键,在这里当按键按下时,该任务会收到一个事件发来的消息

  // makes sure LEDs are off
  HalLedSet( (HAL_LED_1 | HAL_LED_2), HAL_LED_MODE_OFF );

  // For keyfob board set GPIO pins into a power-optimized state
  // Note that there is still some leakage current from the buzzer,
  // accelerometer, LEDs, and buttons on the PCB.

  P0SEL = 0; // Configure Port 0 as GPIO
  P1SEL = 0; // Configure Port 1 as GPIO
  P2SEL = 0; // Configure Port 2 as GPIO

  P0DIR = 0xFC; // Port 0 pins P0.0 and P0.1 as input (buttons),
                // all others (P0.2-P0.7) as output
  P1DIR = 0xFF; // All port 1 pins (P1.0-P1.7) as output
  P2DIR = 0x1F; // All port 1 pins (P2.0-P2.4) as output

  P0 = 0x03; // All pins on port 0 to low except for P0.0 and P0.1 (buttons)
  P1 = 0;   // All pins on port 1 to low
  P2 = 0;   // All pins on port 2 to low

#endif // #if defined( CC2540_MINIDK )

#if (defined HAL_LCD) && (HAL_LCD == TRUE)

#if defined FEATURE_OAD
  #if defined (HAL_IMAGE_A)
    HalLcdWriteStringValue( "BLE Peri-A", OAD_VER_NUM( _imgHdr.ver ), 16, HAL_LCD_LINE_1 );
  #else
    HalLcdWriteStringValue( "BLE Peri-B", OAD_VER_NUM( _imgHdr.ver ), 16, HAL_LCD_LINE_1 );
  #endif // HAL_IMAGE_A
#else
  HalLcdWriteString( "BLE Peripheral", HAL_LCD_LINE_1 );
#endif // FEATURE_OAD

#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)

  // Register callback with SimpleGATTprofile
  VOID SimpleProfile_RegisterAppCBs( &simpleBLEPeripheral_SimpleProfileCBs );//给应用注册回调函数

  // Enable clock divide on halt
  // This reduces active current while radio is active and CC254x MCU
  // is halted
  HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT );

#if defined ( DC_DC_P0_7 )

  // Enable stack to toggle bypass control on TPS62730 (DC/DC converter)
  HCI_EXT_MapPmIoPortCmd( HCI_EXT_PM_IO_PORT_P0, HCI_EXT_PM_IO_PORT_PIN7 );

#endif // defined ( DC_DC_P0_7 )

  // Setup a delayed profile startup
  osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT );//标志SBP_START_DEVICE_EVT启动该event

4.GAP部分的初始化和相关API以及,事件的处理过程。

在上3中的init中可以看到GAP作为Peripheral Role需要设置的核心参数如下

GAPROLE_ADVERT_ENABLED:广播使能。

GAPROLE_ADVERT_DATA:广播时的参数,

GAPROLE_SCAN_RSP_DATA:从机扫描响应,返回的数据包

GAPROLE_MIN_CONN_INTERVAL:处于连接状态后的设备,都会有个hop,一段时间内进行数据交互,以保证两者是连接的。当前后两次交互时,需要等待的最小间隔时间

GAPROLE_MAX_CONN_INTERVAL:...需要等待的最大间隔时间

GAPROLE_SLAVE_LATENCY:处于连接后,从机可以做出不响应连接请求的间隔数目,即跳过n个交互的连接。

GAPROLE_TIMEOUT_MULTIPLIER:从上次成功连接到这次连接成功的最大允许延时。如果规定时间内未成功则认为本次连接失败,丢弃。该值必须比有效连接的间隔大。

GAPROLE_PARAM_UPDATE_ENABLE:请求主机更新参数,主机可以接受也可以拒绝。

 

GAP通过在启动设备事件的任务处理中启动设备,其实主要是向GAP中注册回调函数,让系统在发现自身运行状态变化时,调用该函数,方便应用层进行相关操作。

VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs );//启动设备,注册回调函数,用于监督设备的状态变化:广播、连接、配对、绑定等。

static void peripheralStateNotificationCB( gaprole_States_t newState )//传入参数由GPA自己输入,内部调用回调函数给用户
  switch ( newState )
  {
    case GAPROLE_STARTED://在GAPRole_StartDevice后发生状态变化
      {
        uint8 ownAddress[B_ADDR_LEN];
        uint8 systemId[DEVINFO_SYSTEM_ID_LEN];

        GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);

        // use 6 bytes of device address for 8 bytes of system ID value
        systemId[0] = ownAddress[0];
        systemId[1] = ownAddress[1];
        systemId[2] = ownAddress[2];

        // set middle bytes to zero
        systemId[4] = 0x00;
        systemId[3] = 0x00;

        // shift three bytes up
        systemId[7] = ownAddress[5];
        systemId[6] = ownAddress[4];
        systemId[5] = ownAddress[3];

        DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);

        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          // Display device address
          HalLcdWriteString( bdAddr2Str( ownAddress ),  HAL_LCD_LINE_2 );
          HalLcdWriteString( "Initialized",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    case GAPROLE_ADVERTISING:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Advertising",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    case GAPROLE_CONNECTED:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Connected",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    case GAPROLE_WAITING:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Disconnected",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    case GAPROLE_WAITING_AFTER_TIMEOUT:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Timed Out",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    case GAPROLE_ERROR:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "Error",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

    default:
      {
        #if (defined HAL_LCD) && (HAL_LCD == TRUE)
          HalLcdWriteString( "",  HAL_LCD_LINE_3 );
        #endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
      }
      break;

  }

可以看到GAP Role 作为外设从机时,各种状态的变化,而这些状态 变化都由GAP(不开源部分)调用回调函数,将当前状态参数传入,以使得不同的APP做出反应。体现了一种回调函数设计的便捷性。


5.GATT Server的相关设置函数。

  // Initialize GATT attributes
  GGS_AddService( GATT_ALL_SERVICES );            // GAP Service
  GATTServApp_AddService( GATT_ALL_SERVICES );    // GATT attributes
  DevInfo_AddService();                           // Device Information Service
  SimpleProfile_AddService( GATT_ALL_SERVICES );  // Simple GATT Profile

通常一个GATT中GAP server和GATT server是必须强制存在的(Mandatory)以及自己设计的profile server.

作为GATT的server和client,主要通过Attribute来进行交互,当client请求server读取数据时,通过如下注册的回调函数来进行访问。

  // Register callback with SimpleGATTprofile
  VOID SimpleProfile_RegisterAppCBs( &simpleBLEPeripheral_SimpleProfileCBs );//给应用注册回调函数

在回调函数中对时间做出处理。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宁德住房公积金查询 苏州住房公积金管理中心 太原住房公积金 萍乡市住房公积金个人查询 深圳住房公积金查询余额 长春市住房公积金网 潍坊市住房公积金管理中心 阜阳市住房公积金查询 赣州住房公积金 太原住房公积金查询个人账户 郑州市住房公积金查询 杭州住房公积金管理中心 乐山市住房公积金管理中心 长春住房公积金查询 青海住房公积金查询网 住房公积金管理 宜春住房公积金查询 惠州市住房公积金管理中心 玉林住房公积金查询个人账户 枣庄住房公积金查询 六安住房公积金管理中心 厦门住房公积金查询 渭南市住房公积金个人查询 乐山住房公积金查询个人账户 深圳住房公积金电话多少 南宁住房公积金查询 住房公积金查询电话12329 济宁住房公积金管理中心 宁德市住房公积金查询窗口 兰州市住房公积金查询系统 孝感住房公积金查询 兰州住房公积金查询 滁州住房公积金 上海住房公积金网 个人住房公积金查询网 省住房公积金管理中心 韶关市住房公积金管理中心 长沙住房公积金管理中心 赣州住房公积金查询 西安住房公积金查询 南充住房公积金查询