BLE支持外设和观察者同时工作,虽然TI提供的协议栈例程中并没有外设+广播者的工程,但是TI在如下网站上给出了外设+广播者的工程:
https://processors.wiki.ti.com/index.php/File:SimpleBleCombo.zip#file。
从上述网址下载得到SimpleBleCombo.zip压缩文件,解压后打开,里边有两个工程:外设+观察者(SimpleBLEPeripheralObserver)和中心设备+广播者(SimpleBLECenteralBroadcaster)。
要想实现外设+观察者的功能,可直接将SimpleBLEPeripheralObserver文件夹拷贝到协议栈:BLE-CC254x-1.3.2/Projects/ble/目录下,然后打开工程,编译、下载。然而这么做并没有什么意义,我们所需要的不是整个完整的工程,而是外设+广播的Profile实现文件,并使用这个Profile文件在TI的协议栈的SimpleBLEPeripheral工程做修改,来实现外设+观察者的功能。
1、SimpleBLEPeripheralObserver/Source目录下的peripheralObserverProfile.c和peripheralObserverProfile.h两个文件拷贝到协议栈安装位置BLE-CC254x-1.3.2/Projects/ble/Profiles/Roles目录下。
2、打开SimpleBLEPeripheral工程,选择Workspace为CC2541。
3、在LIB工程组下,剔除CC2541_BLE_peri.lib库文件,然后添加CC2541_BLE_peri_observ.lib库文件。
4、在PROFILES工程组下,剔除peripheral.c和peripheral.h文件,然后添加peripheralObserverProfile.c和peripheralObserverProfile.h两个文件。
5、打开TOOLS工程组下的buildConfig.cfg文件,选择角色为外设+观察者:
//-DHOST_CONFIG=BROADCASTER_CFG
//-DHOST_CONFIG=OBSERVER_CFG
//-DHOST_CONFIG=PERIPHERAL_CFG
//-DHOST_CONFIG=CENTRAL_CFG
//-DHOST_CONFIG=BROADCASTER_CFG+OBSERVER_CFG
-DHOST_CONFIG=PERIPHERAL_CFG+OBSERVER_CFG
//-DHOST_CONFIG=CENTRAL_CFG+BROADCASTER_CFG
//-DHOST_CONFIG=PERIPHERAL_CFG+CENTRAL_CFG
6、打开APP工作组下的simpleBLEPeripheral.c文件。
7、修改头文件:
#include "peripheral.h"
为
#include "peripheralObserverPrifle.h"
8、添加几个宏定义,如下:
/* 最大扫描个数 */
#define DEFAULT_MAX_SCAN_RES 4
/* 扫描持续周期 */
#define DEFAULT_SCAN_DURATION 2000
/* 所有扫描模式:Limited,General */
#define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL
#define DEFAULT_DISCOVERY_ACTIVE_SCAN FALSE
#define DEFAULT_DISCOVERY_WHITE_LIST FALSE
9、定义几个跟观察者相关的变量。
/* 扫描结果个数 */
static uint8 observerScanRes;
/* 扫描索引 */
static uint8 observerScanIdx;
/* 用于保存扫描设备的地址数组 */
static gapDevRec_t observerDevList[DEFAULT_MAX_SCAN_RES];
/* 用于保存扫描到的广播数据 */
static uint8 observerDevAdvData[DEFAULT_MAX_SCAN_RES][B_MAX_ADV_LEN];
/* 扫描状态 */
static uint8 observerScanning = FALSE;
10、删掉#if defined( CC2541_MINIDK )...#endif和它之间的代码,除了与simpleBLEPeripheral_HandleKeys()函数的代码。我使用的是SmartRF开发板,所以要保留按键处理函数。
11、在SimpleBLEPeripheral_Init()函数中注册按键处理函数。
RegisterForKeys( simpleBLEPeripheral_TaskID );
12、在SimpleBLEPeripheral_Init()函数中设置观察者相关配置。
{
uint8 scanRes = DEFAULT_MAX_SCAN_RES;
GAPRole_SetParameter( GAPOBSERVERROLE_MAX_SCAN_RES,
sizeof( uint8 ), &scanRes );
}
GAP_SetParamValue(TGAP_GEN_DISC_SCAN, DEFAULT_SCAN_DURATION );
GAP_SetParamValue( TGAP_LIM_DISC_SCAN, DEFAULT_SCAN_DURATION );
13、去掉peripheralStateNotificationCB()函数GAPROLE_CONNECTED_ADV选项的内容去掉,因为对于外设+观察者,不允许存在连接后进行广播的情况。
/*case GAPROLE_CONNECTED_ADV:
{
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
HalLcdWriteString( "Connected Advertising", HAL_LCD_LINE_3 );
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE)
}
break;*/
14、向GAP Role回调函数添加观察者回调函数ObserverEventCB()。
static gapRolesCBs_t simpleBLEPeripheral_PeripheralCBs =
{
peripheralStateNotificationCB,
NULL,
ObserverEventCB
};
15、编写ObserverEventCB()函数。
static void ObserverEventCB( observerRoleEvent_t *pEvent )
{
switch ( pEvent->gap.opcode )
{
case GAP_DEVICE_INIT_DONE_EVENT:
break;
case GAP_DEVICE_INFO_EVENT:
{
ObserverAddDeviceInfo( pEvent );
}
break;
case GAP_DEVICE_DISCOVERY_EVENT:
{
observerScanning = FALSE;
observerScanRes = pEvent->discCmpl.numDevs;
osal_memcpy( observerDevList, pEvent->discCmpl.pDevList,
(sizeof( gapDevRec_t ) * pEvent->discCmpl.numDevs) );
HalLcdWriteStringValue( "Devices Found", observerScanRes,
10, HAL_LCD_LINE_5 );
if ( observerScanRes > 0 )
{
HalLcdWriteString( "<- To Select", HAL_LCD_LINE_6 );
}
observerScanIdx = observerScanRes;
HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
}
break;
default:
break;
}
}
16、编写ObserverAddDeviceInfo()函数来接收扫描到设备的地址和广播数据。
static void ObserverAddDeviceInfo( observerRoleEvent_t *pEvent )
{
uint8 i;
if ( observerScanRes < DEFAULT_MAX_SCAN_RES )
{
for ( i = 0; i < observerScanRes; i++ )
{
if ( osal_memcmp( pEvent->deviceInfo.addr,
observerDevList[i].addr , B_ADDR_LEN ) )
{
return;
}
}
osal_memcpy( observerDevList[observerScanRes].addr,
pEvent->deviceInfo.addr, B_ADDR_LEN );
observerDevList[observerScanRes].addrType = pEvent->deviceInfo.addrType;
osal_memcpy( observerDevAdvData[observerScanRes],
&(pEvent->deviceInfo.pEvtData[4]),
pEvent->deviceInfo.pEvtData[3] );
observerScanRes++;
}
}
17、修改simpleBLEPeripheral_HandleKeys()函数代码为:
static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
{
VOID shift;
if ( keys == HAL_KEY_UP )
{
uint8 adv_state;
GAPRole_GetParameter( GAPROLE_ADVERT_ENABLED, &adv_state );
if ( adv_state )
adv_state = FALSE;
else
adv_state = TRUE;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &adv_state );
}
if ( keys == HAL_KEY_CENTER )
{
if ( !observerScanning )
{
observerScanning = TRUE;
observerScanRes = 0;
osal_memset(observerDevAdvData, 0, sizeof(observerDevAdvData));
HalLcdWriteString( "Discovering...", HAL_LCD_LINE_5 );
HalLcdWriteString( "", HAL_LCD_LINE_6 );
HalLcdWriteString( "", HAL_LCD_LINE_7 );
GAPObserverRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST );
}
}
if ( keys == HAL_KEY_LEFT )
{
if ( !observerScanning && observerScanRes > 0 )
{
observerScanIdx++;
if ( observerScanIdx >= observerScanRes )
{
observerScanIdx = 0;
}
HalLcdWriteStringValue( "Device", observerScanIdx + 1,
10, HAL_LCD_LINE_5 );
HalLcdWriteString( bdAddr2Str( observerDevList[observerScanIdx].addr ),
HAL_LCD_LINE_6 );
HalLcdWriteString( " ", HAL_LCD_LINE_7);
HalLcdWriteString( (char *)observerDevAdvData[observerScanIdx],
HAL_LCD_LINE_7 );
}
}
}
如上工程就修改完毕了,编译通过并下载进SmartRF开发板中,功能如下:
<1>按下SmartRF的JoyStick上键,打开/关闭广播。
<2>按下SmartRF的JoyStick中间键,开始扫描。扫描成功后,通过按下JoyStick的左键就可以选择扫描到设备地址和广播数据。