diff --git a/features/FEATURE_BLE/ble/BLETypes.h b/features/FEATURE_BLE/ble/BLETypes.h index f30a4da2d0..e5bbbb72ee 100644 --- a/features/FEATURE_BLE/ble/BLETypes.h +++ b/features/FEATURE_BLE/ble/BLETypes.h @@ -628,23 +628,98 @@ struct phy_t : SafeEnum { }; /** - * Type that describe a set of PHY(sical) transports. + * Type that describe a set of PHY(sical) transports. This is used to + * indicate preference for the PHY transports set within it. */ -struct phys_t { - /** - * If equal to 1 then the set includes phy_t::LE_1M. - */ - uint8_t le_1m:1; +class phy_set_t { +public: + enum PhysFlags_t { + PHY_SET_1M = 0x01, + PHY_SET_2M = 0x02, + PHY_SET_CODED = 0x04 + }; + + phy_set_t() : _value(0) { } + phy_set_t(uint8_t value) : _value(value) { } + phy_set_t( + bool phy_1m, + bool phy_2m, + bool phy_coded + ) { + set_1m(phy_1m); + set_2m(phy_2m); + set_coded(phy_coded); + } /** - * If equal to 1 then the set includes phy_t::LE_2M. + * Create an ALL_PHYS parameter used in LE Set PHY Command + * and LE Set Default PHY Command. + * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E - 7.8.49 */ - uint8_t le_2m:1; + static uint8_t all_phys_value( + const phy_set_t& tx_phys, + const phy_set_t& rx_phys + ) { + /* if phy set is empty set corresponding all_phys bit to 1 */ + uint8_t all_phys = 0; + if (tx_phys.value() == 0) { + all_phys |= 0x01; + } + if (rx_phys.value() == 0) { + all_phys |= 0x02; + } + return all_phys; + } - /** - * If equal to 1 then the set includes phy_t::LE_CODED. - */ - uint8_t le_coded:1; + /** Prefer 1M PHY. */ + void set_1m(bool enabled = true) { + if (enabled) { + _value |= PHY_SET_1M; + } else { + _value &= ~PHY_SET_1M; + } + } + + /** Prefer 2M PHY. */ + void set_2m(bool enabled = true) { + if (enabled) { + _value |= PHY_SET_2M; + } else { + _value &= ~PHY_SET_2M; + } + } + + /** Prefer coded PHY. */ + void set_coded(bool enabled = true) { + if (enabled) { + _value |= PHY_SET_CODED; + } else { + _value &= ~PHY_SET_CODED; + } + } + + bool get_1m() { + return (_value & PHY_SET_1M); + } + + bool get_2m() { + return (_value & PHY_SET_2M); + } + + bool get_coded() { + return (_value & PHY_SET_CODED); + } + + operator uint8_t() { + return _value; + } + + uint8_t value() const { + return _value; + } + +private: + uint8_t _value; }; /** diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index cc146e2c7f..dd834fbbec 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -555,7 +555,7 @@ public: /** * Set of BLE PHYs */ - typedef ble::phys_t Phys_t; + typedef ble::phy_set_t PhySet_t; /** * Enumeration of type of symbols that can be used with LE coded PHY. @@ -1451,8 +1451,8 @@ public: * error code. */ virtual ble_error_t setPreferedPhys( - const Phys_t* txPhys, - const Phys_t* rxPhys + const PhySet_t* txPhys, + const PhySet_t* rxPhys ) { return BLE_ERROR_NOT_IMPLEMENTED; } @@ -1481,8 +1481,8 @@ public: */ virtual ble_error_t setPhy( Handle_t connection, - const Phys_t* txPhys, - const Phys_t* rxPhys, + const PhySet_t* txPhys, + const PhySet_t* rxPhys, CodedSymbolPerBit_t codedSymbol ) { return BLE_ERROR_NOT_IMPLEMENTED; diff --git a/features/FEATURE_BLE/ble/generic/GenericGap.h b/features/FEATURE_BLE/ble/generic/GenericGap.h index 33fa638fda..c972730ba8 100644 --- a/features/FEATURE_BLE/ble/generic/GenericGap.h +++ b/features/FEATURE_BLE/ble/generic/GenericGap.h @@ -43,7 +43,8 @@ namespace generic { * @attention: Not part of the public interface of BLE API. */ class GenericGap : public ::Gap, - public pal::ConnectionEventMonitor { + public pal::ConnectionEventMonitor, + public pal::Gap::EventHandler { public: /** @@ -133,6 +134,29 @@ public: const GapScanningParams *scanParams ); + /** + * @see Gap::readPhy + */ + virtual ble_error_t readPhy(Handle_t connection); + + /** + * @see Gap::setPreferedPhys + */ + virtual ble_error_t setPreferedPhys( + const phy_set_t* txPhys, + const phy_set_t* rxPhys + ); + + /** + * @see Gap::setPhy + */ + virtual ble_error_t setPhy( + Handle_t connection, + const phy_set_t* txPhys, + const phy_set_t* rxPhys, + CodedSymbolPerBit_t codedSymbol + ); + /** * @see Gap::disconnect */ @@ -371,6 +395,23 @@ private: void on_address_rotation_timeout(); + /* implements pal::Gap::EventHandler */ +private: + virtual void on_read_phy( + pal::hci_error_code_t hci_status, + Handle_t connection_handle, + ble::phy_t tx_phy, + ble::phy_t rx_phy + ); + + virtual void on_phy_update_complete( + pal::hci_error_code_t hci_status, + Handle_t connection_handle, + ble::phy_t tx_phy, + ble::phy_t rx_phy + ); + +private: pal::EventQueue& _event_queue; pal::Gap &_pal_gap; pal::GenericAccessService &_gap_service; diff --git a/features/FEATURE_BLE/ble/pal/PalGap.h b/features/FEATURE_BLE/ble/pal/PalGap.h index 0df5756e5d..7f45f437c2 100644 --- a/features/FEATURE_BLE/ble/pal/PalGap.h +++ b/features/FEATURE_BLE/ble/pal/PalGap.h @@ -18,8 +18,9 @@ #define BLE_PAL_GAP_H_ #include "platform/Callback.h" -#include "GapTypes.h" +#include "ble/pal/GapTypes.h" #include "GapEvents.h" +#include "blecommon.h" namespace ble { namespace pal { @@ -59,6 +60,28 @@ struct Gap { ControllerSupportedFeatures_t(type value) : SafeEnum(value) { } }; + struct EventHandler { + /** + * @copydoc Gap::EventHandler::onReadPhy + */ + virtual void on_read_phy( + pal::hci_error_code_t status, + connection_handle_t connectionHandle, + ble::phy_t tx_phy, + ble::phy_t rx_phy + ) = 0; + + /** + * @copydoc Gap::EventHandler::onPhyUpdateComplete + */ + virtual void on_phy_update_complete( + pal::hci_error_code_t status, + connection_handle_t connection_handle, + ble::phy_t tx_phy, + ble::phy_t rx_phy + ) = 0; + }; + /** * Initialisation of the instance. An implementation can use this function * to initialise the subsystems needed to realize the operations of this @@ -706,6 +729,29 @@ struct Gap { virtual bool is_feature_supported( ControllerSupportedFeatures_t feature ) = 0; + + /** + * @see Gap::readPhy + */ + virtual ble_error_t read_phy(connection_handle_t connection) = 0; + + /** + * @see Gap::setPreferedPhys + */ + virtual ble_error_t set_prefered_phys( + const phy_set_t& tx_phys, + const phy_set_t& rx_phys + ) = 0; + + /** + * @see Gap::setPhy + */ + virtual ble_error_t set_phy( + connection_handle_t connection, + const phy_set_t& tx_phys, + const phy_set_t& rx_phys, + coded_symbol_per_bit_t coded_symbol + ) = 0; /** * Register a callback which will handle Gap events. @@ -719,8 +765,27 @@ struct Gap { _gap_event_cb = cb; } +public: + /** + * Sets the event handler that us called by the PAL porters to notify the stack of events + * which will in turn be passed onto the user application when appropriate. + * + * @param[in] event_handler the new event handler interface implementation. Memory + * owned by caller who is responsible for updating this pointer if interface changes. + */ + void set_event_handler(EventHandler *event_handler) { + _pal_event_handler = event_handler; + } + + EventHandler* get_event_handler() { + return _pal_event_handler; + } + protected: - Gap() { } + EventHandler *_pal_event_handler; + +protected: + Gap() : _pal_event_handler(NULL) { } virtual ~Gap() { } @@ -743,6 +808,7 @@ private: */ mbed::Callback _gap_event_cb; +private: // Disallow copy construction and copy assignment. Gap(const Gap&); Gap& operator=(const Gap&); diff --git a/features/FEATURE_BLE/source/generic/GenericGap.cpp b/features/FEATURE_BLE/source/generic/GenericGap.cpp index 1a4d061e13..551472af0c 100644 --- a/features/FEATURE_BLE/source/generic/GenericGap.cpp +++ b/features/FEATURE_BLE/source/generic/GenericGap.cpp @@ -425,6 +425,8 @@ GenericGap::GenericGap( // Recover static random identity _random_static_identity_address = _pal_gap.get_random_address(); + + _pal_gap.set_event_handler(this); } GenericGap::~GenericGap() @@ -587,6 +589,63 @@ ble_error_t GenericGap::connect( ); } +ble_error_t GenericGap::readPhy(Handle_t connection) { + return _pal_gap.read_phy(connection); +} + +ble_error_t GenericGap::setPreferedPhys( + const phy_set_t* txPhys, + const phy_set_t* rxPhys +) { + phy_set_t tx_phys(txPhys? txPhys->value() : 0); + phy_set_t rx_phys(rxPhys? rxPhys->value() : 0); + return _pal_gap.set_prefered_phys(tx_phys, rx_phys); +} + +ble_error_t GenericGap::setPhy( + Handle_t connection, + const phy_set_t* txPhys, + const phy_set_t* rxPhys, + CodedSymbolPerBit_t codedSymbol +) { + phy_set_t tx_phys(txPhys? txPhys->value() : 0); + phy_set_t rx_phys(rxPhys? rxPhys->value() : 0); + return _pal_gap.set_phy(connection, tx_phys, rx_phys, codedSymbol); +} + + +void GenericGap::on_read_phy( + pal::hci_error_code_t hci_status, + Handle_t connection_handle, + ble::phy_t tx_phy, + ble::phy_t rx_phy +) { + ble_error_t status = BLE_ERROR_NONE; + if (pal::hci_error_code_t::SUCCESS != hci_status) { + status = BLE_ERROR_UNSPECIFIED; + } + + if (_eventHandler) { + _eventHandler->onPhyUpdateComplete(status, connection_handle, tx_phy, rx_phy); + } +} + +void GenericGap::on_phy_update_complete( + pal::hci_error_code_t hci_status, + Handle_t connection_handle, + ble::phy_t tx_phy, + ble::phy_t rx_phy +) { + ble_error_t status = BLE_ERROR_NONE; + if (pal::hci_error_code_t::SUCCESS != hci_status) { + status = BLE_ERROR_UNSPECIFIED; + } + + if (_eventHandler) { + _eventHandler->onPhyUpdateComplete(status, connection_handle, tx_phy, rx_phy); + } +} + ble_error_t GenericGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason) { if (is_disconnection_reason_valid(reason) == false) { diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalGap.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalGap.h index 022941ee38..2f9fc076b8 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalGap.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalGap.h @@ -16,31 +16,17 @@ class Gap : public ::ble::pal::Gap { public: virtual bool is_feature_supported( Gap::ControllerSupportedFeatures_t feature - ) { - return (HciGetLeSupFeat() & (1 << feature.value())); - } + ); - virtual ble_error_t initialize() { - return BLE_ERROR_NONE; - } + virtual ble_error_t initialize(); - virtual ble_error_t terminate() { - return BLE_ERROR_NONE; - } + virtual ble_error_t terminate(); - virtual address_t get_device_address() { - return address_t(HciGetBdAddr()); - } + virtual address_t get_device_address(); - virtual address_t get_random_address() { - return device_random_address; - } + virtual address_t get_random_address(); - virtual ble_error_t set_random_address(const address_t& address) { - device_random_address = address; - DmDevSetRandAddr(const_cast(address.data())); - return BLE_ERROR_NONE; - } + virtual ble_error_t set_random_address(const address_t& address); virtual ble_error_t set_advertising_parameters( uint16_t advertising_interval_min, @@ -51,75 +37,19 @@ public: const address_t& peer_address, advertising_channel_map_t advertising_channel_map, advertising_filter_policy_t advertising_filter_policy - ) { - DmAdvSetInterval( - DM_ADV_HANDLE_DEFAULT, - advertising_interval_min, - advertising_interval_max - ); - - DmAdvSetAddrType(own_address_type.value()); - - DmAdvSetChannelMap( - DM_ADV_HANDLE_DEFAULT, - advertising_channel_map.value() - ); - - DmDevSetFilterPolicy( - DM_FILT_POLICY_MODE_ADV, - advertising_filter_policy.value() - ); - - DmAdvConfig( - DM_ADV_HANDLE_DEFAULT, - advertising_type.value(), - peer_address_type.value(), - const_cast(peer_address.data()) - ); - - return BLE_ERROR_NONE; - } + ); virtual ble_error_t set_advertising_data( uint8_t advertising_data_length, const advertising_data_t& advertising_data - ) { - DmAdvSetData( - DM_ADV_HANDLE_DEFAULT, - HCI_ADV_DATA_OP_COMP_FRAG, - DM_DATA_LOC_ADV, - advertising_data_length, - const_cast(advertising_data.data()) - ); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t set_scan_response_data( uint8_t scan_response_data_length, const advertising_data_t& scan_response_data - ) { - DmAdvSetData( - DM_ADV_HANDLE_DEFAULT, - HCI_ADV_DATA_OP_COMP_FRAG, - DM_DATA_LOC_SCAN, - scan_response_data_length, - const_cast(scan_response_data.data()) - ); - return BLE_ERROR_NONE; - } + ); - virtual ble_error_t advertising_enable(bool enable) { - if (enable) { - uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT }; - uint16_t adv_durations[] = { /* infinite */ 0 }; - uint8_t max_ea_events[] = { 0 }; - DmAdvStart(1, adv_handles, adv_durations, max_ea_events); - } else { - uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT }; - DmAdvStop(1, adv_handles); - } - return BLE_ERROR_NONE; - } + virtual ble_error_t advertising_enable(bool enable); virtual ble_error_t set_scan_parameters( bool active_scanning, @@ -127,36 +57,12 @@ public: uint16_t scan_window, own_address_type_t own_address_type, scanning_filter_policy_t filter_policy - ) { - use_active_scanning = active_scanning; - DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window); - DmScanSetAddrType(own_address_type.value()); - DmDevSetFilterPolicy( - DM_FILT_POLICY_MODE_SCAN, - filter_policy.value() - ); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t scan_enable( bool enable, bool filter_duplicates - ) { - if (enable) { - uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE; - DmScanStart( - HCI_SCAN_PHY_LE_1M_BIT, - DM_DISC_MODE_NONE, - &scanType, - filter_duplicates, - 0, - 0 - ); - } else { - DmScanStop(); - } - return BLE_ERROR_NONE; - } + ); virtual ble_error_t create_connection( uint16_t scan_interval, @@ -171,74 +77,23 @@ public: uint16_t supervision_timeout, uint16_t minimum_connection_event_length, uint16_t maximum_connection_event_length - ) { - DmConnSetScanInterval(scan_interval, scan_window); - DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value()); - DmConnSetAddrType(own_address_type.value()); + ); - hciConnSpec_t conn_spec = { - connection_interval_min, - connection_interval_max, - connection_latency, - supervision_timeout, - minimum_connection_event_length, - maximum_connection_event_length - }; - DmConnSetConnSpec(&conn_spec); + virtual ble_error_t cancel_connection_creation(); - dmConnId_t connection_id = DmConnOpen( - DM_CLIENT_ID_APP, - HCI_INIT_PHY_LE_1M_BIT, - peer_address_type.value(), - const_cast(peer_address.data()) - ); + virtual uint8_t read_white_list_capacity(); - if (connection_id == DM_CONN_ID_NONE) { - return BLE_ERROR_INTERNAL_STACK_FAILURE; - } - - return BLE_ERROR_NONE; - } - - virtual ble_error_t cancel_connection_creation() { - DmConnClose( - DM_CLIENT_ID_APP, - /* connection handle - invalid */ DM_CONN_ID_NONE, - /* reason - invalid (use success) */ 0x00 - ); - return BLE_ERROR_NONE; - } - - virtual uint8_t read_white_list_capacity() { - return HciGetWhiteListSize(); - } - - virtual ble_error_t clear_whitelist() { - DmDevWhiteListClear(); - return BLE_ERROR_NONE; - } + virtual ble_error_t clear_whitelist(); virtual ble_error_t add_device_to_whitelist( whitelist_address_type_t address_type, address_t address - ) { - DmDevWhiteListAdd( - address_type.value(), - const_cast(address.data()) - ); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t remove_device_from_whitelist( whitelist_address_type_t address_type, address_t address - ) { - DmDevWhiteListRemove( - address_type.value(), - const_cast(address.data()) - ); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t connection_parameters_update( connection_handle_t connection, @@ -248,26 +103,7 @@ public: uint16_t supervision_timeout, uint16_t minimum_connection_event_length, uint16_t maximum_connection_event_length - ) { - if (DmConnCheckIdle(connection) != 0) { - return BLE_ERROR_INVALID_STATE; - } - - hciConnSpec_t connection_spec = { - connection_interval_min, - connection_interval_max, - connection_latency, - supervision_timeout, - minimum_connection_event_length, - maximum_connection_event_length - }; - DmConnUpdate( - connection, - &connection_spec - ); - - return BLE_ERROR_NONE; - } + ); virtual ble_error_t accept_connection_parameter_request( connection_handle_t connection_handle, @@ -277,104 +113,52 @@ public: uint16_t supervision_timeout, uint16_t minimum_connection_event_length, uint16_t maximum_connection_event_length - ) { - hciConnSpec_t connection_spec = { - interval_min, - interval_max, - latency, - supervision_timeout, - minimum_connection_event_length, - maximum_connection_event_length - }; - DmRemoteConnParamReqReply(connection_handle, &connection_spec); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t reject_connection_parameter_request( connection_handle_t connection_handle, hci_error_code_t rejection_reason - ) { - DmRemoteConnParamReqNegReply( - connection_handle, - rejection_reason.value() - ); - return BLE_ERROR_NONE; - } + ); virtual ble_error_t disconnect( connection_handle_t connection, disconnection_reason_t disconnection_reason - ) { - DmConnClose( - DM_CLIENT_ID_APP, - connection, - disconnection_reason.value() - ); - return BLE_ERROR_NONE; - } + ); - virtual bool is_privacy_supported() { - // We only support controller-based privacy, so return whether the controller supports it - return HciLlPrivacySupported(); - } + virtual bool is_privacy_supported(); virtual ble_error_t set_address_resolution( bool enable - ) { - DmPrivSetAddrResEnable(enable); - return BLE_ERROR_NONE; - } + ); + + virtual ble_error_t read_phy(connection_handle_t connection); + + virtual ble_error_t set_prefered_phys( + const phy_set_t& tx_phys, + const phy_set_t& rx_phys + ); + + virtual ble_error_t set_phy( + connection_handle_t connection, + const phy_set_t& tx_phys, + const phy_set_t& rx_phys, + coded_symbol_per_bit_t coded_symbol + ); // singleton of the ARM Cordio client - static Gap& get_gap() { - static Gap _gap; - return _gap; - } + static Gap& get_gap(); -private: - typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg); - -public: /** * Callback which handle wsfMsgHdr_t and forward them to emit_gap_event. */ - static void gap_handler(const wsfMsgHdr_t* msg) { - if (msg == NULL) { - return; - } - - // all handlers are stored in a static array - static const event_handler_t handlers[] = { - &event_handler, - &event_handler, - &event_handler, - &event_handler, - &event_handler - }; - - // event->hdr.param: connection handle - - // traverse all handlers and execute them with the event in input. - // exit if an handler has handled the event. - for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) { - if (handlers[i](msg)) { - return; - } - } - } + static void gap_handler(const wsfMsgHdr_t* msg); private: /** * T shall define a can_convert and convert function and a type */ template - static bool event_handler(const wsfMsgHdr_t* msg) { - if (T::can_convert(msg)) { - get_gap().emit_gap_event(T::convert((const typename T::type*)msg)); - return true; - } - return false; - } + static bool event_handler(const wsfMsgHdr_t* msg); /** * Traits defining can_convert for events. diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp new file mode 100644 index 0000000000..979ef34abc --- /dev/null +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp @@ -0,0 +1,461 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-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. + */ + +#include "CordioPalGap.h" +#include "hci_api.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace cordio { + +bool Gap::is_feature_supported( + Gap::ControllerSupportedFeatures_t feature +) { + return (HciGetLeSupFeat() & (1 << feature.value())); +} + +ble_error_t Gap::initialize() { + return BLE_ERROR_NONE; +} + +ble_error_t Gap::terminate() { + return BLE_ERROR_NONE; +} + +address_t Gap::get_device_address() { + return address_t(HciGetBdAddr()); +} + +address_t Gap::get_random_address() { + return device_random_address; +} + +ble_error_t Gap::set_random_address(const address_t& address) { + device_random_address = address; + DmDevSetRandAddr(const_cast(address.data())); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_advertising_parameters( + uint16_t advertising_interval_min, + uint16_t advertising_interval_max, + advertising_type_t advertising_type, + own_address_type_t own_address_type, + advertising_peer_address_type_t peer_address_type, + const address_t& peer_address, + advertising_channel_map_t advertising_channel_map, + advertising_filter_policy_t advertising_filter_policy +) { + DmAdvSetInterval( + DM_ADV_HANDLE_DEFAULT, + advertising_interval_min, + advertising_interval_max + ); + + DmAdvSetAddrType(own_address_type.value()); + + DmAdvSetChannelMap( + DM_ADV_HANDLE_DEFAULT, + advertising_channel_map.value() + ); + + DmDevSetFilterPolicy( + DM_FILT_POLICY_MODE_ADV, + advertising_filter_policy.value() + ); + + DmAdvConfig( + DM_ADV_HANDLE_DEFAULT, + advertising_type.value(), + peer_address_type.value(), + const_cast(peer_address.data()) + ); + + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_advertising_data( + uint8_t advertising_data_length, + const advertising_data_t& advertising_data +) { + DmAdvSetData( + DM_ADV_HANDLE_DEFAULT, + HCI_ADV_DATA_OP_COMP_FRAG, + DM_DATA_LOC_ADV, + advertising_data_length, + const_cast(advertising_data.data()) + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_scan_response_data( + uint8_t scan_response_data_length, + const advertising_data_t& scan_response_data +) { + DmAdvSetData( + DM_ADV_HANDLE_DEFAULT, + HCI_ADV_DATA_OP_COMP_FRAG, + DM_DATA_LOC_SCAN, + scan_response_data_length, + const_cast(scan_response_data.data()) + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::advertising_enable(bool enable) { + if (enable) { + uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT }; + uint16_t adv_durations[] = { /* infinite */ 0 }; + uint8_t max_ea_events[] = { 0 }; + DmAdvStart(1, adv_handles, adv_durations, max_ea_events); + } else { + uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT }; + DmAdvStop(1, adv_handles); + } + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_scan_parameters( + bool active_scanning, + uint16_t scan_interval, + uint16_t scan_window, + own_address_type_t own_address_type, + scanning_filter_policy_t filter_policy +) { + use_active_scanning = active_scanning; + DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window); + DmScanSetAddrType(own_address_type.value()); + DmDevSetFilterPolicy( + DM_FILT_POLICY_MODE_SCAN, + filter_policy.value() + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::scan_enable( + bool enable, + bool filter_duplicates +) { + if (enable) { + uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE; + DmScanStart( + HCI_SCAN_PHY_LE_1M_BIT, + DM_DISC_MODE_NONE, + &scanType, + filter_duplicates, + 0, + 0 + ); + } else { + DmScanStop(); + } + return BLE_ERROR_NONE; +} + +ble_error_t Gap::create_connection( + uint16_t scan_interval, + uint16_t scan_window, + initiator_policy_t initiator_policy, + connection_peer_address_type_t peer_address_type, + const address_t& peer_address, + own_address_type_t own_address_type, + uint16_t connection_interval_min, + uint16_t connection_interval_max, + uint16_t connection_latency, + uint16_t supervision_timeout, + uint16_t minimum_connection_event_length, + uint16_t maximum_connection_event_length +) { + DmConnSetScanInterval(scan_interval, scan_window); + DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value()); + DmConnSetAddrType(own_address_type.value()); + + hciConnSpec_t conn_spec = { + connection_interval_min, + connection_interval_max, + connection_latency, + supervision_timeout, + minimum_connection_event_length, + maximum_connection_event_length + }; + DmConnSetConnSpec(&conn_spec); + + dmConnId_t connection_id = DmConnOpen( + DM_CLIENT_ID_APP, + HCI_INIT_PHY_LE_1M_BIT, + peer_address_type.value(), + const_cast(peer_address.data()) + ); + + if (connection_id == DM_CONN_ID_NONE) { + return BLE_ERROR_INTERNAL_STACK_FAILURE; + } + + return BLE_ERROR_NONE; +} + +ble_error_t Gap::cancel_connection_creation() { + DmConnClose( + DM_CLIENT_ID_APP, + /* connection handle - invalid */ DM_CONN_ID_NONE, + /* reason - invalid (use success) */ 0x00 + ); + return BLE_ERROR_NONE; +} + +uint8_t Gap::read_white_list_capacity() { + return HciGetWhiteListSize(); +} + +ble_error_t Gap::clear_whitelist() { + DmDevWhiteListClear(); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::add_device_to_whitelist( + whitelist_address_type_t address_type, + address_t address +) { + DmDevWhiteListAdd( + address_type.value(), + const_cast(address.data()) + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::remove_device_from_whitelist( + whitelist_address_type_t address_type, + address_t address +) { + DmDevWhiteListRemove( + address_type.value(), + const_cast(address.data()) + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::connection_parameters_update( + connection_handle_t connection, + uint16_t connection_interval_min, + uint16_t connection_interval_max, + uint16_t connection_latency, + uint16_t supervision_timeout, + uint16_t minimum_connection_event_length, + uint16_t maximum_connection_event_length +) { + if (DmConnCheckIdle(connection) != 0) { + return BLE_ERROR_INVALID_STATE; + } + + hciConnSpec_t connection_spec = { + connection_interval_min, + connection_interval_max, + connection_latency, + supervision_timeout, + minimum_connection_event_length, + maximum_connection_event_length + }; + DmConnUpdate( + connection, + &connection_spec + ); + + return BLE_ERROR_NONE; +} + +ble_error_t Gap::accept_connection_parameter_request( + connection_handle_t connection_handle, + uint16_t interval_min, + uint16_t interval_max, + uint16_t latency, + uint16_t supervision_timeout, + uint16_t minimum_connection_event_length, + uint16_t maximum_connection_event_length +) { + hciConnSpec_t connection_spec = { + interval_min, + interval_max, + latency, + supervision_timeout, + minimum_connection_event_length, + maximum_connection_event_length + }; + DmRemoteConnParamReqReply(connection_handle, &connection_spec); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::reject_connection_parameter_request( + connection_handle_t connection_handle, + hci_error_code_t rejection_reason +) { + DmRemoteConnParamReqNegReply( + connection_handle, + rejection_reason.value() + ); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::disconnect( + connection_handle_t connection, + disconnection_reason_t disconnection_reason +) { + DmConnClose( + DM_CLIENT_ID_APP, + connection, + disconnection_reason.value() + ); + return BLE_ERROR_NONE; +} + +bool Gap::is_privacy_supported() { + // We only support controller-based privacy, so return whether the controller supports it + return HciLlPrivacySupported(); +} + +ble_error_t Gap::set_address_resolution( + bool enable +) { + DmPrivSetAddrResEnable(enable); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::read_phy(connection_handle_t connection) { + HciLeReadPhyCmd(connection); + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_prefered_phys( + const phy_set_t& tx_phys, + const phy_set_t& rx_phys +) { + HciLeSetDefaultPhyCmd( + phy_set_t::all_phys_value(tx_phys, rx_phys), + tx_phys.value(), + rx_phys.value() + ); + + return BLE_ERROR_NONE; +} + +ble_error_t Gap::set_phy( + connection_handle_t connection, + const phy_set_t& tx_phys, + const phy_set_t& rx_phys, + coded_symbol_per_bit_t coded_symbol +) { + /* if phy set is empty set corresponding all_phys bit to 1 */ + uint8_t all_phys = 0; + if (tx_phys.value() == 0) { + all_phys |= 0x01; + } + if (rx_phys.value() == 0) { + all_phys |= 0x02; + } + + HciLeSetPhyCmd( + connection, + phy_set_t::all_phys_value(tx_phys, rx_phys), + tx_phys.value(), + rx_phys.value(), + coded_symbol.value() + ); + + return BLE_ERROR_NONE; +} + +// singleton of the ARM Cordio client +Gap& Gap::get_gap() { + static Gap _gap; + return _gap; +} + +/** + * Callback which handle wsfMsgHdr_t and forward them to emit_gap_event. + */ +void Gap::gap_handler(const wsfMsgHdr_t* msg) { + typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg); + + if (msg == NULL) { + return; + } + + connection_handle_t handle = (connection_handle_t)msg->param; + + switch(msg->event) { + case DM_PHY_READ_IND: + if (get_gap()._pal_event_handler) { + const hciLeReadPhyCmdCmplEvt_t* evt = (const hciLeReadPhyCmdCmplEvt_t*)msg; + + get_gap()._pal_event_handler->on_read_phy( + (hci_error_code_t::type)msg->status, + handle, + (ble::phy_t::type)evt->txPhy, + (ble::phy_t::type)evt->rxPhy + ); + } + break; + case DM_PHY_UPDATE_IND: + if (get_gap()._pal_event_handler) { + const hciLePhyUpdateEvt_t* evt = (const hciLePhyUpdateEvt_t*)msg; + + get_gap()._pal_event_handler->on_phy_update_complete( + (hci_error_code_t::type)msg->status, + handle, + (ble::phy_t::type)evt->txPhy, + (ble::phy_t::type)evt->rxPhy + ); + } + break; + } + + // all handlers are stored in a static array + static const event_handler_t handlers[] = { + &event_handler, + &event_handler, + &event_handler, + &event_handler, + &event_handler + }; + + // event->hdr.param: connection handle + + // traverse all handlers and execute them with the event in input. + // exit if an handler has handled the event. + for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) { + if (handlers[i](msg)) { + return; + } + } +} + +/** + * T shall define a can_convert and convert function and a type + */ +template +bool Gap::event_handler(const wsfMsgHdr_t* msg) { + if (T::can_convert(msg)) { + get_gap().emit_gap_event(T::convert((const typename T::type*)msg)); + return true; + } + return false; +} + + +} // cordio +} // vendor +} // pal +} // ble diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp index 689a6ae96d..58a850ff62 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.cpp @@ -120,28 +120,6 @@ peer_address_type_t convert_identity_address(advertising_peer_address_type_t add #define BLE_GAP_PHY_AUTO 0 #endif -uint8_t to_nordic_phy_set(const ble::phys_t* phys) { - if (!phys) { - return BLE_GAP_PHY_AUTO; - } - - uint8_t nordic_phys = 0; - - if (phys->le_1m) { - nordic_phys |= BLE_GAP_PHY_1MBPS; - } - - if (phys->le_2m) { - nordic_phys |= BLE_GAP_PHY_2MBPS; - } - - if (phys->le_coded) { - nordic_phys |= BLE_GAP_PHY_CODED; - } - - return nordic_phys; -} - } // namespace void radioNotificationStaticCallback(bool param) { @@ -165,7 +143,7 @@ nRF5xGap::nRF5xGap() : Gap(), _prefered_rx_phys(BLE_GAP_PHY_AUTO), _connections_role() { - m_connectionHandle = BLE_CONN_HANDLE_INVALID; + m_connectionHandle = BLE_CONN_HANDLE_INVALID; } /**************************************************************************/ /*! @@ -694,11 +672,11 @@ ble_error_t nRF5xGap::readPhy(Handle_t connection) { } ble_error_t nRF5xGap::setPreferedPhys( - const Phys_t* txPhys, - const Phys_t* rxPhys + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys ) { - uint8_t prefered_tx_phys = to_nordic_phy_set(txPhys); - uint8_t prefered_rx_phys = to_nordic_phy_set(rxPhys); + uint8_t prefered_tx_phys = txPhys? txPhys->value() : 0; + uint8_t prefered_rx_phys = rxPhys? rxPhys->value() : 0; #ifdef S140 ble_opt_t opt = { 0 }; @@ -732,8 +710,8 @@ ble_error_t nRF5xGap::setPreferedPhys( ble_error_t nRF5xGap::setPhy( Handle_t connection, - const Phys_t* txPhys, - const Phys_t* rxPhys, + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys, CodedSymbolPerBit_t codedSymbol ) { #ifdef S140 @@ -741,8 +719,8 @@ ble_error_t nRF5xGap::setPhy( #else // TODO handle coded symbol once supported by the softdevice. ble_gap_phys_t gap_phys = { - to_nordic_phy_set(txPhys), - to_nordic_phy_set(rxPhys) + txPhys? txPhys->value() : 0, + rxPhys? rxPhys->value() : 0 }; uint32_t err = sd_ble_gap_phy_update(connection, &gap_phys); diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h index b482c4a5b6..d8f0bcf365 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF52/source/nRF5xGap.h @@ -92,13 +92,13 @@ public: virtual ble_error_t readPhy(Handle_t connection); virtual ble_error_t setPreferedPhys( - const Phys_t* txPhys, - const Phys_t* rxPhys + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys ); virtual ble_error_t setPhy( Handle_t connection, - const Phys_t* txPhys, - const Phys_t* rxPhys, + const ble::phy_set_t* txPhys, + const ble::phy_set_t* rxPhys, CodedSymbolPerBit_t codedSymbol );