Mbed OS 文档翻译 之 参考(API(蓝牙(GAP)))

GAP

通用访问配置文件是处理连接任务的堆栈层。 这包括链接建立和终止,广告和扫描。

具有要发布的数据的设备可以使用 GAP 进行广告。它们可以在广告本身中包含数据,在扫描响应内部,或者在建立连接后让对等设备对其进行查询。

该过程的另一方面是扫描行为,其侦听广告,允许您通过扫描请求查询广告商以获取更多数据,或者连接以便向对等设备查询所需数据。

广告,扫描和连接都有参数,可让您在所需的功耗水平,延迟和这些过程的效率之间找到折衷方案。

广告

广告包括定期广播包含有关设备的有价值信息的少量数据。在 BLE 广告信道上监听的对等设备可以扫描这些分组。

扫描仪还可以通过发送扫描请求从设备广告中请求附加信息。如果广播公司接受扫描请求,则它可以使用包含附加信息的扫描响应包进行回复。

扫描

扫描包括侦听对等广告包。通过扫描,设备可以识别其环境中可用的设备。

如果设备主动扫描,它会向可扫描广告商发送扫描请求并收集其扫描响应。

隐私

隐私是一种允许设备避免被其他(不受信任的)设备跟踪的功能。该设备通过周期性地生成新的随机地址来实现它。随机地址可以是可解析的随机地址,使得可信设备能够将其识别为属于同一设备。这些可信设备在配对期间接收身份解析密钥(IRK)。 SecurityManager 处理此问题并依赖于接受和存储 IRK 的其他设备。

您需要在初始化 SecurityManager 之后调用 enablePrivacy() 来启用隐私,因为隐私需要 SecurityManager 来处理 IRK。使用 setCentralPrivacyConfiguration() 设置启用隐私的设备的行为,该设置指定设备使用随机地址的设备应该是什么,以及 setPeripheralPrivacyConfiguration。启用隐私的设备生成的随机地址可以是两种类型:可解析(由具有 IRK 的设备)和不可解析的。您不能使用无法解析的地址进行连接和可连接的广告;因此,无论隐私配置如何,都可以使用可解析的。

调制方案

当主机和控制器支持时,您可以选择不同的调制方案:

  • LE 1M PHY。
  • LE 2M PHY。
  • LE coded PHY。

这些在带宽,功率使用和错误恢复能力之间提供了不同的折衷(参见 BLUETOOTH SPECIFICATION Version 5.0 Vol 1,Part A-1.2)。

您可以使用 setPreferredPhys() 设置首选 PHY(分别用于 RX 和 TX)。您还可以使用 setPhy() 在所选连接上设置当前使用的 PHY。这两个设置都只是建议性的,并且允许控制器根据您的请求,对等方支持的功能和连接的物理条件,自行决定使用最佳PHY。

您可以使用 readPhy() 查询当前使用的 PHY,它通过调用注册的事件处理程序返回结果。您可以使用 setEventHandler() 注册该处理程序。事件通知当前使用的 PHY 以及 PHY 的任何变化,控制器或对等体可以自动触发。

GAP 类参考

Gap 类参考

