Skip to content

Commit

Permalink
feat: extend GattClient interface with enable/disable indication/noti…
Browse files Browse the repository at this point in the history
…fication (#744)

* feat: extend GattClient interface with enabling/disabling notifications and indications

* Split UdpateReceived in NotificationReceived and IndicationReceived; add IndicationDone

* Update tests

* services/ble/GattClient: Refactor
  • Loading branch information
richardapeters authored Nov 4, 2024
1 parent d003065 commit e110c4d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 12 deletions.
14 changes: 11 additions & 3 deletions services/ble/Gatt.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ message Characteristic
uint32 properties = 4;
}

message Descriptr
message Descriptr
//'Descriptor' keyword is not allowed by Echo code generator
{
bytes uuid = 1 [(bytes_size) = 16];
Expand Down Expand Up @@ -100,6 +100,13 @@ service GattClient
rpc Read(Handle) returns (Nothing) { option (method_id) = 8; }
rpc Write(CharacteristicData) returns (Nothing) { option (method_id) = 9; }
rpc WriteWithoutResponse(CharacteristicData) returns (Nothing) { option (method_id) = 10; }

rpc EnableNotification(Handle) returns (Nothing) { option (method_id) = 11; };
rpc DisableNotification(Handle) returns (Nothing) { option (method_id) = 12; };
rpc EnableIndication(Handle) returns (Nothing) { option (method_id) = 13; };
rpc DisableIndication(Handle) returns (Nothing) { option (method_id) = 14; };

rpc IndicationDone(Nothing) returns (Nothing) { option (method_id) = 15; };
}

service GattClientResponse
Expand All @@ -119,8 +126,9 @@ service GattClientResponse

rpc ReadComplete(ReadResult) returns (Nothing) { option (method_id) = 8; }
rpc WriteComplete(GattResult) returns (Nothing) { option (method_id) = 9; }
rpc SubscriptionChangeDone(Nothing) returns (Nothing) { option (method_id) = 10; }

rpc IndicationReceived(CharacteristicData) returns (Nothing) { option (method_id) = 10; }
rpc NotificationReceived(CharacteristicData) returns (Nothing) { option (method_id) = 11; }
rpc IndicationReceived(CharacteristicData) returns (Nothing) { option (method_id) = 11; }
rpc NotificationReceived(CharacteristicData) returns (Nothing) { option (method_id) = 12; }
}

29 changes: 27 additions & 2 deletions services/ble/GattClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,40 @@ namespace services
GattClientCharacteristicOperationsObserver::Subject().DisableIndication(*this, onDone);
}

void GattClientCharacteristic::UpdateReceived(AttAttribute::Handle handle, infra::ConstByteRange data)
void GattClientCharacteristic::NotificationReceived(AttAttribute::Handle handle, infra::ConstByteRange data)
{
if (handle == (Handle() + GattDescriptor::ClientCharacteristicConfiguration::valueHandleOffset))
GattClientCharacteristicUpdate::SubjectType::NotifyObservers([&data](auto& obs)
{
obs.UpdateReceived(data);
obs.NotificationReceived(data);
});
}

void GattClientCharacteristic::IndicationReceived(AttAttribute::Handle handle, infra::ConstByteRange data, const infra::Function<void()>& onDone)
{
if (handle == (Handle() + GattDescriptor::ClientCharacteristicConfiguration::valueHandleOffset))
{
onIndicationDone = onDone;
observers = 1;
auto indicationReceived = [this]()
{
--observers;
if (observers == 0)
onIndicationDone();
};

GattClientCharacteristicUpdate::SubjectType::NotifyObservers([this, &data, &indicationReceived](auto& obs)
{
++observers;
obs.IndicationReceived(data, indicationReceived);
});

indicationReceived();
}
else
onDone();
}

AttAttribute::Handle GattClientCharacteristic::CharacteristicValueHandle() const
{
return valueHandle;
Expand Down
14 changes: 11 additions & 3 deletions services/ble/GattClient.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef SERVICES_GATT_CLIENT_HPP
#define SERVICES_GATT_CLIENT_HPP

#include "infra/util/AutoResetFunction.hpp"
#include "infra/util/ByteRange.hpp"
#include "infra/util/IntrusiveForwardList.hpp"
#include "infra/util/Observer.hpp"
Expand All @@ -17,7 +18,8 @@ namespace services
public:
using infra::Observer<GattClientCharacteristicUpdateObserver, GattClientCharacteristicUpdate>::Observer;

virtual void UpdateReceived(infra::ConstByteRange data) = 0;
virtual void NotificationReceived(infra::ConstByteRange data) = 0;
virtual void IndicationReceived(infra::ConstByteRange data, const infra::Function<void()>& onDone) = 0;
};

class GattClientCharacteristicUpdate
Expand All @@ -32,7 +34,8 @@ namespace services
public:
using infra::Observer<GattClientStackUpdateObserver, GattClientCharacteristicOperations>::Observer;

