diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp index ac5b5404c5..717e38da39 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.cpp @@ -104,7 +104,8 @@ nRF5xGap::nRF5xGap() : Gap(), _privacy_enabled(false), _peripheral_privacy_configuration(default_peripheral_privacy_configuration), _central_privacy_configuration(default_central_privacy_configuration), - _non_private_address_type(LegacyAddressType::RANDOM_STATIC) + _non_private_address_type(LegacyAddressType::RANDOM_STATIC), + _connections_role() { m_connectionHandle = BLE_CONN_HANDLE_INVALID; } @@ -682,6 +683,8 @@ ble_error_t nRF5xGap::reset(void) /* Clear the internal whitelist */ whitelistAddressesSize = 0; + /* Reset existing mapping between a connection and its role */ + release_all_connections_role(); return BLE_ERROR_NONE; } @@ -1195,6 +1198,8 @@ void nRF5xGap::processDisconnectionEvent( Handle_t handle, DisconnectionReason_t reason ) { + release_connection_role(handle); + if (_connection_event_handler) { _connection_event_handler->on_disconnected( handle, @@ -1214,6 +1219,9 @@ void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t // set the new connection handle as the _default_ handle in gap setConnectionHandle(handle); + // add the connection and the role of the device in the local table + allocate_connection_role(handle, static_cast(evt.role)); + // deal with own address LegacyAddressType_t own_addr_type; Address_t own_address; @@ -1375,5 +1383,46 @@ void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { ); } +ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + role = c.is_peripheral ? PERIPHERAL : CENTRAL; + return BLE_ERROR_NONE; + } + } + + return BLE_ERROR_INVALID_PARAM; +} + +void nRF5xGap::allocate_connection_role( + ble::connection_handle_t connection, + Role_t role +) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated == false) { + c.connection = connection; + c.is_peripheral = (role == Gap::PERIPHERAL); + c.is_allocated = true; + return; + } + } +} +void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + c.is_allocated = false; + return; + } + } +} + +void nRF5xGap::release_all_connections_role() { + for (size_t i = 0; i < max_connections_count; ++i) { + _connections_role[i].is_allocated = false; + } +} diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.h index a1f2700218..ecdf770fe2 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.h +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF51/source/nRF5xGap.h @@ -259,12 +259,26 @@ public: DisconnectionReason_t reason ); + /** + * Return the role of the local peripheral for a given connection. + * + * @param[in] connection The connection queried. + * @param[out] role The role of the local device in the connection. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + ble_error_t get_role(ble::connection_handle_t connection, Role_t& role); + private: friend void btle_handler(ble_evt_t *p_ble_evt); void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt); void on_advertising_packet(const ble_gap_evt_adv_report_t &evt); + void allocate_connection_role(ble::connection_handle_t, Role_t); + void release_connection_role(ble::connection_handle_t); + void release_all_connections_role(); + uint16_t m_connectionHandle; ConnectionEventMonitor::EventHandler* _connection_event_handler; @@ -275,6 +289,23 @@ private: AddressType_t _non_private_address_type; Address_t _non_private_address; + struct connection_role_t { + connection_role_t() : + connection(), + is_peripheral(false), + is_allocated(false) + { } + + ble::connection_handle_t connection; + uint8_t is_peripheral:1; + uint8_t is_allocated:1; + }; + + static const size_t max_connections_count = + NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT; + + connection_role_t _connections_role[max_connections_count]; + /* * Allow instantiation from nRF5xn when required. */ 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 a5053b23f4..1e96afa68b 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 @@ -133,7 +133,8 @@ nRF5xGap::nRF5xGap() : Gap(), _privacy_enabled(false), _peripheral_privacy_configuration(default_peripheral_privacy_configuration), _central_privacy_configuration(default_central_privacy_configuration), - _non_private_address_type(LegacyAddressType::RANDOM_STATIC) + _non_private_address_type(LegacyAddressType::RANDOM_STATIC), + _connections_role() { m_connectionHandle = BLE_CONN_HANDLE_INVALID; } @@ -743,6 +744,9 @@ ble_error_t nRF5xGap::reset(void) /* Clear the internal whitelist */ whitelistAddressesSize = 0; + /* Reset existing mapping between a connection and its role */ + release_all_connections_role(); + return BLE_ERROR_NONE; } @@ -1278,6 +1282,8 @@ void nRF5xGap::processDisconnectionEvent( Handle_t handle, DisconnectionReason_t reason ) { + release_connection_role(handle); + if (_connection_event_handler) { _connection_event_handler->on_disconnected( handle, @@ -1326,6 +1332,9 @@ void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t // set the new connection handle as the _default_ handle in gap setConnectionHandle(handle); + // add the connection and the role of the device in the local table + allocate_connection_role(handle, static_cast(evt.role)); + // deal with own address LegacyAddressType_t own_addr_type; ble::address_t own_address; @@ -1457,3 +1466,48 @@ void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) { ); } +ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + role = c.is_peripheral ? PERIPHERAL : CENTRAL; + return BLE_ERROR_NONE; + + } + } + + return BLE_ERROR_INVALID_PARAM; +} + +void nRF5xGap::allocate_connection_role( + ble::connection_handle_t connection, + Role_t role +) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated == false) { + c.connection = connection; + c.is_peripheral = (role == Gap::PERIPHERAL); + c.is_allocated = true; + return; + } + } +} +void nRF5xGap::release_connection_role(ble::connection_handle_t connection) { + for (size_t i = 0; i < max_connections_count; ++i) { + connection_role_t& c = _connections_role[i]; + if (c.is_allocated && c.connection == connection) { + c.is_allocated = false; + return; + } + } +} + +void nRF5xGap::release_all_connections_role() { + for (size_t i = 0; i < max_connections_count; ++i) { + _connections_role[i].is_allocated = false; + } +} + + + 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 c8ef171ca4..4e52a60f28 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 @@ -265,6 +265,16 @@ public: DisconnectionReason_t reason ); + /** + * Return the role of the local peripheral for a given connection. + * + * @param[in] connection The connection queried. + * @param[out] role The role of the local device in the connection. + * + * @return BLE_ERROR_NONE in case of success or an appropriate error code. + */ + ble_error_t get_role(ble::connection_handle_t connection, Role_t& role); + private: friend void btle_handler(const ble_evt_t *p_ble_evt); friend void btle_handler(const ble_evt_t *p_ble_evt, void *p_context); @@ -272,6 +282,11 @@ private: ble_error_t update_identities_list(bool resolution_enabled); void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt); void on_advertising_packet(const ble_gap_evt_adv_report_t &evt); + + void allocate_connection_role(ble::connection_handle_t, Role_t); + void release_connection_role(ble::connection_handle_t); + void release_all_connections_role(); + uint16_t m_connectionHandle; ConnectionEventMonitor::EventHandler* _connection_event_handler; @@ -281,6 +296,23 @@ private: AddressType_t _non_private_address_type; Address_t _non_private_address; + struct connection_role_t { + connection_role_t() : + connection(), + is_peripheral(false), + is_allocated(false) + { } + + ble::connection_handle_t connection; + uint8_t is_peripheral:1; + uint8_t is_allocated:1; + }; + + static const size_t max_connections_count = + NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT; + + connection_role_t _connections_role[max_connections_count]; + /* * Allow instantiation from nRF5xn when required. */