diff --git a/ble/gap_connection.cc b/ble/gap_connection.cc index e67bbc2..0f8e536 100644 --- a/ble/gap_connection.cc +++ b/ble/gap_connection.cc @@ -15,14 +15,14 @@ namespace gap uint8_t peer_address_id) { this->set_handle(connection_handle); - this->get_connecteable()->connection().get_negotiation_state().clear_all_pending(); + this->get_connecteable()->gap.get_negotiation_state().clear_all_pending(); } void connection::disconnect(uint16_t connection_handle, ble::hci::error_code error_code) { this->set_handle(ble::gap::handle_invalid); - this->get_connecteable()->connection().get_negotiation_state().clear_all_pending(); + this->get_connecteable()->gap.get_negotiation_state().clear_all_pending(); } } // namespace gap diff --git a/ble/gap_event_logger.h b/ble/gap_event_logger.h index 7ce9608..cf8fb4b 100644 --- a/ble/gap_event_logger.h +++ b/ble/gap_event_logger.h @@ -24,7 +24,7 @@ class event_logger: public ble::gap::event_observer public: logger::level log_level; - virtual ~event_logger() override = default; + virtual ~event_logger() override = default; event_logger(event_logger const&) = delete; event_logger(event_logger &&) = delete; diff --git a/ble/gap_event_observable.h b/ble/gap_event_observable.h new file mode 100644 index 0000000..db7898b --- /dev/null +++ b/ble/gap_event_observable.h @@ -0,0 +1,65 @@ +/** + * @file ble/gap_event_observable.h + * @copyright (c) 2018, natersoz. Distributed under the Apache 2.0 license. + */ + +#pragma once + +#include "ble/gap_event_observer.h" + +namespace ble +{ +namespace gap +{ + +class event_observable +{ + virtual ~event_observable() = default; + + event_observable() = default; + event_observable(event_observable const&) = delete; + event_observable(event_observable &&) = delete; + event_observable& operator=(event_observable const&) = delete; + event_observable& operator=(event_observable&&) = delete; + + void attach(event_observer& observer) + { + if (not observer.hook.is_linked()) + { + this->observer_list.push_back(observer); + } + } + + void attach_first(event_observer& observer) + { + if (not observer.hook.is_linked()) + { + this->observer_list.push_front(observer); + } + } + + void detach(event_observer& observer) + { + if (observer.hook.is_linked()) + { + observer.hook.unlink(); + } + } + +private: + using list_type = boost::intrusive::list< + event_observer, + boost::intrusive::constant_time_size, + boost::intrusive::member_hook< + event_observer, + typename event_observer::list_hook_type, + &event_observer::hook> + >; + + list_type observer_list; +}; + +} // namespace gap +} // namespace ble + + diff --git a/ble/gatts_event_observer.cc b/ble/gatts_event_observer.cc index 45c7ace..bf330e2 100644 --- a/ble/gatts_event_observer.cc +++ b/ble/gatts_event_observer.cc @@ -41,7 +41,7 @@ void event_observer::write(uint16_t conection_handle, return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { /// This GATTS request is from a different connection. /// @todo Is it normal for this connection to get notified of other @@ -52,7 +52,7 @@ void event_observer::write(uint16_t conection_handle, } ble::gatt::characteristic *characteristic = - connectable->service_container().find_characteristic(attribute_handle); + connectable->service_container.find_characteristic(attribute_handle); if (not characteristic) { logger.warn("GATTS write(0x%04x, 0x%04x): invalid handle", @@ -92,7 +92,7 @@ void event_observer::write_cancel(uint16_t conection_handle, return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; @@ -113,7 +113,7 @@ void event_observer::read_authorization_request(uint16_t conection_handle, return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; @@ -123,13 +123,14 @@ void event_observer::read_authorization_request(uint16_t conection_handle, } // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST -void event_observer::write_authorization_request(uint16_t conection_handle, - uint16_t attribute_handle, - att::op_code write_operation_type, - bool authorization_required, - att::length_t offset, - att::length_t length, - void const* data) +void event_observer::write_authorization_request( + uint16_t conection_handle, + uint16_t attribute_handle, + att::op_code write_operation_type, + bool authorization_required, + att::length_t offset, + att::length_t length, + void const* data) { ble::profile::connectable* connectable = this->get_connecteable(); if (not connectable) @@ -138,7 +139,7 @@ void event_observer::write_authorization_request(uint16_t conection_handle, return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; @@ -175,19 +176,20 @@ void event_observer::exchange_mtu_request(uint16_t conection_handle, return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; } ble::att::length_t const att_mtu_length_maximum = - connectable->ble_stack().get_constraints().att_mtu_maximum_length; + connectable->stack.get_constraints().att_mtu_maximum_length; client_rx_mtu_size = std::min(client_rx_mtu_size, att_mtu_length_maximum); client_rx_mtu_size = std::max(client_rx_mtu_size, att::mtu_length_minimum); - connectable->gatts()->exchange_mtu_reply(conection_handle, client_rx_mtu_size); + connectable->gatts.operations->exchange_mtu_reply(conection_handle, + client_rx_mtu_size); } // BLE_GATTS_EVT_TIMEOUT, // always BLE_GATT_TIMEOUT_SRC_PROTOCOL (0) @@ -200,7 +202,7 @@ void event_observer::timeout(uint16_t conection_handle, uint8_t timeout_source) return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; @@ -211,8 +213,8 @@ void event_observer::timeout(uint16_t conection_handle, uint8_t timeout_source) } // BLE_GATTS_EVT_HVN_TX_COMPLETE -void event_observer::handle_value_notifications_tx_completed(uint16_t conection_handle, - uint8_t count) +void event_observer::handle_value_notifications_tx_completed( + uint16_t conection_handle, uint8_t count) { ble::profile::connectable* connectable = this->get_connecteable(); if (not connectable) @@ -221,7 +223,7 @@ void event_observer::handle_value_notifications_tx_completed(uint16_t conection_ return; } - if (connectable->connection().get_connection_handle() != conection_handle) + if (connectable->gap.get_connection_handle() != conection_handle) { // This GATTS request is from a different connection. return; diff --git a/ble/nordic_ble_common_event_observable.cc b/ble/nordic_ble_common_event_observable.cc index 49acc3c..9347f12 100644 --- a/ble/nordic_ble_common_event_observable.cc +++ b/ble/nordic_ble_common_event_observable.cc @@ -3,56 +3,35 @@ * @copyright (c) 2018, natersoz. Distributed under the Apache 2.0 license. */ -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" - #include "logger.h" namespace nordic { -template<> -void ble_event_observable::notify( - ble_common_event_observer::event_enum_t event_type, - ble_common_event_observer::event_data_t const& event_data) +void ble_common_event_notify(ble::common::event_observer& observer, + enum BLE_COMMON_EVTS event_type, + ble_common_evt_t const& event_data) { - for (auto observer_iter = this->observer_list_.begin(); - observer_iter != this->observer_list_.end(); ) + auto const memory_type = static_cast( + event_data.params.user_mem_request.type); + + switch (event_type) { - logger &logger = logger::instance(); + case BLE_EVT_USER_MEM_REQUEST: + observer.memory_request(event_data.conn_handle, memory_type, 0u, 1u); + break; - // Increment the iterator prior to using it. - // If the client removes itself during the completion callback - // then the iterator will be valid and can continue. - auto &observer = *observer_iter; - ++observer_iter; + case BLE_EVT_USER_MEM_RELEASE: + observer.memory_release(event_data.conn_handle, + memory_type, + event_data.params.user_mem_release.mem_block.p_mem, + event_data.params.user_mem_release.mem_block.len); + break; - switch (event_type) - { - case BLE_EVT_USER_MEM_REQUEST: - // User Memory request. @ref ble_evt_user_mem_request_t - { - observer.interface_reference.memory_request( - event_data.conn_handle, - static_cast(event_data.params.user_mem_request.type), - 0u, - 1u); - } - break; - case BLE_EVT_USER_MEM_RELEASE: - // User Memory release. @ref ble_evt_user_mem_release_t - { - observer.interface_reference.memory_release( - event_data.conn_handle, - static_cast(event_data.params.user_mem_release.type), - event_data.params.user_mem_release.mem_block.p_mem, - event_data.params.user_mem_release.mem_block.len); - } - break; - default: - logger.warn("unhandled Nordic common event: %u", event_type); - break; - } + default: + logger::instance().warn("unhandled Nordic common event: %u", event_type); + break; } } diff --git a/ble/nordic_ble_event_observable.h b/ble/nordic_ble_event_observable.h deleted file mode 100644 index 5b80be9..0000000 --- a/ble/nordic_ble_event_observable.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file nordic_ble_event_observable.h - * @copyright (c) 2018, natersoz. Distributed under the Apache 2.0 license. - * - * A template class for publishing Noridc BLE events. - * The event type is parameterized in templates and instantiated by type in - * nordic_ble_event_observable.cc. - * - * BLE event types that are published by the Nordic softdevice: - * enum BLE_COMMON_EVTS - * enum BLE_GAP_EVTS - * enum BLE_GATTC_EVTS - * enum BLE_GATTS_EVTS - * enum BLE_L2CAP_EVTS @todo not yet implemeneted - */ - -#pragma once - -#include "nordic_ble_event_observer.h" -#include "project_assert.h" -#include - -namespace nordic -{ - -template -class ble_event_observable -{ -public: - ~ble_event_observable() = default; - ble_event_observable() = default; - - ble_event_observable(ble_event_observable const&) = delete; - ble_event_observable(ble_event_observable&&) = delete; - ble_event_observable& operator=(ble_event_observable const &) = delete; - ble_event_observable& operator=(ble_event_observable&&) = delete; - - void attach(observer_type& observer) - { - ASSERT(not observer.is_attached()); - observer.observable_ = this; - this->observer_list_.push_back(observer); - } - - void attach_first(observer_type& observer) - { - ASSERT(not observer.is_attached()); - observer.observable_ = this; - this->observer_list_.push_front(observer); - } - - void detach(observer_type& observer) - { - ASSERT(observer.is_attached()); - observer.observable_ = nullptr; - observer.hook_.unlink(); - } - - void notify(typename observer_type::event_enum_t event_type, - typename observer_type::event_data_t const& event_data); - -private: - using observer_list = - boost::intrusive::list< - observer_type, - boost::intrusive::constant_time_size, - boost::intrusive::member_hook< - observer_type, - boost::intrusive::list_member_hook< -// nordic::ble_event_observer::list_hook_type - boost::intrusive::link_mode - >, - &observer_type::hook_> - >; - - observer_list observer_list_; -}; - -struct ble_observables -{ - static ble_observables& instance(); - - ~ble_observables() = default; - ble_observables() = default; - - ble_observables(ble_observables const&) = delete; - ble_observables(ble_observables&&) = delete; - ble_observables& operator=(ble_observables const &) = delete; - ble_observables& operator=(ble_observables&&) = delete; - - ble_event_observable common_event_observable; - ble_event_observable gap_event_observable; - ble_event_observable gattc_event_observable; - ble_event_observable gattc_discovery_observable; - ble_event_observable gatts_event_observable; -}; - -/** - * Specialized hack to aquire 128-bit UUIDs which have not been - * pre-registered with the Nordic softdevice. - * - * @param connection_handle The connection handle to re-request the GATT handle - * from in order to resolve it. - * @param gatt_handle The attribute handle for which a 128-bit UUID was - * reported by the Nordic softdevice as 'unknown'. - * - * @return uint32_t NRF_SUCCESS if successful. - */ -uint32_t gattc_uuid128_acquire(uint16_t connection_handle, uint16_t gatt_handle); - -} // namespace nordic diff --git a/ble/nordic_ble_event_observables.cc b/ble/nordic_ble_event_observables.cc index 6bb9285..e251574 100644 --- a/ble/nordic_ble_event_observables.cc +++ b/ble/nordic_ble_event_observables.cc @@ -3,40 +3,87 @@ * @copyright (c) 2018, natersoz. Distributed under the Apache 2.0 license. */ -#include "nordic_ble_event_observable.h" +#include "ble/profile_connectable.h" + +#include "nordic_ble_event_observer.h" #include "section_macros.h" #include "project_assert.h" +#include "logger.h" #include -// Instantiate the nordic::ble_obseverables class instance as a singleton. -static nordic::ble_observables ble_observables_instance; +namespace nordic +{ + +static ble::profile::connectable::container ble_connectable_container; +static ble::common::event_observer nordic_common_event_observer; -// Allow access to the nordic::ble_obseverables singleton. -nordic::ble_observables& nordic::ble_observables::instance() +void register_ble_connectable(ble::profile::connectable& ble_connectable) { - return ble_observables_instance; + if (not ble_connectable.is_linked()) + { + ble_connectable_container.push_back(ble_connectable); + } + else + { + logger::instance().warn( + "register_ble_connectable(0x%p) connectable already connected", + &ble_connectable); + } + + ble_connectable_container.push_back(ble_connectable); +} + +void deregister_ble_connectable(ble::profile::connectable& ble_connectable) +{ + if (ble_connectable.is_linked()) + { + ble_connectable.unlink(); + } + else + { + logger::instance().warn( + "deregister_ble_connectable(0x%p) connectable not connected", + &ble_connectable); + } } static void nordic_ble_event_handler(ble_evt_t const *ble_event, void *context) { - auto *ble_observables = reinterpret_cast(context); - ASSERT(ble_observables == &ble_observables_instance); + ble::profile::connectable::container* container = + reinterpret_cast(context); + ASSERT(container == &ble_connectable_container); if ((ble_event->header.evt_id >= BLE_EVT_BASE) && // Common BLE events. (ble_event->header.evt_id <= BLE_EVT_LAST)) { - ble_observables->common_event_observable.notify( + nordic::ble_common_event_notify( + nordic_common_event_observer, static_cast(ble_event->header.evt_id), ble_event->evt.common_evt); - } else if ((ble_event->header.evt_id >= BLE_GAP_EVT_BASE) && (ble_event->header.evt_id <= BLE_GAP_EVT_LAST)) { - ble_observables->gap_event_observable.notify( - static_cast(ble_event->header.evt_id), - ble_event->evt.gap_evt); + for (auto iter = ble_connectable_container.begin(); + iter != ble_connectable_container.end(); ) + { + // Increment the iterator prior to using it. + // If the client removes itself during the notification callback + // then the iterator will remain valid and can continue. + ble::profile::connectable& connectable = *iter; + ++iter; + + /// @todo Check connection handle and only notify the connectable + /// object for which the connection handle matches. (?) + /// If the connection handle of the connectable is invalid then + /// notify since it is not yet connected and this might be its + /// connection notification. + nordic::ble_gap_event_notify( + connectable.gap, + static_cast(ble_event->header.evt_id), + ble_event->evt.gap_evt); + } } else if ((ble_event->header.evt_id >= BLE_GATTC_EVT_BASE) && (ble_event->header.evt_id <= BLE_GATTC_EVT_LAST)) @@ -44,28 +91,72 @@ static void nordic_ble_event_handler(ble_evt_t const *ble_event, void *context) enum BLE_GATTC_EVTS const gattc_event = static_cast(ble_event->header.evt_id); - // Note that GATTC events are broken up into 2 parts within this C++ - // framework: gattc responses and discovery responses. - // They are demultiplexed here into separate observers. - // The Nordic response for reading by UUID marks the beginning of - // the non-discovery responses. - if (gattc_event >= BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP) + for (auto iter = ble_connectable_container.begin(); + iter != ble_connectable_container.end(); ) { - ble_observables->gattc_event_observable.notify( - gattc_event, ble_event->evt.gattc_evt); - } - else - { - ble_observables->gattc_discovery_observable.notify( - gattc_event, ble_event->evt.gattc_evt); + // Increment the iterator prior to using it. + // If the client removes itself during the notification callback + // then the iterator will remain valid and can continue. + ble::profile::connectable& connectable = *iter; + ++iter; + + // Note that GATTC events are broken up into 2 parts: + // gattc responses and discovery responses. + // They are demultiplexed here into separate observers. + // The Nordic response for reading by UUID marks the beginning + // of the non-discovery responses. + if (gattc_event >= BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP) + { + if (connectable.gattc.event_observer) + { + ble_gattc_event_notify(*connectable.gattc.event_observer, + gattc_event, + ble_event->evt.gattc_evt); + } + } + else + { + if (connectable.gattc.service_builder) + { + ble_discovery_response(*connectable.gattc.service_builder, + gattc_event, + ble_event->evt.gattc_evt); + } + } } } else if ((ble_event->header.evt_id >= BLE_GATTS_EVT_BASE) && (ble_event->header.evt_id <= BLE_GATTS_EVT_LAST)) { - ble_observables->gatts_event_observable.notify( - static_cast(ble_event->header.evt_id), - ble_event->evt.gatts_evt); + enum BLE_GATTS_EVTS const gatts_event = + static_cast(ble_event->header.evt_id); + + for (auto iter = ble_connectable_container.begin(); + iter != ble_connectable_container.end(); ) + { + // Increment the iterator prior to using it. + // If the client removes itself during the notification callback + // then the iterator will remain valid and can continue. + ble::profile::connectable& connectable = *iter; + ++iter; + + // Note that GATTC events are broken up into 2 parts: + // gattc responses and discovery responses. + // They are demultiplexed here into separate observers. + // The Nordic response for reading by UUID marks the beginning + // of the non-discovery responses. + if (connectable.gatts.event_observer) + { + ble_gatts_event_notify(*connectable.gatts.event_observer, + gatts_event, + ble_event->evt.gatts_evt); + } + } + } + else + { + logger::instance().warn("Unknown nordic BLE event: 0x%02x", + ble_event->header.evt_id); } } @@ -75,5 +166,7 @@ static nrf_sdh_ble_evt_observer_t sdh_ble_event_observer IN_SECTION(".sdh_ble_observers") = { .handler = nordic_ble_event_handler, - .p_context = &ble_observables_instance + .p_context = &ble_connectable_container }; + +} // namespace nordic diff --git a/ble/nordic_ble_event_observer.h b/ble/nordic_ble_event_observer.h index 26f4a26..3c30390 100644 --- a/ble/nordic_ble_event_observer.h +++ b/ble/nordic_ble_event_observer.h @@ -1,78 +1,75 @@ /** * @file nordic_ble_event_observer.h * @copyright (c) 2018, natersoz. Distributed under the Apache 2.0 license. - * - * Observer interface for receiving Noridc BLE softdevice events. */ #pragma once -#include "ble/common_event_observer.h" // Abstract BLE event observers +#include "ble/common_event_observer.h" // BLE event observer interfaces #include "ble/gap_event_observer.h" #include "ble/gattc_event_observer.h" #include "ble/gattc_discovery_observer.h" #include "ble/gatts_event_observer.h" +#include "ble/profile_connectable.h" -#include +#include // Nordic BLE softdevice headers #include #include #include -#include +#include namespace nordic { +void ble_common_event_notify(ble::common::event_observer& observer, + enum BLE_COMMON_EVTS event_type, + ble_common_evt_t const& event_data); -template -class ble_event_observable; - -template -class ble_event_observer -{ -public: - using event_enum_t = event_enum_type; - using event_data_t = event_data_type; - - virtual ~ble_event_observer() = default; - - ble_event_observer() = delete; - ble_event_observer(ble_event_observer const&) = delete; - ble_event_observer(ble_event_observer&&) = delete; - ble_event_observer& operator=(ble_event_observer const &) = delete; - ble_event_observer& operator=(ble_event_observer&&) = delete; +void ble_gap_event_notify(ble::gap::event_observer& observer, + enum BLE_GAP_EVTS gap_event_type, + ble_gap_evt_t const& gap_event_data); - explicit ble_event_observer(interface_type &interface): - interface_reference(interface), - observable_(nullptr) {} +void ble_gatts_event_notify(ble::gatts::event_observer& observer, + enum BLE_GATTS_EVTS gatts_event_type, + ble_gatts_evt_t const& gatts_event_data); - bool is_attached() const { return bool(this->observable_); } +void ble_gattc_event_notify(ble::gattc::event_observer& observer, + enum BLE_GATTC_EVTS event_type, + ble_gattc_evt_t const& event_data); - interface_type& interface_reference; +void ble_discovery_response(ble::gattc::discovery_observer& observer, + enum BLE_GATTC_EVTS event_type, + ble_gattc_evt_t const& event_data); -private: - using list_hook_type = boost::intrusive::list_member_hook< - boost::intrusive::link_mode - >; - - list_hook_type hook_; - - using observable_type = - ble_event_observable >; - - observable_type volatile *observable_; +/** + * Enable the Nordic softdevice events to be observed by the + * ble::profile::connectable class. + * + * @param ble_connectable The ble::profile::connectable reference to receive + * BLE events. + */ +void register_ble_connectable(ble::profile::connectable& ble_connectable); - friend observable_type; -}; +/** + * Disable the Nordic softdevice events from being observed by the + * ble::profile::connectable class. + * + * @param ble_connectable The ble::profile::connectable reference to disable + * receiving BLE events. + */ +void deregister_ble_connectable(ble::profile::connectable& ble_connectable); -using ble_common_event_observer = ble_event_observer; -using ble_gap_event_observer = ble_event_observer; -using ble_gattc_event_observer = ble_event_observer; -using ble_gattc_discovery_observer = ble_event_observer; -using ble_gatts_event_observer = ble_event_observer; -// TBD using ble_l2cap_event_observer = ble_event_observer; +/** + * Specialized hack to aquire 128-bit UUIDs which have not been + * pre-registered with the Nordic softdevice. + * + * @param connection_handle The connection handle to re-request the GATT handle + * from in order to resolve it. + * @param gatt_handle The attribute handle for which a 128-bit UUID was + * reported by the Nordic softdevice as 'unknown'. + * + * @return uint32_t NRF_SUCCESS if successful. + */ +uint32_t gattc_uuid128_acquire(uint16_t connection_handle, uint16_t gatt_handle); } // namespace nordic diff --git a/ble/nordic_ble_gap_event_observable.cc b/ble/nordic_ble_gap_event_observable.cc index de85ffc..47ffc51 100644 --- a/ble/nordic_ble_gap_event_observable.cc +++ b/ble/nordic_ble_gap_event_observable.cc @@ -6,7 +6,6 @@ * into the Nordic BLE observables. */ -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" #include "ble/nordic_ble_gap_logger.h" @@ -22,7 +21,8 @@ namespace nordic * Convert Nordic BLE_GAP_SEC_STATUS GAP Security status values to * ble::gap::pairing_failure enum values. */ -static ble::gap::security::pairing_failure auth_status_to_pairing_failure(uint8_t auth_status) +static ble::gap::security::pairing_failure auth_status_to_pairing_failure( + uint8_t auth_status) { if (auth_status > BLE_GAP_SEC_STATUS_RFU_RANGE1_END) { @@ -40,500 +40,500 @@ static ble::gap::security::pairing_failure auth_status_to_pairing_failure(uint8_ break; } - logger::instance().warn("unhandled nordic::auth_status_to_pairing_failure(%u)", auth_status); + logger::instance().warn( + "unhandled nordic::auth_status_to_pairing_failure(%u)", auth_status); return ble::gap::security::pairing_failure::failure_unknown; } -template<> -void ble_event_observable::notify( - ble_gap_event_observer::event_enum_t event_type, - ble_gap_event_observer::event_data_t const& event_data) +void ble_gap_event_notify( + ble::gap::event_observer& observer, + enum BLE_GAP_EVTS event_type, + ble_gap_evt_t const& event_data) { logger &logger = logger::instance(); - for (auto observer_iter = this->observer_list_.begin(); - observer_iter != this->observer_list_.end(); ) + switch (event_type) { - // Increment the iterator prior to using it. - // If the client removes itself during the completion callback - // then the iterator will be valid and can continue. - ble_gap_event_observer &observer = *observer_iter; - ++observer_iter; + case BLE_GAP_EVT_CONNECTED: + { + logger::instance().debug("GAP connect: h: 0x%04x, role: %u, peer: ", + event_data.conn_handle, event_data.params.connected.role); + log_address(logger::level::debug, + event_data.params.connected.peer_addr); + + ble::gap::address peer_address( + event_data.params.connected.peer_addr.addr, + event_data.params.connected.peer_addr.addr_type); + + observer.connect( + event_data.conn_handle, + peer_address, + event_data.params.connected.peer_addr.addr_id_peer); + } + break; + + case BLE_GAP_EVT_DISCONNECTED: + { + logger::instance().debug( + "GAP disconnect: h: 0x%04x, hci error: 0x%02x", + event_data.conn_handle, event_data.params.disconnected.reason); + + observer.disconnect( + event_data.conn_handle, + static_cast( + event_data.params.disconnected.reason)); + } + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE: + // The connection interval, slave latency, supervision timeout + // have been updated. + { + ble::gap::connection_parameters const conn_params = { + event_data.params.conn_param_update.conn_params.min_conn_interval, + event_data.params.conn_param_update.conn_params.max_conn_interval, + event_data.params.conn_param_update.conn_params.slave_latency, + event_data.params.conn_param_update.conn_params.conn_sup_timeout + }; + + logger::instance().debug( + "GAP connection params update: h: 0x%04x, interval:" + " (%u, %u), latency: %u, sup_timeout: %u", + event_data.conn_handle, + conn_params.interval_min, conn_params.interval_max, + conn_params.slave_latency, conn_params.supervision_timeout); + + observer.connection_parameter_update( + event_data.conn_handle, + conn_params); + } + break; + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + /// @todo Nordic secific: Reply with sd_ble_gap_sec_params_reply. + /// Receive ble_gap_evt_sec_params_request_t + { + ble_gap_sec_params_t const &sec_params = + event_data.params.sec_params_request.peer_params; + ble::gap::security::pairing_request const pairing_request = { + .io_caps = static_cast(sec_params.io_caps), + .oob = static_cast(sec_params.oob), + .auth_required = { + .mitm = bool(sec_params.mitm), + .lesc = bool(sec_params.lesc), + .keypress = bool(sec_params.keypress), + .ct2 = false /// @todo ?? + }, + + .encryption_key_size_min = sec_params.min_key_size, + .encryption_key_size_max = sec_params.max_key_size, + // The peer is making the request, + // therefore the peer is the initiator. + .initiator_key_distribution = { + .enc_key = bool(sec_params.kdist_peer.enc), + .id_key = bool(sec_params.kdist_peer.id), + .sign_key = bool(sec_params.kdist_peer.sign), + .link_key = bool(sec_params.kdist_peer.link) + }, + .responder_key_distribution = { + .enc_key = bool(sec_params.kdist_own.enc), + .id_key = bool(sec_params.kdist_own.id), + .sign_key = bool(sec_params.kdist_own.sign), + .link_key = bool(sec_params.kdist_own.link) + }, + }; + + logger::instance().debug("GAP secutiry pairing request: h: 0x%04x", + event_data.conn_handle); + logger::instance().debug("io_caps: 0x%04x, oob: %u", + pairing_request.io_caps, + pairing_request.oob); + logger::instance().debug("auth_req: mitm: %u, lesc: %u, keypress: %u, ct2: %u", + pairing_request.auth_required.mitm, + pairing_request.auth_required.lesc, + pairing_request.auth_required.keypress, + pairing_request.auth_required.ct2); + logger::instance().debug("key dist init: enc: %u, id: %u, sign: %u, link: %u", + pairing_request.initiator_key_distribution.enc_key, + pairing_request.initiator_key_distribution.id_key, + pairing_request.initiator_key_distribution.sign_key, + pairing_request.initiator_key_distribution.link_key); + logger::instance().debug("key dist resp: enc: %u, id: %u, sign: %u, link: %u", + pairing_request.initiator_key_distribution.enc_key, + pairing_request.initiator_key_distribution.id_key, + pairing_request.initiator_key_distribution.sign_key, + pairing_request.initiator_key_distribution.link_key); + + observer.security_pairing_request( + event_data.conn_handle, + bool(sec_params.bond), + pairing_request); + } + break; + + case BLE_GAP_EVT_SEC_INFO_REQUEST: + /// Receive ble_gap_evt_sec_info_request_t. + /// @todo Nordic specific: Reply with sd_ble_gap_sec_info_reply. + { + ble_gap_evt_sec_info_request_t const& info_request = event_data.params.sec_info_request; + + ble::gap::security::key_distribution const key_dist = { + .enc_key = bool(info_request.enc_info), + .id_key = bool(info_request.id_info), + .sign_key = bool(info_request.sign_info), + .link_key = false + }; + + ble::gap::security::master_id const master_id = { + .ediv = info_request.master_id.ediv, + .rand = utility::to_array(info_request.master_id.rand) + }; + + ble::gap::address const peer_address(info_request.peer_addr.addr, + info_request.peer_addr.addr_type); + + logger::instance().debug("GAP secutiry info request: h: 0x%04x", + event_data.conn_handle); + logger::instance().debug("key dist: enc: %u, id: %u, sign: %u, link: %u", + key_dist.enc_key, key_dist.id_key, + key_dist.sign_key, key_dist.link_key); + + observer.security_information_request( + event_data.conn_handle, + key_dist, + master_id, + peer_address); + } + break; + + case BLE_GAP_EVT_PASSKEY_DISPLAY: + /// Receive ble_gap_evt_passkey_display_t + /// @todo Nordic specific: reply with sd_ble_gap_auth_key_reply + { + ble::gap::security::pass_key const pass_key = + utility::to_array(event_data.params.passkey_display.passkey); + + logger::instance().debug("GAP passkey display: h: 0x%04x, '%c%c%c%c%c%c'", + event_data.conn_handle, + pass_key[0], pass_key[1], pass_key[2], + pass_key[3], pass_key[4], pass_key[5]); + + observer.security_passkey_display( + event_data.conn_handle, + pass_key, + bool(event_data.params.passkey_display.match_request)); + } + break; + + case BLE_GAP_EVT_KEY_PRESSED: + { + logger::instance().debug("GAP key press event: h: 0x%04x, %u", + event_data.conn_handle, + event_data.params.key_pressed.kp_not); + + // Since Nordic BLE_GAP_KP_NOT_TYPES also take their values from the + // Core BT specification we can just cast to the passkey_event enum type. + observer.security_key_pressed( + event_data.conn_handle, + static_cast(event_data.params.key_pressed.kp_not)); + } + break; + + case BLE_GAP_EVT_AUTH_KEY_REQUEST: + { + logger::instance().debug("GAP auth key request: h: 0x%04x, %u", + event_data.conn_handle, + event_data.params.auth_key_request.key_type); + + /// @todo Nordic Specific: What part of the BT Core does this map to? + /// Investigate how this works in practice and understand it. + /// For now just pass through. + observer.security_authentication_key_request( + event_data.conn_handle, + event_data.params.auth_key_request.key_type); + } + break; + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + { + /// The peer has requested a Diffie-Hellman key calculation. + /// @todo Nordic Specific: Reply with sd_ble_gap_lesc_dhkey_reply. + ble::gap::security::pubk const public_key = utility::to_array( + event_data.params.lesc_dhkey_request.p_pk_peer->pk); + + logger::instance().debug("GAP DH key request: h: 0x%04x", event_data.conn_handle); + logger::instance().write_data(logger::level::debug, + event_data.params.lesc_dhkey_request.p_pk_peer->pk, + sizeof(event_data.params.lesc_dhkey_request.p_pk_peer->pk)); + + observer.security_DH_key_calculation_request( + event_data.conn_handle, + public_key, + bool(event_data.params.lesc_dhkey_request.oobd_req)); + } + break; + + case BLE_GAP_EVT_AUTH_STATUS: + { + /// @todo Nordic Specific: Determine how this maps to Core spec. + ble_gap_evt_auth_status_t const &auth_status = event_data.params.auth_status; + + ble::gap::security::pairing_failure const pairing_status = + auth_status_to_pairing_failure(auth_status.auth_status); + + uint8_t const sec_mode_1_levels = + (auth_status.sm1_levels.lv1 ? 1u : 0u) | + (auth_status.sm1_levels.lv2 ? 2u : 0u) | + (auth_status.sm1_levels.lv3 ? 4u : 0u) | + (auth_status.sm1_levels.lv4 ? 8u : 0u) ; + + uint8_t const sec_mode_2_levels = + (auth_status.sm2_levels.lv1 ? 1u : 0u) | + (auth_status.sm2_levels.lv2 ? 2u : 0u) | + (auth_status.sm2_levels.lv3 ? 4u : 0u) | + (auth_status.sm2_levels.lv4 ? 8u : 0u) ; + + ble::gap::security::key_distribution const kdist_own = { + .enc_key = bool(auth_status.kdist_own.enc), + .id_key = bool(auth_status.kdist_own.id), + .sign_key = bool(auth_status.kdist_own.sign), + .link_key = bool(auth_status.kdist_own.link) + }; + + ble::gap::security::key_distribution const kdist_peer = { + .enc_key = bool(auth_status.kdist_peer.enc), + .id_key = bool(auth_status.kdist_peer.id), + .sign_key = bool(auth_status.kdist_peer.sign), + .link_key = bool(auth_status.kdist_peer.link) + }; + + logger::instance().debug("GAP auth status: h: 0x%04x, sm_1: %u, sm_2: %u, status: %u", + event_data.conn_handle, sec_mode_1_levels, sec_mode_2_levels, pairing_status); + logger::instance().debug("key dist own : enc: %u, id: %u, sign: %u, link: %u", + kdist_own.enc_key, kdist_own.id_key, kdist_own.sign_key, kdist_own.link_key); + logger::instance().debug("key dist peer: enc: %u, id: %u, sign: %u, link: %u", + kdist_peer.enc_key, kdist_peer.id_key, kdist_peer.sign_key, kdist_peer.link_key); + + observer.security_authentication_status( + event_data.conn_handle, + pairing_status, + auth_status.error_src, + bool(auth_status.bonded), + sec_mode_1_levels, + sec_mode_2_levels, + kdist_own, + kdist_peer); + } + break; + + case BLE_GAP_EVT_CONN_SEC_UPDATE: + { + logger::instance().debug("GAP security update: h: 0x%04x, mode: %u, level: %u, key size: %u", + event_data.conn_handle, + event_data.params.conn_sec_update.conn_sec.sec_mode.sm, + event_data.params.conn_sec_update.conn_sec.sec_mode.lv, + event_data.params.conn_sec_update.conn_sec.encr_key_size); + + observer.connection_security_update( + event_data.conn_handle, + event_data.params.conn_sec_update.conn_sec.sec_mode.sm, + event_data.params.conn_sec_update.conn_sec.sec_mode.lv, + event_data.params.conn_sec_update.conn_sec.encr_key_size); + } + break; + + case BLE_GAP_EVT_TIMEOUT: + { + logger::instance().debug("GAP timeout: h: 0x%04x, reason: %u", + event_data.conn_handle, event_data.params.timeout.src); + + observer.timeout_expiration( + event_data.conn_handle, + static_cast(event_data.params.timeout.src)); + } + break; + + case BLE_GAP_EVT_RSSI_CHANGED: + { + logger::instance().debug("GAP rssi changed: h: 0x%04x, rssi: %d", + event_data.conn_handle, event_data.params.rssi_changed.rssi); + + observer.rssi_update( + event_data.conn_handle, + event_data.params.rssi_changed.rssi); + } + break; + + case BLE_GAP_EVT_ADV_REPORT: + { + ble::gap::address const peer_address( + event_data.params.adv_report.peer_addr.addr, + event_data.params.adv_report.peer_addr.addr_type); + + ble::gap::address const direct_address( + event_data.params.adv_report.direct_addr.addr, + event_data.params.adv_report.direct_addr.addr_type); + + // Note: unused report fields: + // primary_phy, secondary_phy, ch_index, set_id, data_id + // aux_pointer + + logger::instance().debug( + "GAP advert report: h: 0x%04x, rssi: %d, peer: ", + event_data.conn_handle, event_data.params.adv_report.rssi); + log_address(logger::level::debug, + event_data.params.adv_report.peer_addr); + + logger::instance().debug("direct: "); + log_address(logger::level::debug, + event_data.params.adv_report.direct_addr); + + observer.advertising_report( + event_data.conn_handle, + peer_address, + direct_address, + event_data.params.adv_report.rssi, + false, + event_data.params.adv_report.data.p_data, + event_data.params.adv_report.data.len); + } + break; + + case BLE_GAP_EVT_SEC_REQUEST: + { + ble::gap::security::authentication_required const auth_req = { + .mitm = bool(event_data.params.sec_request.mitm), + .lesc = bool(event_data.params.sec_request.lesc), + .keypress = bool(event_data.params.sec_request.keypress), + .ct2 = false /// @todo check this value. + }; + + logger::instance().debug("GAP secutiry request: h: 0x%04x", event_data.conn_handle); + logger::instance().debug("auth_req: mitm: %u, lesc: %u, keypress: %u, ct2: %u", + auth_req.mitm, auth_req.lesc, auth_req.keypress, auth_req.ct2); + + observer.security_request( + event_data.conn_handle, + bool(event_data.params.sec_request.bond), + auth_req); + } + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: + { + /// @todo Nordic Specific: Reply with sd_ble_gap_conn_param_update. + ble::gap::connection_parameters const conn_params = { + event_data.params.conn_param_update_request.conn_params.min_conn_interval, + event_data.params.conn_param_update_request.conn_params.max_conn_interval, + event_data.params.conn_param_update_request.conn_params.slave_latency, + event_data.params.conn_param_update_request.conn_params.conn_sup_timeout + }; + + logger::instance().debug( + "GAP connection params update request: h: 0x%04x, interval: (%u, %u), latency: %u, sup_timeout: %u", + event_data.conn_handle, + conn_params.interval_min, conn_params.interval_max, + conn_params.slave_latency, conn_params.supervision_timeout); + + observer.connection_parameter_update_request( + event_data.conn_handle, + conn_params); + } + break; + + case BLE_GAP_EVT_SCAN_REQ_REPORT: + { + ble::gap::address const peer_address( + event_data.params.scan_req_report.peer_addr.addr, + event_data.params.scan_req_report.peer_addr.addr_type); + + logger::instance().debug( + "GAP scan request report: h: 0x%04x, rssi: %d, peer: ", + event_data.conn_handle, event_data.params.scan_req_report.rssi); + + log_address(logger::level::debug, + event_data.params.scan_req_report.peer_addr); + + observer.scan_report_request( + event_data.conn_handle, + peer_address, + event_data.params.scan_req_report.rssi); + } + break; + + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + /// @todo Nordic Specific: Reply with sd_ble_gap_phy_update. + { + logger::instance().debug( + "GAP phy update request: h: 0x%04x, rx: %u, tx: %u", + event_data.conn_handle, + event_data.params.phy_update_request.peer_preferred_phys.rx_phys, + event_data.params.phy_update_request.peer_preferred_phys.tx_phys); + + observer.phy_update_request( + event_data.conn_handle, + static_cast(event_data.params.phy_update_request.peer_preferred_phys.rx_phys), + static_cast(event_data.params.phy_update_request.peer_preferred_phys.tx_phys)); + } + break; + + case BLE_GAP_EVT_PHY_UPDATE: + { + logger::instance().debug( + "GAP phy update request: h: 0x%04x, rx: %u, tx: %u", + event_data.conn_handle, + event_data.params.phy_update.rx_phy, event_data.params.phy_update.tx_phy); + + observer.phy_update( + event_data.conn_handle, + static_cast(event_data.params.phy_update.status), + static_cast(event_data.params.phy_update.rx_phy), + static_cast(event_data.params.phy_update.tx_phy)); + } + break; - switch (event_type) + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + /// @todo Nordic specific: reply with sd_ble_gap_data_length_update { - case BLE_GAP_EVT_CONNECTED: - { - logger::instance().debug("GAP connect: h: 0x%04x, role: %u, peer: ", - event_data.conn_handle, event_data.params.connected.role); - log_address(logger::level::debug, - event_data.params.connected.peer_addr); - - ble::gap::address peer_address( - event_data.params.connected.peer_addr.addr, - event_data.params.connected.peer_addr.addr_type); - - observer.interface_reference.connect( - event_data.conn_handle, - peer_address, - event_data.params.connected.peer_addr.addr_id_peer); - } - break; - - case BLE_GAP_EVT_DISCONNECTED: - { - logger::instance().debug( - "GAP disconnect: h: 0x%04x, hci error: 0x%02x", - event_data.conn_handle, event_data.params.disconnected.reason); - - observer.interface_reference.disconnect( - event_data.conn_handle, - static_cast(event_data.params.disconnected.reason)); - } - break; - - // The connection interval, slave latency, supervision timeout have been updated. - case BLE_GAP_EVT_CONN_PARAM_UPDATE: - { - ble::gap::connection_parameters const conn_params = { - event_data.params.conn_param_update.conn_params.min_conn_interval, - event_data.params.conn_param_update.conn_params.max_conn_interval, - event_data.params.conn_param_update.conn_params.slave_latency, - event_data.params.conn_param_update.conn_params.conn_sup_timeout - }; - - logger::instance().debug( - "GAP connection params update: h: 0x%04x, interval: (%u, %u), latency: %u, sup_timeout: %u", - event_data.conn_handle, - conn_params.interval_min, conn_params.interval_max, - conn_params.slave_latency, conn_params.supervision_timeout); - - observer.interface_reference.connection_parameter_update( - event_data.conn_handle, - conn_params); - } - break; - - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - /// @todo Nordic secific: Reply with sd_ble_gap_sec_params_reply. - /// Receive ble_gap_evt_sec_params_request_t - { - ble_gap_sec_params_t const &sec_params = event_data.params.sec_params_request.peer_params; - ble::gap::security::pairing_request const pairing_request = { - .io_caps = static_cast(sec_params.io_caps), - .oob = static_cast(sec_params.oob), - .auth_required = { - .mitm = bool(sec_params.mitm), - .lesc = bool(sec_params.lesc), - .keypress = bool(sec_params.keypress), - .ct2 = false /// @todo ?? - }, - - .encryption_key_size_min = sec_params.min_key_size, - .encryption_key_size_max = sec_params.max_key_size, - // The peer is making the request, - // therefore the peer is the initiator. - .initiator_key_distribution = { - .enc_key = bool(sec_params.kdist_peer.enc), - .id_key = bool(sec_params.kdist_peer.id), - .sign_key = bool(sec_params.kdist_peer.sign), - .link_key = bool(sec_params.kdist_peer.link) - }, - .responder_key_distribution = { - .enc_key = bool(sec_params.kdist_own.enc), - .id_key = bool(sec_params.kdist_own.id), - .sign_key = bool(sec_params.kdist_own.sign), - .link_key = bool(sec_params.kdist_own.link) - }, - }; - - logger::instance().debug("GAP secutiry pairing request: h: 0x%04x", event_data.conn_handle); - logger::instance().debug("io_caps: 0x%04x, oob: %u", pairing_request.io_caps, pairing_request.oob); - logger::instance().debug("auth_req: mitm: %u, lesc: %u, keypress: %u, ct2: %u", - pairing_request.auth_required.mitm, - pairing_request.auth_required.lesc, - pairing_request.auth_required.keypress, - pairing_request.auth_required.ct2); - logger::instance().debug("key dist init: enc: %u, id: %u, sign: %u, link: %u", - pairing_request.initiator_key_distribution.enc_key, - pairing_request.initiator_key_distribution.id_key, - pairing_request.initiator_key_distribution.sign_key, - pairing_request.initiator_key_distribution.link_key); - logger::instance().debug("key dist resp: enc: %u, id: %u, sign: %u, link: %u", - pairing_request.initiator_key_distribution.enc_key, - pairing_request.initiator_key_distribution.id_key, - pairing_request.initiator_key_distribution.sign_key, - pairing_request.initiator_key_distribution.link_key); - - observer.interface_reference.security_pairing_request( - event_data.conn_handle, - bool(sec_params.bond), - pairing_request); - } - break; - - case BLE_GAP_EVT_SEC_INFO_REQUEST: - /// Receive ble_gap_evt_sec_info_request_t. - /// @todo Nordic specific: Reply with sd_ble_gap_sec_info_reply. - { - ble_gap_evt_sec_info_request_t const& info_request = event_data.params.sec_info_request; - - ble::gap::security::key_distribution const key_dist = { - .enc_key = bool(info_request.enc_info), - .id_key = bool(info_request.id_info), - .sign_key = bool(info_request.sign_info), - .link_key = false - }; - - ble::gap::security::master_id const master_id = { - .ediv = info_request.master_id.ediv, - .rand = utility::to_array(info_request.master_id.rand) - }; - - ble::gap::address const peer_address(info_request.peer_addr.addr, - info_request.peer_addr.addr_type); - - logger::instance().debug("GAP secutiry info request: h: 0x%04x", event_data.conn_handle); - logger::instance().debug("key dist: enc: %u, id: %u, sign: %u, link: %u", - key_dist.enc_key, key_dist.id_key, key_dist.sign_key, key_dist.link_key); - - observer.interface_reference.security_information_request( - event_data.conn_handle, - key_dist, - master_id, - peer_address); - } - break; - - case BLE_GAP_EVT_PASSKEY_DISPLAY: - /// Receive ble_gap_evt_passkey_display_t - /// @todo Nordic specific: reply with sd_ble_gap_auth_key_reply - { - ble::gap::security::pass_key const pass_key = - utility::to_array(event_data.params.passkey_display.passkey); - - logger::instance().debug("GAP passkey display: h: 0x%04x, '%c%c%c%c%c%c'", - event_data.conn_handle, - pass_key[0], pass_key[1], pass_key[2], - pass_key[3], pass_key[4], pass_key[5]); - - observer.interface_reference.security_passkey_display( - event_data.conn_handle, - pass_key, - bool(event_data.params.passkey_display.match_request)); - } - break; - - case BLE_GAP_EVT_KEY_PRESSED: - { - logger::instance().debug("GAP key press event: h: 0x%04x, %u", - event_data.conn_handle, - event_data.params.key_pressed.kp_not); - - // Since Nordic BLE_GAP_KP_NOT_TYPES also take their values from the - // Core BT specification we can just cast to the passkey_event enum type. - observer.interface_reference.security_key_pressed( - event_data.conn_handle, - static_cast(event_data.params.key_pressed.kp_not)); - } - break; - - case BLE_GAP_EVT_AUTH_KEY_REQUEST: - { - logger::instance().debug("GAP auth key request: h: 0x%04x, %u", - event_data.conn_handle, - event_data.params.auth_key_request.key_type); - - /// @todo Nordic Specific: What part of the BT Core does this map to? - /// Investigate how this works in practice and understand it. - /// For now just pass through. - observer.interface_reference.security_authentication_key_request( - event_data.conn_handle, - event_data.params.auth_key_request.key_type); - } - break; - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: - { - /// The peer has requested a Diffie-Hellman key calculation. - /// @todo Nordic Specific: Reply with sd_ble_gap_lesc_dhkey_reply. - ble::gap::security::pubk const public_key = utility::to_array( - event_data.params.lesc_dhkey_request.p_pk_peer->pk); - - logger::instance().debug("GAP DH key request: h: 0x%04x", event_data.conn_handle); - logger::instance().write_data(logger::level::debug, - event_data.params.lesc_dhkey_request.p_pk_peer->pk, - sizeof(event_data.params.lesc_dhkey_request.p_pk_peer->pk)); - - observer.interface_reference.security_DH_key_calculation_request( - event_data.conn_handle, - public_key, - bool(event_data.params.lesc_dhkey_request.oobd_req)); - } - break; - - case BLE_GAP_EVT_AUTH_STATUS: - { - /// @todo Nordic Specific: Determine how this maps to Core spec. - ble_gap_evt_auth_status_t const &auth_status = event_data.params.auth_status; - - ble::gap::security::pairing_failure const pairing_status = - auth_status_to_pairing_failure(auth_status.auth_status); - - uint8_t const sec_mode_1_levels = - (auth_status.sm1_levels.lv1 ? 1u : 0u) | - (auth_status.sm1_levels.lv2 ? 2u : 0u) | - (auth_status.sm1_levels.lv3 ? 4u : 0u) | - (auth_status.sm1_levels.lv4 ? 8u : 0u) ; - - uint8_t const sec_mode_2_levels = - (auth_status.sm2_levels.lv1 ? 1u : 0u) | - (auth_status.sm2_levels.lv2 ? 2u : 0u) | - (auth_status.sm2_levels.lv3 ? 4u : 0u) | - (auth_status.sm2_levels.lv4 ? 8u : 0u) ; - - ble::gap::security::key_distribution const kdist_own = { - .enc_key = bool(auth_status.kdist_own.enc), - .id_key = bool(auth_status.kdist_own.id), - .sign_key = bool(auth_status.kdist_own.sign), - .link_key = bool(auth_status.kdist_own.link) - }; - - ble::gap::security::key_distribution const kdist_peer = { - .enc_key = bool(auth_status.kdist_peer.enc), - .id_key = bool(auth_status.kdist_peer.id), - .sign_key = bool(auth_status.kdist_peer.sign), - .link_key = bool(auth_status.kdist_peer.link) - }; - - logger::instance().debug("GAP auth status: h: 0x%04x, sm_1: %u, sm_2: %u, status: %u", - event_data.conn_handle, sec_mode_1_levels, sec_mode_2_levels, pairing_status); - logger::instance().debug("key dist own : enc: %u, id: %u, sign: %u, link: %u", - kdist_own.enc_key, kdist_own.id_key, kdist_own.sign_key, kdist_own.link_key); - logger::instance().debug("key dist peer: enc: %u, id: %u, sign: %u, link: %u", - kdist_peer.enc_key, kdist_peer.id_key, kdist_peer.sign_key, kdist_peer.link_key); - - observer.interface_reference.security_authentication_status( - event_data.conn_handle, - pairing_status, - auth_status.error_src, - bool(auth_status.bonded), - sec_mode_1_levels, - sec_mode_2_levels, - kdist_own, - kdist_peer); - } - break; - - case BLE_GAP_EVT_CONN_SEC_UPDATE: - { - logger::instance().debug("GAP security update: h: 0x%04x, mode: %u, level: %u, key size: %u", - event_data.conn_handle, - event_data.params.conn_sec_update.conn_sec.sec_mode.sm, - event_data.params.conn_sec_update.conn_sec.sec_mode.lv, - event_data.params.conn_sec_update.conn_sec.encr_key_size); - - observer.interface_reference.connection_security_update( - event_data.conn_handle, - event_data.params.conn_sec_update.conn_sec.sec_mode.sm, - event_data.params.conn_sec_update.conn_sec.sec_mode.lv, - event_data.params.conn_sec_update.conn_sec.encr_key_size); - } - break; - - case BLE_GAP_EVT_TIMEOUT: - { - logger::instance().debug("GAP timeout: h: 0x%04x, reason: %u", - event_data.conn_handle, event_data.params.timeout.src); - - observer.interface_reference.timeout_expiration( - event_data.conn_handle, - static_cast(event_data.params.timeout.src)); - } - break; - - case BLE_GAP_EVT_RSSI_CHANGED: - { - logger::instance().debug("GAP rssi changed: h: 0x%04x, rssi: %d", - event_data.conn_handle, event_data.params.rssi_changed.rssi); - - observer.interface_reference.rssi_update( - event_data.conn_handle, - event_data.params.rssi_changed.rssi); - } - break; - - case BLE_GAP_EVT_ADV_REPORT: - { - ble::gap::address const peer_address( - event_data.params.adv_report.peer_addr.addr, - event_data.params.adv_report.peer_addr.addr_type); - - ble::gap::address const direct_address( - event_data.params.adv_report.direct_addr.addr, - event_data.params.adv_report.direct_addr.addr_type); - - // Note: unused report fields: - // primary_phy, secondary_phy, ch_index, set_id, data_id - // aux_pointer - - logger::instance().debug( - "GAP advert report: h: 0x%04x, rssi: %d, peer: ", - event_data.conn_handle, event_data.params.adv_report.rssi); - log_address(logger::level::debug, - event_data.params.adv_report.peer_addr); - - logger::instance().debug("direct: "); - log_address(logger::level::debug, - event_data.params.adv_report.direct_addr); - - observer.interface_reference.advertising_report( - event_data.conn_handle, - peer_address, - direct_address, - event_data.params.adv_report.rssi, - false, - event_data.params.adv_report.data.p_data, - event_data.params.adv_report.data.len); - } - break; - - case BLE_GAP_EVT_SEC_REQUEST: - { - ble::gap::security::authentication_required const auth_req = { - .mitm = bool(event_data.params.sec_request.mitm), - .lesc = bool(event_data.params.sec_request.lesc), - .keypress = bool(event_data.params.sec_request.keypress), - .ct2 = false /// @todo check this value. - }; - - logger::instance().debug("GAP secutiry request: h: 0x%04x", event_data.conn_handle); - logger::instance().debug("auth_req: mitm: %u, lesc: %u, keypress: %u, ct2: %u", - auth_req.mitm, auth_req.lesc, auth_req.keypress, auth_req.ct2); - - observer.interface_reference.security_request( - event_data.conn_handle, - bool(event_data.params.sec_request.bond), - auth_req); - } - break; - - case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: - { - /// @todo Nordic Specific: Reply with sd_ble_gap_conn_param_update. - ble::gap::connection_parameters const conn_params = { - event_data.params.conn_param_update_request.conn_params.min_conn_interval, - event_data.params.conn_param_update_request.conn_params.max_conn_interval, - event_data.params.conn_param_update_request.conn_params.slave_latency, - event_data.params.conn_param_update_request.conn_params.conn_sup_timeout - }; - - logger::instance().debug( - "GAP connection params update request: h: 0x%04x, interval: (%u, %u), latency: %u, sup_timeout: %u", - event_data.conn_handle, - conn_params.interval_min, conn_params.interval_max, - conn_params.slave_latency, conn_params.supervision_timeout); - - observer.interface_reference.connection_parameter_update_request( - event_data.conn_handle, - conn_params); - } - break; - - case BLE_GAP_EVT_SCAN_REQ_REPORT: - { - ble::gap::address const peer_address( - event_data.params.scan_req_report.peer_addr.addr, - event_data.params.scan_req_report.peer_addr.addr_type); - - logger::instance().debug( - "GAP scan request report: h: 0x%04x, rssi: %d, peer: ", - event_data.conn_handle, event_data.params.scan_req_report.rssi); - - log_address(logger::level::debug, - event_data.params.scan_req_report.peer_addr); - - observer.interface_reference.scan_report_request( - event_data.conn_handle, - peer_address, - event_data.params.scan_req_report.rssi); - } - break; - - case BLE_GAP_EVT_PHY_UPDATE_REQUEST: - /// @todo Nordic Specific: Reply with sd_ble_gap_phy_update. - { - logger::instance().debug( - "GAP phy update request: h: 0x%04x, rx: %u, tx: %u", - event_data.conn_handle, - event_data.params.phy_update_request.peer_preferred_phys.rx_phys, - event_data.params.phy_update_request.peer_preferred_phys.tx_phys); - - observer.interface_reference.phy_update_request( - event_data.conn_handle, - static_cast(event_data.params.phy_update_request.peer_preferred_phys.rx_phys), - static_cast(event_data.params.phy_update_request.peer_preferred_phys.tx_phys)); - } - break; - - case BLE_GAP_EVT_PHY_UPDATE: - { - logger::instance().debug( - "GAP phy update request: h: 0x%04x, rx: %u, tx: %u", - event_data.conn_handle, - event_data.params.phy_update.rx_phy, event_data.params.phy_update.tx_phy); - - observer.interface_reference.phy_update( - event_data.conn_handle, - static_cast(event_data.params.phy_update.status), - static_cast(event_data.params.phy_update.rx_phy), - static_cast(event_data.params.phy_update.tx_phy)); - } - break; - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: - /// @todo Nordic specific: reply with sd_ble_gap_data_length_update - { - logger::instance().debug( - "GAP phy update request: h: 0x%04x, rx: (%u, %u), tx: (%u, %u)", - event_data.conn_handle, - event_data.params.data_length_update_request.peer_params.max_rx_octets, - event_data.params.data_length_update_request.peer_params.max_rx_time_us, - event_data.params.data_length_update_request.peer_params.max_tx_octets, - event_data.params.data_length_update_request.peer_params.max_tx_time_us); - - observer.interface_reference.link_layer_update_request( - event_data.conn_handle, - event_data.params.data_length_update_request.peer_params.max_rx_octets, - event_data.params.data_length_update_request.peer_params.max_rx_time_us, - event_data.params.data_length_update_request.peer_params.max_tx_octets, - event_data.params.data_length_update_request.peer_params.max_tx_time_us); - } - break; - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE: - { - logger::instance().debug( - "GAP phy update request: h: 0x%04x, rx: (%u, %u), tx: (%u, %u)", - event_data.conn_handle, - event_data.params.data_length_update_request.peer_params.max_rx_octets, - event_data.params.data_length_update_request.peer_params.max_rx_time_us, - event_data.params.data_length_update_request.peer_params.max_tx_octets, - event_data.params.data_length_update_request.peer_params.max_tx_time_us); - - observer.interface_reference.link_layer_update( - event_data.conn_handle, - event_data.params.data_length_update.effective_params.max_rx_octets, - event_data.params.data_length_update.effective_params.max_rx_time_us, - event_data.params.data_length_update.effective_params.max_tx_octets, - event_data.params.data_length_update.effective_params.max_tx_time_us); - } - break; - - default: - logger.warn("unhandled GAP event: %u", event_type); - break; + logger::instance().debug( + "GAP phy update request: h: 0x%04x, rx: (%u, %u), tx: (%u, %u)", + event_data.conn_handle, + event_data.params.data_length_update_request.peer_params.max_rx_octets, + event_data.params.data_length_update_request.peer_params.max_rx_time_us, + event_data.params.data_length_update_request.peer_params.max_tx_octets, + event_data.params.data_length_update_request.peer_params.max_tx_time_us); + + observer.link_layer_update_request( + event_data.conn_handle, + event_data.params.data_length_update_request.peer_params.max_rx_octets, + event_data.params.data_length_update_request.peer_params.max_rx_time_us, + event_data.params.data_length_update_request.peer_params.max_tx_octets, + event_data.params.data_length_update_request.peer_params.max_tx_time_us); } + break; + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE: + { + logger::instance().debug( + "GAP phy update request: h: 0x%04x, rx: (%u, %u), tx: (%u, %u)", + event_data.conn_handle, + event_data.params.data_length_update_request.peer_params.max_rx_octets, + event_data.params.data_length_update_request.peer_params.max_rx_time_us, + event_data.params.data_length_update_request.peer_params.max_tx_octets, + event_data.params.data_length_update_request.peer_params.max_tx_time_us); + + observer.link_layer_update( + event_data.conn_handle, + event_data.params.data_length_update.effective_params.max_rx_octets, + event_data.params.data_length_update.effective_params.max_rx_time_us, + event_data.params.data_length_update.effective_params.max_tx_octets, + event_data.params.data_length_update.effective_params.max_tx_time_us); + } + break; + + default: + logger.warn("unhandled GAP event: %u", event_type); + break; } } diff --git a/ble/nordic_ble_gattc_discovery_observable.cc b/ble/nordic_ble_gattc_discovery_observable.cc index a4af518..45c34f5 100644 --- a/ble/nordic_ble_gattc_discovery_observable.cc +++ b/ble/nordic_ble_gattc_discovery_observable.cc @@ -8,7 +8,6 @@ #include "ble/att.h" #include "ble/nordic_ble_att.h" -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" #include @@ -16,260 +15,250 @@ #include "nordic_error.h" #include "logger.h" +#include "project_assert.h" namespace nordic { -template<> -void ble_event_observable::notify( - ble_gattc_discovery_observer::event_enum_t event_type, - ble_gattc_discovery_observer::event_data_t const& event_data) +void ble_discovery_response(ble::gattc::discovery_observer& observer, + enum BLE_GATTC_EVTS event_type, + ble_gattc_evt_t const& event_data) { logger &logger = logger::instance(); - for (auto observer_iter = this->observer_list_.begin(); - observer_iter != this->observer_list_.end(); ) + switch (event_type) { - // Increment the iterator prior to using it. - // If the client removes itself during the completion callback - // then the iterator will be valid and can continue. - ble_gattc_discovery_observer &observer = *observer_iter; - ++observer_iter; + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + logger.debug("BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: count: %u", + event_data.params.prim_srvc_disc_rsp.count); - switch (event_type) + for (uint16_t iter = 0u; + iter < event_data.params.prim_srvc_disc_rsp.count; ++iter) { - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - logger.debug("BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: count: %u", - event_data.params.prim_srvc_disc_rsp.count); - - for (uint16_t iter = 0u; - iter < event_data.params.prim_srvc_disc_rsp.count; ++iter) + ble_gattc_service_t const* service = + &event_data.params.prim_srvc_disc_rsp.services[iter]; + + /* The Nordic Unknown UUID type means that a 128-bit UUID was + * received which was no pre-regisetered with the softdevice. + * Issue a raw read request on the GATT start handle. + * When the read response comes in, it will need to be parsed + * as a 128-bit UUID. + */ + if (service->uuid.type == BLE_UUID_TYPE_UNKNOWN) { - ble_gattc_service_t const* service = - &event_data.params.prim_srvc_disc_rsp.services[iter]; - - /* The Nordic Unknown UUID type means that a 128-bit UUID was - * received which was no pre-regisetered with the softdevice. - * Issue a raw read request on the GATT start handle. - * When the read response comes in, it will need to be parsed - * as a 128-bit UUID. - */ - if (service->uuid.type == BLE_UUID_TYPE_UNKNOWN) + // If this call should fail the do not return. + // Keep discovering services as best can be done. + uint32_t const error_code = gattc_uuid128_acquire( + event_data.conn_handle, + service->handle_range.start_handle); + + if (error_code == NRF_SUCCESS) { - // If this call should fail the do not return. - // Keep discovering services as best can be done. - uint32_t const error_code = gattc_uuid128_acquire( - event_data.conn_handle, - service->handle_range.start_handle); - - if (error_code == NRF_SUCCESS) - { - // The call to gattc_uuid128_acquire() set up a read - // response from which service discovery will continue. - return; - } + // The call to gattc_uuid128_acquire() set up a read + // response from which service discovery will continue. + return; } + } - ble::att::uuid const uuid = nordic::to_att_uuid(service->uuid); + ble::att::uuid const uuid = nordic::to_att_uuid(service->uuid); - char uuid_char_buffer[ble::att::uuid::conversion_length]; - uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + char uuid_char_buffer[ble::att::uuid::conversion_length]; + uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - logger.debug("BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP[0x%04x:0x%04x]: %s", - service->handle_range.start_handle, - service->handle_range.end_handle, - uuid_char_buffer); + logger.debug("BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP[0x%04x:0x%04x]: %s", + service->handle_range.start_handle, + service->handle_range.end_handle, + uuid_char_buffer); - observer.interface_reference.service_discovered( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - service->handle_range.start_handle, - service->handle_range.end_handle, - uuid, - iter + 1u >= event_data.params.prim_srvc_disc_rsp.count); - } - break; + observer.service_discovered( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + service->handle_range.start_handle, + service->handle_range.end_handle, + uuid, + iter + 1u >= event_data.params.prim_srvc_disc_rsp.count); + } + break; - case BLE_GATTC_EVT_REL_DISC_RSP: - // Relationship Discovery Response event. - // See ble_gattc_evt_rel_disc_rsp_t. - for (uint16_t iter = 0u; - iter < event_data.params.rel_disc_rsp.count; ++iter) - { - ble_gattc_include_t const* include_disc_rsp = - &event_data.params.rel_disc_rsp.includes[iter]; + case BLE_GATTC_EVT_REL_DISC_RSP: + // Relationship Discovery Response event. + // See ble_gattc_evt_rel_disc_rsp_t. + for (uint16_t iter = 0u; + iter < event_data.params.rel_disc_rsp.count; ++iter) + { + ble_gattc_include_t const* include_disc_rsp = + &event_data.params.rel_disc_rsp.includes[iter]; + + ble_gattc_service_t const* service = &include_disc_rsp->included_srvc; + + ble::att::uuid const uuid = nordic::to_att_uuid(service->uuid); + + char uuid_char_buffer[ble::att::uuid::conversion_length]; + uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + + logger.debug("BLE_GATTC_EVT_REL_DISC_RSP[0x%04:0x%04x]: incl: 0x%04x, %s", + service->handle_range.start_handle, + service->handle_range.end_handle, + include_disc_rsp->handle, + uuid_char_buffer); + + observer.relationship_discovered( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + service->handle_range.start_handle, + service->handle_range.end_handle, + include_disc_rsp->handle, + uuid, + iter + 1u >= event_data.params.rel_disc_rsp.count); + } + break; - ble_gattc_service_t const* service = &include_disc_rsp->included_srvc; + case BLE_GATTC_EVT_CHAR_DISC_RSP: + // Characteristic Discovery Response event. + // See ble_gattc_evt_char_disc_rsp_t. + if (event_data.params.char_disc_rsp.count == 0u) + { + ble::gatt::properties const properties; + ble::att::uuid uuid; + + observer.characteristic_discovered( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + ble::att::handle_maximum, + ble::att::handle_maximum, + uuid, + properties, + true); + } - ble::att::uuid const uuid = nordic::to_att_uuid(service->uuid); + for (uint16_t iter = 0u; + iter < event_data.params.char_disc_rsp.count; ++iter) + { + ble_gattc_char_t const* char_disc_rsp = + &event_data.params.char_disc_rsp.chars[iter]; + + ble::att::uuid const uuid = nordic::to_att_uuid(char_disc_rsp->uuid); + + char uuid_char_buffer[ble::att::uuid::conversion_length]; + uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + + ble::gatt::properties const properties = nordic::to_att_properties( + char_disc_rsp->char_props); + + logger.debug("BLE_GATTC_EVT_CHAR_DISC_RSP: " + "decl: 0x%04x, value: 0x%04x, props: 0x%04x, %s", + char_disc_rsp->handle_decl, + char_disc_rsp->handle_value, + properties.get(), + uuid_char_buffer); + + observer.characteristic_discovered( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + char_disc_rsp->handle_decl, + char_disc_rsp->handle_value, + uuid, + properties, + iter + 1u >= event_data.params.char_disc_rsp.count); + } + break; - char uuid_char_buffer[ble::att::uuid::conversion_length]; - uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + case BLE_GATTC_EVT_DESC_DISC_RSP: + // Descriptor Discovery Response event. + // See ble_gattc_evt_desc_disc_rsp_t. + for (uint16_t iter = 0u; + iter < event_data.params.desc_disc_rsp.count; ++iter) + { + ble_gattc_desc_t const* desc_disc_rsp = + &event_data.params.desc_disc_rsp.descs[iter]; - logger.debug("BLE_GATTC_EVT_REL_DISC_RSP[0x%04:0x%04x]: incl: 0x%04x, %s", - service->handle_range.start_handle, - service->handle_range.end_handle, - include_disc_rsp->handle, - uuid_char_buffer); + ble::att::uuid const uuid = nordic::to_att_uuid(desc_disc_rsp->uuid); - observer.interface_reference.relationship_discovered( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - service->handle_range.start_handle, - service->handle_range.end_handle, - include_disc_rsp->handle, - uuid, - iter + 1u >= event_data.params.rel_disc_rsp.count); - } - break; + char uuid_char_buffer[ble::att::uuid::conversion_length]; + uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - case BLE_GATTC_EVT_CHAR_DISC_RSP: - // Characteristic Discovery Response event. - // See ble_gattc_evt_char_disc_rsp_t. - if (event_data.params.char_disc_rsp.count == 0u) - { - ble::gatt::properties const properties; - ble::att::uuid uuid; + logger.debug("BLE_GATTC_EVT_CHAR_DISC_RSP[0x%04]: %s", + desc_disc_rsp->handle, uuid_char_buffer); - observer.interface_reference.characteristic_discovered( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - ble::att::handle_maximum, - ble::att::handle_maximum, - uuid, - properties, - true); - } + observer.descriptor_discovered( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + desc_disc_rsp->handle, + uuid, + iter + 1u >= event_data.params.desc_disc_rsp.count); + } + break; + case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP: + // Attribute Information Response event. + // See ble_gattc_evt_attr_info_disc_rsp_t. + switch (event_data.params.attr_info_disc_rsp.format) + { + case BLE_GATTC_ATTR_INFO_FORMAT_16BIT: for (uint16_t iter = 0u; - iter < event_data.params.char_disc_rsp.count; ++iter) + iter < event_data.params.attr_info_disc_rsp.count; ++iter) { - ble_gattc_char_t const* char_disc_rsp = - &event_data.params.char_disc_rsp.chars[iter]; + ble_gattc_attr_info16_t const* gattc_attr = + &event_data.params.attr_info_disc_rsp.info.attr_info16[iter]; - ble::att::uuid const uuid = nordic::to_att_uuid(char_disc_rsp->uuid); + ble::att::uuid uuid(gattc_attr->uuid.uuid); - char uuid_char_buffer[ble::att::uuid::conversion_length]; - uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + // char uuid_char_buffer[ble::att::uuid::conversion_length]; + // uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - ble::gatt::properties const properties = nordic::to_att_properties( - char_disc_rsp->char_props); + logger.debug("BLE_GATTC_EVT_ATTR_INFO_DISC_RSP [0x%04]: 0x%04x", + gattc_attr->handle, gattc_attr->uuid); - logger.debug("BLE_GATTC_EVT_CHAR_DISC_RSP: " - "decl: 0x%04x, value: 0x%04x, props: 0x%04x, %s", - char_disc_rsp->handle_decl, - char_disc_rsp->handle_value, - properties.get(), - uuid_char_buffer); - - observer.interface_reference.characteristic_discovered( + observer.attribute_discovered( event_data.conn_handle, nordic::to_att_error_code(event_data.gatt_status), event_data.error_handle, - char_disc_rsp->handle_decl, - char_disc_rsp->handle_value, + gattc_attr->handle, uuid, - properties, - iter + 1u >= event_data.params.char_disc_rsp.count); + iter + 1u >= event_data.params.attr_info_disc_rsp.count); } break; - case BLE_GATTC_EVT_DESC_DISC_RSP: - // Descriptor Discovery Response event. - // See ble_gattc_evt_desc_disc_rsp_t. + case BLE_GATTC_ATTR_INFO_FORMAT_128BIT: for (uint16_t iter = 0u; - iter < event_data.params.desc_disc_rsp.count; ++iter) + iter < event_data.params.attr_info_disc_rsp.count; ++iter) { - ble_gattc_desc_t const* desc_disc_rsp = - &event_data.params.desc_disc_rsp.descs[iter]; + ble_gattc_attr_info128_t const* gattc_attr = + &event_data.params.attr_info_disc_rsp.info.attr_info128[iter]; - ble::att::uuid const uuid = nordic::to_att_uuid(desc_disc_rsp->uuid); + ble::att::uuid uuid(gattc_attr->uuid.uuid128); char uuid_char_buffer[ble::att::uuid::conversion_length]; uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - logger.debug("BLE_GATTC_EVT_CHAR_DISC_RSP[0x%04]: %s", - desc_disc_rsp->handle, uuid_char_buffer); + logger.debug("BLE_GATTC_EVT_ATTR_INFO_DISC_RSP [0x%04]: %s", + gattc_attr->handle, uuid); - observer.interface_reference.descriptor_discovered( + observer.attribute_discovered( event_data.conn_handle, nordic::to_att_error_code(event_data.gatt_status), event_data.error_handle, - desc_disc_rsp->handle, + gattc_attr->handle, uuid, - iter + 1u >= event_data.params.desc_disc_rsp.count); - } - break; - - case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP: - // Attribute Information Response event. - // See ble_gattc_evt_attr_info_disc_rsp_t. - switch (event_data.params.attr_info_disc_rsp.format) - { - case BLE_GATTC_ATTR_INFO_FORMAT_16BIT: - for (uint16_t iter = 0u; - iter < event_data.params.attr_info_disc_rsp.count; ++iter) - { - ble_gattc_attr_info16_t const* gattc_attr = - &event_data.params.attr_info_disc_rsp.info.attr_info16[iter]; - - ble::att::uuid uuid(gattc_attr->uuid.uuid); - - // char uuid_char_buffer[ble::att::uuid::conversion_length]; - // uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - - logger.debug("BLE_GATTC_EVT_ATTR_INFO_DISC_RSP [0x%04]: 0x%04x", - gattc_attr->handle, gattc_attr->uuid); - - observer.interface_reference.attribute_discovered( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - gattc_attr->handle, - uuid, - iter + 1u >= event_data.params.attr_info_disc_rsp.count); - } - break; - - case BLE_GATTC_ATTR_INFO_FORMAT_128BIT: - for (uint16_t iter = 0u; - iter < event_data.params.attr_info_disc_rsp.count; ++iter) - { - ble_gattc_attr_info128_t const* gattc_attr = - &event_data.params.attr_info_disc_rsp.info.attr_info128[iter]; - - ble::att::uuid uuid(gattc_attr->uuid.uuid128); - - char uuid_char_buffer[ble::att::uuid::conversion_length]; - uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - - logger.debug("BLE_GATTC_EVT_ATTR_INFO_DISC_RSP [0x%04]: %s", - gattc_attr->handle, uuid); - - observer.interface_reference.attribute_discovered( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - gattc_attr->handle, - uuid, - iter + 1u >= event_data.params.attr_info_disc_rsp.count); - } - break; - - default: - logger.error("unknown Nordic attribute uuid discovery format: %u", - event_data.params.attr_info_disc_rsp.format); - ASSERT(0); - break; + iter + 1u >= event_data.params.attr_info_disc_rsp.count); } break; default: + logger.error("unknown Nordic attribute uuid discovery format: %u", + event_data.params.attr_info_disc_rsp.format); + ASSERT(0); break; } + break; + + default: + break; } } diff --git a/ble/nordic_ble_gattc_event_observable.cc b/ble/nordic_ble_gattc_event_observable.cc index 113e803..d359aa2 100644 --- a/ble/nordic_ble_gattc_event_observable.cc +++ b/ble/nordic_ble_gattc_event_observable.cc @@ -8,7 +8,6 @@ #include "ble/att.h" #include "ble/nordic_ble_att.h" -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" #include "ble/profile_connectable.h" #include "ble/gattc_event_observer.h" @@ -64,211 +63,199 @@ uint32_t gattc_uuid128_acquire(uint16_t connection_handle, uint16_t gatt_handle) return error_code; } -template<> -void ble_event_observable::notify( - ble_gattc_event_observer::event_enum_t event_type, - ble_gattc_event_observer::event_data_t const& event_data) +void ble_gattc_event_notify(ble::gattc::event_observer& observer, + enum BLE_GATTC_EVTS event_type, + ble_gattc_evt_t const& event_data) { logger &logger = logger::instance(); - for (auto observer_iter = this->observer_list_.begin(); - observer_iter != this->observer_list_.end(); ) + switch (event_type) { - // Increment the iterator prior to using it. - // If the client removes itself during the completion callback - // then the iterator will be valid and can continue. - ble_gattc_event_observer &observer = *observer_iter; - ++observer_iter; - - switch (event_type) + case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP: + // Read By UUID Response event. + // See ble_gattc_evt_char_val_by_uuid_read_rsp_t. { - case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP: - // Read By UUID Response event. - // See ble_gattc_evt_char_val_by_uuid_read_rsp_t. + ble_gattc_evt_char_val_by_uuid_read_rsp_t const &read_rsp = + event_data.params.char_val_by_uuid_read_rsp; + + // Data is held in (handle, value) pairs. The length in bytes + // of the value is value_length. + uint32_t const value_length = read_rsp.value_len; + uint8_t const* hv_pair_ptr = read_rsp.handle_value; + + for (uint16_t iter = 0u; + iter < event_data.params.char_val_by_uuid_read_rsp.count; ++iter) { - ble_gattc_evt_char_val_by_uuid_read_rsp_t const &read_rsp = - event_data.params.char_val_by_uuid_read_rsp; + uint16_t handle = *hv_pair_ptr++; + handle <<= 8u; + handle |= *hv_pair_ptr++; + handle = __REV16(handle); // 16-bit endian swap. - // Data is held in (handle, value) pairs. The length in bytes - // of the value is value_length. - uint32_t const value_length = read_rsp.value_len; - uint8_t const* hv_pair_ptr = read_rsp.handle_value; + observer.read_characteristic_by_uuid_response( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + handle, + &hv_pair_ptr, + value_length); - for (uint16_t iter = 0u; - iter < event_data.params.char_val_by_uuid_read_rsp.count; ++iter) - { - uint16_t handle = *hv_pair_ptr++; - handle <<= 8u; - handle |= *hv_pair_ptr++; - handle = __REV16(handle); // 16-bit endian swap. - - observer.interface_reference.read_characteristic_by_uuid_response( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - handle, - &hv_pair_ptr, - value_length); - - hv_pair_ptr += value_length; - } + hv_pair_ptr += value_length; } - break; + } + break; - case BLE_GATTC_EVT_READ_RSP: - // Read Response event. - // See ble_gattc_evt_read_rsp_t. - if ((uuid128_read_pending.connection_handle == event_data.conn_handle) && - (uuid128_read_pending.gattc_handle == event_data.params.read_rsp.handle)) - { - ble_uuid128_t uuid_128; - ASSERT(event_data.params.read_rsp.len >= sizeof(uuid_128.uuid128)); - memcpy(uuid_128.uuid128, - event_data.params.read_rsp.data, - sizeof(uuid_128.uuid128)); + case BLE_GATTC_EVT_READ_RSP: + // Read Response event. + // See ble_gattc_evt_read_rsp_t. + if ((uuid128_read_pending.connection_handle == event_data.conn_handle) && + (uuid128_read_pending.gattc_handle == event_data.params.read_rsp.handle)) + { + ble_uuid128_t uuid_128; + ASSERT(event_data.params.read_rsp.len >= sizeof(uuid_128.uuid128)); + memcpy(uuid_128.uuid128, + event_data.params.read_rsp.data, + sizeof(uuid_128.uuid128)); - uint8_t uuid_type = BLE_UUID_TYPE_VENDOR_BEGIN; - uint32_t error_code = sd_ble_uuid_vs_add(&uuid_128, &uuid_type); + uint8_t uuid_type = BLE_UUID_TYPE_VENDOR_BEGIN; + uint32_t error_code = sd_ble_uuid_vs_add(&uuid_128, &uuid_type); - if (error_code == NRF_SUCCESS) - { - uint16_t const connection_handle = uuid128_read_pending.connection_handle; - uint16_t const gattc_handle = uuid128_read_pending.gattc_handle; - - uuid128_read_pending.connection_handle = ble::gap::handle_invalid; - uuid128_read_pending.gattc_handle = ble::att::handle_invalid; - - /// @todo Hardcoded to primary services discovery. - /// This needs to be made generic by adding a functor to the - /// state storage struct uuid128_read_pending_t. - error_code = sd_ble_gattc_primary_services_discover( - connection_handle, gattc_handle, nullptr); - - if (error_code != NRF_SUCCESS) - { - logger::instance().error( - "sd_ble_gattc_primary_services_discover() failed: 0x%04x '%s'", - error_code, nordic_error_string(error_code)); - } - } - else - { - ASSERT(uuid128_read_pending.connection_handle == ble::gap::handle_invalid); - ASSERT(uuid128_read_pending.gattc_handle == ble::att::handle_invalid); + if (error_code == NRF_SUCCESS) + { + uint16_t const connection_handle = uuid128_read_pending.connection_handle; + uint16_t const gattc_handle = uuid128_read_pending.gattc_handle; - ble::att::uuid uuid = nordic::to_att_uuid(uuid_128); - char uuid_char_buffer[ble::att::uuid::conversion_length]; - uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); + uuid128_read_pending.connection_handle = ble::gap::handle_invalid; + uuid128_read_pending.gattc_handle = ble::att::handle_invalid; + /// @todo Hardcoded to primary services discovery. + /// This needs to be made generic by adding a functor to the + /// state storage struct uuid128_read_pending_t. + error_code = sd_ble_gattc_primary_services_discover( + connection_handle, gattc_handle, nullptr); + + if (error_code != NRF_SUCCESS) + { logger::instance().error( - "sd_ble_uuid_vs_add(%s) failed: 0x%04x '%s'", - uuid_char_buffer, error_code, nordic_error_string(error_code)); + "sd_ble_gattc_primary_services_discover() failed: 0x%04x '%s'", + error_code, nordic_error_string(error_code)); } } else { - observer.interface_reference.read_response( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - event_data.params.read_rsp.handle, - event_data.params.read_rsp.data, - event_data.params.read_rsp.offset, - event_data.params.read_rsp.len); - } - break; - - case BLE_GATTC_EVT_CHAR_VALS_READ_RSP: - // Read multiple Response event. - // See ble_gattc_evt_char_vals_read_rsp_t. - observer.interface_reference.read_multi_response( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - event_data.params.char_vals_read_rsp.values, - event_data.params.char_vals_read_rsp.len); - break; + ASSERT(uuid128_read_pending.connection_handle == ble::gap::handle_invalid); + ASSERT(uuid128_read_pending.gattc_handle == ble::att::handle_invalid); - case BLE_GATTC_EVT_WRITE_RSP: - // Write Response event. - // See ble_gattc_evt_write_rsp_t. - observer.interface_reference.write_response( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - nordic::to_att_write_op_code(event_data.params.write_rsp.write_op), - event_data.params.write_rsp.handle, - event_data.params.write_rsp.data, - event_data.params.write_rsp.offset, - event_data.params.write_rsp.len); - break; + ble::att::uuid uuid = nordic::to_att_uuid(uuid_128); + char uuid_char_buffer[ble::att::uuid::conversion_length]; + uuid.to_chars(std::begin(uuid_char_buffer), std::end(uuid_char_buffer)); - case BLE_GATTC_EVT_HVX: - // Handle Value Notification or Indication event. - // Confirm indication with sd_ble_gattc_hv_confirm. - // See ble_gattc_evt_hvx_t. - switch (event_data.params.hvx.type) - { - case BLE_GATT_HVX_NOTIFICATION: - observer.interface_reference.handle_notification( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - event_data.params.hvx.handle, - event_data.params.hvx.data, - event_data.params.hvx.len); - break; - - case BLE_GATT_HVX_INDICATION: - observer.interface_reference.handle_indication( - event_data.conn_handle, - nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle, - event_data.params.hvx.handle, - event_data.params.hvx.data, - event_data.params.hvx.len); - break; - - default: - logger.error("BLE_GATTC_EVT_HVX: unknown type: %u", - event_data.params.hvx.type); - break; + logger::instance().error( + "sd_ble_uuid_vs_add(%s) failed: 0x%04x '%s'", + uuid_char_buffer, error_code, nordic_error_string(error_code)); } - break; - - case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: - // Exchange MTU Response event. - // See ble_gattc_evt_exchange_mtu_rsp_t. - observer.interface_reference.exchange_mtu_response( + } + else + { + observer.read_response( event_data.conn_handle, nordic::to_att_error_code(event_data.gatt_status), event_data.error_handle, - event_data.params.exchange_mtu_rsp.server_rx_mtu); - break; - - case BLE_GATTC_EVT_TIMEOUT: - // Timeout event. - // See ble_gattc_evt_timeout_t. - observer.interface_reference.timeout( + event_data.params.read_rsp.handle, + event_data.params.read_rsp.data, + event_data.params.read_rsp.offset, + event_data.params.read_rsp.len); + } + break; + + case BLE_GATTC_EVT_CHAR_VALS_READ_RSP: + // Read multiple Response event. + // See ble_gattc_evt_char_vals_read_rsp_t. + observer.read_multi_response( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + event_data.params.char_vals_read_rsp.values, + event_data.params.char_vals_read_rsp.len); + break; + + case BLE_GATTC_EVT_WRITE_RSP: + // Write Response event. + // See ble_gattc_evt_write_rsp_t. + observer.write_response( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + nordic::to_att_write_op_code(event_data.params.write_rsp.write_op), + event_data.params.write_rsp.handle, + event_data.params.write_rsp.data, + event_data.params.write_rsp.offset, + event_data.params.write_rsp.len); + break; + + case BLE_GATTC_EVT_HVX: + // Handle Value Notification or Indication event. + // Confirm indication with sd_ble_gattc_hv_confirm. + // See ble_gattc_evt_hvx_t. + switch (event_data.params.hvx.type) + { + case BLE_GATT_HVX_NOTIFICATION: + observer.handle_notification( event_data.conn_handle, nordic::to_att_error_code(event_data.gatt_status), - event_data.error_handle); + event_data.error_handle, + event_data.params.hvx.handle, + event_data.params.hvx.data, + event_data.params.hvx.len); break; - case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE: - // Write without Response transmission complete. - // See ble_gattc_evt_write_cmd_tx_complete_t. - observer.interface_reference.write_command_tx_completed( + case BLE_GATT_HVX_INDICATION: + observer.handle_indication( event_data.conn_handle, nordic::to_att_error_code(event_data.gatt_status), event_data.error_handle, - event_data.params.write_cmd_tx_complete.count); + event_data.params.hvx.handle, + event_data.params.hvx.data, + event_data.params.hvx.len); break; default: + logger.error("BLE_GATTC_EVT_HVX: unknown type: %u", + event_data.params.hvx.type); break; } - + break; + + case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: + // Exchange MTU Response event. + // See ble_gattc_evt_exchange_mtu_rsp_t. + observer.exchange_mtu_response( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + event_data.params.exchange_mtu_rsp.server_rx_mtu); + break; + + case BLE_GATTC_EVT_TIMEOUT: + // Timeout event. + // See ble_gattc_evt_timeout_t. + observer.timeout( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle); + break; + + case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE: + // Write without Response transmission complete. + // See ble_gattc_evt_write_cmd_tx_complete_t. + observer.write_command_tx_completed( + event_data.conn_handle, + nordic::to_att_error_code(event_data.gatt_status), + event_data.error_handle, + event_data.params.write_cmd_tx_complete.count); + break; + + default: + break; } } diff --git a/ble/nordic_ble_gatts_event_observable.cc b/ble/nordic_ble_gatts_event_observable.cc index adcdc59..f4d7f05 100644 --- a/ble/nordic_ble_gatts_event_observable.cc +++ b/ble/nordic_ble_gatts_event_observable.cc @@ -6,13 +6,13 @@ * into the Nordic BLE observables. */ -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" #include "ble/gatts_event_observer.h" #include "ble/att.h" #include "ble_gatt.h" // Nordic softdevice header #include "logger.h" +#include "project_assert.h" namespace nordic { @@ -63,182 +63,171 @@ static void handle_system_attribute_missing(uint16_t conection_handle, } } -template<> -void ble_event_observable::notify( - ble_gatts_event_observer::event_enum_t event_type, - ble_gatts_event_observer::event_data_t const& event_data) +void ble_gatts_event_notify(ble::gatts::event_observer& observer, + enum BLE_GATTS_EVTS event_type, + ble_gatts_evt_t const& event_data) { logger &logger = logger::instance(); - for (auto observer_iter = this->observer_list_.begin(); - observer_iter != this->observer_list_.end(); ) + switch (event_type) { - // Increment the iterator prior to using it. - // If the client removes itself during the completion callback - // then the iterator will be valid and can continue. - ble_gatts_event_observer &observer = *observer_iter; - ++observer_iter; + case BLE_GATTS_EVT_WRITE: + // Write operation performed. + // See @ref ble_gatts_evt_write_t. + logger::instance().debug( + "GATTS write: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u, ar: %u, off: %u, len: %u", + event_data.conn_handle, + event_data.params.write.handle, + event_data.params.write.uuid.uuid, + nordic_write_type_opcode(event_data.params.write.op), + bool(event_data.params.write.auth_required), + event_data.params.write.offset, + event_data.params.write.len); + + if (event_data.params.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL) + { + observer.write_cancel( + event_data.conn_handle, + event_data.params.write.handle, + nordic_write_type_opcode(event_data.params.write.op), + bool(event_data.params.write.auth_required), + event_data.params.write.offset, + event_data.params.write.len, + event_data.params.write.data); + } + else + { + observer.write( + event_data.conn_handle, + event_data.params.write.handle, + nordic_write_type_opcode(event_data.params.write.op), + bool(event_data.params.write.auth_required), + event_data.params.write.offset, + event_data.params.write.len, + event_data.params.write.data); + } + break; - switch (event_type) + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + // Reply with @ref sd_ble_gatts_rw_authorize_reply. + if (event_data.params.authorize_request.type == BLE_GATTS_AUTHORIZE_TYPE_READ) { - case BLE_GATTS_EVT_WRITE: - // Write operation performed. - // See @ref ble_gatts_evt_write_t. - logger::instance().debug( - "GATTS write: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u, ar: %u, off: %u, len: %u", - event_data.conn_handle, - event_data.params.write.handle, - event_data.params.write.uuid.uuid, - nordic_write_type_opcode(event_data.params.write.op), - bool(event_data.params.write.auth_required), - event_data.params.write.offset, - event_data.params.write.len); - - if (event_data.params.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL) - { - observer.interface_reference.write_cancel( - event_data.conn_handle, - event_data.params.write.handle, - nordic_write_type_opcode(event_data.params.write.op), - bool(event_data.params.write.auth_required), - event_data.params.write.offset, - event_data.params.write.len, - event_data.params.write.data); - } - else - { - observer.interface_reference.write( - event_data.conn_handle, - event_data.params.write.handle, - nordic_write_type_opcode(event_data.params.write.op), - bool(event_data.params.write.auth_required), - event_data.params.write.offset, - event_data.params.write.len, - event_data.params.write.data); - } - break; - - case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: - // Reply with @ref sd_ble_gatts_rw_authorize_reply. - if (event_data.params.authorize_request.type == BLE_GATTS_AUTHORIZE_TYPE_READ) - { - logger::instance().debug( - "GATTS rd_ar: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u", - event_data.conn_handle, - event_data.params.write.handle, - event_data.params.write.uuid.uuid, - event_data.params.write.offset); - - observer.interface_reference.read_authorization_request( - event_data.conn_handle, - event_data.params.authorize_request.request.read.handle, - event_data.params.authorize_request.request.read.offset); - } - else if (event_data.params.authorize_request.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) - { - logger::instance().debug( - "GATTS wr_ar: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u, ar: %u, off: %u, len: %u", - event_data.conn_handle, - event_data.params.write.handle, - event_data.params.write.uuid.uuid, - nordic_write_type_opcode(event_data.params.write.op), - bool(event_data.params.write.auth_required), - event_data.params.write.offset, - event_data.params.write.len); - observer.interface_reference.write_authorization_request( - event_data.conn_handle, - event_data.params.authorize_request.request.write.handle, - nordic_write_type_opcode(event_data.params.authorize_request.request.write.op), - bool(event_data.params.authorize_request.request.write.auth_required), - event_data.params.authorize_request.request.write.offset, - event_data.params.authorize_request.request.write.len, - event_data.params.authorize_request.request.write.data); - } - else - { - logger.error("invalid authorization request type: %u", - event_data.params.authorize_request.type); - } - break; - - case BLE_GATTS_EVT_SYS_ATTR_MISSING: - // Note: This is a Nordic specific GATTS operation and not part of - // the Bluetooth Core specification. Handle it within this module. - // See comments in handle_system_attribute_missing(); logger::instance().debug( - "BLE_GATTS_EVT_SYS_ATTR_MISSING: c: 0x%04x, hint: 0x%02x", + "GATTS rd_ar: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u", event_data.conn_handle, - event_data.params.sys_attr_missing.hint); + event_data.params.write.handle, + event_data.params.write.uuid.uuid, + event_data.params.write.offset); - handle_system_attribute_missing( + observer.read_authorization_request( event_data.conn_handle, - event_data.params.sys_attr_missing.hint); - break; - - case BLE_GATTS_EVT_HVC: - // Handle Value Confirmation. + event_data.params.authorize_request.request.read.handle, + event_data.params.authorize_request.request.read.offset); + } + else if (event_data.params.authorize_request.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) + { logger::instance().debug( - "GATTS handle value confirmation: c: 0x%04x, h: 0x%04x", + "GATTS wr_ar: c: 0x%04x, h: 0x%04x, u: 0x%04x, o: %u, ar: %u, off: %u, len: %u", event_data.conn_handle, - event_data.params.hvc.handle); - - observer.interface_reference.handle_value_confirmation( + event_data.params.write.handle, + event_data.params.write.uuid.uuid, + nordic_write_type_opcode(event_data.params.write.op), + bool(event_data.params.write.auth_required), + event_data.params.write.offset, + event_data.params.write.len); + observer.write_authorization_request( event_data.conn_handle, - event_data.params.hvc.handle); - break; + event_data.params.authorize_request.request.write.handle, + nordic_write_type_opcode(event_data.params.authorize_request.request.write.op), + bool(event_data.params.authorize_request.request.write.auth_required), + event_data.params.authorize_request.request.write.offset, + event_data.params.authorize_request.request.write.len, + event_data.params.authorize_request.request.write.data); + } + else + { + logger.error("invalid authorization request type: %u", + event_data.params.authorize_request.type); + } + break; - case BLE_GATTS_EVT_SC_CONFIRM: - // Service Changed Confirmation. - // No additional event structure applies. - logger::instance().debug( - "GATTS service change confirmation: c: 0x%04x", - event_data.conn_handle); + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + // Note: This is a Nordic specific GATTS operation and not part of + // the Bluetooth Core specification. Handle it within this module. + // See comments in handle_system_attribute_missing(); + logger::instance().debug( + "BLE_GATTS_EVT_SYS_ATTR_MISSING: c: 0x%04x, hint: 0x%02x", + event_data.conn_handle, + event_data.params.sys_attr_missing.hint); + + handle_system_attribute_missing( + event_data.conn_handle, + event_data.params.sys_attr_missing.hint); + break; - observer.interface_reference.service_change_confirmation( - event_data.conn_handle); - break; + case BLE_GATTS_EVT_HVC: + // Handle Value Confirmation. + logger::instance().debug( + "GATTS handle value confirmation: c: 0x%04x, h: 0x%04x", + event_data.conn_handle, + event_data.params.hvc.handle); - case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: - // Exchange MTU Request. - // Reply with @ref sd_ble_gatts_exchange_mtu_reply. - logger::instance().debug( - "GATTS exchange mtu request: c: 0x%04x, client_rx_mtu: %u", - event_data.conn_handle, - event_data.params.exchange_mtu_request.client_rx_mtu); + observer.handle_value_confirmation( + event_data.conn_handle, + event_data.params.hvc.handle); + break; - observer.interface_reference.exchange_mtu_request( - event_data.conn_handle, - event_data.params.exchange_mtu_request.client_rx_mtu); - break; + case BLE_GATTS_EVT_SC_CONFIRM: + // Service Changed Confirmation. + // No additional event structure applies. + logger::instance().debug( + "GATTS service change confirmation: c: 0x%04x", + event_data.conn_handle); - case BLE_GATTS_EVT_TIMEOUT: - // Peer failed to respond to an ATT request in time. - logger::instance().debug( - "GATTS timeout: c: 0x%04x, source: %u", - event_data.conn_handle, - event_data.params.timeout.src); + observer.service_change_confirmation( + event_data.conn_handle); + break; - observer.interface_reference.timeout( - event_data.conn_handle, - event_data.params.timeout.src); - break; + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + // Exchange MTU Request. + // Reply with @ref sd_ble_gatts_exchange_mtu_reply. + logger::instance().debug( + "GATTS exchange mtu request: c: 0x%04x, client_rx_mtu: %u", + event_data.conn_handle, + event_data.params.exchange_mtu_request.client_rx_mtu); + + observer.exchange_mtu_request( + event_data.conn_handle, + event_data.params.exchange_mtu_request.client_rx_mtu); + break; - case BLE_GATTS_EVT_HVN_TX_COMPLETE: - // Handle Value Notification transmission complete. - logger::instance().debug( - "GATTS hvn tx completed: c: 0x%04x, n: %u", - event_data.conn_handle, - event_data.params.hvn_tx_complete.count); + case BLE_GATTS_EVT_TIMEOUT: + // Peer failed to respond to an ATT request in time. + logger::instance().debug( + "GATTS timeout: c: 0x%04x, source: %u", + event_data.conn_handle, + event_data.params.timeout.src); - observer.interface_reference.handle_value_notifications_tx_completed( - event_data.conn_handle, - event_data.params.hvn_tx_complete.count); - break; + observer.timeout( + event_data.conn_handle, + event_data.params.timeout.src); + break; - default: - logger.warn("unhandled GATTS event: %u", event_type); - break; - } + case BLE_GATTS_EVT_HVN_TX_COMPLETE: + // Handle Value Notification transmission complete. + logger::instance().debug( + "GATTS hvn tx completed: c: 0x%04x, n: %u", + event_data.conn_handle, + event_data.params.hvn_tx_complete.count); + + observer.handle_value_notifications_tx_completed( + event_data.conn_handle, + event_data.params.hvn_tx_complete.count); + break; + + default: + logger.warn("unhandled GATTS event: %u", event_type); + break; } } diff --git a/ble/profile_connectable.h b/ble/profile_connectable.h index babdcc2..26a5256 100644 --- a/ble/profile_connectable.h +++ b/ble/profile_connectable.h @@ -16,127 +16,186 @@ #include "ble/gatt_service_container.h" #include "ble/hci_error_codes.h" +#include + namespace ble { namespace profile { /** - * @class connectable + * @struct connectable * A base class for profile::peripheral and profile::central, aggregate the * specific classes which compose a BLE profile which connects with a peer. */ -class connectable +struct connectable { public: + /** + * @struct ble::profile::connectable::gatts + * Aggregates ble::gatts::event_observer + * ble::gatts::operations. + */ + struct gatts + { + ~gatts() = default; + + gatts(gatts const&) = delete; + gatts(gatts&&) = delete; + gatts& operator=(gatts const&) = delete; + gatts& operator=(gatts&&) = delete; + + gatts(ble::gatts::event_observer& evt_observer, + ble::gatts::operations& ops) + : event_observer(&evt_observer), operations(&ops) {} + + gatts() : event_observer(nullptr), operations(nullptr) {} + + ble::gatts::event_observer* const event_observer; + ble::gatts::operations* const operations; + }; + + /** + * @struct ble::profile::connectable::gattc + * Aggregates ble::gatts::event_observer, + * ble::gatts::operations, + * ble::gattc::service_builder. + */ + struct gattc + { + ~gattc() = default; + + gattc(gattc const&) = delete; + gattc(gattc&&) = delete; + gattc& operator=(gattc const&) = delete; + gattc& operator=(gattc&&) = delete; + + gattc() + : event_observer(nullptr), + operations(nullptr), + service_builder(nullptr) {} + + gattc(ble::gattc::event_observer& evt_observer, + ble::gattc::operations& ops, + ble::gattc::service_builder& svc_builder) + : event_observer(&evt_observer), + operations(&ops), + service_builder(&svc_builder) {} + + ble::gattc::event_observer* const event_observer; + ble::gattc::operations* const operations; + ble::gattc::service_builder* const service_builder; + }; + virtual ~connectable() = default; connectable() = delete; connectable(connectable const&) = delete; - connectable(connectable &&) = delete; + connectable(connectable&&) = delete; connectable& operator=(connectable const&) = delete; connectable& operator=(connectable&&) = delete; /// ctor: A connectable with both GATT server and client. connectable(ble::stack& ble_stack, - ble::gap::connection& ble_gap_connection, - ble::gatts::event_observer& ble_gatts_event_observer, - ble::gatts::operations& ble_gatts_operations, - ble::gattc::event_observer& ble_gattc_event_observer, - ble::gattc::operations& ble_gattc_operations, - ble::gattc::service_builder& ble_gattc_service_builder) - : ble_stack_(ble_stack), - gap_connection_(ble_gap_connection), - gatts_event_observer_(&ble_gatts_event_observer), - gatts_operations_(&ble_gatts_operations), - gattc_event_observer_(&ble_gattc_event_observer), - gattc_operations_(&ble_gattc_operations), - gattc_service_builder_(&ble_gattc_service_builder), - service_builder_completion_(nullptr) + ble::gap::connection& gap_connection, + ble::gatts::event_observer& gatts_event_observer, + ble::gatts::operations& gatts_operations, + ble::gattc::event_observer& gattc_event_observer, + ble::gattc::operations& gattc_operations, + ble::gattc::service_builder& gattc_service_builder) + : stack(ble_stack), + gap(gap_connection), + gatts(gatts_event_observer, gatts_operations), + gattc(gattc_event_observer, gattc_operations, gattc_service_builder), + service_builder_completion(nullptr) { - this->gap_connection_.set_connecteable(this); - this->gatts_event_observer_->set_connecteable(this); - this->gatts_operations_->set_connecteable(this); - this->gattc_event_observer_->set_connecteable(this); + this->gap.set_connecteable(this); + this->gatts.event_observer->set_connecteable(this); + this->gatts.operations->set_connecteable(this); + this->gattc.event_observer->set_connecteable(this); } /// ctor: A connectable with a GATT server only; no client. connectable(ble::stack& ble_stack, - ble::gap::connection& ble_gap_connection, - ble::gatts::event_observer& ble_gatts_event_observer, - ble::gatts::operations& ble_gatts_operations) - : ble_stack_(ble_stack), - gap_connection_(ble_gap_connection), - gatts_event_observer_(&ble_gatts_event_observer), - gatts_operations_(&ble_gatts_operations), - gattc_event_observer_(nullptr), - gattc_operations_(nullptr), - gattc_service_builder_(nullptr), - service_builder_completion_(nullptr) + ble::gap::connection& gap_connection, + ble::gatts::event_observer& gatts_event_observer, + ble::gatts::operations& gatts_operations) + : stack(ble_stack), + gap(gap_connection), + gatts(gatts_event_observer, gatts_operations), + service_builder_completion(nullptr) { - this->gap_connection_.set_connecteable(this); - this->gatts_event_observer_->set_connecteable(this); - this->gatts_operations_->set_connecteable(this); + this->gap.set_connecteable(this); + this->gatts.event_observer->set_connecteable(this); + this->gatts.operations->set_connecteable(this); } /// ctor: A connectable with a GATT client only; no server. connectable(ble::stack& ble_stack, - ble::gap::connection& ble_gap_connection, - ble::gattc::event_observer& ble_gattc_event_observer, - ble::gattc::operations& ble_gattc_operations, - ble::gattc::service_builder& ble_gattc_service_builder) - : ble_stack_(ble_stack), - gap_connection_(ble_gap_connection), - gatts_event_observer_(nullptr), - gatts_operations_(nullptr), - gattc_event_observer_(&ble_gattc_event_observer), - gattc_operations_(&ble_gattc_operations), - gattc_service_builder_(&ble_gattc_service_builder), - service_builder_completion_(nullptr) + ble::gap::connection& gap_connection, + ble::gattc::event_observer& gattc_event_observer, + ble::gattc::operations& gattc_operations, + ble::gattc::service_builder& gattc_service_builder) + : stack(ble_stack), + gap(gap_connection), + gattc(gattc_event_observer, gattc_operations, gattc_service_builder), + service_builder_completion(nullptr) { - this->gap_connection_.set_connecteable(this); - this->gattc_event_observer_->set_connecteable(this); + this->gap.set_connecteable(this); + this->gattc.event_observer->set_connecteable(this); } - ble::stack& ble_stack() { return this->ble_stack_; } - ble::stack const& ble_stack() const { return this->ble_stack_; } - - ble::gap::connection const& connection() const { return this->gap_connection_; } - ble::gap::connection& connection() { return this->gap_connection_; } - - ble::gatts::operations const* gatts() const { return this->gatts_operations_; } - ble::gatts::operations* gatts() { return this->gatts_operations_; } - - ble::gattc::operations const* gattc() const { return this->gattc_operations_; } - ble::gattc::operations* gattc() { return this->gattc_operations_; } - - ble::gattc::service_builder const* service_builder() const { return this->gattc_service_builder_; } - ble::gattc::service_builder* service_builder() { return this->gattc_service_builder_; } - - ble::gatt::service_container const& service_container() const { return this->service_container_; } - ble::gatt::service_container& service_container() { return this->service_container_; } + ble::stack& stack; + ble::gap::connection& gap; + struct gatts gatts; + struct gattc gattc; + ble::gattc::service_builder::completion_notify* service_builder_completion; + ble::gatt::service_container service_container; void service_add(ble::gatt::service &service_to_add) { service_to_add.connectable_ = this; - this->service_container_.push_back(service_to_add); + this->service_container.push_back(service_to_add); - if (this->gatts_operations_) + if (this->gatts.operations) { - this->gatts_operations_->service_add(service_to_add); + this->gatts.operations->service_add(service_to_add); } } + bool is_linked() const { return this->hook_.is_linked(); } + void unlink() { return this->hook_.unlink(); } + private: - ble::stack& ble_stack_; - ble::gap::connection& gap_connection_; - ble::gatts::event_observer* gatts_event_observer_; - ble::gatts::operations* gatts_operations_; - ble::gattc::event_observer* gattc_event_observer_; - ble::gattc::operations* gattc_operations_; - ble::gattc::service_builder* gattc_service_builder_; - ble::gattc::service_builder::completion_notify* service_builder_completion_; - ble::gatt::service_container service_container_; + using list_hook_type = boost::intrusive::list_member_hook< + boost::intrusive::link_mode + >; + + list_hook_type hook_; + + using list_type = boost::intrusive::list< + connectable, + boost::intrusive::constant_time_size, + boost::intrusive::member_hook + >; + + friend class container; + +public: + class container: public connectable::list_type + { + public: + ~container() = default; + + container() = default; + container(container const&) = delete; + container(container &&) = delete; + container& operator=(container const&) = delete; + container& operator=(container&&) = delete; + + }; }; } // namespace profile diff --git a/ble/service/adc_sensor_service.h b/ble/service/adc_sensor_service.h index 806b28a..caa1561 100644 --- a/ble/service/adc_sensor_service.h +++ b/ble/service/adc_sensor_service.h @@ -173,17 +173,18 @@ struct adc_samples_characteristic: public gatt::characteristic { logger::instance().debug( "notify: c: 0x%04x, h: 0x%04x, data: 0x%p, len: %u", - connectable->connection().get_connection_handle(), + connectable->gap.get_connection_handle(), this->value_handle, adc_samples, adc_samples_length * sizeof(sample_type)); - att::length_t const length = connectable->gatts()->notify( - connectable->connection().get_connection_handle(), - this->value_handle, - 0u, - adc_samples_length * sizeof(sample_type), - adc_samples); + att::length_t const length = + connectable->gatts.operations->notify( + connectable->gap.get_connection_handle(), + this->value_handle, + 0u, + adc_samples_length * sizeof(sample_type), + adc_samples); logger::instance().debug("notified length: %u", length); } diff --git a/ble_central/ble_gap_connection.cc b/ble_central/ble_gap_connection.cc index bd30b04..cbd9d16 100644 --- a/ble_central/ble_gap_connection.cc +++ b/ble_central/ble_gap_connection.cc @@ -41,7 +41,7 @@ void ble_gap_connection::connect(uint16_t connection_handle, this->operations().connection_parameter_update_request( this->get_connection_handle(), this->get_connection_parameters()); - this->get_connecteable()->gattc()->exchange_mtu_request( + this->get_connecteable()->gattc.operations->exchange_mtu_request( connection_handle, this->mtu_size_); } @@ -283,9 +283,9 @@ void ble_gap_connection::negotiation_complete::notify(enum reason completion_rea logger& logger = logger::instance(); logger.info("BLE GAP negotiation complete, starting service discovery"); - this->ble_gap_connection_->get_connecteable()->service_builder()->discover_services( + this->ble_gap_connection_->get_connecteable()->gattc.service_builder->discover_services( this->ble_gap_connection_->get_connection_handle(), - this->ble_gap_connection_->get_connecteable()->service_container(), + this->ble_gap_connection_->get_connecteable()->service_container, ble::att::handle_minimum, ble::att::handle_maximum, &this->ble_gap_connection_->service_discovery_complete_); diff --git a/ble_central/ble_gattc_observer.cc b/ble_central/ble_gattc_observer.cc index 2e66325..642e310 100644 --- a/ble_central/ble_gattc_observer.cc +++ b/ble_central/ble_gattc_observer.cc @@ -128,7 +128,7 @@ void ble_gattc_observer::exchange_mtu_response( error_handle, server_rx_mtu_size); - ble::gap::connection &gap_connection = this->get_connecteable()->connection(); + ble::gap::connection &gap_connection = this->get_connecteable()->gap; gap_connection.get_negotiation_state().set_gatt_mtu_exchange_pending(false); } diff --git a/ble_central/main.cc b/ble_central/main.cc index 6296d0b..ce03f6c 100644 --- a/ble_central/main.cc +++ b/ble_central/main.cc @@ -25,9 +25,9 @@ #include "ble/gatt_characteristic.h" #include "ble/gatt_descriptors.h" #include "ble/nordic_ble_gap_operations.h" +#include "ble/nordic_ble_event_observer.h" #include "ble/profile_central.h" -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_gap_operations.h" #include "ble/nordic_ble_gap_scanning.h" #include "ble/nordic_ble_gattc_operations.h" @@ -123,25 +123,16 @@ int main(void) gattc_operations, gattc_service_builder); - nordic::ble_observables& nordic_observables = nordic::ble_observables::instance(); - - ble::gap::event_logger gap_event_logger(logger::level::info); - nordic::ble_gap_event_observer nordic_gap_event_logger(gap_event_logger); - nordic::ble_gap_event_observer nordic_gap_event_observer(gap_connection); - nordic::ble_gattc_event_observer nordic_gattc_event_observer(gattc_observer); - nordic::ble_gattc_discovery_observer nordic_gattc_discovery_observer(gattc_service_builder); - - nordic_observables.gap_event_observable.attach_first(nordic_gap_event_logger); - nordic_observables.gap_event_observable.attach(nordic_gap_event_observer); - nordic_observables.gattc_event_observable.attach(nordic_gattc_event_observer); - nordic_observables.gattc_discovery_observable.attach(nordic_gattc_discovery_observer); + // Register our ble::profile::central object to receive BLE notifications + // from the Nordic BLE stack. + nordic::register_ble_connectable(ble_central); unsigned int const peripheral_count = 0u; unsigned int const central_count = 1u; - ble_central.ble_stack().init(peripheral_count, central_count); - ble_central.ble_stack().enable(); + ble_central.stack.init(peripheral_count, central_count); + ble_central.stack.enable(); - ble::stack::version const version = ble_central.ble_stack().get_version(); + ble::stack::version const version = ble_central.stack.get_version(); logger::instance().info("version: %s, git hash: %02x%02x%02x%02x", version_info.version, diff --git a/ble_peripheral/ble_peripheral_init.cc b/ble_peripheral/ble_peripheral_init.cc index 8e55400..c8d55d1 100644 --- a/ble_peripheral/ble_peripheral_init.cc +++ b/ble_peripheral/ble_peripheral_init.cc @@ -20,7 +20,6 @@ #include "ble/service/current_time_service.h" #include "ble/service/nordic_saadc_sensor_service.h" -#include "ble/nordic_ble_event_observable.h" #include "ble/nordic_ble_event_observer.h" #include "ble/nordic_ble_gap_advertising.h" #include "ble/nordic_ble_gap_operations.h" @@ -97,12 +96,6 @@ static ble::profile::peripheral ble_peripheral(ble_stack, gap_connection, gatts_observer, gatts_operations); - -static ble::gap::event_logger gap_event_logger(logger::level::info); -static nordic::ble_gap_event_observer nordic_gap_event_logger(gap_event_logger); -static nordic::ble_gap_event_observer nordic_gap_event_observer(gap_connection); -static nordic::ble_gatts_event_observer nordic_gatts_event_observer(gatts_observer); - // GAP service: 0x1800 // device name: uuid = 0x2a00 // appearance : uuid = 0x2a01 @@ -150,9 +143,9 @@ ble::profile::peripheral& ble_peripheral_init() { unsigned int const peripheral_count = 1u; unsigned int const central_count = 0u; - ble_peripheral.ble_stack().init(peripheral_count, central_count); - ble_peripheral.ble_stack().enable(); - ble::stack::version const version = ble_peripheral.ble_stack().get_version(); + ble_peripheral.stack.init(peripheral_count, central_count); + ble_peripheral.stack.enable(); + ble::stack::version const version = ble_peripheral.stack.get_version(); logger::instance().info( "BLE stack version: link layer: %u, company id: 0x%04x, vendor: 0x%x", @@ -167,11 +160,10 @@ ble::profile::peripheral& ble_peripheral_init() static_cast(version.vendor_specific[1] >> 8u), static_cast(version.vendor_specific[1] >> 0u)); - nordic::ble_observables& nordic_observables = nordic::ble_observables::instance(); - - nordic_observables.gap_event_observable.attach_first(nordic_gap_event_logger); - nordic_observables.gap_event_observable.attach(nordic_gap_event_observer); - nordic_observables.gatts_event_observable.attach(nordic_gatts_event_observer); + // Register our BLE peripheral profile object to receive BLE events + // from the Nordic ble stack. + /// @todo perhaps the registration of events should be part of the ble::stack object? + nordic::register_ble_connectable(ble_peripheral); ble_peer_init();