ELEC-C7222
Libraries for ELEC C7222 Course Work
Loading...
Searching...
No Matches
attribute.hpp
Go to the documentation of this file.
1
5#ifndef ELEC_C7222_BLE_GATT_ATTRIBUTE_H_
6#define ELEC_C7222_BLE_GATT_ATTRIBUTE_H_
7
8#include <functional>
9#include <iostream>
10#include <string>
11#include <vector>
12
13#include "ble_error.hpp"
14#include "non_copyable.hpp"
15#include "uuid.hpp"
16
17namespace c7222 {
18
119class Attribute : public MovableOnly {
120 public:
123
130 enum class Properties : std::uint16_t {
132 kNone = 0x0000,
137 kWritePermissionBit0 = 0x0001,
139 kRead = 0x0002,
141 kWriteWithoutResponse = 0x0004,
143 kWrite = 0x0008,
148 kWritePermissionBit1 = 0x0010,
150 kReadPermissionSc = 0x0020,
154 kWritePermissionSc = 0x0080,
161 kDynamic = 0x0100,
167 kUuid128 = 0x0200,
172 kReadPermissionBit0 = 0x0400,
177 kReadPermissionBit1 = 0x0800,
184 };
185
191 using ReadCallback = std::function<uint16_t(uint16_t offset, uint8_t* buffer, uint16_t buffer_size)>;
192
198 using WriteCallback = std::function<BleError(uint16_t offset, const uint8_t* data, uint16_t size)>;
200
204
210 static bool IsPrimaryServiceDeclaration(const Attribute& attr);
211
217 static bool IsSecondaryServiceDeclaration(const Attribute& attr);
218
224 static bool IsServiceDeclaration(const Attribute& attr);
225
231 static bool IsIncludedServiceDeclaration(const Attribute& attr);
232
238 static bool IsCharacteristicDeclaration(const Attribute& attr);
239
246
253
260
267
273 static bool IsDescriptor(const Attribute& attr);
275
278
284 static Attribute PrimaryServiceDeclaration(const Uuid& service_uuid, uint16_t handle = 0);
285
291 static Attribute SecondaryServiceDeclaration(const Uuid& service_uuid, uint16_t handle = 0);
292
302 static Attribute IncludedServiceDeclaration(uint16_t start_handle,
303 uint16_t end_handle,
304 const Uuid& service_uuid,
305 uint16_t handle = 0);
306
316 static Attribute CharacteristicDeclaration(uint8_t properties,
317 uint16_t value_handle,
318 const Uuid& characteristic_uuid,
319 uint16_t handle = 0);
320
324 static Attribute ClientCharacteristicConfiguration(uint16_t value, uint16_t handle = 0);
325
329 static Attribute ServerCharacteristicConfiguration(uint16_t value, uint16_t handle = 0);
330
336 static Attribute CharacteristicUserDescription(const std::string& description,
337 uint16_t handle = 0);
338
344 static Attribute CharacteristicExtendedProperties(uint16_t value, uint16_t handle = 0);
345
352 int8_t exponent,
353 uint16_t unit,
354 uint8_t name_space,
355 uint16_t description,
356 uint16_t handle = 0);
357
363 static Attribute CharacteristicAggregateFormat(const std::vector<uint16_t>& handles,
364 uint16_t handle = 0);
366
369
376 Attribute() = default;
377
379 Attribute(Attribute&&) noexcept = default;
380
382 Attribute& operator=(Attribute&&) noexcept = default;
383
387 Attribute(const Uuid& uuid, uint16_t properties, uint16_t handle = 0);
393 Attribute(const Uuid& uuid, uint16_t properties, const uint8_t* data, size_t size, uint16_t handle = 0);
395
398
403 [[nodiscard]] uint16_t GetHandle() const {
404 return handle_;
405 }
406
411 void SetHandle(uint16_t handle) {
412 handle_ = handle;
413 }
414
419 [[nodiscard]] const Uuid& GetUuid() const {
420 return uuid_;
421 }
422
427 [[nodiscard]] bool IsUuid128() const {
428 return uuid_.Is128Bit();
429 }
430
434 [[nodiscard]] bool IsValid() const {
435 return handle_ != 0 && uuid_.IsValid();
436 }
437
443 [[nodiscard]] bool IsThisAttribute(const Uuid& uuid) const {
444 return uuid_ == uuid;
445 }
446
452 [[nodiscard]] bool IsThisAttribute(uint16_t handle) const {
453 return handle != 0 && handle_ == handle;
454 }
455
462 [[nodiscard]] bool IsThisAttribute(const Uuid& uuid, uint16_t handle) const {
463 return uuid_ == uuid && handle_ == handle;
464 }
466
469
474 [[nodiscard]] uint16_t GetProperties() const {
475 return properties_;
476 }
477
482 void SetProperties(uint16_t properties) {
483 properties_ = properties;
484 UpdateUuidProperty();
485 }
487
490
495 [[nodiscard]] const std::vector<uint8_t>& GetDynamicValue() const {
496 return dynamic_value_;
497 }
498
505 [[nodiscard]] const uint8_t* GetValueData() const {
506 if((properties_ & static_cast<uint16_t>(Properties::kDynamic)) != 0) {
507 return dynamic_value_.empty() ? nullptr : dynamic_value_.data();
508 }
509 return static_value_ptr_;
510 }
511
517 [[nodiscard]] size_t GetValueSize() const {
518 if((properties_ & static_cast<uint16_t>(Properties::kDynamic)) != 0) {
519 return dynamic_value_.size();
520 }
521 return static_value_size_;
522 }
523
532 bool SetValue(const uint8_t* data, size_t size);
533
541 bool SetStaticValue(const uint8_t* data, size_t size);
542
549 bool SetValue(std::vector<uint8_t>&& data);
550
557 bool SetValue(const std::vector<uint8_t>& data);
558
564 bool SetStaticValue(const std::vector<uint8_t>& data);
565
577 template<typename T>
578 bool SetValue(const T& value) {
579 static_assert(std::is_trivial<T>::value,
580 "T must be a trivial type for binary conversion");
581 return SetValue(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
582 }
584
587
594 read_callback_ = std::move(callback);
595 }
596
601 [[nodiscard]] bool HasReadCallback() const {
602 return static_cast<bool>(read_callback_);
603 }
604
613 uint16_t InvokeReadCallback(uint16_t offset, uint8_t* buffer, uint16_t buffer_size) const;
614
621 write_callback_ = std::move(callback);
622 }
623
628 [[nodiscard]] bool HasWriteCallback() const {
629 return static_cast<bool>(write_callback_);
630 }
631
644 BleError InvokeWriteCallback(uint16_t offset, const uint8_t* data, uint16_t size);
646
649
654 friend std::ostream& operator<<(std::ostream& os, const Attribute& attr);
656
657 private:
669 void UpdateUuidProperty() {
670 if(uuid_.Is128Bit()) {
671 properties_ |= static_cast<uint16_t>(Properties::kUuid128);
672 } else {
673 properties_ &= ~static_cast<uint16_t>(Properties::kUuid128);
674 }
675 }
676
677 // ========== Core Attribute Identity ==========
678
687 Uuid uuid_{};
688
697 uint16_t handle_ = 0;
698
711 uint16_t properties_ = 0;
712
713 // ========== Static Attribute Value Storage ==========
714
730 const uint8_t* static_value_ptr_ = nullptr;
731
740 size_t static_value_size_ = 0;
741
742 // ========== Dynamic Attribute Value Storage ==========
743
760 std::vector<uint8_t> dynamic_value_{};
761
762 // ========== Callback Functions ==========
763
781 ReadCallback read_callback_{};
782
804 WriteCallback write_callback_{};
805};
806
811std::ostream& operator<<(std::ostream& os, const Attribute& attr);
812
813// Bitwise operators for Attribute::Properties enum
814// These operators enable convenient property flag manipulation:
815// uint16_t props = Attribute::Properties::kRead | Attribute::Properties::kWrite;
816
822 return static_cast<uint16_t>(lhs) | static_cast<uint16_t>(rhs);
823}
824
830 return static_cast<uint16_t>(lhs) & static_cast<uint16_t>(rhs);
831}
832
838 return static_cast<uint16_t>(lhs) ^ static_cast<uint16_t>(rhs);
839}
840
845constexpr uint16_t operator~(Attribute::Properties value) {
846 return static_cast<uint16_t>(~static_cast<uint16_t>(value));
847}
848
853constexpr uint16_t operator|=(uint16_t& lhs, Attribute::Properties rhs) {
854 lhs = static_cast<uint16_t>(lhs | static_cast<uint16_t>(rhs));
855 return lhs;
856}
857
862constexpr uint16_t operator&=(uint16_t& lhs, Attribute::Properties rhs) {
863 lhs = static_cast<uint16_t>(lhs & static_cast<uint16_t>(rhs));
864 return lhs;
865}
866
871constexpr uint16_t operator^=(uint16_t& lhs, Attribute::Properties rhs) {
872 lhs = static_cast<uint16_t>(lhs ^ static_cast<uint16_t>(rhs));
873 return lhs;
874}
875
880constexpr uint16_t operator|(uint16_t lhs, Attribute::Properties rhs) {
881 return lhs | static_cast<uint16_t>(rhs);
882}
883
887constexpr uint16_t operator&(uint16_t lhs, Attribute::Properties rhs) {
888 return lhs & static_cast<uint16_t>(rhs);
889}
890
894constexpr uint16_t operator^(uint16_t lhs, Attribute::Properties rhs) {
895 return lhs ^ static_cast<uint16_t>(rhs);
896}
897
901constexpr uint16_t operator|(Attribute::Properties lhs, uint16_t rhs) {
902 return static_cast<uint16_t>(lhs) | rhs;
903}
904
908constexpr uint16_t operator&(Attribute::Properties lhs, uint16_t rhs) {
909 return static_cast<uint16_t>(lhs) & rhs;
910}
911
915constexpr uint16_t operator^(Attribute::Properties lhs, uint16_t rhs) {
916 return static_cast<uint16_t>(lhs) ^ rhs;
917}
918
919} // namespace c7222
920
921#endif // ELEC_C7222_BLE_GATT_ATTRIBUTE_H_
BLE error codes.
ATT attribute wrapper with BTstack-compatible fields.
Definition attribute.hpp:119
bool IsThisAttribute(const Uuid &uuid, uint16_t handle) const
Check if this attribute matches both UUID and handle.
Definition attribute.hpp:462
Attribute()=default
Default-construct an invalid attribute.
static bool IsCharacteristicExtendedProperties(const Attribute &attr)
Check if an attribute is a Characteristic Extended Properties descriptor.
std::function< BleError(uint16_t offset, const uint8_t *data, uint16_t size)> WriteCallback
Callback type for writing attribute value. Parameters: offset, source data, data size Returns: BleErr...
Definition attribute.hpp:198
static bool IsCharacteristicUserDescription(const Attribute &attr)
Check if an attribute is a Characteristic User Description.
bool IsValid() const
Check if this attribute has a valid handle and UUID.
Definition attribute.hpp:434
uint16_t InvokeReadCallback(uint16_t offset, uint8_t *buffer, uint16_t buffer_size) const
Invoke the read callback.
const std::vector< uint8_t > & GetDynamicValue() const
Get value as vector (for compatibility). Note: Returns empty for static attributes because they are D...
Definition attribute.hpp:495
static Attribute CharacteristicDeclaration(uint8_t properties, uint16_t value_handle, const Uuid &characteristic_uuid, uint16_t handle=0)
Create a Characteristic Declaration payload.
BleError InvokeWriteCallback(uint16_t offset, const uint8_t *data, uint16_t size)
Invoke the write callback.
static Attribute CharacteristicUserDescription(const std::string &description, uint16_t handle=0)
Create a Characteristic User Description with a UTF-8 string.
void SetWriteCallback(WriteCallback callback)
Set the write callback for this attribute. Called when a remote client writes this attribute.
Definition attribute.hpp:620
uint16_t GetProperties() const
Get the properties bitmask of the attribute.
Definition attribute.hpp:474
bool SetValue(const T &value)
Set attribute value from a typed value (generic template). Converts any trivial type to bytes and sto...
Definition attribute.hpp:578
bool SetValue(const std::vector< uint8_t > &data)
Set attribute value from lvalue vector (copy semantics). Only allowed for dynamic attributes.
bool SetStaticValue(const uint8_t *data, size_t size)
Set attribute value for static attributes. Copies the data into owned storage and updates the static ...
bool IsThisAttribute(const Uuid &uuid) const
Check if this attribute matches a UUID.
Definition attribute.hpp:443
static Attribute PrimaryServiceDeclaration(const Uuid &service_uuid, uint16_t handle=0)
Create a Primary Service Declaration with a service UUID payload.
static Attribute ClientCharacteristicConfiguration(uint16_t value, uint16_t handle=0)
Create a Client Characteristic Configuration with a 16-bit value.
void SetReadCallback(ReadCallback callback)
Set the read callback for this attribute. Called when a remote client reads this attribute.
Definition attribute.hpp:593
std::function< uint16_t(uint16_t offset, uint8_t *buffer, uint16_t buffer_size)> ReadCallback
Callback type for reading attribute value. Parameters: offset, destination buffer,...
Definition attribute.hpp:191
void SetHandle(uint16_t handle)
Set the ATT handle.
Definition attribute.hpp:411
bool HasWriteCallback() const
Check if a write callback is registered.
Definition attribute.hpp:628
static bool IsServerCharacteristicConfiguration(const Attribute &attr)
Check if an attribute is a Server Characteristic Configuration Descriptor.
static bool IsPrimaryServiceDeclaration(const Attribute &attr)
Check if an attribute is a Primary Service Declaration.
friend std::ostream & operator<<(std::ostream &os, const Attribute &attr)
Stream insertion operator for Attribute. Outputs the attribute handle, UUID, and parsed properties fl...
void SetProperties(uint16_t properties)
Set the properties bitmask of the attribute.
Definition attribute.hpp:482
bool IsThisAttribute(uint16_t handle) const
Check if this attribute matches a handle.
Definition attribute.hpp:452
bool SetValue(std::vector< uint8_t > &&data)
Set attribute value from rvalue vector (move semantics). Only allowed for dynamic attributes.
static Attribute IncludedServiceDeclaration(uint16_t start_handle, uint16_t end_handle, const Uuid &service_uuid, uint16_t handle=0)
Create an Included Service Declaration payload.
static bool IsClientCharacteristicConfiguration(const Attribute &attr)
Check if an attribute is a Client Characteristic Configuration Descriptor.
Properties
Attribute flags with direct BTstack ATT_PROPERTY_* mapping.
Definition attribute.hpp:130
@ kUuid128
Entry uses a 128-bit UUID in the ATT DB.
@ kReadPermissionBit0
Read permission bit 0 (LSB of a 2-bit read security level). Combined with kReadPermissionBit1 by the ...
@ kDynamic
Value is dynamic (handled by callbacks, not fixed DB storage).
@ kNone
No properties set.
@ kAuthenticatedSignedWrite
Attribute supports Authenticated Signed Write.
@ kReadPermissionSc
Read requires Secure Connections (SC) per BTstack flags.
@ kRead
Attribute can be read via ATT Read Request.
@ kWritePermissionSc
Write requires Secure Connections (SC) per BTstack flags.
@ kWritePermissionBit1
Write permission bit 1 (MSB of a 2-bit write security level). Combined with kWritePermissionBit0 by t...
@ kWritePermissionBit0
Write permission bit 0 (LSB of a 2-bit write security level). Combined with kWritePermissionBit1 by t...
@ kReadPermissionBit1
Read permission bit 1 (MSB of a 2-bit read security level). Combined with kReadPermissionBit0 by the ...
@ kEncryptionKeySizeMask
Mask for encryption key size requirement (bits 12-15).
@ kWrite
Attribute can be written via Write Request (with response).
@ kWriteWithoutResponse
Attribute can be written via Write Command (no response).
bool HasReadCallback() const
Check if a read callback is registered.
Definition attribute.hpp:601
static Attribute CharacteristicAggregateFormat(const std::vector< uint16_t > &handles, uint16_t handle=0)
Create a Characteristic Aggregate Format from a list of handles.
bool SetValue(const uint8_t *data, size_t size)
Set attribute value. Only allowed for dynamic attributes; static attributes are immutable because the...
static Attribute SecondaryServiceDeclaration(const Uuid &service_uuid, uint16_t handle=0)
Create a Secondary Service Declaration with a service UUID payload.
uint16_t GetHandle() const
Get the ATT handle.
Definition attribute.hpp:403
Attribute(Attribute &&) noexcept=default
Move constructor (transfers storage and callbacks).
bool SetStaticValue(const std::vector< uint8_t > &data)
Set attribute value for static attributes from vector (copy semantics).
bool IsUuid128() const
Check if the attribute UUID is 128-bit.
Definition attribute.hpp:427
const Uuid & GetUuid() const
Get the attribute UUID.
Definition attribute.hpp:419
static Attribute ServerCharacteristicConfiguration(uint16_t value, uint16_t handle=0)
Create a Server Characteristic Configuration with a 16-bit value.
static Attribute CharacteristicExtendedProperties(uint16_t value, uint16_t handle=0)
Create a Characteristic Extended Properties with a 16-bit value.
const uint8_t * GetValueData() const
Get pointer to attribute value data.
Definition attribute.hpp:505
static bool IsServiceDeclaration(const Attribute &attr)
Check if an attribute is any Service Declaration (Primary or Secondary).
static bool IsCharacteristicDeclaration(const Attribute &attr)
Check if an attribute is a Characteristic Declaration.
static bool IsDescriptor(const Attribute &attr)
Check if an attribute is a descriptor (not declaration or value).
static Attribute CharacteristicPresentationFormat(uint8_t format, int8_t exponent, uint16_t unit, uint8_t name_space, uint16_t description, uint16_t handle=0)
Create a Characteristic Presentation Format payload (0x2904).
size_t GetValueSize() const
Get size of attribute value.
Definition attribute.hpp:517
static bool IsIncludedServiceDeclaration(const Attribute &attr)
Check if an attribute is an Included Service Declaration.
static bool IsSecondaryServiceDeclaration(const Attribute &attr)
Check if an attribute is a Secondary Service Declaration.
Convenience base that allows move but forbids copy.
Definition non_copyable.hpp:91
UUID storage for 16-bit and 128-bit UUIDs.
Definition uuid.hpp:53
bool Is128Bit() const
Returns true if this UUID is 128-bit.
bool IsValid() const
Returns true if the UUID has been initialized to 16- or 128-bit.
Definition uuid.hpp:166
C7222 course abstractions namespace.
Definition ble.hpp:20
constexpr uint16_t operator|=(uint16_t &lhs, Attribute::Properties rhs)
Bitwise OR assignment: uint16_t |= Properties.
Definition attribute.hpp:853
constexpr uint16_t operator|(Attribute::Properties lhs, Attribute::Properties rhs)
Bitwise OR for two Properties values.
Definition attribute.hpp:821
BleError
BLE error codes used across HCI/L2CAP/ATT/GATT and BTstack helpers.
Definition ble_error.hpp:19
constexpr uint16_t operator&=(uint16_t &lhs, Attribute::Properties rhs)
Bitwise AND assignment: uint16_t &= Properties.
Definition attribute.hpp:862
std::ostream & operator<<(std::ostream &os, const BleAddress &addr)
constexpr uint16_t operator^=(uint16_t &lhs, Attribute::Properties rhs)
Bitwise XOR assignment: uint16_t ^= Properties.
Definition attribute.hpp:871
constexpr uint16_t operator^(Attribute::Properties lhs, Attribute::Properties rhs)
Bitwise XOR for two Properties values.
Definition attribute.hpp:837
constexpr uint16_t operator&(Attribute::Properties lhs, Attribute::Properties rhs)
Bitwise AND for two Properties values.
Definition attribute.hpp:829
constexpr uint16_t operator~(Attribute::Properties value)
Bitwise NOT for a Properties value.
Definition attribute.hpp:845
Base classes to control copy/move semantics.
GATT UUID wrapper.