mirror of https://github.com/ARMmbed/mbed-os.git
460 lines
14 KiB
C++
460 lines
14 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2018 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.
|
|
*/
|
|
|
|
#ifndef MBED_EXTENDED_CONNECT_PARAMETERS_H__
|
|
#define MBED_EXTENDED_CONNECT_PARAMETERS_H__
|
|
|
|
#include "ble/BLETypes.h"
|
|
#include "mbed_assert.h"
|
|
|
|
namespace ble {
|
|
|
|
/**
|
|
* @addtogroup ble
|
|
* @{
|
|
* @addtogroup gap
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Parameters defining the connection initiation process.
|
|
*
|
|
* The connection initiation process is divided in two different phases. First
|
|
* the initiating device scan for the peer it should connect. Once the peer has
|
|
* been found, it sends a connection request that contains the connection
|
|
* parameters.
|
|
*
|
|
* @par Scan parameters
|
|
*
|
|
* The scan parameters are defined by two durations: the scan interval and the
|
|
* scan window. The scan interval is the duration between two scan cycle and the
|
|
* scan window defines how long the device search during a scan cycle.
|
|
*
|
|
* The scan window and the scan interval can be set at construction time or by
|
|
* calling setScanParameters().
|
|
*
|
|
* @par Connection parameters
|
|
*
|
|
* A Bluetooth connection is defined by three parameters:
|
|
* - Connection interval: The time between two connection events. A minimum
|
|
* and a maximum connection interval are requested to help the Bluetooth
|
|
* subsystem deal with concurrent radio processing.
|
|
* - Slave latency: Number of connection events that can be ignored by the
|
|
* slave.
|
|
* - Supervision timeout: Time after which the connection is considered lost
|
|
* if the connected devices haven't exchanged a single packet. It is important
|
|
* to note that even if the application doesn't send actual data, the Bluetooth
|
|
* controller takes care of sending empty data packets to maintain the
|
|
* connection alive.
|
|
*
|
|
* These parameters can be set at construction time or by calling the function
|
|
* setConnectionParameters().
|
|
*
|
|
* @par PHY
|
|
*
|
|
* Bluetooth 5 have introduced the support of different physical layer to either
|
|
* increase the range or the throughput. Multiple PHY can be configured
|
|
* independently for scanning and connecting.
|
|
*
|
|
* Legacy connection happens on the 1M PHY (phy_t::LE_1M). It is the only PHY
|
|
* that can be configured on legacy systems.
|
|
*
|
|
* The constructor, setScanParameters() and setConnectionParameters() accept
|
|
* a phy_t parameter that defines to which PHY the parameters set applies.
|
|
*
|
|
* @par Other parameters:
|
|
*
|
|
* It is possible to defined what type of address is used to establish the
|
|
* connection and whether or not if the whitelist should be used to find the peer
|
|
* to connect to.
|
|
*
|
|
* @par Example:
|
|
*
|
|
* Thanks to the fluent API it is easy to compose the connection parameters at
|
|
* instantiation point:
|
|
*
|
|
* @code
|
|
*
|
|
void do_connect(ble::Gap& gap, ble::target_peer_address_type_t addr_type, ble::address_t& address)
|
|
{
|
|
using namespace ble;
|
|
|
|
gap.connect(
|
|
addr_type,
|
|
address,
|
|
ConnectionParameters()
|
|
.setScanParameters(
|
|
phy_t::LE_1M,
|
|
scan_interval_t(millisecond_t(500)),
|
|
scan_window_t(millisecond_t(250))
|
|
)
|
|
.setConnectionParameters(
|
|
phy_t::LE_1M,
|
|
conn_interval_t(millisecond_t(100)),
|
|
conn_interval_t(millisecond_t(200)),
|
|
slave_latency_t(0),
|
|
supervision_timeout_t(millisecond_t(1000))
|
|
)
|
|
.setOwnAddressType(own_address_type_t::RANDOM)
|
|
);
|
|
}
|
|
*
|
|
* @endcode
|
|
*
|
|
* @note It is not possible to configure phy_t::LE_2M for scanning.
|
|
*
|
|
* @see ble::Gap::connect()
|
|
*/
|
|
class ConnectionParameters {
|
|
enum {
|
|
LE_1M_INDEX = 0,
|
|
LE_2M_INDEX = 1,
|
|
LE_CODED_INDEX = 2,
|
|
MAX_PARAM_PHYS = 3
|
|
};
|
|
|
|
public:
|
|
/**
|
|
* Create a ConnectionParameters object.
|
|
*
|
|
* @param phy The PHY being configured.
|
|
* @param scanInterval Interval between two scans.
|
|
* @param scanWindow Scan duration during a scan interval.
|
|
* @param minConnectionInterval Minimum value of the connection interval.
|
|
* @param maxConnectionInterval Maximum value of the connection interval.
|
|
* @param slaveLatency Maximum number of packets the slave can drop.
|
|
* @param connectionSupervisionTimeout Time after which the connection is
|
|
* considered lost if no data exchanged have taken place.
|
|
* @param minEventLength Minimum duration of a connection event.
|
|
* @param maxEventLength Maximum duration of a connection event
|
|
*/
|
|
ConnectionParameters(
|
|
phy_t phy = phy_t::LE_1M,
|
|
scan_interval_t scanInterval = scan_interval_t::min(),
|
|
scan_window_t scanWindow = scan_window_t::min(),
|
|
conn_interval_t minConnectionInterval = conn_interval_t::min(),
|
|
conn_interval_t maxConnectionInterval = conn_interval_t::max(),
|
|
slave_latency_t slaveLatency = slave_latency_t::min(),
|
|
supervision_timeout_t connectionSupervisionTimeout = supervision_timeout_t::max(),
|
|
conn_event_length_t minEventLength = conn_event_length_t::min(),
|
|
conn_event_length_t maxEventLength = conn_event_length_t::max()
|
|
);
|
|
|
|
/* setters */
|
|
|
|
/**
|
|
* Set the scan parameters for a given PHY.
|
|
*
|
|
* @param phy PHY being configured.
|
|
* @param scanInterval Interval between two scans.
|
|
* @param scanWindow Scan duration within a scan interval.
|
|
*
|
|
* @note It is useless to configure the 2M PHY as it is not used during
|
|
* scanning.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &setScanParameters(
|
|
phy_t phy,
|
|
scan_interval_t scanInterval,
|
|
scan_window_t scanWindow
|
|
);
|
|
|
|
/**
|
|
* Set the conenction parameters of a given PHY.
|
|
*
|
|
* @param phy The PHY being configured.
|
|
* @param minConnectionInterval Minimum connection interval.
|
|
* @param maxConnectionInterval Maximum connection interval.
|
|
* @param slaveLatency Maximum number of packets the slave can drop.
|
|
* @param connectionSupervisionTimeout Time after which the connection is
|
|
* considered lost if no data exchanged have taken place.
|
|
* @param minEventLength Minimum duration of a connection event.
|
|
* @param maxEventLength Maximum duration of a connection event.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &setConnectionParameters(
|
|
phy_t phy,
|
|
conn_interval_t minConnectionInterval,
|
|
conn_interval_t maxConnectionInterval,
|
|
slave_latency_t slaveLatency,
|
|
supervision_timeout_t connectionSupervisionTimeout,
|
|
conn_event_length_t minEventLength = conn_event_length_t::min(),
|
|
conn_event_length_t maxEventLength = conn_event_length_t::max()
|
|
);
|
|
|
|
/**
|
|
* Address type used by the local device to connect the peer.
|
|
* @param ownAddress Type of address used to initiate the connection.
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &setOwnAddressType(own_address_type_t ownAddress)
|
|
{
|
|
_ownAddressType = ownAddress;
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Set if the whitelist should be used to find the peer.
|
|
*
|
|
* @param filterPolicy The initiator filter to apply.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &setFilterPolicy(initiator_filter_policy_t filterPolicy)
|
|
{
|
|
_filterPolicy = filterPolicy;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Enable or disable phys.
|
|
*
|
|
* @param phy1M true to enable the 1M PHY and false to disable it.
|
|
* @param phy2M true to enable the 2M PHY and false to disable it.
|
|
* @param phyCoded true to enable the CODED PHY and false to disable it.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &togglePhy(bool phy1M, bool phy2M, bool phyCoded)
|
|
{
|
|
handlePhyToggle(phy_t::LE_1M, phy1M);
|
|
handlePhyToggle(phy_t::LE_2M, phy2M);
|
|
handlePhyToggle(phy_t::LE_CODED, phyCoded);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Disable an individual PHY.
|
|
*
|
|
* @param phy The PHY to disable.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &disablePhy(phy_t phy = phy_t::LE_1M)
|
|
{
|
|
handlePhyToggle(phy, false);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Enable an individual PHY.
|
|
*
|
|
* @param phy The PHY to enable.
|
|
*
|
|
* @return A reference to this.
|
|
*/
|
|
ConnectionParameters &enablePhy(phy_t phy = phy_t::LE_1M)
|
|
{
|
|
handlePhyToggle(phy, true);
|
|
return *this;
|
|
}
|
|
|
|
/* getters */
|
|
|
|
/**
|
|
* Return the local address type used.
|
|
*
|
|
* @return The local address type to use.
|
|
*/
|
|
own_address_type_t getOwnAddressType() const
|
|
{
|
|
return _ownAddressType;
|
|
}
|
|
|
|
/**
|
|
* Return the initiator policy.
|
|
*
|
|
* @return The initiator policy.
|
|
*/
|
|
initiator_filter_policy_t getFilterPolicy() const
|
|
{
|
|
return _filterPolicy;
|
|
}
|
|
|
|
/**
|
|
* Return the number of PHY enabled.
|
|
* @return The number of PHY enabled.
|
|
*/
|
|
uint8_t getNumberOfEnabledPhys() const
|
|
{
|
|
return (
|
|
_enabledPhy[LE_1M_INDEX] * 1 +
|
|
_enabledPhy[LE_2M_INDEX] * 1 +
|
|
_enabledPhy[LE_CODED_INDEX] * 1
|
|
);
|
|
}
|
|
|
|
#if !defined(DOXYGEN_ONLY)
|
|
|
|
phy_set_t getPhySet() const
|
|
{
|
|
phy_set_t set(
|
|
_enabledPhy[LE_1M_INDEX],
|
|
_enabledPhy[LE_2M_INDEX],
|
|
_enabledPhy[LE_CODED_INDEX]
|
|
);
|
|
return set;
|
|
}
|
|
|
|
/* these return pointers to arrays of settings valid only across the number of active PHYs */
|
|
|
|
const uint16_t *getScanIntervalArray() const
|
|
{
|
|
return &_scanInterval[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getScanWindowArray() const
|
|
{
|
|
return &_scanWindow[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getMinConnectionIntervalArray() const
|
|
{
|
|
return &_minConnectionInterval[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getMaxConnectionIntervalArray() const
|
|
{
|
|
return &_maxConnectionInterval[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getSlaveLatencyArray() const
|
|
{
|
|
return &_slaveLatency[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getConnectionSupervisionTimeoutArray() const
|
|
{
|
|
return &_connectionSupervisionTimeout[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getMinEventLengthArray() const
|
|
{
|
|
return &_minEventLength[getFirstEnabledIndex()];
|
|
}
|
|
|
|
const uint16_t *getMaxEventLengthArray() const
|
|
{
|
|
return &_maxEventLength[getFirstEnabledIndex()];
|
|
}
|
|
|
|
#endif
|
|
|
|
private:
|
|
uint8_t getFirstEnabledIndex() const
|
|
{
|
|
if (_enabledPhy[LE_1M_INDEX]) {
|
|
return LE_1M_INDEX;
|
|
} else if (_enabledPhy[LE_2M_INDEX]) {
|
|
return LE_2M_INDEX;
|
|
} else if (_enabledPhy[LE_CODED_INDEX]) {
|
|
return LE_CODED_INDEX;
|
|
}
|
|
/* this should never happen, it means you were trying to start a connection with a blank set
|
|
* of paramters - you need to enabled at least one PHY */
|
|
MBED_ASSERT("Trying to use connection parameters without any PHY defined.");
|
|
return 0;
|
|
}
|
|
|
|
/** Handle toggling PHYs on and off and return the correct index to use to set the configuration elements.
|
|
*
|
|
* @param phy Which PHY is being toggle.
|
|
* @param enable On or Off.
|
|
* @return The index to the array of settings.
|
|
*/
|
|
uint8_t handlePhyToggle(phy_t phy, bool enable)
|
|
{
|
|
uint8_t index = phyToIndex(phy);
|
|
|
|
bool was_swapped = isSwapped();
|
|
|
|
_enabledPhy[index] = enable;
|
|
|
|
bool is_swapped = isSwapped();
|
|
|
|
if (was_swapped != is_swapped) {
|
|
swapCodedAnd2M();
|
|
}
|
|
|
|
if (is_swapped && index == LE_CODED_INDEX) {
|
|
/* to keep the data contiguous coded params are in place of the missing 2M params */
|
|
index = LE_2M_INDEX;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
uint8_t phyToIndex(phy_t phy) const
|
|
{
|
|
uint8_t index;
|
|
switch (phy.value()) {
|
|
case phy_t::LE_1M:
|
|
index = LE_1M_INDEX;
|
|
break;
|
|
case phy_t::LE_2M:
|
|
index = LE_2M_INDEX;
|
|
break;
|
|
case phy_t::LE_CODED:
|
|
index = LE_CODED_INDEX;
|
|
break;
|
|
default:
|
|
index = MAX_PARAM_PHYS;
|
|
MBED_ASSERT("Illegal PHY");
|
|
break;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
bool isSwapped() const
|
|
{
|
|
return (
|
|
_enabledPhy[LE_1M_INDEX] &&
|
|
!_enabledPhy[LE_2M_INDEX] &&
|
|
_enabledPhy[LE_CODED_INDEX]
|
|
);
|
|
}
|
|
|
|
/** Handle the swapping of 2M and CODED so that the array is ready for the pal call. */
|
|
void swapCodedAnd2M();
|
|
|
|
private:
|
|
initiator_filter_policy_t _filterPolicy;
|
|
own_address_type_t _ownAddressType;
|
|
|
|
uint16_t _scanInterval[MAX_PARAM_PHYS]; /* 0.625 ms */
|
|
uint16_t _scanWindow[MAX_PARAM_PHYS]; /* 0.625 ms */
|
|
uint16_t _minConnectionInterval[MAX_PARAM_PHYS]; /* 1.25 ms */
|
|
uint16_t _maxConnectionInterval[MAX_PARAM_PHYS]; /* 1.25 ms */
|
|
uint16_t _slaveLatency[MAX_PARAM_PHYS]; /* events */
|
|
uint16_t _connectionSupervisionTimeout[MAX_PARAM_PHYS]; /* 10 ms */
|
|
uint16_t _minEventLength[MAX_PARAM_PHYS]; /* 0.625 ms */
|
|
uint16_t _maxEventLength[MAX_PARAM_PHYS]; /* 0.625 ms */
|
|
|
|
bool _enabledPhy[MAX_PARAM_PHYS];
|
|
};
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|
|
|
|
} // namespace ble
|
|
|
|
#endif /* ifndef MBED_EXTENDED_CONNECT_PARAMETERS_H__ */
|