SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.syd-tek.com/

TI 一主三从主机端分析

工程目录如下:

TI 一主三从主机端分析【发现服务流程】

向上按键处理:

TI 一主三从主机端分析【发现服务流程】

其中simpleBLEScanning代表目前蓝牙有没有在扫描状态,置1代表处于扫描状态,如果目前不是扫描态则进入if分支开始扫描并且设置simpleBLEScanning为1,这里在扫描事件的时候清除这个标志,如下:

TI 一主三从主机端分析【发现服务流程】

注意:这里有一个过滤机制:if ( DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE )也就是说只有广播中的service uuid满足相关要求的设备才会保存下来,这里要求广播中的UUID必须等于SIMPLEPROFILE_SERV_UUID!

发现完成后按下中间键将进入连接流程:

TI 一主三从主机端分析【发现服务流程】

这里调用performPeriodicTask_AutoConnect函数进行连接,其源代码如下:

// 执行动连接
static void performPeriodicTask_AutoConnect( void )  // 执行动连接
{
    uint8 addrType;
    uint8 *peerAddr;
    
    BLE_DEV *p =  &(gDev[simpleBLEScanIdx]);

    //NPI_PrintString("  [KEY_CENTER]\r\n");
    NPI_PrintValue("Idx=", simpleBLEScanIdx, 10);
    //NPI_PrintValue("State=", p->simpleBLEState, 10);
    //NPI_PrintValue("num=", connectedPeripheralNum, 10);
    //NPI_PrintValue("res=", simpleBLEScanRes, 10);

    
    // Connect or disconnect
    //if ( p->simpleBLEState == BLE_STATE_IDLE
    //    || connectedPeripheralNum < MAX_PERIPHERAL_NUM)
    if ( p->simpleBLEState == BLE_STATE_IDLE )
    {
      // if there is a scan result
      if ( simpleBLEScanRes > 0
        && simpleBLEScanIdx < simpleBLEScanRes )
      {
        // connect to current device in scan result
        peerAddr = simpleBLEDevList[simpleBLEScanIdx].addr;
        addrType = simpleBLEDevList[simpleBLEScanIdx].addrType;
      
        p->simpleBLEState = BLE_STATE_CONNECTING;
        //osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
        GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
                                      DEFAULT_LINK_WHITE_LIST,
                                      addrType, peerAddr );
 
        LCD_WRITE_STRING( "Connecting", HAL_LCD_LINE_1 );
        LCD_WRITE_STRING( bdAddr2Str( peerAddr ), HAL_LCD_LINE_2 );
      }
    }
    else if ( p->simpleBLEState == BLE_STATE_CONNECTING ||
              p->simpleBLEState == BLE_STATE_CONNECTED ||
              p->simpleBLEState == BLE_STATE_DISCONNECTING)
    {
      // disconnect
      p->simpleBLEState = BLE_STATE_DISCONNECTING;

      gStatus = GAPCentralRole_TerminateLink( p->simpleBLEConnHandle );
      
      LCD_WRITE_STRING( "Disconnecting", HAL_LCD_LINE_1 );
    }
}

这里如果相应地址不是连接状态将进行连接,如果是连接状态将断开连接!

这里将调用GAPCentralRole_EstablishLink函数进行连接,当连接完成的时候将进行下面的回调:

TI 一主三从主机端分析【发现服务流程】

这里开启一个定时器去发现服务:osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );

TI 一主三从主机端分析【发现服务流程】

之后将进入如下系统回调:

/*********************************************************************
 * @fn      simpleBLEGATTDiscoveryEvent
 *
 * @brief   Process GATT discovery event
 *
 * @return  none
 */

