Dawn Framework 1.0
Universal data acquisition framework for embedded systems
prph_aios.cxx
1// dawn/src/proto/nimble/prph_aios.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/nimble/prph_aios.hxx"
7
8#include <cstdlib>
9#include <cstring>
10#include <new>
11
12#include "dawn/io/common.hxx"
13#include "dawn/proto/nimble/gatt_runtime.hxx"
14#include "host/ble_hs_mbuf.h"
15#include "os/os_mbuf.h"
16
17using namespace dawn;
18
19#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
20static ble_uuid_any_t *aiosMakeUuid16(uint16_t value)
21{
22 ble_uuid_any_t *uuid = new (std::nothrow) ble_uuid_any_t{};
23 if (uuid == nullptr)
24 {
25 return nullptr;
26 }
27
28 uuid->u.type = BLE_UUID_TYPE_16;
29 uuid->u16.value = value;
30 return uuid;
31}
32
33static void aiosFreeUuid(const ble_uuid_t *uuid)
34{
35 if (uuid != nullptr)
36 {
37 delete reinterpret_cast<const ble_uuid_any_t *>(uuid);
38 }
39}
40
41static int aiosReadFieldRaw(CIOCommon *io, io_ddata_t *data, uint8_t *value, uint8_t *len)
42{
43 int ret;
44
45 if (io == nullptr)
46 {
47 *len = 0;
48 return OK;
49 }
50
51 if (io->getDataSize() > CProtoNimblePrphAios::AIOS_RAW_DESCRIPTOR_MAX)
52 {
53 return -EOVERFLOW;
54 }
55
56 ret = io->getData(*data, io->getDataDim());
57 if (ret < 0)
58 {
59 return ret;
60 }
61
62 *len = static_cast<uint8_t>(io->getDataSize());
63 std::memcpy(value, data->getDataPtr(), *len);
64 return OK;
65}
66#endif
67
68#ifdef CONFIG_DAWN_IO_NOTIFY
69int CProtoNimblePrphAios::notifierCb(void *priv, io_ddata_t *data)
70{
71 SPrphNotiferCb *ncb = static_cast<SPrphNotiferCb *>(priv);
72
73 if (ncb == nullptr)
74 {
75 DAWNERR("NULL ncb pointer\n");
76 return -EINVAL;
77 }
78
79 CIOCommon *io = reinterpret_cast<CIOCommon *>(ncb->io);
80
81 if (io == nullptr)
82 {
83 DAWNERR("NULL io pointer\n");
84 return -EINVAL;
85 }
86
87 // Copy data to local storage and check if value changed
88
89 std::memcpy(ncb->data->getDataPtr(), data->getDataPtr(), ncb->data->getDataSize());
90
91 // Notify nimble
92
93 ble_gatts_chr_updated(ncb->handle);
94
95 return OK;
96}
97#endif
98
99#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
100int CProtoNimblePrphAios::descriptorCb(uint16_t conn_handle,
101 uint16_t attr_handle,
102 struct ble_gatt_access_ctxt *ctxt,
103 void *arg)
104{
105 SAiosDscCb *dcb = static_cast<SAiosDscCb *>(arg);
106 int ret;
107
108 (void)conn_handle;
109 (void)attr_handle;
110
111 if (dcb == nullptr || ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC)
112 {
113 return BLE_ATT_ERR_UNLIKELY;
114 }
115
116# if defined(CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_VALUE_TRIGGER_SETTING) || \
117 defined(CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_TIME_TRIGGER_SETTING)
118 if (dcb->kind == AIOS_DESC_VALUE_TRIGGER_SETTING || dcb->kind == AIOS_DESC_TIME_TRIGGER_SETTING)
119 {
120 ret = aiosReadFieldRaw(dcb->field.io, dcb->field.data, dcb->data, &dcb->len);
121 if (ret < 0)
122 {
123 DAWNERR("AIOS raw descriptor field read failed %d\n", ret);
124 return BLE_ATT_ERR_UNLIKELY;
125 }
126 }
127# endif
128
129 ret = os_mbuf_append(ctxt->om, dcb->data, dcb->len);
130 if (ret < 0)
131 {
132 DAWNERR("AIOS descriptor append failed %d\n", ret);
133 return BLE_ATT_ERR_UNLIKELY;
134 }
135
136 return 0;
137}
138#endif
139
140// NOTE: For analog IO - 4B data are supported
141
142int CProtoNimblePrphAios::callbackAnalog(uint16_t conn_handle,
143 uint16_t attr_handle,
144 struct ble_gatt_access_ctxt *ctxt,
145 void *arg)
146{
147 SPrphNotiferCb *ncb = static_cast<SPrphNotiferCb *>(arg);
148 CIOCommon *io = reinterpret_cast<CIOCommon *>(ncb->io);
149 uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid);
150 int ret;
151
153 {
154 DAWNERR("AIOS analog UUID mismatch\n");
155 return BLE_ATT_ERR_UNLIKELY;
156 }
157
158 switch (ctxt->op)
159 {
160 case BLE_GATT_ACCESS_OP_READ_CHR:
161 {
162 size_t size = std::min(ncb->data->getDataSize(), sizeof(uint32_t));
163 uint32_t retval = 0;
164
165#ifdef CONFIG_DAWN_IO_NOTIFY
166 if (!io->isNotify())
167#endif
168 {
169 // Get data
170
171 ret = io->getData(*ncb->data, 1);
172 if (ret < 0)
173 {
174 return BLE_ATT_ERR_UNLIKELY;
175 }
176 }
177
178 // Copy data
179
180 std::memcpy(&retval, &ncb->data->get<uint32_t>(0), size);
181
182 // Write data
183
184 ret = os_mbuf_append(ctxt->om, &retval, sizeof(uint32_t));
185 if (ret < 0)
186 {
187 DAWNERR("os_mbuf_append failed %d\n", ret);
188 }
189
190 return 0;
191 }
192
193 case BLE_GATT_ACCESS_OP_WRITE_CHR:
194 {
195 size_t size = std::min(ncb->data->getDataSize(), sizeof(uint32_t));
196 uint16_t len = 0;
197 uint32_t retval = 0;
198
199 // Get data
200
201 ret = ble_hs_mbuf_to_flat(ctxt->om, &retval, sizeof(uint32_t), &len);
202 if (ret < 0)
203 {
204 return BLE_ATT_ERR_UNLIKELY;
205 }
206
207 // Copy data
208
209 std::memcpy(&ncb->data->get<uint32_t>(0), &retval, size);
210
211 // Write state
212
213 ret = io->setData(*ncb->data);
214 if (ret < 0)
215 {
216 return BLE_ATT_ERR_UNLIKELY;
217 }
218
219 return 0;
220 }
221
222 default:
223 {
224 DAWNERR("AIOS GATT operation not supported\n");
225 return BLE_ATT_ERR_UNLIKELY;
226 return BLE_ATT_ERR_UNLIKELY;
227 }
228 }
229
230 return BLE_ATT_ERR_UNLIKELY;
231}
232
233// NOTE: For digial IO - 1B data are supported
234int CProtoNimblePrphAios::callbackDigital(uint16_t conn_handle,
235 uint16_t attr_handle,
236 struct ble_gatt_access_ctxt *ctxt,
237 void *arg)
238{
239 SPrphNotiferCb *ncb = static_cast<SPrphNotiferCb *>(arg);
240 CIOCommon *io = reinterpret_cast<CIOCommon *>(ncb->io);
241 uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid);
242 int ret;
243
245 {
246 DAWNERR("AIOS digital UUID mismatch\n");
247 return BLE_ATT_ERR_UNLIKELY;
248 }
249
250 switch (ctxt->op)
251 {
252 case BLE_GATT_ACCESS_OP_READ_CHR:
253 {
254#ifdef CONFIG_DAWN_IO_NOTIFY
255 if (!io->isNotify())
256#endif
257 {
258 // Get data
259
260 ret = io->getData(*ncb->data, 1);
261 if (ret < 0)
262 {
263 return BLE_ATT_ERR_UNLIKELY;
264 }
265 }
266
267 // Write data
268
269 ret = os_mbuf_append(ctxt->om, &ncb->data->get<bool>(0), sizeof(bool));
270 if (ret < 0)
271 {
272 DAWNERR("os_mbuf_append failed %d\n", ret);
273 }
274
275 return 0;
276 }
277
278 case BLE_GATT_ACCESS_OP_WRITE_CHR:
279 {
280 uint16_t len;
281
282 // Get data
283
284 ret = ble_hs_mbuf_to_flat(ctxt->om, &ncb->data->get<bool>(0), sizeof(bool), &len);
285 if (ret < 0)
286 {
287 return BLE_ATT_ERR_UNLIKELY;
288 }
289
290 // Write state
291
292 ret = io->setData(*ncb->data);
293 if (ret < 0)
294 {
295 return BLE_ATT_ERR_UNLIKELY;
296 }
297
298 return 0;
299 }
300
301 default:
302 {
303 DAWNERR("AIOS GATT operation not supported\n");
304 return BLE_ATT_ERR_UNLIKELY;
305 return BLE_ATT_ERR_UNLIKELY;
306 }
307 }
308
309 return BLE_ATT_ERR_UNLIKELY;
310}
311
312#ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_AGGREGATE
313int CProtoNimblePrphAios::callbackAggregate(uint16_t conn_handle,
314 uint16_t attr_handle,
315 struct ble_gatt_access_ctxt *ctxt,
316 void *arg)
317{
318 CProtoNimblePrphAios *service = static_cast<CProtoNimblePrphAios *>(arg);
319 uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid);
320
321 UNUSED(conn_handle);
322 UNUSED(attr_handle);
323
324 if (service == nullptr || ctxt->op != BLE_GATT_ACCESS_OP_READ_CHR ||
326 {
327 return BLE_ATT_ERR_UNLIKELY;
328 }
329
330 return service->appendAggregateValue(ctxt->om);
331}
332
333int CProtoNimblePrphAios::appendAggregateValue(struct os_mbuf *om)
334{
335 int ret;
336
337 for (auto const objid : vio)
338 {
339 CIOCommon *io = cb->getObject(objid);
340 SPrphNotiferCb *ncb = ioCbMap[objid];
341 uint8_t type = ioTypeMap[objid];
342
343 if (io == nullptr || ncb == nullptr || ncb->data == nullptr || !io->isRead())
344 {
345 continue;
346 }
347
348# ifdef CONFIG_DAWN_IO_NOTIFY
349 if (!io->isNotify())
350# endif
351 {
352 ret = io->getData(*ncb->data, 1);
353 if (ret < 0)
354 {
355 return BLE_ATT_ERR_UNLIKELY;
356 }
357 }
358
359 if (type == PRPH_AIOS_TYPE_DIGITAL)
360 {
361 bool value = false;
362 std::memcpy(&value, ncb->data->getDataPtr(), sizeof(value));
363 ret = os_mbuf_append(om, &value, sizeof(value));
364 if (ret < 0)
365 {
366 DAWNERR("AIOS aggregate digital append failed %d\n", ret);
367 return BLE_ATT_ERR_UNLIKELY;
368 }
369 }
370 else if (type == PRPH_AIOS_TYPE_ANALOG)
371 {
372 size_t size = std::min(ncb->data->getDataSize(), sizeof(uint32_t));
373 uint32_t value = 0;
374
375 std::memcpy(&value, ncb->data->getDataPtr(), size);
376 ret = os_mbuf_append(om, &value, sizeof(value));
377 if (ret < 0)
378 {
379 DAWNERR("AIOS aggregate analog append failed %d\n", ret);
380 return BLE_ATT_ERR_UNLIKELY;
381 }
382 }
383 }
384
385 return 0;
386}
387#endif
388
389int CProtoNimblePrphAios::allocAIOS()
390{
391 // Configure service
392
393 svc.type = BLE_GATT_SVC_TYPE_PRIMARY;
394 svc.uuid = reinterpret_cast<const ble_uuid_t *>(IProtoNimblePrphCb::UUID_AIOS);
395 svc.includes = nullptr;
396
397 // One more characteristic for end of array
398
399 noChar = cb->getObjectsLen() + 1;
400#ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_AGGREGATE
401 if (aggregateEnabled)
402 {
403 noChar++;
404 }
405#endif
406
407 // Allocate memory for characterisitcs
408
409 svc.characteristics = new (std::nothrow) ble_gatt_chr_def[noChar]();
410 if (svc.characteristics == nullptr)
411 {
412 DAWNERR("Failed to allocate characteristics\n");
413 return -ENOMEM;
414 }
415
416 return OK;
417}
418
419int CProtoNimblePrphAios::createAIOS()
420{
421 const uint32_t *char_uuid = nullptr;
422 int ret;
423 int j = 0;
424
425 if (svc.characteristics == nullptr)
426 {
427 DAWNERR("Failed to allocate characteristics\n");
428 return -ENOMEM;
429 }
430
431 // Configure service
432
433 svc.type = BLE_GATT_SVC_TYPE_PRIMARY;
434 svc.uuid = reinterpret_cast<const ble_uuid_t *>(IProtoNimblePrphCb::UUID_AIOS);
435 svc.includes = nullptr;
436
437 for (auto const objid : vio)
438 {
439 CIOCommon *io = cb->getObject(objid);
440
441 // NOTE: NimBLE C API declares svc.characteristics as
442 // const ble_gatt_chr_def*, but Dawn allocates it dynamically
443 // and needs write access to populate fields at runtime.
444
445 struct ble_gatt_chr_def *chr = const_cast<struct ble_gatt_chr_def *>(&svc.characteristics[j]);
446 SPrphNotiferCb *ncb;
447
448 if (io == nullptr)
449 {
450 DAWNERR("AIOS IO not found\n");
451 return -EIO;
452 }
453
454 // Seekable IOs not supported by AIOS
455
456 if (io->isSeekable())
457 {
458 DAWNERR("seekable IO not supported by AIOS"
459 " (objid=0x%08" PRIx32 ")\n",
460 io->getIdV());
461 return -ENOTSUP;
462 }
463
464 ncb = nimbleGattNotifierCreate(io);
465 if (ncb == nullptr)
466 {
467 DAWNERR("AIOS notifier allocation failed\n");
468 return -ENOMEM;
469 }
470
471 // Connect callback data
472
473 ioCbMap.insert_or_assign(objid, ncb);
474
475 // Fill characteristic, access_cb is fill later
476
477 nimbleGattChrInit(*chr, ncb);
478 char_uuid = nullptr;
479
480 // Check characteristic properties
481
482#ifdef CONFIG_DAWN_IO_NOTIFY
483 ret = nimbleGattChrNotifySet(*chr, *io, *ncb, notifierCb, objid);
484 if (ret < 0)
485 {
486 DAWNERR("AIOS notifier setup failed\n");
487 }
488#endif
489
490 nimbleGattChrAccessSet(*chr, *io);
491
492 // Get IO class
493
494 switch (ioTypeMap[objid])
495 {
497 {
498 chr->access_cb = CProtoNimblePrphAios::callbackDigital;
500 break;
501 }
502
504 {
505 chr->access_cb = CProtoNimblePrphAios::callbackAnalog;
507 break;
508 }
509
510 default:
511 {
512 DAWNERR("unknown AIOS type %d\n", ioTypeMap[objid]);
513 return -EINVAL;
514 }
515 }
516
517 // Assignsome dummy value
518
519 if (char_uuid == nullptr)
520 {
521 DAWNERR("No UUID for AIOS IO\n");
522 return -EINVAL;
523 }
524
525 ret = nimbleGattChrUuid128Set(*chr, char_uuid);
526 if (ret != OK)
527 {
528 DAWNERR("AIOS UUID allocation failed\n");
529 return ret;
530 }
531
532 ret = configureDescriptors(chr, objid);
533 if (ret != OK)
534 {
535 return ret;
536 }
537
538 // Next service
539
540 j++;
541 }
542
543#ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_AGGREGATE
544 if (aggregateEnabled)
545 {
546 struct ble_gatt_chr_def *chr = const_cast<struct ble_gatt_chr_def *>(&svc.characteristics[j]);
547
548 nimbleGattChrInit(*chr, this);
549 ret = nimbleGattChrUuid128Set(*chr, IProtoNimblePrphCb::UUID_AGGREGATE);
550 if (ret != OK)
551 {
552 DAWNERR("AIOS aggregate UUID allocation failed\n");
553 return ret;
554 }
555
556 chr->access_cb = CProtoNimblePrphAios::callbackAggregate;
557 chr->flags = BLE_GATT_CHR_F_READ;
558 j++;
559 }
560#endif
561
562 return OK;
563}
564
565void CProtoNimblePrphAios::deleteAIOS()
566{
567 // NOTE: svc.characteristics fields are const-qualified per NimBLE API.
568 // Dawn allocated this memory and is the rightful owner, so the cast is safe.
569
570 if (svc.characteristics)
571 {
572 for (size_t i = 0; i < noChar - 1; i++)
573 {
574 if (svc.characteristics[i].uuid)
575 {
576 if (ble_uuid_u16(svc.characteristics[i].uuid) == IProtoNimblePrphCb::UUID16_AGGREGATE)
577 {
578 nimbleGattChrUuidFree(
579 const_cast<struct ble_gatt_chr_def &>(svc.characteristics[i]));
580 continue;
581 }
582
583 nimbleGattChrUuidFree(const_cast<struct ble_gatt_chr_def &>(svc.characteristics[i]));
584 }
585
586#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
587 if (svc.characteristics[i].descriptors)
588 {
589 struct ble_gatt_dsc_def *dsc =
590 const_cast<struct ble_gatt_dsc_def *>(svc.characteristics[i].descriptors);
591
592 for (size_t j = 0; dsc[j].uuid != nullptr; j++)
593 {
594 SAiosDscCb *dcb = static_cast<SAiosDscCb *>(dsc[j].arg);
595
596 aiosFreeUuid(dsc[j].uuid);
597 if (dcb != nullptr)
598 {
599 delete dcb->field.data;
600 delete dcb;
601 }
602 }
603
604 delete[] dsc;
605 }
606#endif
607
608 nimbleGattChrNotifierFree(const_cast<struct ble_gatt_chr_def &>(svc.characteristics[i]));
609 }
610
611 delete[] const_cast<ble_gatt_chr_def *>(svc.characteristics);
612
613 svc.characteristics = nullptr;
614 }
615
616 ioCbMap.clear();
617 created = false;
618}
619
620int CProtoNimblePrphAios::configureDescriptors(struct ble_gatt_chr_def *chr,
622{
623#ifndef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
624 UNUSED(chr);
625 UNUSED(objid);
626 return OK;
627#else
628 const auto metaIt = ioMetaMap.find(objid);
629 SAiosMeta *meta;
630 struct ble_gatt_dsc_def *dsc;
631 size_t descCount;
632 size_t idx;
633
634 if (metaIt == ioMetaMap.end())
635 {
636 return OK;
637 }
638
639 meta = const_cast<SAiosMeta *>(&metaIt->second);
640 descCount = 0;
641# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_USER_DESCRIPTION
642 meta->desc &= ~AIOS_DESC_USER_DESCRIPTION;
643# endif
644 if (meta->desc & AIOS_DESC_USER_DESCRIPTION)
645 {
646 descCount++;
647 }
648
649# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_NUMBER_OF_DIGITALS
650 meta->desc &= ~AIOS_DESC_NUMBER_OF_DIGITALS;
651# endif
652 if (meta->desc & AIOS_DESC_NUMBER_OF_DIGITALS)
653 {
654 descCount++;
655 }
656
657# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_VALUE_TRIGGER_SETTING
658 meta->desc &= ~AIOS_DESC_VALUE_TRIGGER_SETTING;
659# endif
660 if (meta->desc & AIOS_DESC_VALUE_TRIGGER_SETTING)
661 {
662 descCount++;
663 }
664
665# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_TIME_TRIGGER_SETTING
666 meta->desc &= ~AIOS_DESC_TIME_TRIGGER_SETTING;
667# endif
668 if (meta->desc & AIOS_DESC_TIME_TRIGGER_SETTING)
669 {
670 descCount++;
671 }
672
673# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_PRESENTATION_FORMAT
674 meta->desc &= ~AIOS_DESC_PRESENTATION_FORMAT;
675# endif
676 if (meta->desc & AIOS_DESC_PRESENTATION_FORMAT)
677 {
678 descCount++;
679 }
680
681# ifndef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_EXTENDED_PROPERTIES
682 meta->desc &= ~AIOS_DESC_EXTENDED_PROPERTIES;
683# endif
684 if (meta->desc & AIOS_DESC_EXTENDED_PROPERTIES)
685 {
686 descCount++;
687 }
688
689 if (descCount == 0)
690 {
691 return OK;
692 }
693
694 dsc = new (std::nothrow) ble_gatt_dsc_def[descCount + 1]();
695 if (dsc == nullptr)
696 {
697 return -ENOMEM;
698 }
699
700 idx = 0;
701# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_USER_DESCRIPTION
702 if (meta->desc & AIOS_DESC_USER_DESCRIPTION)
703 {
704 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
705 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_CHR_USER_DESCRIPTION);
706 if (dcb == nullptr || uuid == nullptr)
707 {
708 delete dcb;
709 aiosFreeUuid(uuid ? &uuid->u : nullptr);
710 goto fail;
711 }
712
713 dcb->kind = AIOS_DESC_USER_DESCRIPTION;
714 dcb->len = 0;
715 while (dcb->len < AIOS_USER_DESCRIPTION_MAX && meta->userDescription[dcb->len] != '\0')
716 {
717 dcb->data[dcb->len] = static_cast<uint8_t>(meta->userDescription[dcb->len]);
718 dcb->len++;
719 }
720
721 dsc[idx].uuid = &uuid->u;
722 dsc[idx].att_flags = BLE_ATT_F_READ;
723 dsc[idx].access_cb = descriptorCb;
724 dsc[idx].arg = dcb;
725 idx++;
726 }
727# endif
728
729# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_NUMBER_OF_DIGITALS
730 if (meta->desc & AIOS_DESC_NUMBER_OF_DIGITALS)
731 {
732 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
733 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_NUMBER_OF_DIGITALS);
734 if (dcb == nullptr || uuid == nullptr)
735 {
736 delete dcb;
737 aiosFreeUuid(uuid ? &uuid->u : nullptr);
738 goto fail;
739 }
740
741 dcb->kind = AIOS_DESC_NUMBER_OF_DIGITALS;
742 dcb->len = 1;
743 dcb->data[0] = meta->numberOfDigitals;
744
745 dsc[idx].uuid = &uuid->u;
746 dsc[idx].att_flags = BLE_ATT_F_READ;
747 dsc[idx].access_cb = descriptorCb;
748 dsc[idx].arg = dcb;
749 idx++;
750 }
751# endif
752
753# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_EXTENDED_PROPERTIES
754 if (meta->desc & AIOS_DESC_EXTENDED_PROPERTIES)
755 {
756 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
757 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_EXTENDED_PROPERTIES);
758 if (dcb == nullptr || uuid == nullptr)
759 {
760 delete dcb;
761 aiosFreeUuid(uuid ? &uuid->u : nullptr);
762 goto fail;
763 }
764
765 dcb->kind = AIOS_DESC_EXTENDED_PROPERTIES;
766 dcb->len = AIOS_EXTENDED_PROPERTIES_SIZE;
767 dcb->data[0] = static_cast<uint8_t>(meta->extendedProperties & 0xff);
768 dcb->data[1] = static_cast<uint8_t>((meta->extendedProperties >> 8) & 0xff);
769
770 dsc[idx].uuid = &uuid->u;
771 dsc[idx].att_flags = BLE_ATT_F_READ;
772 dsc[idx].access_cb = descriptorCb;
773 dsc[idx].arg = dcb;
774 idx++;
775 }
776# endif
777
778# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_PRESENTATION_FORMAT
779 if (meta->desc & AIOS_DESC_PRESENTATION_FORMAT)
780 {
781 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
782 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_PRESENTATION_FORMAT);
783 if (dcb == nullptr || uuid == nullptr)
784 {
785 delete dcb;
786 aiosFreeUuid(uuid ? &uuid->u : nullptr);
787 goto fail;
788 }
789
790 dcb->kind = AIOS_DESC_PRESENTATION_FORMAT;
791 dcb->len = AIOS_PRESENTATION_FORMAT_SIZE;
792 std::memcpy(dcb->data, meta->presentationFormat, dcb->len);
793
794 dsc[idx].uuid = &uuid->u;
795 dsc[idx].att_flags = BLE_ATT_F_READ;
796 dsc[idx].access_cb = descriptorCb;
797 dsc[idx].arg = dcb;
798 idx++;
799 }
800# endif
801
802# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_VALUE_TRIGGER_SETTING
803 if (meta->desc & AIOS_DESC_VALUE_TRIGGER_SETTING)
804 {
805 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
806 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_VALUE_TRIGGER_SETTING);
807 if (dcb == nullptr || uuid == nullptr)
808 {
809 delete dcb;
810 aiosFreeUuid(uuid ? &uuid->u : nullptr);
811 goto fail;
812 }
813
814 dcb->kind = AIOS_DESC_VALUE_TRIGGER_SETTING;
815 dcb->field.io = cb->getObject(meta->valueTriggerSettingObjid);
816 if (dcb->field.io == nullptr)
817 {
818 delete dcb;
819 aiosFreeUuid(&uuid->u);
820 goto fail;
821 }
822
823 dcb->field.data = dcb->field.io->ddata_alloc(1);
824 if (dcb->field.data == nullptr)
825 {
826 delete dcb;
827 aiosFreeUuid(&uuid->u);
828 goto fail;
829 }
830
831 dsc[idx].uuid = &uuid->u;
832 dsc[idx].att_flags = BLE_ATT_F_READ;
833 dsc[idx].access_cb = descriptorCb;
834 dsc[idx].arg = dcb;
835 idx++;
836 }
837# endif
838
839# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_TIME_TRIGGER_SETTING
840 if (meta->desc & AIOS_DESC_TIME_TRIGGER_SETTING)
841 {
842 SAiosDscCb *dcb = new (std::nothrow) SAiosDscCb{};
843 ble_uuid_any_t *uuid = aiosMakeUuid16(UUID16_TIME_TRIGGER_SETTING);
844 if (dcb == nullptr || uuid == nullptr)
845 {
846 delete dcb;
847 aiosFreeUuid(uuid ? &uuid->u : nullptr);
848 goto fail;
849 }
850
851 dcb->kind = AIOS_DESC_TIME_TRIGGER_SETTING;
852 dcb->field.io = cb->getObject(meta->timeTriggerSettingObjid);
853 if (dcb->field.io == nullptr)
854 {
855 delete dcb;
856 aiosFreeUuid(&uuid->u);
857 goto fail;
858 }
859
860 dcb->field.data = dcb->field.io->ddata_alloc(1);
861 if (dcb->field.data == nullptr)
862 {
863 delete dcb;
864 aiosFreeUuid(&uuid->u);
865 goto fail;
866 }
867
868 dsc[idx].uuid = &uuid->u;
869 dsc[idx].att_flags = BLE_ATT_F_READ;
870 dsc[idx].access_cb = descriptorCb;
871 dsc[idx].arg = dcb;
872 idx++;
873 }
874# endif
875
876 chr->descriptors = dsc;
877 return OK;
878
879fail:
880 for (size_t i = 0; i < idx; i++)
881 {
882 aiosFreeUuid(dsc[i].uuid);
883 SAiosDscCb *dcb = static_cast<SAiosDscCb *>(dsc[i].arg);
884 if (dcb != nullptr)
885 {
886 delete dcb->field.data;
887 delete dcb;
888 }
889 }
890
891 delete[] dsc;
892 return -ENOMEM;
893#endif
894}
895
896void CProtoNimblePrphAios::allocObject(const SProtoNimblePrphIOBindAiosObjid &obj,
897 const uint32_t *ext)
898{
899 uint8_t type = cfgIdIOBindAiosCfgObjTypeGet(obj.cfg);
900#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
901 SAiosMeta meta{};
902#endif
903
904 DAWNINFO("AIOS allocate type=%d object 0x%" PRIx32 "\n", type, obj.objid.v);
905
906 if (type != PRPH_AIOS_TYPE_DIGITAL && type != PRPH_AIOS_TYPE_ANALOG)
907 {
908 DAWNERR("Invalid AIOS type %d for object 0x%" PRIx32 "\n", type, obj.objid.v);
909 return;
910 }
911
912 // Store type for later
913
914 ioTypeMap.insert_or_assign(obj.objid.v, type);
915
916#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
917 for (uint32_t i = 0; i < obj.extCount; i++)
918 {
919 uint8_t kind = cfgIdIOBindAiosExtKindGet(ext[0]);
920 uint8_t size = cfgIdIOBindAiosExtSizeGet(ext[0]);
921 const uint32_t *data = &ext[1];
922
923 switch (kind)
924 {
926# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_USER_DESCRIPTION
927 if (size == AIOS_USER_DESCRIPTION_MAX / sizeof(uint32_t))
928 {
929 meta.desc |= AIOS_DESC_USER_DESCRIPTION;
930 std::memcpy(meta.userDescription, data, sizeof(meta.userDescription));
931 }
932# endif
933 break;
934
936# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_NUMBER_OF_DIGITALS
937 if (size == 1)
938 {
939 meta.desc |= AIOS_DESC_NUMBER_OF_DIGITALS;
940 meta.numberOfDigitals = static_cast<uint8_t>(data[0]);
941 }
942# endif
943 break;
944
946# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_VALUE_TRIGGER_SETTING
947 if (size == 1)
948 {
949 meta.desc |= AIOS_DESC_VALUE_TRIGGER_SETTING;
950 meta.valueTriggerSettingObjid = data[0];
951 }
952# endif
953 break;
954
956# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_TIME_TRIGGER_SETTING
957 if (size == 1)
958 {
959 meta.desc |= AIOS_DESC_TIME_TRIGGER_SETTING;
960 meta.timeTriggerSettingObjid = data[0];
961 }
962# endif
963 break;
964
966# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_PRESENTATION_FORMAT
967 if (size == 2)
968 {
969 meta.desc |= AIOS_DESC_PRESENTATION_FORMAT;
970 meta.presentationFormat[0] = static_cast<uint8_t>(data[0] & 0xff);
971 meta.presentationFormat[1] = static_cast<uint8_t>((data[0] >> 8) & 0xff);
972 meta.presentationFormat[2] = static_cast<uint8_t>((data[0] >> 16) & 0xff);
973 meta.presentationFormat[3] = static_cast<uint8_t>((data[0] >> 24) & 0xff);
974 meta.presentationFormat[4] = static_cast<uint8_t>(data[1] & 0xff);
975 meta.presentationFormat[5] = static_cast<uint8_t>((data[1] >> 8) & 0xff);
976 meta.presentationFormat[6] = static_cast<uint8_t>((data[1] >> 16) & 0xff);
977 }
978# endif
979 break;
980
982# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_EXTENDED_PROPERTIES
983 if (size == 1)
984 {
985 meta.desc |= AIOS_DESC_EXTENDED_PROPERTIES;
986 meta.extendedProperties = static_cast<uint16_t>(data[0] & 0xffff);
987 }
988# endif
989 break;
990
991 default:
992 break;
993 }
994
995 ext += 1 + size;
996 }
997
998 if (meta.desc != 0)
999 {
1000 ioMetaMap.insert_or_assign(obj.objid.v, meta);
1001 }
1002#endif
1003
1004 // Allocate object in map
1005
1006 cb->regObject(obj.objid.v);
1007#ifdef CONFIG_DAWN_PROTO_NIMBLE_EXTENDED_METADATA
1008# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_VALUE_TRIGGER_SETTING
1009 if (meta.valueTriggerSettingObjid != 0)
1010 {
1011 cb->regObject(meta.valueTriggerSettingObjid);
1012 }
1013# endif
1014
1015# ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_DESC_TIME_TRIGGER_SETTING
1016 if (meta.timeTriggerSettingObjid != 0)
1017 {
1018 cb->regObject(meta.timeTriggerSettingObjid);
1019 }
1020# endif
1021#endif
1022
1023 vio.push_back(obj.objid.v);
1024}
1025
1026// Assumption: Configuration item passed by caller is a valid type supported by
1027// this class.
1028void CProtoNimblePrphAios::configureDesc(const SObjectCfg::SObjectCfgItem *item)
1029{
1030 // Iterrate over objectid list
1031
1032 for (size_t k = 0; k < item->cfgid.s.size;)
1033 {
1034 const SProtoNimblePrphIOBindAios *tmp =
1035 reinterpret_cast<const SProtoNimblePrphIOBindAios *>(&item->data[k]);
1036
1037 uint8_t size = cfgIdIOBindAiosCfg0SizeGet(tmp->cfg0);
1038#ifdef CONFIG_DAWN_PROTO_NIMBLE_AIOS_AGGREGATE
1039 aggregateEnabled = aggregateEnabled || cfgIdIOBindAiosCfg1AggregateGet(tmp->cfg1);
1040#endif
1041
1042 size_t pos = k + sizeof(SProtoNimblePrphIOBindAios) / sizeof(uint32_t);
1043 for (size_t i = 0; i < size; i++)
1044 {
1045 const SProtoNimblePrphIOBindAiosObjid *obj =
1046 reinterpret_cast<const SProtoNimblePrphIOBindAiosObjid *>(&item->data[pos]);
1047 const uint32_t *ext =
1048 &item->data[pos + sizeof(SProtoNimblePrphIOBindAiosObjid) / sizeof(uint32_t)];
1049
1050 // Allocate object
1051
1052 allocObject(*obj, ext);
1053
1054 pos += sizeof(SProtoNimblePrphIOBindAiosObjid) / sizeof(uint32_t);
1055 for (uint32_t e = 0; e < obj->extCount; e++)
1056 {
1057 pos += 1 + cfgIdIOBindAiosExtSizeGet(item->data[pos]);
1058 }
1059 }
1060
1061 k = pos;
1062 }
1063}
1064
1065CProtoNimblePrphAios::CProtoNimblePrphAios(const SObjectCfg::SObjectCfgItem *desc_,
1066 IProtoNimblePrphCb *cb_)
1067 : IProtoNimblePrphService(desc_, cb_)
1068 , created(false)
1069{
1070 // Service ID not assigned yet
1071
1072 id = -1;
1073 noChar = 0;
1074 aggregateEnabled = false;
1075}
1076
1077CProtoNimblePrphAios::~CProtoNimblePrphAios()
1078{
1079 deinit();
1080}
1081
1083{
1084 int ret;
1085
1086 // Configure object
1087
1088 configureDesc(desc);
1089
1090 // Allocate service
1091
1092 ret = allocAIOS();
1093 if (ret != OK)
1094 {
1095 return ret;
1096 }
1097
1098 // Register service in singleton
1099
1100 id = cb->serviceRegister(&svc);
1101 if (id < 0)
1102 {
1103 DAWNERR("AIOS service registration failed\n");
1104 return -EIO;
1105 }
1106
1107 return OK;
1108}
1109
1111{
1112 deleteAIOS();
1113 return OK;
1114}
1115
1117{
1118 int ret;
1119
1120 if (created)
1121 {
1122 return cb->startService(id);
1123 }
1124
1125 // Create service
1126
1127 ret = createAIOS();
1128 if (ret != OK)
1129 {
1130 deleteAIOS();
1131 allocAIOS();
1132 return ret;
1133 }
1134
1135 created = true;
1136
1137 // Signal start to peripheral handler
1138
1139 return cb->startService(id);
1140}
1141
1143{
1144 // Signal stop to peripheral handler
1145
1146 return cb->stopService(id);
1147}
Base class for all I/O objects.
Definition common.hxx:27
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
Definition common.hxx:392
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
Definition common.hxx:353
virtual bool isNotify() const =0
Check if IO supports notifications.
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
Definition common.hxx:502
virtual size_t getDataDim() const =0
Get data vector dimension.
virtual size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
Definition object.cxx:155
Automation I/O Service (AIOS) for BLE Peripheral.
Definition prph_aios.hxx:27
int stop()
Stop service.
int deinit()
Deinitialize service.
@ PRPH_AIOS_TYPE_ANALOG
Analog I/O (ADC, DAC).
Definition prph_aios.hxx:60
@ PRPH_AIOS_TYPE_DIGITAL
Digital I/O (GPIO, buttons, LEDs).
Definition prph_aios.hxx:59
int start()
Start service.
int init()
Initialize service.
@ AIOS_EXT_VALUE_TRIGGER_SETTING
Value Trigger Setting descriptor.
Definition prph_aios.hxx:67
@ AIOS_EXT_TIME_TRIGGER_SETTING
Time Trigger Setting descriptor.
Definition prph_aios.hxx:68
@ AIOS_EXT_NUMBER_OF_DIGITALS
Number of Digitals descriptor.
Definition prph_aios.hxx:66
@ AIOS_EXT_EXTENDED_PROPERTIES
Characteristic Extended Properties descriptor.
Definition prph_aios.hxx:70
@ AIOS_EXT_USER_DESCRIPTION
Characteristic User Description descriptor.
Definition prph_aios.hxx:65
@ AIOS_EXT_PRESENTATION_FORMAT
Characteristic Presentation Format descriptor.
Definition prph_aios.hxx:69
Interface for BLE peripheral services with GATT characteristics.
Definition iprph.hxx:24
virtual int startService(int id)=0
Start a specific service.
static uint16_t UUID16_AGGREGATE
16-bit UUID for Aggregate characteristic.
Definition iprph.hxx:141
virtual size_t getObjectsLen()=0
Get count of registered I/O objects.
static uint32_t UUID_ANALOG[4]
Analog Characteristic UUID (0x2A58).
Definition iprph.hxx:125
virtual CIOCommon * getObject(SObjectId::ObjectId id)=0
Get protocol object by ID.
static uint16_t UUID16_ANALOG
16-bit UUID for Analog characteristic.
Definition iprph.hxx:129
static uint32_t UUID_DIGITAL[4]
Digital Characteristic UUID (0x2A56).
Definition iprph.hxx:113
static uint32_t UUID_AGGREGATE[4]
Aggregate Characteristic UUID (0x2A5A).
Definition iprph.hxx:137
virtual int serviceRegister(struct ble_gatt_svc_def *svc)=0
Register a GATT service with the peripheral.
static uint16_t UUID16_DIGITAL
16-bit UUID for Digital characteristic.
Definition iprph.hxx:117
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.
static uint32_t UUID_AIOS[4]
Automation I/O Service UUID (0x1815).
Definition iprph.hxx:32
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).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
uint32_t ObjectId
ObjectID type - single 32-bit value.
Definition objectid.hxx:44
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
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.