virtual void UpdateReceived(AttAttribute::Handle handle, infra::ConstByteRange data) = 0;
virtual void NotificationReceived(AttAttribute::Handle handle, infra::ConstByteRange data) = 0;
virtual void IndicationReceived(AttAttribute::Handle handle, infra::ConstByteRange data, const infra::Function<void()>& onDone) = 0;
};

class GattClientCharacteristicOperationsObserver
Expand Down Expand Up @@ -85,7 +88,12 @@ namespace services
GattCharacteristic::PropertyFlags CharacteristicProperties() const override;

// Implementation of GattClientStackUpdateObserver
void UpdateReceived(AttAttribute::Handle handle, infra::ConstByteRange data) override;
void NotificationReceived(AttAttribute::Handle handle, infra::ConstByteRange data) override;
void IndicationReceived(AttAttribute::Handle handle, infra::ConstByteRange data, const infra::Function<void()>& onDone) override;

private:
infra::AutoResetFunction<void()> onIndicationDone;
uint32_t observers;
};

class GattClientService
Expand Down
35 changes: 32 additions & 3 deletions services/ble/test/TestGattClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,24 @@ class GattClientCharacteristicTest

TEST_F(GattClientCharacteristicTest, receives_valid_notification_should_notify_observers)
{
EXPECT_CALL(gattUpdateObserver, UpdateReceived(infra::ByteRangeContentsEqual(infra::MakeStringByteRange("string"))));
EXPECT_CALL(gattUpdateObserver, NotificationReceived(infra::ByteRangeContentsEqual(infra::MakeStringByteRange("string"))));
operations.infra::Subject<services::GattClientStackUpdateObserver>::NotifyObservers([](auto& observer)
{
observer.UpdateReceived(characteristicValueHandle, infra::MakeStringByteRange("string"));
observer.NotificationReceived(characteristicValueHandle, infra::MakeStringByteRange("string"));
});
}

TEST_F(GattClientCharacteristicTest, receives_valid_indication_should_notify_observers)
{
infra::VerifyingFunction<void()> callback;

EXPECT_CALL(gattUpdateObserver, IndicationReceived(infra::ByteRangeContentsEqual(infra::MakeStringByteRange("string")), testing::_)).WillOnce(testing::InvokeArgument<1>());
operations.infra::Subject<services::GattClientStackUpdateObserver>::NotifyObservers([&callback](auto& observer)
{
observer.IndicationReceived(characteristicValueHandle, infra::MakeStringByteRange("string"), [&callback]()
{
callback.callback();
});
});
}

Expand All @@ -90,7 +104,22 @@ TEST_F(GattClientCharacteristicTest, receives_invalid_notification_should_not_no

operations.infra::Subject<services::GattClientStackUpdateObserver>::NotifyObservers([&invalidCharacteristicValueHandle](auto& observer)
{
observer.UpdateReceived(invalidCharacteristicValueHandle, infra::MakeStringByteRange("string"));
observer.NotificationReceived(invalidCharacteristicValueHandle, infra::MakeStringByteRange("string"));
});
}

TEST_F(GattClientCharacteristicTest, receives_invalid_indication_should_not_notify_observers)
{
const services::AttAttribute::Handle invalidCharacteristicValueHandle = 0x7;

infra::VerifyingFunction<void()> callback;

operations.infra::Subject<services::GattClientStackUpdateObserver>::NotifyObservers([&invalidCharacteristicValueHandle, &callback](auto& observer)
{
observer.IndicationReceived(invalidCharacteristicValueHandle, infra::MakeStringByteRange("string"), [&callback]()
{
callback.callback();
});
});
}

Expand Down
17 changes: 16 additions & 1 deletion services/ble/test_doubles/GattClientMock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,28 @@ namespace services
: public services::GattClientCharacteristicUpdateObserver
{
public:
MOCK_METHOD(void, UpdateReceived, (infra::ConstByteRange data), (override));
using services::GattClientCharacteristicUpdateObserver::GattClientCharacteristicUpdateObserver;

MOCK_METHOD(void, NotificationReceived, (infra::ConstByteRange data), (override));
MOCK_METHOD(void, IndicationReceived, (infra::ConstByteRange data, const infra::Function<void()>& onDone), (override));
};

class GattClientStackUpdateObserverMock
: public services::GattClientStackUpdateObserver
{
public:
using services::GattClientStackUpdateObserver::GattClientStackUpdateObserver;

MOCK_METHOD(void, NotificationReceived, (AttAttribute::Handle handle, infra::ConstByteRange data), (override));
MOCK_METHOD(void, IndicationReceived, (AttAttribute::Handle handle, infra::ConstByteRange data, const infra::Function<void()>& onDone), (override));
};

class GattClientCharacteristicOperationsObserverMock
: public services::GattClientCharacteristicOperationsObserver
{
public:
using services::GattClientCharacteristicOperationsObserver::GattClientCharacteristicOperationsObserver;

MOCK_METHOD(AttAttribute::Handle, CharacteristicValueHandle, (), (const, override));
MOCK_METHOD(GattCharacteristic::PropertyFlags, CharacteristicProperties, (), (const, override));
};
Expand Down

0 comments on commit e110c4d

Please sign in to comment.