static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
  attReadByTypeReq_t req;
  BLE_DEV *p =  simpleBLECentralGetDev(pMsg->connHandle);
 
   if ( p->simpleBLEDiscState == BLE_DISC_STATE_SVC )   
   {    
      // Service found, store handles    
      if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&       
       pMsg->msg.findByTypeValueRsp.numInfo > 0 )   
      {      
        p->simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;  
        p->simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;    
      }    
 
      // If procedure complete    
      if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  &&           
      pMsg->hdr.status == bleProcedureComplete ) ||         
      ( pMsg->method == ATT_ERROR_RSP ) )   
      {      
        if ( p->simpleBLESvcStartHdl != 0 )      
        {        
          // Discover characteristic       
          p->simpleBLEDiscState = BLE_DISC_STATE_CHAR1;      
          req.startHandle = p->simpleBLESvcStartHdl;    
          req.endHandle = p->simpleBLESvcEndHdl;    
          req.type.len = ATT_BT_UUID_SIZE;
          req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);    
          req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);      
          GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );     
        }    
      }  
  }  
  else if ( p->simpleBLEDiscState == BLE_DISC_STATE_CHAR1 )  
  {    
    NPI_PrintValue("1 pMsg->method", pMsg->method, 10);
    NPI_PrintValue("1 numPairs", pMsg->msg.readByTypeRsp.numPairs, 10);
    // Characteristic found, store handle    
     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&      
        pMsg->msg.readByTypeRsp.numPairs > 0 )
        {      
           p->simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],                         
           pMsg->msg.readByTypeRsp.dataList[1] );      
    
           LCD_WRITE_STRING( "CHAR 1 Found", HAL_LCD_LINE_3 );      
           p->simpleBLEProcedureInProgress = TRUE;      
       }
     else // pMsg->msg.readByTypeRsp.numPairs is 0.
     {
       p->simpleBLEDiscState = BLE_DISC_STATE_CHAR6;    
       req.startHandle = p->simpleBLESvcStartHdl;  
       req.endHandle = p->simpleBLESvcEndHdl;   
       req.type.len = ATT_BT_UUID_SIZE;    
       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);   
       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);    
       GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );  
     }
  }        
  else if (p->simpleBLEDiscState == BLE_DISC_STATE_CHAR6)  
  {     // Characteristic found, store handle    
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&     
    pMsg->msg.readByTypeRsp.numPairs > 0 )    
    {      
      p->simpleBLECharHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],                                      
      pMsg->msg.readByTypeRsp.dataList[1] );     
      LCD_WRITE_STRING( "CHAR 6 Found", HAL_LCD_LINE_4 );
      p->simpleBLEProcedureInProgress = FALSE;  
    }    
    p->simpleBLEDiscState = BLE_DISC_STATE_IDLE;
  }
}

这个函数就是我们发现服务后的操作, 这里,我们现实去发现服务 CHAR1, 然后再去发现CHAR6, 总共是2个, 当然可以去找更多,看有没有必要了, 这里的代码你可以琢磨一下,不详细讲了

接下来按下S1按键将发送数据,如下:

TI 一主三从主机端分析【发现服务流程】

这里开启SBP_PERIODIC_EVT定时器进行数据轮训发送,定时器回调如下:

  if ( events & SBP_PERIODIC_EVT )
  {
    // Restart timer
    if ( SBP_PERIODIC_EVT_PERIOD )
    {
      osal_start_timerEx( simpleBLETaskId, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );
    }

    // Perform periodic application task
    performPeriodicTask();  // amomcu 用于发送数据


    return (events ^ SBP_PERIODIC_EVT);
  }

其调用performPeriodicTask函数进行发送,其源代码如下:

// amomcu 用于发送数据
static void performPeriodicTask( void )
{
    static int index = 0;
    char str[32] = {0};
    //uint8 value[20];
#if 0// 用于调试
    for(int i = 0; i < simpleBLEScanRes; i++)
    {
        sprintf(str, "[%d].[%d,%d],[%08x,%d,%d]\r\n",
            i, gDev[i].simpleBLECharHdl[0],gDev[i].simpleBLECharHdl[5],
            gDev[i].simpleBLEConnHandle,
            gDev[i].simpleBLEState,
            simpleBLEScanIdx);
        NPI_PrintString((uint8*)str);            

        /*
[0].[37,53],[00000000]
[1].[37,53],[00000001]
        */
    }
    NPI_PrintString("\r\n");
#endif    

#if 0
    // 往从机写入char1的值, 注意char1 是一个字节长度的
    value[0] = gDev[simpleBLEScanIdx].simpleBLECharVal;
    OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, value, 1);
