diff --git a/features/FEATURE_BLE/ble/Gap.h b/features/FEATURE_BLE/ble/Gap.h index 022b07a28b..0f5f4e87ce 100644 --- a/features/FEATURE_BLE/ble/Gap.h +++ b/features/FEATURE_BLE/ble/Gap.h @@ -324,9 +324,17 @@ public: * * @param event Connection event @see ConnectionCompleteEvent_t for details. */ - void onConnectionComplete(const ble::ConnectionCompleteEvent &event) { } + virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) { } - void onDisconnection(const ble::DisconnectionEvent &event) { } + virtual void onUpdateConnectionParametersRequest( + const ble::UpdateConnectionParametersRequestEvent &event + ) { } + + virtual void onConnectionParametersUpdateComplete( + const ble::ConnectionParametersUpdateCompleteEvent &event + ) { } + + virtual void onDisconnection(const ble::DisconnectionEvent &event) { } /** * Function invoked when the current transmitter and receiver PHY have @@ -710,6 +718,34 @@ public: */ virtual ble_error_t cancelConnect(); + virtual ble_error_t updateConnectionParameters( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervision_timeout, + ble::conn_event_length_t minConnectionEventLength = ble::conn_event_length_t(0), + ble::conn_event_length_t maxConnectionEventLength = ble::conn_event_length_t(0) + ); + + virtual ble_error_t manageConnectionParametersUpdateRequest( + bool userManageConnectionUpdateRequest + ); + + virtual ble_error_t acceptConnectionParametersUpdate( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervision_timeout, + ble::conn_event_length_t minConnectionEventLength = ble::conn_event_length_t(0), + ble::conn_event_length_t maxConnectionEventLength = ble::conn_event_length_t(0) + ); + + virtual ble_error_t rejectConnectionParametersUpdate( + ble::connection_handle_t connectionHandle + ); + /** * Initiate a disconnection procedure. * diff --git a/features/FEATURE_BLE/ble/gap/Events.h b/features/FEATURE_BLE/ble/gap/Events.h index 845439427a..2b7a8cfbc2 100644 --- a/features/FEATURE_BLE/ble/gap/Events.h +++ b/features/FEATURE_BLE/ble/gap/Events.h @@ -552,7 +552,6 @@ private: const address_t &peerAddress; }; - struct DisconnectionEvent { DisconnectionEvent( connection_handle_t connectionHandle, @@ -574,6 +573,104 @@ private: ble::disconnection_reason_t reason; }; +struct UpdateConnectionParametersRequestEvent { + UpdateConnectionParametersRequestEvent( + connection_handle_t connectionHandle, + const conn_interval_t &minConnectionInterval, + const conn_interval_t &maxConnectionInterval, + const slave_latency_t &slaveLatency, + const supervision_timeout_t &supervision_timeout + ) : + connectionHandle(connectionHandle), + minConnectionInterval(minConnectionInterval), + maxConnectionInterval(maxConnectionInterval), + slaveLatency(slaveLatency), + supervisionTimeout(supervision_timeout) + { } + + connection_handle_t getConnectionHandle() const + { + return connectionHandle; + } + + const conn_interval_t &getMinConnectionInterval() const + { + return minConnectionInterval; + } + + const conn_interval_t &getMaxConnectionInterval() const + { + return maxConnectionInterval; + } + + const slave_latency_t &getSlaveLatency() const + { + return slaveLatency; + } + + const supervision_timeout_t &getSupervisionTimeout() const + { + return supervisionTimeout; + } + +private: + ble::connection_handle_t connectionHandle; + ble::conn_interval_t minConnectionInterval; + ble::conn_interval_t maxConnectionInterval; + ble::slave_latency_t slaveLatency; + ble::supervision_timeout_t supervisionTimeout; +}; + +struct ConnectionParametersUpdateCompleteEvent { + ConnectionParametersUpdateCompleteEvent( + ble_error_t status, + connection_handle_t connectionHandle, + const conn_interval_t &connectionInterval, + const slave_latency_t &slaveLatency, + const supervision_timeout_t &supervisionTimeout + ) : + status(status), + connectionHandle(connectionHandle), + connectionInterval(connectionInterval), + slaveLatency(slaveLatency), + supervisionTimeout(supervisionTimeout) + { } + + ble_error_t getStatus() const + { + return status; + } + + connection_handle_t getConnectionHandle() const + { + return connectionHandle; + } + + const conn_interval_t &getConnectionInterval() const + { + return connectionInterval; + } + + const slave_latency_t &getSlaveLatency() const + { + return slaveLatency; + } + + const supervision_timeout_t &getSupervisionTimeout() const + { + return supervisionTimeout; + } + +private: + ble_error_t status; + ble::connection_handle_t connectionHandle; + ble::conn_interval_t connectionInterval; + ble::slave_latency_t slaveLatency; + ble::supervision_timeout_t supervisionTimeout; + +}; + + } // namespace ble #endif //BLE_GAP_EVENTS_H diff --git a/features/FEATURE_BLE/ble/generic/GenericGap.h b/features/FEATURE_BLE/ble/generic/GenericGap.h index 103bf26c8e..bcee4c6857 100644 --- a/features/FEATURE_BLE/ble/generic/GenericGap.h +++ b/features/FEATURE_BLE/ble/generic/GenericGap.h @@ -304,6 +304,34 @@ public: */ virtual ble_error_t cancelConnect(); + virtual ble_error_t manageConnectionParametersUpdateRequest( + bool userManageConnectionUpdateRequest + ); + + virtual ble_error_t updateConnectionParameters( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervisionTimeout, + ble::conn_event_length_t minConnectionEventLength, + ble::conn_event_length_t maxConnectionEventLength + ); + + virtual ble_error_t acceptConnectionParametersUpdate( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervisionTimeout, + ble::conn_event_length_t minConnectionEventLength, + ble::conn_event_length_t maxConnectionEventLength + ); + + virtual ble_error_t rejectConnectionParametersUpdate( + ble::connection_handle_t connectionHandle + ); + /** * @see Gap::readPhy */ @@ -659,6 +687,22 @@ private: const ble::address_t &address ); + virtual void on_connection_update_complete( + pal::hci_error_code_t status, + connection_handle_t connection_handle, + uint16_t connection_interval, + uint16_t connection_latency, + uint16_t supervision_timeout + ); + + virtual void on_remote_connection_parameter( + connection_handle_t connection_handle, + uint16_t connection_interval_min, + uint16_t connection_interval_max, + uint16_t connection_latency, + uint16_t supervision_timeout + ); + private: pal::EventQueue& _event_queue; pal::Gap &_pal_gap; @@ -722,6 +766,7 @@ private: // deprecation flags mutable bool _deprecated_scan_api_used : 1; mutable bool _non_deprecated_scan_api_used : 1; + bool _user_manage_connection_parameter_requests : 1; private: ble_error_t setExtendedAdvertisingParameters( diff --git a/features/FEATURE_BLE/ble/pal/PalGap.h b/features/FEATURE_BLE/ble/pal/PalGap.h index f04329e58b..391ef0a959 100644 --- a/features/FEATURE_BLE/ble/pal/PalGap.h +++ b/features/FEATURE_BLE/ble/pal/PalGap.h @@ -219,6 +219,22 @@ struct Gap { connection_peer_address_type_t scanner_address_type, const address_t &address ) = 0; + + virtual void on_connection_update_complete( + hci_error_code_t status, + connection_handle_t connection_handle, + uint16_t connection_interval, + uint16_t connection_latency, + uint16_t supervision_timeout + ) = 0; + + virtual void on_remote_connection_parameter( + connection_handle_t connection_handle, + uint16_t connection_interval_min, + uint16_t connection_interval_max, + uint16_t connection_latency, + uint16_t supervision_timeout + ) = 0; }; /** diff --git a/features/FEATURE_BLE/source/Gap.cpp b/features/FEATURE_BLE/source/Gap.cpp index ba95146bed..98800da628 100644 --- a/features/FEATURE_BLE/source/Gap.cpp +++ b/features/FEATURE_BLE/source/Gap.cpp @@ -271,6 +271,42 @@ ble_error_t Gap::cancelConnect() { return BLE_ERROR_NOT_IMPLEMENTED; } +ble_error_t Gap::updateConnectionParameters( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervision_timeout, + ble::conn_event_length_t minConnectionEventLength, + ble::conn_event_length_t maxConnectionEventLength +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t Gap::manageConnectionParametersUpdateRequest( + bool userManageConnectionUpdateRequest +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t Gap::acceptConnectionParametersUpdate( + ble::connection_handle_t connectionHandle, + ble::conn_interval_t minConnectionInterval, + ble::conn_interval_t maxConnectionInterval, + ble::slave_latency_t slaveLatency, + ble::supervision_timeout_t supervision_timeout, + ble::conn_event_length_t minConnectionEventLength, + ble::conn_event_length_t maxConnectionEventLength +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + +ble_error_t Gap::rejectConnectionParametersUpdate( + ble::connection_handle_t connectionHandle +) { + return BLE_ERROR_NOT_IMPLEMENTED; +} + ble_error_t Gap::disconnect( ble::connection_handle_t connectionHandle, ble::local_disconnection_reason_t reason diff --git a/features/FEATURE_BLE/source/generic/GenericGap.cpp b/features/FEATURE_BLE/source/generic/GenericGap.cpp index df0b10225d..970448d04d 100644 --- a/features/FEATURE_BLE/source/generic/GenericGap.cpp +++ b/features/FEATURE_BLE/source/generic/GenericGap.cpp @@ -419,7 +419,8 @@ GenericGap::GenericGap( _random_address_rotating(false), _advertising_timeout(), _scan_timeout(), - _connection_event_handler(NULL) + _connection_event_handler(NULL), + _user_manage_connection_parameter_requests(false) { _pal_gap.initialize(); @@ -646,6 +647,67 @@ ble_error_t GenericGap::connect( ); } +ble_error_t GenericGap::manageConnectionParametersUpdateRequest(bool flag) { + _user_manage_connection_parameter_requests = flag; +} + +ble_error_t GenericGap::updateConnectionParameters( + connection_handle_t connectionHandle, + conn_interval_t minConnectionInterval, + conn_interval_t maxConnectionInterval, + slave_latency_t slaveLatency, + supervision_timeout_t supervisionTimeout, + conn_event_length_t minConnectionEventLength, + conn_event_length_t maxConnectionEventLength +) { + if (supervisionTimeout <= (1 + slaveLatency.value()) * maxConnectionInterval * 2) { + return BLE_ERROR_INVALID_PARAM; + } + + return _pal_gap.connection_parameters_update( + connectionHandle, + minConnectionInterval.value(), + maxConnectionInterval.value(), + slaveLatency.value(), + supervisionTimeout.value(), + minConnectionEventLength.value(), + maxConnectionEventLength.value() + ); +} + +ble_error_t GenericGap::acceptConnectionParametersUpdate( + connection_handle_t connectionHandle, + conn_interval_t minConnectionInterval, + conn_interval_t maxConnectionInterval, + slave_latency_t slaveLatency, + supervision_timeout_t supervisionTimeout, + conn_event_length_t minConnectionEventLength, + conn_event_length_t maxConnectionEventLength +) { + if (supervisionTimeout <= (1 + slaveLatency.value()) * maxConnectionInterval * 2) { + return BLE_ERROR_INVALID_PARAM; + } + + return _pal_gap.accept_connection_parameter_request( + connectionHandle, + minConnectionInterval.value(), + maxConnectionInterval.value(), + slaveLatency.value(), + supervisionTimeout.value(), + minConnectionEventLength.value(), + maxConnectionEventLength.value() + ); +} + +ble_error_t GenericGap::rejectConnectionParametersUpdate( + ble::connection_handle_t connectionHandle +) { + return _pal_gap.reject_connection_parameter_request( + connectionHandle, + pal::hci_error_code_t::UNACCEPTABLE_CONNECTION_PARAMETERS + ); +} + ble_error_t GenericGap::cancelConnect() { return _pal_gap.cancel_connection_creation(); @@ -2374,6 +2436,63 @@ void GenericGap::on_scan_request_received( ); } +void GenericGap::on_connection_update_complete( + pal::hci_error_code_t status, + connection_handle_t connection_handle, + uint16_t connection_interval, + uint16_t connection_latency, + uint16_t supervision_timeout +) { + if (!_eventHandler) { + return; + } + + _eventHandler->onConnectionParametersUpdateComplete( + ConnectionParametersUpdateCompleteEvent( + status == pal::hci_error_code_t::SUCCESS ? BLE_ERROR_NONE : BLE_ERROR_UNSPECIFIED, + connection_handle, + conn_interval_t(connection_interval), + slave_latency_t(connection_latency), + supervision_timeout_t(supervision_timeout) + ) + ); +} + +void GenericGap::on_remote_connection_parameter( + connection_handle_t connection_handle, + uint16_t connection_interval_min, + uint16_t connection_interval_max, + uint16_t connection_latency, + uint16_t supervision_timeout +) { + if (_user_manage_connection_parameter_requests) { + // ignore for now as it is + _pal_gap.accept_connection_parameter_request( + connection_handle, + connection_interval_min, + connection_interval_max, + connection_latency, + supervision_timeout, + /* connection event length min */ 0, + /* connection event length max */ 0 + ); + } else { + if (!_eventHandler) { + return; + } + + _eventHandler->onUpdateConnectionParametersRequest( + UpdateConnectionParametersRequestEvent( + connection_handle, + conn_interval_t(connection_interval_min), + conn_interval_t(connection_interval_max), + connection_latency, + supervision_timeout_t(supervision_timeout) + ) + ); + } +} + ble_error_t GenericGap::setScanParameters(const ScanParameters ¶ms) { useVersionTwoAPI(); diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp index cc867679f6..d2034d4fd0 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalGap.cpp @@ -560,6 +560,36 @@ void Gap::gap_handler(const wsfMsgHdr_t* msg) { evt->pData ); } break; + + case DM_CONN_UPDATE_IND: { + if (!handler) { + break; + } + + const hciLeConnUpdateCmplEvt_t* evt = (const hciLeConnUpdateCmplEvt_t*) msg; + handler->on_connection_update_complete( + (hci_error_code_t::type) evt->status, + evt->hdr.param, + evt->connInterval, + evt->connLatency, + evt->supTimeout + ); + } break; + + case DM_REM_CONN_PARAM_REQ_IND: { + if (!handler) { + break; + } + + const hciLeRemConnParamReqEvt_t* evt = (const hciLeRemConnParamReqEvt_t*) msg; + handler->on_remote_connection_parameter( + evt->hdr.param, + evt->intervalMin, + evt->intervalMax, + evt->latency, + evt->timeout + ); + } break; } // all handlers are stored in a static array