libGulliBLE
characteristic.hpp
Go to the documentation of this file.
1//
2// Created by spak on 9/23/21.
3//
4
5#ifndef LIBGULLIBLE_CHARACTERISTIC_HPP
6#define LIBGULLIBLE_CHARACTERISTIC_HPP
7
8#include <ble/uuid.hpp>
9#include <mlab/bin_data.hpp>
10#include <mlab/observable.hpp>
11#include <mlab/unique_tracker.hpp>
12#include <utility>
13
14namespace ble {
15
16 enum struct retcode : int {
17 ok = 0,
18 invalid_handle = BLE_ATT_ERR_INVALID_HANDLE,
19 read_not_permitted = BLE_ATT_ERR_READ_NOT_PERMITTED,
20 write_not_permitted = BLE_ATT_ERR_WRITE_NOT_PERMITTED,
21 invalid_pdu = BLE_ATT_ERR_INVALID_PDU,
22 insufficient_authen = BLE_ATT_ERR_INSUFFICIENT_AUTHEN,
23 req_not_supported = BLE_ATT_ERR_REQ_NOT_SUPPORTED,
24 invalid_offset = BLE_ATT_ERR_INVALID_OFFSET,
25 insufficient_author = BLE_ATT_ERR_INSUFFICIENT_AUTHOR,
26 prepare_queue_full = BLE_ATT_ERR_PREPARE_QUEUE_FULL,
27 attr_not_found = BLE_ATT_ERR_ATTR_NOT_FOUND,
28 attr_not_long = BLE_ATT_ERR_ATTR_NOT_LONG,
29 insufficient_key_sz = BLE_ATT_ERR_INSUFFICIENT_KEY_SZ,
30 invalid_attr_value_len = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN,
31 unlikely = BLE_ATT_ERR_UNLIKELY,
32 insufficient_enc = BLE_ATT_ERR_INSUFFICIENT_ENC,
33 unsupported_group = BLE_ATT_ERR_UNSUPPORTED_GROUP,
34 insufficient_res = BLE_ATT_ERR_INSUFFICIENT_RES
35 };
36
37 enum struct access_type : std::uint8_t {
38 none = 0b00,
39 r = 0b01,
40 w = 0b10,
41 rw = 0b11
42 };
43
44 [[nodiscard]] inline bool operator&(access_type l, access_type r);
45
46 [[nodiscard]] inline access_type operator|(access_type l, access_type r);
47
48 [[nodiscard]] inline std::uint16_t to_nimble(access_type a);
49
51 : public mlab::uniquely_tracked,
52 public std::enable_shared_from_this<characteristic_base> {
53
55 std::unique_ptr<ble_uuid_any_t> _nimble_uuid;
57 mlab::bin_data _buffer;
58
59 static int _nimble_characteristic_access_callback(std::uint16_t conn_handle, std::uint16_t attr_handle,
60 ble_gatt_access_ctxt *ctxt, void *tracker);
61
62 protected:
63 [[nodiscard]] virtual retcode on_access(std::uint16_t conn_handle, std::uint16_t attr_handle,
64 ble_gatt_access_ctxt &ctxt);
65
66 [[nodiscard]] virtual retcode on_read(std::uint16_t conn_handle, std::uint16_t attr_handle,
67 ble_gatt_access_ctxt &ctxt);
68
69 [[nodiscard]] virtual retcode on_write(std::uint16_t conn_handle, std::uint16_t attr_handle,
70 ble_gatt_access_ctxt &ctxt);
71
72 [[nodiscard]] virtual retcode do_read(mlab::bin_data &data, std::uint16_t conn_handle,
73 std::uint16_t attr_handle) = 0;
74
75 [[nodiscard]] virtual retcode do_write(mlab::bin_data const &data, std::uint16_t conn_handle,
76 std::uint16_t attr_handle) = 0;
77
78 public:
79 static constexpr ble_gatt_chr_def void_definition = {
80 .uuid = nullptr,
81 .access_cb = nullptr,
82 .arg = nullptr,
83 .descriptors = nullptr,
84 .flags = 0,
85 .min_key_size = 0,
86 .val_handle = nullptr};
87
89
90 [[nodiscard]] inline access_type access() const;
91
92 [[nodiscard]] inline uuid const &chr_uuid() const;
93
94 [[nodiscard]] ble_gatt_chr_def get_definition() const;
95
96 virtual ~characteristic_base() = default;
97 };
98
99 namespace impl {
100
101 template <class T, bool>
103 std::shared_ptr<mlab::observable<T>> _value;
104
105 public:
107 std::shared_ptr<mlab::observable<T>> init = nullptr);
108
110
111 [[nodiscard]] inline mlab::observable_cref<T> value() const;
112
113 [[nodiscard]] inline mlab::observable_ref<T> value();
114
115 [[nodiscard]] inline std::shared_ptr<mlab::observable<T>> const &value_ptr() const;
116 };
117
118 template <class T>
119 class stored_characteristic_base<T, true> : public stored_characteristic_base<T, false> {
120 protected:
121 [[nodiscard]] retcode do_read(mlab::bin_data &data, std::uint16_t conn_handle,
122 std::uint16_t attr_handle) override;
123
124 [[nodiscard]] retcode do_write(mlab::bin_data const &data, std::uint16_t conn_handle,
125 std::uint16_t attr_handle) override;
126
127 public:
131 };
132
133 }// namespace impl
134
135 template <class T>
138 T, mlab::bin_data::is_injectable<T>::value and mlab::bin_stream::is_extractable<T>::value> {
139 public:
145 static constexpr bool has_synthetic_rw_methods = mlab::bin_data::is_injectable<T>::value and
146 mlab::bin_stream::is_extractable<T>::value;
147
151 };
152
153}// namespace ble
154
155namespace ble {
156
157 template <class T, bool B>
159 uuid const &u, access_type access, std::shared_ptr<mlab::observable<T>> init)
160 : characteristic_base{u, access},
161 _value{init != nullptr ? std::move(init) : std::make_shared<mlab::observable<T>>()} {}
162
163 template <class T, bool B>
165 uuid const &u, access_type access, T init)
166 : characteristic_base{u, access},
167 _value{std::make_shared<mlab::observable<T>>(std::forward<T>(init))} {}
168
169
170 template <class T, bool B>
171 mlab::observable_cref<T> impl::stored_characteristic_base<T, B>::value() const {
172 return _value->cref();
173 }
174
175 template <class T, bool B>
176 std::shared_ptr<mlab::observable<T>> const &impl::stored_characteristic_base<T, B>::value_ptr() const {
177 return _value;
178 }
179
180 template <class T, bool B>
182 return _value->ref();
183 }
184
185 template <class T>
186 retcode impl::stored_characteristic_base<T, true>::do_read(mlab::bin_data &data, std::uint16_t, std::uint16_t) {
187 data << static_cast<T>(value());
188 return retcode::ok;
189 }
190
191 template <class T>
192 retcode
193 impl::stored_characteristic_base<T, true>::do_write(mlab::bin_data const &data, std::uint16_t, std::uint16_t) {
194 mlab::bin_stream s{data};
195 T obj{};
196 s >> obj;
197 if (s.bad()) {
199 }
200 value() = std::forward<T>(obj);
201 return retcode::ok;
202 }
203
205 return _access;
206 }
207
209 return _uuid;
210 }
211
212 std::uint16_t to_nimble(access_type a) {
213 switch (a) {
214 case access_type::r:
215 return BLE_GATT_CHR_F_READ;
216 case access_type::w:
217 return BLE_GATT_CHR_F_WRITE;
218 case access_type::rw:
219 return BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE;
220 default:
221 [[fallthrough]];
223 return 0;
224 }
225 }
226
228 return (static_cast<std::uint8_t>(l) & static_cast<std::uint8_t>(r)) != 0;
229 }
230
232 return static_cast<access_type>(static_cast<std::uint8_t>(l) | static_cast<std::uint8_t>(r));
233 }
234}// namespace ble
235
236
237#endif//LIBGULLIBLE_CHARACTERISTIC_HPP
mlab::bin_data & data
Definition: characteristic.cpp:49
Definition: characteristic.hpp:52
virtual retcode do_read(mlab::bin_data &data, std::uint16_t conn_handle, std::uint16_t attr_handle)=0
access_type access() const
Definition: characteristic.hpp:204
virtual ~characteristic_base()=default
virtual retcode on_write(std::uint16_t conn_handle, std::uint16_t attr_handle, ble_gatt_access_ctxt &ctxt)
Definition: characteristic.cpp:71
uuid _uuid
Definition: characteristic.hpp:54
virtual retcode do_write(mlab::bin_data const &data, std::uint16_t conn_handle, std::uint16_t attr_handle)=0
virtual retcode on_read(std::uint16_t conn_handle, std::uint16_t attr_handle, ble_gatt_access_ctxt &ctxt)
Definition: characteristic.cpp:58
virtual retcode on_access(std::uint16_t conn_handle, std::uint16_t attr_handle, ble_gatt_access_ctxt &ctxt)
Definition: characteristic.cpp:28
static int _nimble_characteristic_access_callback(std::uint16_t conn_handle, std::uint16_t attr_handle, ble_gatt_access_ctxt *ctxt, void *tracker)
Definition: characteristic.cpp:17
characteristic_base(uuid u, access_type access)
Definition: characteristic.cpp:13
access_type _access
Definition: characteristic.hpp:56
ble_gatt_chr_def get_definition() const
Definition: characteristic.cpp:85
uuid const & chr_uuid() const
Definition: characteristic.hpp:208
std::unique_ptr< ble_uuid_any_t > _nimble_uuid
Definition: characteristic.hpp:55
mlab::bin_data _buffer
Definition: characteristic.hpp:57
static constexpr ble_gatt_chr_def void_definition
Definition: characteristic.hpp:79
Definition: characteristic.hpp:102
std::shared_ptr< mlab::observable< T > > const & value_ptr() const
Definition: characteristic.hpp:176
stored_characteristic_base(uuid const &u, access_type access, std::shared_ptr< mlab::observable< T > > init=nullptr)
Definition: characteristic.hpp:158
mlab::observable_ref< T > value()
Definition: characteristic.hpp:181
std::shared_ptr< mlab::observable< T > > _value
Definition: characteristic.hpp:103
mlab::observable_cref< T > value() const
Definition: characteristic.hpp:171
stored_characteristic_base(uuid const &u, access_type access, T init)
Definition: characteristic.hpp:164
Definition: characteristic.hpp:138
static constexpr bool has_synthetic_rw_methods
True iff the do_read and do_write methods have already been automatically synthesized....
Definition: characteristic.hpp:145
Definition: uuid.hpp:72
Definition: characteristic.hpp:14
bool operator&(access_type l, access_type r)
Definition: characteristic.hpp:227
std::uint16_t to_nimble(access_type a)
Definition: characteristic.hpp:212
retcode
Definition: characteristic.hpp:16
@ invalid_attr_value_len
access_type
Definition: characteristic.hpp:37
access_type operator|(access_type l, access_type r)
Definition: characteristic.hpp:231