#else
    if(index == 0)
    {
        // 往从机写入char1的值, 注意char1 是一个字节长度的
#if 0        
        OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, &(gDev[simpleBLEScanIdx].simpleBLECharVal), 1);

        // 发送的数据同样显示在显示屏上
        sprintf(str, "Char1: %d", gDev[simpleBLEScanIdx].simpleBLECharVal);
        HalLcdWriteString(str,  HAL_LCD_LINE_6 );

        gDev[simpleBLEScanIdx].simpleBLECharVal++;
#else
        OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, &simpleBLESendValue, 1);

        // 发送的数据同样显示在显示屏上
        sprintf(str, "Char1: %d", simpleBLESendValue);
        HalLcdWriteString(str,  HAL_LCD_LINE_6 );

        simpleBLESendValue++;
#endif

        HalLedBlink (HAL_LED_1, 1, 50, 100);//这个的意思是, 100ms内,以50%的占空比闪烁1次, 实际就是点亮50ms  
    }
    else if(index == 1)            
    {        
        uint32 time = osal_GetSystemClock();

        sprintf(str, "time=%06ld", time);

        // 往从机写入char6的值, 注意char6 是一个最大字节数为19的buffer, 这里为简单没有做长度判断
        OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR6, (uint8*)str, osal_strlen(str));

        // 发送的数据同样显示在显示屏上
        sprintf(str, "CHAR6: time=%06ld", time);
        HalLcdWriteString(str,  HAL_LCD_LINE_7 );
        
        // 更换成下一个从机, 注意我们都是先发
        simpleBLEScanIdx++;
        simpleBLEScanIdx %= simpleBLEScanRes;

        HalLedBlink (HAL_LED_2, 1, 50, 100);//这个的意思是, 100ms内,以50%的占空比闪烁1次, 实际就是点亮50ms  
    }

    index++;
    index %=2;
#endif    
}

主机发送函数到此为止!


这里上传本博客使用到的源代码:

http://download.csdn.net/detail/chengdong1314/9881528

更多更详细的教程请看上面资源里的《1主3从教程(阿莫单片机2014-12-13更新).pdf》,资源中更有一些视频资料!


发现服务流程

1.在simpleBLECentralEventCB回调函数的建立连接GAP_LINK_ESTABLISHED_EVENT分支中开启一个定时器事件:osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );

注意:该事件只会被调用一次,虽然叫做定时器,但是不会被重复的调用

2.在定时器事件到来的时候,SimpleBLECentral_ProcessEvent函数会被回调并且进入 if ( events & START_DISCOVERY_EVT )分支,该分支中调用simpleBLECentralStartDiscovery函数开始服务特性handle的发现

注意:只会进入一次

3.simpleBLECentralStartDiscovery函数将调用GATT_DiscPrimaryServiceByUUID发现透传的主要服务的handle

4.GATT_DiscPrimaryServiceByUUID函数被调用之后协议栈会产生回调进入simpleBLECentralProcessGATTMsg函数的 else if ( p->simpleBLEDiscState != BLE_DISC_STATE_IDLE )分支,这里将发现特性的handle



相关文章:

  • 2021-08-17
  • 2021-07-31
  • 2021-08-23
  • 2022-01-07
  • 2021-05-24
  • 2022-12-23
  • 2021-04-12
猜你喜欢
  • 2021-12-09
  • 2022-01-08
  • 2021-04-12
  • 2021-05-17
  • 2022-12-23
  • 2021-06-13
  • 2022-01-17
相关资源
相似解决方案