Dawn Framework 1.0
Universal data acquisition framework for embedded systems
prph_custom.cxx
1// dawn/src/proto/nimble/prph_custom.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/nimble/prph_custom.hxx"
7
8#include <cstdlib>
9#include <cstring>
10#include <new>
11
12#include "host/ble_hs_mbuf.h"
13#include "host/ble_uuid.h"
14#include "os/os_mbuf.h"
15
16using namespace dawn;
17
18#ifdef CONFIG_DAWN_IO_NOTIFY
19int CProtoNimblePrphCustom::notifierCb(void *priv, io_ddata_t *data)
20{
21 SCustomCharCb *ccb = static_cast<SCustomCharCb *>(priv);
22
23 if (ccb == nullptr || ccb->io == nullptr || ccb->data == nullptr)
24 {
25 return -EINVAL;
26 }
27
28 std::memcpy(ccb->data->getDataPtr(), data->getDataPtr(), ccb->data->getDataSize());
29 ble_gatts_chr_updated(ccb->handle);
30 return OK;
31}
32#endif
33
34int CProtoNimblePrphCustom::callback(uint16_t conn_handle,
35 uint16_t attr_handle,
36 struct ble_gatt_access_ctxt *ctxt,
37 void *arg)
38{
39 SCustomCharCb *ccb = static_cast<SCustomCharCb *>(arg);
40 int ret;
41
42 if (ccb == nullptr || ccb->io == nullptr || ccb->data == nullptr)
43 {
44 return BLE_ATT_ERR_UNLIKELY;
45 }
46
47 switch (ctxt->op)
48 {
49 case BLE_GATT_ACCESS_OP_READ_CHR:
50 {
51 ret = ccb->io->getData(*ccb->data, 1);
52 if (ret < 0)
53 {
54 return BLE_ATT_ERR_UNLIKELY;
55 }
56
57 ret = os_mbuf_append(ctxt->om, ccb->data->getDataPtr(), ccb->data->getDataSize());
58 return ret < 0 ? BLE_ATT_ERR_UNLIKELY : 0;
59 }
60
61 case BLE_GATT_ACCESS_OP_WRITE_CHR:
62 {
63 uint16_t len = 0;
64
65 ret =
66 ble_hs_mbuf_to_flat(ctxt->om, ccb->data->getDataPtr(), ccb->data->getDataSize(), &len);
67 if (ret < 0)
68 {
69 return BLE_ATT_ERR_UNLIKELY;
70 }
71
72 ret = ccb->io->setData(*ccb->data);
73 return ret < 0 ? BLE_ATT_ERR_UNLIKELY : 0;
74 }
75
76 default:
77 return BLE_ATT_ERR_UNLIKELY;
78 }
79}
80
81CProtoNimblePrphCustom::CProtoNimblePrphCustom(const SObjectCfg::SObjectCfgItem *item,
83 : IProtoNimblePrphService(item, cb_)
84 , id(-1)
85 , created(false)
86 , chrs(nullptr)
87{
88 std::memset(&svc, 0, sizeof(svc));
89}
90
91CProtoNimblePrphCustom::~CProtoNimblePrphCustom()
92{
93 deinit();
94}
95
96void CProtoNimblePrphCustom::configureDesc(const SObjectCfg::SObjectCfgItem *item)
97{
98 const SProtoNimblePrphCustomSvc *blob;
99 uint32_t count;
100
101 blob = reinterpret_cast<const SProtoNimblePrphCustomSvc *>(item->data);
102 count = blob->cfg0;
103
104 svc.type = BLE_GATT_SVC_TYPE_PRIMARY;
105 svc.includes = nullptr;
106 svc.uuid = nullptr;
107
108 for (uint32_t i = 0; i < count; i++)
109 {
110 SCustomChar entry{};
111 entry.objid = blob->chr[i].objid.v;
112 entry.flags = static_cast<uint8_t>(blob->chr[i].flags & 0xff);
113 std::memcpy(entry.uuid, blob->chr[i].uuid, sizeof(entry.uuid));
114 vchars.push_back(entry);
115 cb->regObject(entry.objid);
116 vio.push_back(entry.objid);
117 }
118}
119
120int CProtoNimblePrphCustom::allocCustom()
121{
122 const SProtoNimblePrphCustomSvc *blob;
123
124 blob = reinterpret_cast<const SProtoNimblePrphCustomSvc *>(desc->data);
125
126 chrs = new (std::nothrow) ble_gatt_chr_def[vchars.size() + 1]();
127 if (chrs == nullptr)
128 {
129 return -ENOMEM;
130 }
131
132 ble_uuid128_t *svc_uuid = new (std::nothrow) ble_uuid128_t{};
133 if (svc_uuid == nullptr)
134 {
135 delete[] chrs;
136 chrs = nullptr;
137 return -ENOMEM;
138 }
139
140 svc_uuid->u.type = BLE_UUID_TYPE_128;
141 std::memcpy(svc_uuid->value, blob->uuid, sizeof(svc_uuid->value));
142 svc.uuid = &svc_uuid->u;
143 svc.characteristics = chrs;
144 return OK;
145}
146
147int CProtoNimblePrphCustom::createCustom()
148{
149 for (size_t i = 0; i < vchars.size(); i++)
150 {
151 CIOCommon *io = cb->getObject(vchars[i].objid);
152 SCustomCharCb *ccb;
153 uint8_t effective = 0;
154
155 if (io == nullptr)
156 {
157 return -EIO;
158 }
159
160 if (vchars[i].flags & CUSTOM_CHR_F_READ && io->isRead())
161 {
162 effective |= BLE_GATT_CHR_F_READ;
163 }
164
165 if (vchars[i].flags & CUSTOM_CHR_F_WRITE && io->isWrite())
166 {
167 effective |= BLE_GATT_CHR_F_WRITE;
168 }
169
170#ifdef CONFIG_DAWN_IO_NOTIFY
171 if (vchars[i].flags & CUSTOM_CHR_F_NOTIFY && io->isNotify())
172 {
173 effective |= BLE_GATT_CHR_F_NOTIFY;
174 }
175#endif
176
177 if (effective == 0)
178 {
179 return -EINVAL;
180 }
181
182 ble_uuid128_t *chr_uuid = new (std::nothrow) ble_uuid128_t{};
183 ccb = new (std::nothrow) SCustomCharCb{};
184 if (chr_uuid == nullptr || ccb == nullptr)
185 {
186 delete chr_uuid;
187 delete ccb;
188 return -ENOMEM;
189 }
190
191 chr_uuid->u.type = BLE_UUID_TYPE_128;
192 std::memcpy(chr_uuid->value, vchars[i].uuid, sizeof(chr_uuid->value));
193
194 ccb->io = io;
195 ccb->handle = 0;
196 ccb->data = io->ddata_alloc(1);
197 if (ccb->data == nullptr)
198 {
199 delete chr_uuid;
200 delete ccb;
201 return -ENOMEM;
202 }
203
204#ifdef CONFIG_DAWN_IO_NOTIFY
205 if (effective & BLE_GATT_CHR_F_NOTIFY)
206 {
207 int ret = io->setNotifier(notifierCb, 0, ccb);
208 if (ret < 0)
209 {
210 delete ccb->data;
211 delete chr_uuid;
212 delete ccb;
213 return ret;
214 }
215 }
216#endif
217
218 vcbs.push_back(ccb);
219
220 chrs[i].uuid = &chr_uuid->u;
221 chrs[i].access_cb = callback;
222 chrs[i].arg = ccb;
223 chrs[i].descriptors = nullptr;
224 chrs[i].flags = effective;
225 chrs[i].min_key_size = 0;
226 chrs[i].val_handle = (effective & BLE_GATT_CHR_F_NOTIFY) ? &ccb->handle : nullptr;
227 }
228
229 return OK;
230}
231
232void CProtoNimblePrphCustom::deleteCustom()
233{
234 for (auto *ccb : vcbs)
235 {
236 if (ccb != nullptr)
237 {
238#ifdef CONFIG_DAWN_IO_NOTIFY
239 if (ccb->io != nullptr && ccb->io->isNotify())
240 {
241 ccb->io->setNotifier(nullptr, 0, nullptr);
242 }
243#endif
244
245 if (ccb->data != nullptr)
246 {
247 delete ccb->data;
248 }
249 delete ccb;
250 }
251 }
252 vcbs.clear();
253
254 if (chrs != nullptr)
255 {
256 for (size_t i = 0; i < vchars.size(); i++)
257 {
258 if (chrs[i].uuid != nullptr)
259 {
260 delete reinterpret_cast<const ble_uuid128_t *>(chrs[i].uuid);
261 }
262 }
263
264 delete[] chrs;
265 chrs = nullptr;
266 }
267
268 if (svc.uuid != nullptr)
269 {
270 delete reinterpret_cast<const ble_uuid128_t *>(svc.uuid);
271 svc.uuid = nullptr;
272 }
273
274 svc.characteristics = nullptr;
275 created = false;
276}
277
279{
280 int ret;
281
282 configureDesc(desc);
283 ret = allocCustom();
284 if (ret != OK)
285 {
286 return ret;
287 }
288
289 id = cb->serviceRegister(&svc);
290 return id < 0 ? -EIO : OK;
291}
292
294{
295 deleteCustom();
296 return OK;
297}
298
300{
301 int ret;
302
303 if (created)
304 {
305 return cb->startService(id);
306 }
307
308 ret = createCustom();
309 if (ret != OK)
310 {
311 deleteCustom();
312 allocCustom();
313 return ret;
314 }
315
316 created = true;
317 return cb->startService(id);
318}
319
321{
322 return cb->stopService(id);
323}
Base class for all I/O objects.
Definition common.hxx:27
virtual bool isWrite() const =0
Check if IO supports write operations.
virtual bool isNotify() const =0
Check if IO supports notifications.
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
Definition common.cxx:247
virtual bool isRead() const =0
Check if IO supports read operations.
int deinit()
Deinitialize service.
int init()
Initialize service.
int start()
Start service.
Interface for BLE peripheral services with GATT characteristics.
Definition iprph.hxx:24
virtual int startService(int id)=0
Start a specific service.
virtual CIOCommon * getObject(SObjectId::ObjectId id)=0
Get protocol object by ID.
virtual int serviceRegister(struct ble_gatt_svc_def *svc)=0
Register a GATT service with the peripheral.
virtual void regObject(SObjectId::ObjectId id)=0
Register an I/O object for this service.
virtual int stopService(int id)=0
Stop a specific service.
Base interface for GATT services exposed by BLE peripheral.
Definition iprph.hxx:467
std::vector< SObjectId::ObjectId > vio
Vector of I/O objects exposed by this service.
Definition iprph.hxx:557
const SObjectCfg::SObjectCfgItem * desc
Configuration descriptor for this service.
Definition iprph.hxx:574
IProtoNimblePrphCb * cb
Callback interface to peripheral.
Definition iprph.hxx:566
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
Heap-allocated dynamic I/O data buffer.
Definition ddata.hxx:21
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).
Definition ddata.hxx:180