Skip to content

Commit

Permalink
feat: add GATT Client (discovery attributes) (#131)
Browse files Browse the repository at this point in the history
Merged PR 11381: [ECR] GATT Client (discovery attributes)

GATT Client (discovery attributes).

(cherry picked from commit f128b77ef3378c861caaf9d237c5113bbe9b6440)

Co-authored-by: Santos, Gabriel <Gabriel.Santos_1@philips.com>
  • Loading branch information
richardapeters and gabrielsantosphilips authored May 9, 2023
1 parent 201687e commit 121c351
Show file tree
Hide file tree
Showing 6 changed files with 377 additions and 4 deletions.
4 changes: 4 additions & 0 deletions hal_st/middlewares/ble_middleware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ target_sources(hal_st.ble_middleware PRIVATE
GapPeripheralSt.hpp
GapSt.cpp
GapSt.hpp
GattClientSt.cpp
GattClientSt.hpp
GattServerSt.cpp
GattServerSt.hpp
HciEventObserver.hpp
Expand All @@ -32,6 +34,8 @@ target_sources(hal_st.ble_middleware PRIVATE
TracingGapCentralSt.hpp
TracingGapPeripheralSt.cpp
TracingGapPeripheralSt.hpp
TracingGattClientSt.cpp
TracingGattClientSt.hpp
TracingGattServerSt.cpp
TracingGattServerSt.hpp
TracingSystemTransportLayer.cpp
Expand Down
235 changes: 235 additions & 0 deletions hal_st/middlewares/ble_middleware/GattClientSt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#include "hal_st/middlewares/ble_middleware/GattClientSt.hpp"
#include "infra/event/EventDispatcherWithWeakPtr.hpp"
#include "infra/stream/InputStream.hpp"
#include "infra/util/Endian.hpp"

extern "C"
{
#include "auto/ble_gatt_aci.h"
#include "ble/ble.h"
#include "ble/core/ble_core.h"
}

namespace hal
{
GattClientSt::GattClientSt(hal::HciEventSource& hciEventSource)
: hal::HciEventSink(hciEventSource)
, connectionHandle(invalidConnection)
{}

void GattClientSt::StartServiceDiscovery()
{
onDiscoveryCompletion = [](services::GattClientDiscoveryObserver& observer) { observer.ServiceDiscoveryComplete(); };

aci_gatt_disc_all_primary_services(connectionHandle);
}

void GattClientSt::StartCharacteristicDiscovery(const services::GattService& service)
{
onDiscoveryCompletion = [](services::GattClientDiscoveryObserver& observer) { observer.CharacteristicDiscoveryComplete(); };

aci_gatt_disc_all_char_of_service(connectionHandle, service.Handle(), service.EndHandle());
}

void GattClientSt::StartDescriptorDiscovery(const services::GattService& service)
{
onDiscoveryCompletion = [](services::GattClientDiscoveryObserver& observer) { observer.DescriptorDiscoveryComplete(); };

aci_gatt_disc_all_char_desc(connectionHandle, service.Handle(), service.EndHandle());
}

void GattClientSt::HciEvent(hci_event_pckt& event)
{
switch (event.evt)
{
case HCI_DISCONNECTION_COMPLETE_EVT_CODE:
HandleHciDisconnectEvent(event);
break;
case HCI_LE_META_EVT_CODE:
HandleHciLeMetaEvent(event);
break;
case HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE:
HandleHciVendorSpecificDebugEvent(event);
break;
default:
break;
}
}

void GattClientSt::HandleHciLeMetaEvent(hci_event_pckt& eventPacket)
{
auto metaEvent = reinterpret_cast<evt_le_meta_event*>(eventPacket.data);

switch (metaEvent->subevent)
{
case HCI_LE_ENHANCED_CONNECTION_COMPLETE_SUBEVT_CODE:
HandleHciLeEnhancedConnectionCompleteEvent(metaEvent);
break;
case HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODE:
HandleHciLeConnectionCompleteEvent(metaEvent);
break;
default:
break;
}
}

void GattClientSt::HandleHciVendorSpecificDebugEvent(hci_event_pckt& eventPacket)
{
auto vendorEvent = reinterpret_cast<evt_blecore_aci*>(eventPacket.data);

switch (vendorEvent->ecode)
{
case ACI_ATT_READ_BY_GROUP_TYPE_RESP_VSEVT_CODE:
HandleAttReadByGroupTypeResponse(vendorEvent);
break;
case ACI_ATT_READ_BY_TYPE_RESP_VSEVT_CODE:
HandleAttReadByTypeResponse(vendorEvent);
break;
case ACI_ATT_FIND_INFO_RESP_VSEVT_CODE:
HandleAttFindInfoResponse(vendorEvent);
break;
case ACI_GATT_PROC_COMPLETE_VSEVT_CODE:
HandleGattCompleteResponse(vendorEvent);
break;
default:
break;
}
}

void GattClientSt::HandleAttReadByGroupTypeResponse(evt_blecore_aci* vendorEvent)
{
const uint8_t uuid16 = 6;
auto attReadByGroupResponse = *reinterpret_cast<aci_att_read_by_group_type_resp_event_rp0*>(vendorEvent->data);

infra::ByteRange data(&attReadByGroupResponse.Attribute_Data_List[0], &attReadByGroupResponse.Attribute_Data_List[0] + attReadByGroupResponse.Data_Length);
infra::ByteInputStream stream(data, infra::softFail);

really_assert(attReadByGroupResponse.Connection_Handle == connectionHandle);

HandleServiceDiscovered(stream, attReadByGroupResponse.Attribute_Data_Length == uuid16);
}

void GattClientSt::HandleAttReadByTypeResponse(evt_blecore_aci* vendorEvent)
{
const uint8_t uuid16 = 7;
auto attReadByTypeResponse = *reinterpret_cast<aci_att_read_by_type_resp_event_rp0*>(vendorEvent->data);

infra::ByteRange data(&attReadByTypeResponse.Handle_Value_Pair_Data[0], &attReadByTypeResponse.Handle_Value_Pair_Data[0] + attReadByTypeResponse.Data_Length);
infra::ByteInputStream stream(data, infra::softFail);

really_assert(attReadByTypeResponse.Connection_Handle == connectionHandle);

HandleCharacteristicDiscovered(stream, attReadByTypeResponse.Handle_Value_Pair_Length == uuid16);
}

void GattClientSt::HandleAttFindInfoResponse(evt_blecore_aci* vendorEvent)
{
auto attFindInfoResponse = *reinterpret_cast<aci_att_find_info_resp_event_rp0*>(vendorEvent->data);

infra::ByteRange data(&attFindInfoResponse.Handle_UUID_Pair[0], &attFindInfoResponse.Handle_UUID_Pair[0] + attFindInfoResponse.Event_Data_Length);
infra::ByteInputStream stream(data, infra::softFail);

really_assert(attFindInfoResponse.Connection_Handle == connectionHandle);

HandleDescriptorDiscovered(stream, attFindInfoResponse.Format == UUID_TYPE_16);
}

void GattClientSt::HandleGattCompleteResponse(evt_blecore_aci* vendorEvent)
{
auto gattProcedureEvent = *reinterpret_cast<aci_gatt_proc_complete_event_rp0*>(vendorEvent->data);

really_assert(gattProcedureEvent.Connection_Handle == connectionHandle);
really_assert(gattProcedureEvent.Error_Code == BLE_STATUS_SUCCESS);

if (onDiscoveryCompletion)
infra::Subject<services::GattClientDiscoveryObserver>::NotifyObservers(std::exchange(onDiscoveryCompletion, nullptr));
}

void GattClientSt::HandleHciLeConnectionCompleteEvent(evt_le_meta_event* metaEvent)
{
auto connectionCompleteEvent = *reinterpret_cast<hci_le_connection_complete_event_rp0*>(metaEvent->data);

really_assert(connectionCompleteEvent.Status == BLE_STATUS_SUCCESS);

connectionHandle = connectionCompleteEvent.Connection_Handle;
}

void GattClientSt::HandleHciLeEnhancedConnectionCompleteEvent(evt_le_meta_event* metaEvent)
{
auto enhancedConnectionCompleteEvent = *reinterpret_cast<hci_le_enhanced_connection_complete_event_rp0*>(metaEvent->data);

really_assert(enhancedConnectionCompleteEvent.Status == BLE_STATUS_SUCCESS);

connectionHandle = enhancedConnectionCompleteEvent.Connection_Handle;
}

void GattClientSt::HandleHciDisconnectEvent(hci_event_pckt& eventPacket)
{
auto disconnectionCompleteEvent = *reinterpret_cast<hci_disconnection_complete_event_rp0*>(eventPacket.data);

really_assert(disconnectionCompleteEvent.Connection_Handle == connectionHandle);
really_assert(disconnectionCompleteEvent.Status == BLE_STATUS_SUCCESS);

connectionHandle = GattClientSt::invalidConnection;
}

void GattClientSt::HandleServiceDiscovered(infra::DataInputStream& stream, bool isUuid16)
{
while (!stream.Empty())
{
Atttributes attributes;

stream >> attributes.startHandle >> attributes.endHandle;

HandleUuidFromDiscovery(stream, isUuid16, attributes.type);

really_assert(!stream.Failed());

infra::Subject<services::GattClientDiscoveryObserver>::NotifyObservers([&attributes](auto& observer) { observer.ServiceDiscovered(attributes.type, attributes.startHandle, attributes.endHandle); });
}
}

void GattClientSt::HandleCharacteristicDiscovered(infra::DataInputStream& stream, bool isUuid16)
{
while (!stream.Empty())
{
Atttributes attributes;

stream >> attributes.startHandle >> attributes.properties >> attributes.endHandle;

HandleUuidFromDiscovery(stream, isUuid16, attributes.type);

really_assert(!stream.Failed());

infra::Subject<services::GattClientDiscoveryObserver>::NotifyObservers([&attributes](auto& observer) { observer.CharacteristicDiscovered(attributes.type, attributes.startHandle, attributes.endHandle, attributes.properties); });
}
}

void GattClientSt::HandleDescriptorDiscovered(infra::DataInputStream& stream, bool isUuid16)
{
while (!stream.Empty())
{
Atttributes attributes;

stream >> attributes.startHandle;

HandleUuidFromDiscovery(stream, isUuid16, attributes.type);

really_assert(!stream.Failed());

infra::Subject<services::GattClientDiscoveryObserver>::NotifyObservers([&attributes](auto& observer) { observer.DescriptorDiscovered(attributes.type, attributes.startHandle); });
}
}

void GattClientSt::HandleUuidFromDiscovery(infra::DataInputStream& stream, bool isUuid16, services::AttAttribute::Uuid& type)
{
if (isUuid16)
{
stream >> type.Emplace<services::AttAttribute::Uuid16>();
}
else
{
stream >> type.Emplace<services::AttAttribute::Uuid128>();
}
}
}
66 changes: 66 additions & 0 deletions hal_st/middlewares/ble_middleware/GattClientSt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef HAL_ST_GATT_CLIENT_ST_HPP
#define HAL_ST_GATT_CLIENT_ST_HPP

#include "ble/ble.h"
#include "hal_st/middlewares/ble_middleware/HciEventObserver.hpp"
#include "infra/util/AutoResetFunction.hpp"
#include "infra/util/BoundedVector.hpp"
#include "infra/stream/ByteInputStream.hpp"
#include "services/ble/GattClient.hpp"

namespace hal
{
class GattClientSt
: public services::GattClientDiscovery
, public hal::HciEventSink
{
public:
explicit GattClientSt(hal::HciEventSource& hciEventSource);

// Implementation of services::GattClientDiscovery
virtual void StartServiceDiscovery() override;
virtual void StartCharacteristicDiscovery(const services::GattService& service) override;
virtual void StartDescriptorDiscovery(const services::GattService& service) override;

// Implementation of hal::HciEventSink
virtual void HciEvent(hci_event_pckt& event) override;

protected:
virtual void HandleHciDisconnectEvent(hci_event_pckt& eventPacket);
virtual void HandleHciLeMetaEvent(hci_event_pckt& eventPacket);
virtual void HandleHciVendorSpecificDebugEvent(hci_event_pckt& eventPacket);

virtual void HandleHciLeConnectionCompleteEvent(evt_le_meta_event* metaEvent);
virtual void HandleHciLeEnhancedConnectionCompleteEvent(evt_le_meta_event* metaEvent);

virtual void HandleGattCompleteResponse(evt_blecore_aci* vendorEvent);

virtual void HandleAttReadByGroupTypeResponse(evt_blecore_aci* vendorEvent);
virtual void HandleAttReadByTypeResponse(evt_blecore_aci* vendorEvent);
virtual void HandleAttFindInfoResponse(evt_blecore_aci* vendorEvent);

private:
void HandleServiceDiscovered(infra::DataInputStream& stream, bool isUuid16);
void HandleCharacteristicDiscovered(infra::DataInputStream& stream, bool isUuid16);
void HandleDescriptorDiscovered(infra::DataInputStream& stream, bool isUuid16);
void HandleUuidFromDiscovery(infra::DataInputStream& stream, bool isUuid16, services::AttAttribute::Uuid& type);

private:
struct Atttributes
{
services::AttAttribute::Uuid type;
services::AttAttribute::Handle startHandle;
services::AttAttribute::Handle endHandle;
services::GattCharacteristic::PropertyFlags properties;
};

private:
uint16_t connectionHandle;

static constexpr uint16_t invalidConnection = 0xffff;

infra::Function<void(services::GattClientDiscoveryObserver&)> onDiscoveryCompletion;
};
}

#endif
43 changes: 43 additions & 0 deletions hal_st/middlewares/ble_middleware/TracingGattClientSt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "hal_st/middlewares/ble_middleware/TracingGattClientSt.hpp"
#include "infra/stream/StringOutputStream.hpp"

namespace infra
{
TextOutputStream& operator<<(TextOutputStream& stream, const services::AttAttribute::Uuid& uuid)
{
if (uuid.Is<services::AttAttribute::Uuid16>())
stream << "0x" << hex << uuid.Get<services::AttAttribute::Uuid16>();
else
stream << "[" << AsHex(MakeByteRange(uuid.Get<services::AttAttribute::Uuid128>())) << "]";

return stream;
}
}

namespace hal
{
TracingGattClientSt::TracingGattClientSt(hal::HciEventSource& hciEventSource, services::Tracer& tracer)
: GattClientSt(hciEventSource)
, tracer(tracer)
{
tracer.Trace() << "TracingGattClientSt::TracingGattClientSt()";
}

void TracingGattClientSt::StartServiceDiscovery()
{
tracer.Trace() << "TracingGattClientSt::StartServiceDiscovery";
GattClientSt::StartServiceDiscovery();
}

void TracingGattClientSt::StartCharacteristicDiscovery(const services::GattService& service)
{
tracer.Trace() << "TracingGattClientSt::StartCharacteristicDiscovery";
GattClientSt::StartCharacteristicDiscovery(service);
}

void TracingGattClientSt::StartDescriptorDiscovery(const services::GattService& service)
{
tracer.Trace() << "TracingGattClientSt::StartDescriptorDiscovery";
GattClientSt::StartDescriptorDiscovery(service);
}
}
25 changes: 25 additions & 0 deletions hal_st/middlewares/ble_middleware/TracingGattClientSt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef HAL_ST_TRACING_GATT_CLIENT_ST_HPP
#define HAL_ST_TRACING_GATT_CLIENT_ST_HPP

#include "hal_st/middlewares/ble_middleware/GattClientSt.hpp"
#include "services/tracer/Tracer.hpp"

namespace hal
{
class TracingGattClientSt
: public GattClientSt
{
public:
explicit TracingGattClientSt(hal::HciEventSource& hciEventSource, services::Tracer& tracer);

// Implementation of services::GattClientDiscovery
virtual void StartServiceDiscovery() override;
virtual void StartCharacteristicDiscovery(const services::GattService& service) override;
virtual void StartDescriptorDiscovery(const services::GattService& service) override;

private:
services::Tracer& tracer;
};
}

#endif
Loading

0 comments on commit 121c351

Please sign in to comment.