数据结构
struct   AdvertisementCallbackParams_t
struct   CentralPrivacyConfiguration_t
struct   ConnectionCallbackParams_t
struct   ConnectionParams_t
struct   DisconnectionCallbackParams_t
struct   GapState_t
struct   PeripheralPrivacyConfiguration_t
struct   Whitelist_t
公共类型
enum   DeprecatedAddressType_t { ADDR_TYPE_PUBLIC = BLEProtocol::AddressType::PUBLIC, ADDR_TYPE_RANDOM_STATIC = BLEProtocol::AddressType::RANDOM_STATIC, ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE }
enum   TimeoutSource_t { TIMEOUT_SRC_ADVERTISING = 0x00, TIMEOUT_SRC_SECURITY_REQUEST = 0x01, TIMEOUT_SRC_SCAN = 0x02, TIMEOUT_SRC_CONN = 0x03 }
enum   DisconnectionReason_t {
  AUTHENTICATION_FAILURE = 0x05, CONNECTION_TIMEOUT = 0x08, REMOTE_USER_TERMINATED_CONNECTION = 0x13, REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES = 0x14,
  REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF = 0x15, LOCAL_HOST_TERMINATED_CONNECTION = 0x16, CONN_INTERVAL_UNACCEPTABLE = 0x3B
}
enum   AdvertisingPolicyMode_t { ADV_POLICY_IGNORE_WHITELIST = 0, ADV_POLICY_FILTER_SCAN_REQS = 1, ADV_POLICY_FILTER_CONN_REQS = 2, ADV_POLICY_FILTER_ALL_REQS = 3 }
enum   ScanningPolicyMode_t { SCAN_POLICY_IGNORE_WHITELIST = 0, SCAN_POLICY_FILTER_ALL_ADV = 1 }
enum   InitiatorPolicyMode_t { INIT_POLICY_IGNORE_WHITELIST = 0, INIT_POLICY_FILTER_ALL_ADV = 1 }
enum   Role_t { PERIPHERAL = 0x1, CENTRAL = 0x2 }
typedef BLEProtocol::AddressType_t  AddressType_t
typedef BLEProtocol::AddressType_t  addr_type_t
typedef BLEProtocol::AddressBytes_t  Address_t
typedef BLEProtocol::AddressBytes_t  address_t
typedef ble::connection_handle_t  Handle_t
typedef ble::random_address_type_t  RandomAddressType_t
typedef ble::peer_address_type_t  PeerAddressType_t
typedef FunctionPointerWithContext< const AdvertisementCallbackParams_t * >  AdvertisementReportCallback_t
typedef FunctionPointerWithContext< TimeoutSource_t TimeoutEventCallback_t
typedef CallChainOfFunctionPointersWithContext< TimeoutSource_t TimeoutEventCallbackChain_t
typedef FunctionPointerWithContext< const ConnectionCallbackParams_t * >  ConnectionEventCallback_t
typedef CallChainOfFunctionPointersWithContext< const ConnectionCallbackParams_t * >  ConnectionEventCallbackChain_t
typedef FunctionPointerWithContext< const DisconnectionCallbackParams_t * >  DisconnectionEventCallback_t
typedef CallChainOfFunctionPointersWithContext< const DisconnectionCallbackParams_t * >  DisconnectionEventCallbackChain_t
typedef FunctionPointerWithContext< bool >  RadioNotificationEventCallback_t
typedef FunctionPointerWithContext< const Gap * >  GapShutdownCallback_t
typedef CallChainOfFunctionPointersWithContext< const Gap * >  GapShutdownCallbackChain_t
公共成员函数
virtual ble_error_t  setAddress (BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address)
virtual ble_error_t  getAddress (BLEProtocol::AddressType_t *typeP, BLEProtocol::AddressBytes_t address)
virtual uint16_t  getMinAdvertisingInterval (void) const
virtual uint16_t  getMinNonConnectableAdvertisingInterval (void) const
virtual uint16_t  getMaxAdvertisingInterval (void) const
virtual ble_error_t  stopAdvertising (void)
virtual ble_error_t  stopScan ()
virtual ble_error_t  connect (const BLEProtocol::AddressBytes_t peerAddr, PeerAddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
virtual ble_error_t  connect (const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
ble_error_t  connect (const BLEProtocol::AddressBytes_t peerAddr, DeprecatedAddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
virtual ble_error_t  disconnect (Handle_t connectionHandle, DisconnectionReason_t reason)
virtual ble_error_t  disconnect (DisconnectionReason_t reason)
virtual ble_error_t  getPreferredConnectionParams (ConnectionParams_t *params)
virtual ble_error_t  setPreferredConnectionParams (const ConnectionParams_t *params)
virtual ble_error_t  updateConnectionParams (Handle_t handle, const ConnectionParams_t *params)
virtual ble_error_t  setDeviceName (const uint8_t *deviceName)
virtual ble_error_t  getDeviceName (uint8_t *deviceName, unsigned *lengthP)
virtual ble_error_t  setAppearance (GapAdvertisingData::Appearance appearance)
virtual ble_error_t  getAppearance (GapAdvertisingData::Appearance *appearanceP)
virtual ble_error_t  setTxPower (int8_t txPower)
virtual void  getPermittedTxPowerValues (const int8_t **valueArrayPP, size_t *countP)
virtual uint8_t  getMaxWhitelistSize (void) const
virtual ble_error_t  getWhitelist (Whitelist_t &whitelist) const
virtual ble_error_t  setWhitelist (const Whitelist_t &whitelist)
virtual ble_error_t  setAdvertisingPolicyMode (AdvertisingPolicyMode_t mode)
virtual ble_error_t  setScanningPolicyMode (ScanningPolicyMode_t mode)
virtual ble_error_t  setInitiatorPolicyMode (InitiatorPolicyMode_t mode)
virtual AdvertisingPolicyMode_t  getAdvertisingPolicyMode (void) const
virtual ScanningPolicyMode_t  getScanningPolicyMode (void) const
virtual InitiatorPolicyMode_t  getInitiatorPolicyMode (void) const
GapState_t  getState (void) const
void  setAdvertisingType (GapAdvertisingParams::AdvertisingType_t advType)
void  setAdvertisingInterval (uint16_t interval)
void  setAdvertisingTimeout (uint16_t timeout)
ble_error_t  startAdvertising (void)
void  clearAdvertisingPayload (void)
ble_error_t  accumulateAdvertisingPayload (uint8_t flags)
ble_error_t  accumulateAdvertisingPayload (GapAdvertisingData::Appearance app)
ble_error_t  accumulateAdvertisingPayloadTxPower (int8_t power)
ble_error_t  accumulateAdvertisingPayload (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
ble_error_t  updateAdvertisingPayload (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
ble_error_t  setAdvertisingPayload (const GapAdvertisingData &payload)
const GapAdvertisingData getAdvertisingPayload (void) const
ble_error_t  accumulateScanResponse (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
void  clearScanResponse (void)
ble_error_t  setScanParams (uint16_t interval=GapScanningParams::SCAN_INTERVAL_MAX, uint16_t window=GapScanningParams::SCAN_WINDOW_MAX, uint16_t timeout=0, bool activeScanning=false)
ble_error_t  setScanParams (const GapScanningParams &scanningParams)
ble_error_t  setScanInterval (uint16_t interval)
ble_error_t  setScanWindow (uint16_t window)
ble_error_t  setScanTimeout (uint16_t timeout)
ble_error_t  setActiveScanning (bool activeScanning)
ble_error_t  startScan (void(*callback)(const AdvertisementCallbackParams_t *params))
template<typename T >
ble_error_t  startScan (T *object, void(T::*callbackMember)(const AdvertisementCallbackParams_t *params))
virtual ble_error_t  initRadioNotification (void)
virtual ble_error_t  enablePrivacy (bool enable)
virtual ble_error_t  setPeripheralPrivacyConfiguration (const PeripheralPrivacyConfiguration_t *configuration)
virtual ble_error_t  getPeripheralPrivacyConfiguration (PeripheralPrivacyConfiguration_t *configuration)
virtual ble_error_t  setCentralPrivacyConfiguration (const CentralPrivacyConfiguration_t *configuration)
virtual ble_error_t  getCentralPrivacyConfiguration (CentralPrivacyConfiguration_t *configuration)
GapAdvertisingParams getAdvertisingParams (void)
const GapAdvertisingParams getAdvertisingParams (void) const
void  setAdvertisingParams (const GapAdvertisingParams &newParams)
void  onTimeout (TimeoutEventCallback_t callback)
TimeoutEventCallbackChain_t onTimeout ()
void  onConnection (ConnectionEventCallback_t callback)
template<typename T >
void  onConnection (T *tptr, void(T::*mptr)(const ConnectionCallbackParams_t *))
ConnectionEventCallbackChain_t onConnection ()
void  onDisconnection (DisconnectionEventCallback_t callback)
template<typename T >
void  onDisconnection (T *tptr, void(T::*mptr)(const DisconnectionCallbackParams_t *))
DisconnectionEventCallbackChain_t onDisconnection ()
void  onRadioNotification (void(*callback)(bool param))
template<typename T >
void  onRadioNotification (T *tptr, void(T::*mptr)(bool))
void  onShutdown (const GapShutdownCallback_t &callback)
template<typename T >
void  onShutdown (T *objPtr, void(T::*memberPtr)(const Gap *))
GapShutdownCallbackChain_t onShutdown ()
virtual ble_error_t  reset (void)
void  processConnectionEvent (Handle_t handle, Role_t role, PeerAddressType_t peerAddrType, const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t ownAddrType, const BLEProtocol::AddressBytes_t ownAddr, const ConnectionParams_t *connectionParams, const uint8_t *peerResolvableAddr=NULL, const uint8_t *localResolvableAddr=NULL)
void  processConnectionEvent (Handle_t handle, Role_t role, BLEProtocol::AddressType_t peerAddrType, const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t ownAddrType, const BLEProtocol::AddressBytes_t ownAddr, const ConnectionParams_t *connectionParams, const uint8_t *peerResolvableAddr=NULL, const uint8_t *localResolvableAddr=NULL)
void  processDisconnectionEvent (Handle_t handle, DisconnectionReason_t reason)
void  processAdvertisementReport (const BLEProtocol::AddressBytes_t peerAddr, int8_t rssi, bool isScanResponse, GapAdvertisingParams::AdvertisingType_t type, uint8_t advertisingDataLen, const uint8_t *advertisingData, PeerAddressType_t addressType)
void  processAdvertisementReport (const BLEProtocol::AddressBytes_t peerAddr, int8_t rssi, bool isScanResponse, GapAdvertisingParams::AdvertisingType_t type, uint8_t advertisingDataLen, const uint8_t *advertisingData, BLEProtocol::AddressType_t addressType=BLEProtocol::AddressType::RANDOM_STATIC)
void  processTimeoutEvent (TimeoutSource_t source)
静态公共成员函数
static uint16_t  MSEC_TO_GAP_DURATION_UNITS (uint32_t durationInMillis)
static ble_error_t  getRandomAddressType (const BLEProtocol::AddressBytes_t address, RandomAddressType_t *addressType)
静态公共属性
static const unsigned  ADDR_LEN = BLEProtocol::ADDR_LEN
static const uint16_t  UNIT_1_25_MS = 1250
static const PeripheralPrivacyConfiguration_t  default_peripheral_privacy_configuration
static const CentralPrivacyConfiguration_t  default_central_privacy_configuration
受保护的成员函数
virtual ble_error_t  startRadioScan (const GapScanningParams &scanningParams)
  Gap ()
受保护的属性
GapAdvertisingParams  _advParams
GapAdvertisingData  _advPayload
GapScanningParams  _scanningParams
GapAdvertisingData  _scanResponse
uint8_t  connectionCount
GapState_t  state
bool  scanningActive
TimeoutEventCallbackChain_t  timeoutCallbackChain
RadioNotificationEventCallback_t  radioNotificationCallback
AdvertisementReportCallback_t  onAdvertisementReport
ConnectionEventCallbackChain_t  connectionCallChain
DisconnectionEventCallbackChain_t  disconnectionCallChain

GAP 示例

这是一个示例,演示如何使用 GAP API 来通告,扫描,连接和断开连接以及参数如何影响这些操作的效率。

main.cpp                                                                                                                                                 导入到 Mbed IDE

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"

/** This example demonstrates all the basic setup required
 *  to advertise, scan and connect to other devices.
 *
 *  It contains a single class that performs both scans and advertisements.
 *
 *  The demonstrations happens in sequence, after each "mode" ends
 *  the demo jumps to the next mode to continue. There are several modes
 *  that show scanning and several showing advertising. These are configured
 *  according to the two arrays containing parameters. During scanning
 *  a connection will be made to a connectable device upon its discovery.
 */

static const uint8_t DEVICE_NAME[]        = "GAP_device";

/* Duration of each mode in milliseconds */
static const size_t MODE_DURATION_MS      = 6000;

/* Time between each mode in milliseconds */
static const size_t TIME_BETWEEN_MODES_MS = 2000;

/* how long to wait before disconnecting in milliseconds */
static const size_t CONNECTION_DURATION = 3000;

typedef struct {
    GapAdvertisingParams::AdvertisingType_t adv_type;
    uint16_t interval;
    uint16_t timeout;
} AdvModeParam_t;

typedef struct {
    uint16_t interval;
    uint16_t window;
    uint16_t timeout;
    bool active;
} ScanModeParam_t;

/** the entries in this array are used to configure our advertising
 *  parameters for each of the modes we use in our demo */
static const AdvModeParam_t advertising_params[] = {
    /*            advertising type                        interval  timeout */
    { GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED,      40,/*ms*/ 3/*s*/},
    { GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED,       100,       4     },
    { GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED, 100,       0     }
};

/* when we cycle through all our advertising modes we will move to scanning modes */

/** the entries in this array are used to configure our scanning
 *  parameters for each of the modes we use in our demo */
static const ScanModeParam_t scanning_params[] = {
/* interval      window    timeout       active */
    {   4,/*ms*/   4,/*ms*/   0,/*s*/    false },
    { 160,       100,         3,         false },
    { 160,        40,         0,         true  },
    { 500,        10,         0,         false }
};

/* parameters to use when attempting to connect to maximise speed of connection */
static const GapScanningParams connection_scan_params(
    GapScanningParams::SCAN_INTERVAL_MAX,
    GapScanningParams::SCAN_WINDOW_MAX,
    3,
    false
);

/* get number of items in our arrays */
static const size_t SCAN_PARAM_SET_MAX =
    sizeof(scanning_params) / sizeof(GapScanningParams);
static const size_t ADV_PARAM_SET_MAX  =
    sizeof(advertising_params) / sizeof(GapAdvertisingParams);


/** Demonstrate advertising, scanning and connecting
 */
class GAPDevice : private mbed::NonCopyable<GAPDevice>
{
public:
    GAPDevice() :
        _ble(BLE::Instance()),
        _led1(LED1, 0),
        _set_index(0),
        _is_in_scanning_mode(false),
        _is_connecting(false),
        _on_duration_end_id(0),
        _scan_count(0) { };

    ~GAPDevice()
    {
        if (_ble.hasInitialized()) {
            _ble.shutdown();
        }
    };

    /** Start BLE interface initialisation */
    void run()
    {
        ble_error_t error;

        if (_ble.hasInitialized()) {
            printf("Ble instance already initialised.\r\n");
            return;
        }

        /* this will inform us off all events so we can schedule their handling
         * using our event queue */
        _ble.onEventsToProcess(
            makeFunctionPointer(this, &GAPDevice::schedule_ble_events)
        );

        /* handle timeouts, for example when connection attempts fail */
        _ble.gap().onTimeout(
            makeFunctionPointer(this, &GAPDevice::on_timeout)
        );

        error = _ble.init(this, &GAPDevice::on_init_complete);

        if (error) {
            printf("Error returned by BLE::init.\r\n");
            return;
        }

        /* to show we're running we'll blink every 500ms */
        _event_queue.call_every(500, this, &GAPDevice::blink);

        /* this will not return until shutdown */
        _event_queue.dispatch_forever();
    };

private:
    /** This is called when BLE interface is initialised and starts the first mode */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
    {
        if (event->error) {
            printf("Error during the initialisation\r\n");
            return;
        }

        /* print device address */
        Gap::AddressType_t addr_type;
        Gap::Address_t addr;
        _ble.gap().getAddress(&addr_type, addr);
        printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
               addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);

        /* all calls are serialised on the user thread through the event queue */
        _event_queue.call(this, &GAPDevice::demo_mode_start);
    };

    /** queue up start of the current demo mode */
    void demo_mode_start()
    {
        if (_is_in_scanning_mode) {
            /* when scanning we want to connect to a peer device so we need to
             * attach callbacks that are used by Gap to notify us of events */
            _ble.gap().onConnection(this, &GAPDevice::on_connect);
            _ble.gap().onDisconnection(this, &GAPDevice::on_disconnect);

            _event_queue.call(this, &GAPDevice::scan);
        } else {
            _event_queue.call(this, &GAPDevice::advertise);
        }

        /* for performance measurement keep track of duration of the demo mode */
        _demo_duration.start();
        /* keep track of our state */
        _is_connecting = false;

        /* queue up next demo mode */
        _on_duration_end_id = _event_queue.call_in(
            MODE_DURATION_MS, this, &GAPDevice::on_duration_end
        );

        printf("\r\n");
    }

    /** Set up and start advertising */
    void advertise()
    {
        ble_error_t error;
        GapAdvertisingData advertising_data;

        /* add advertising flags */
        advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE
                                  | GapAdvertisingData::BREDR_NOT_SUPPORTED);

        /* add device name */
        advertising_data.addData(
            GapAdvertisingData::COMPLETE_LOCAL_NAME,
            DEVICE_NAME,
            sizeof(DEVICE_NAME)
        );

        error = _ble.gap().setAdvertisingPayload(advertising_data);

        if (error) {
            printf("Error during Gap::setAdvertisingPayload\r\n");
            return;
        }

        /* set the advertising parameters according to currently selected set,
         * see @AdvertisingType_t for explanation of modes */
        GapAdvertisingParams::AdvertisingType_t adv_type =
            advertising_params[_set_index].adv_type;

        /* how many milliseconds between advertisements, lower interval
         * increases the chances of being seen at the cost of more power */
        uint16_t interval = advertising_params[_set_index].interval;

        /* advertising will continue for this many seconds or until connected */
        uint16_t timeout = advertising_params[_set_index].timeout;

        _ble.gap().setAdvertisingType(adv_type);
        _ble.gap().setAdvertisingInterval(interval);
        _ble.gap().setAdvertisingTimeout(timeout);

        error = _ble.gap().startAdvertising();

        if (error) {
            printf("Error during Gap::startAdvertising.\r\n");
            return;
        }

        printf("Advertising started (type: 0x%x, interval: %dms, timeout: %ds)\r\n",
               adv_type, interval, timeout);
    };

    /** Set up and start scanning */
    void scan()
    {
        ble_error_t error;

        /* scanning happens repeatedly, interval is the number of milliseconds
         * between each cycle of scanning */
        uint16_t interval = scanning_params[_set_index].interval;

        /* number of milliseconds we scan for each time we enter
         * the scanning cycle after the interval set above */
        uint16_t window = scanning_params[_set_index].window;

        /* how long to repeat the cycles of scanning in seconds */
        uint16_t timeout = scanning_params[_set_index].timeout;

        /* active scanning will send a scan request to any scanable devices that
         * we see advertising */
        bool active = scanning_params[_set_index].active;

        /* set the scanning parameters according to currently selected set */
        error = _ble.gap().setScanParams(interval, window, timeout, active);

        if (error) {
            printf("Error during Gap::setScanParams\r\n");
            return;
        }

        /* start scanning and attach a callback that will handle advertisements
         * and scan requests responses */
        error = _ble.gap().startScan(this, &GAPDevice::on_scan);

        if (error) {
            printf("Error during Gap::startScan\r\n");
            return;
        }

        printf("Scanning started (interval: %dms, window: %dms, timeout: %ds).\r\n",
               interval, window, timeout);
    };

    /** After a set duration this cycles to the next demo mode
     *  unless a connection happened first */
    void on_duration_end()
    {
        print_performance();

        /* alloted time has elapsed, move to next demo mode */
        _event_queue.call(this, &GAPDevice::demo_mode_end);
    };

    /** Look at scan payload to find a peer device and connect to it */
    void on_scan(const Gap::AdvertisementCallbackParams_t *params)
    {
        /* keep track of scan events for performance reporting */
        _scan_count++;

        /* don't bother with analysing scan result if we're already connecting */
        if (_is_connecting) {
            return;
        }

        /* parse the advertising payload, looking for a discoverable device */
        for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
            /* The advertising payload is a collection of key/value records where
             * byte 0: length of the record excluding this byte
             * byte 1: The key, it is the type of the data
             * byte [2..N] The value. N is equal to byte0 - 1 */
            const uint8_t record_length = params->advertisingData[i];
            if (record_length == 0) {
                continue;
            }
            const uint8_t type = params->advertisingData[i + 1];
            const uint8_t *value = params->advertisingData + i + 2;

            /* connect to a discoverable device */
            if ((type == GapAdvertisingData::FLAGS)
                && (*value & GapAdvertisingData::LE_GENERAL_DISCOVERABLE)) {

                /* abort timeout as the mode will end on disconnection */
                _event_queue.cancel(_on_duration_end_id);

                printf("We found a connectable device\r\n");

                ble_error_t error = _ble.gap().connect(
                    params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC,
                    NULL, &connection_scan_params
                );

                if (error) {
                    printf("Error during Gap::connect\r\n");
                    /* since no connection will be attempted end the mode */
                    _event_queue.call(this, &GAPDevice::demo_mode_end);
                    return;
                }

                /* we may have already scan events waiting
                 * to be processed so we need to remember
                 * that we are already connecting and ignore them */
                _is_connecting = true;

                return;
            }

            i += record_length;
        }
    };

    /** This is called by Gap to notify the application we connected,
     *  in our case it immediately disconnects */
    void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
    {
        print_performance();

        printf("Connected in %dms\r\n", _demo_duration.read_ms());

        /* cancel the connect timeout since we connected */
        _event_queue.cancel(_on_duration_end_id);

        _event_queue.call_in(
            CONNECTION_DURATION, &_ble.gap(), &Gap::disconnect, Gap::REMOTE_USER_TERMINATED_CONNECTION
        );
    };

    /** This is called by Gap to notify the application we disconnected,
     *  in our case it calls demo_mode_end() to progress the demo */
    void on_disconnect(const Gap::DisconnectionCallbackParams_t *event)
    {
        printf("Disconnected\r\n");

        /* we have successfully disconnected ending the demo, move to next mode */
        _event_queue.call(this, &GAPDevice::demo_mode_end);
    };

    /** called if timeout is reached during advertising, scanning
     *  or connection initiation */
    void on_timeout(const Gap::TimeoutSource_t source)
    {
        _demo_duration.stop();

        switch (source) {
            case Gap::TIMEOUT_SRC_ADVERTISING:
                printf("Stopped advertising early due to timeout parameter\r\n");
                break;
            case Gap::TIMEOUT_SRC_SCAN:
                printf("Stopped scanning early due to timeout parameter\r\n");
                break;
            case Gap::TIMEOUT_SRC_CONN:
                printf("Failed to connect after scanning %d advertisements\r\n", _scan_count);
                _event_queue.call(this, &GAPDevice::print_performance);
                _event_queue.call(this, &GAPDevice::demo_mode_end);
                break;
            default:
                printf("Unexpected timeout\r\n");
                break;
        }
    };

    /** clean up after last run, cycle to the next mode and launch it */
    void demo_mode_end()
    {
        /* reset the demo ready for the next mode */
        _scan_count = 0;
        _demo_duration.stop();
        _demo_duration.reset();

        /* cycle through all demo modes */
        _set_index++;

        /* switch between advertising and scanning when we go
         * through all the params in the array */
        if (_set_index >= (_is_in_scanning_mode? SCAN_PARAM_SET_MAX : ADV_PARAM_SET_MAX)) {
            _set_index = 0;
            _is_in_scanning_mode = !_is_in_scanning_mode;
        }

        _ble.shutdown();
        _event_queue.break_dispatch();
    };

    /** print some information about our radio activity */
    void print_performance()
    {
        /* measure time from mode start, may have been stopped by timeout */
        uint16_t duration = _demo_duration.read_ms();

        if (_is_in_scanning_mode) {
            /* convert ms into timeslots for accurate calculation as internally
             * all durations are in timeslots (0.625ms) */
            uint16_t interval_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                scanning_params[_set_index].interval
            );
            uint16_t window_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                scanning_params[_set_index].window
            );
            uint16_t duration_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                duration
            );
            /* this is how long we scanned for in timeslots */
            uint16_t rx_ts = (duration_ts / interval_ts) * window_ts;
            /* convert to milliseconds */
            uint16_t rx_ms = (rx_ts * GapScanningParams::UNIT_0_625_MS) / 1000;

            printf("We have scanned for %dms with an interval of %d"
                    " timeslot and a window of %d timeslots\r\n",
                    duration, interval_ts, window_ts);

            printf("We have been listening on the radio for at least %dms\r\n", rx_ms);

        } else /* advertising */ {

            /* convert ms into timeslots for accurate calculation as internally
             * all durations are in timeslots (0.625ms) */
            uint16_t interval_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
                advertising_params[_set_index].interval
            );
            uint16_t duration_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
                duration
            );
            /* this is how many times we advertised */
            uint16_t events = duration_ts / interval_ts;

            printf("We have advertised for %dms"
                   " with an interval of %d timeslots\r\n",
                   duration, interval_ts);

            /* non-scannable and non-connectable advertising
             * skips rx events saving on power consumption */
            if (advertising_params[_set_index].adv_type
                == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
                printf("We created at least %d tx events\r\n", events);
            } else {
                printf("We created at least %d tx and rx events\r\n", events);
            }
        }
    };

    /** Schedule processing of events from the BLE middleware in the event queue. */
    void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
    {
        _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
    };

    /** Blink LED to show we're running */
    void blink(void)
    {
        _led1 = !_led1;
    };

private:
    BLE                &_ble;
    events::EventQueue  _event_queue;
    DigitalOut          _led1;

    /* Keep track of our progress through demo modes */
    size_t              _set_index;
    bool                _is_in_scanning_mode;
    bool                _is_connecting;

    /* Remember the call id of the function on _event_queue
     * so we can cancel it if we need to end the mode early */
    int                 _on_duration_end_id;

    /* Measure performance of our advertising/scanning */
    Timer               _demo_duration;
    size_t              _scan_count;
};

int main()
{
    GAPDevice gap_device;

    while (1) {
        gap_device.run();
        wait_ms(TIME_BETWEEN_MODES_MS);
        printf("\r\nStarting next GAP demo mode\r\n");
    };

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u012325601/article/details/82080772