Dawn Framework 1.0
Universal data acquisition framework for embedded systems
object.cxx
1// dawn/src/proto/wakaama/object.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "object_binding.hxx"
7
8#include <cerrno>
9#include <cinttypes>
10#include <cstring>
11#include <limits>
12#include <new>
13
14#if defined(CONFIG_DAWN_DTYPE_B16) || defined(CONFIG_DAWN_DTYPE_UB16)
15# include "dawn/porting/fixedmath.hxx"
16#endif
17
18using namespace dawn;
19using namespace dawn::wakaama_internal;
20
21namespace
22{
23template<typename T>
24T readScalar(const void *ptr)
25{
26 T val;
27
28 std::memcpy(&val, ptr, sizeof(T));
29 return val;
30}
31
32template<typename T>
33int storeSigned(void *ptr, int64_t val)
34{
35 if (val < static_cast<int64_t>(std::numeric_limits<T>::min()) ||
36 val > static_cast<int64_t>(std::numeric_limits<T>::max()))
37 {
38 return -ERANGE;
39 }
40
41 *static_cast<T *>(ptr) = static_cast<T>(val);
42 return OK;
43}
44
45template<typename T>
46int storeUnsigned(void *ptr, uint64_t val)
47{
48 if (val > static_cast<uint64_t>(std::numeric_limits<T>::max()))
49 {
50 return -ERANGE;
51 }
52
53 *static_cast<T *>(ptr) = static_cast<T>(val);
54 return OK;
55}
56
57template<typename T>
58int decodeAndStoreSigned(void *ptr, const lwm2m_data_t &data)
59{
60 int64_t val = 0;
61
62 if (!lwm2m_data_decode_int(&data, &val))
63 {
64 return -EINVAL;
65 }
66
67 return storeSigned<T>(ptr, val);
68}
69
70template<typename T>
71int decodeAndStoreUnsigned(void *ptr, const lwm2m_data_t &data)
72{
73 uint64_t val = 0;
74
75 if (!lwm2m_data_decode_uint(&data, &val))
76 {
77 return -EINVAL;
78 }
79
80 return storeUnsigned<T>(ptr, val);
81}
82
83#ifdef CONFIG_DAWN_DTYPE_BLOCK
84bool bufferValue(const lwm2m_data_t &data, const uint8_t **buffer, size_t *length)
85{
86 if (buffer == nullptr || length == nullptr)
87 {
88 return false;
89 }
90
91 switch (data.type)
92 {
93 case LWM2M_TYPE_STRING:
94 case LWM2M_TYPE_OPAQUE:
95 case LWM2M_TYPE_CORE_LINK:
96 break;
97
98 default:
99 return false;
100 }
101
102 *buffer = data.value.asBuffer.buffer;
103 *length = data.value.asBuffer.length;
104 return *length == 0 || *buffer != nullptr;
105}
106#endif
107} // namespace
108
110 : proto(proto_)
111 , configStatus(OK)
112 , lwm2m()
113{
114 configStatus = configureDesc(item);
115}
116
121
122int ObjectBinding::configureDesc(const SObjectCfg::SObjectCfgItem *item)
123{
124 const SProtoWakaamaIOBind *bind;
125 constexpr size_t bindWords = sizeof(SProtoWakaamaIOBind) / sizeof(uint32_t);
126 size_t count;
127
128 if (item == nullptr)
129 {
130 return -EINVAL;
131 }
132
133 if (sizeof(SProtoWakaamaIOBind) % sizeof(uint32_t) != 0 || item->cfgid.s.size == 0 ||
134 (item->cfgid.s.size % bindWords) != 0)
135 {
136 return -EINVAL;
137 }
138
139 std::memset(&lwm2m, 0, sizeof(lwm2m));
140
141 count = item->cfgid.s.size / bindWords;
142 bind = reinterpret_cast<const SProtoWakaamaIOBind *>(item->data);
143
144 for (size_t i = 0; i < count; i++)
145 {
146 int ret = allocObject(bind[i]);
147 if (ret < 0)
148 {
149 return ret;
150 }
151 }
152
153 return OK;
154}
155
156int ObjectBinding::allocObject(const SProtoWakaamaIOBind &bind)
157{
158 Resource res;
159
160 if ((bind.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_RWE) == 0 ||
161 (bind.access & ~CProtoWakaama::PROTO_WAKAAMA_ACCESS_RWE) != 0)
162 {
163 return -EINVAL;
164 }
165
166 if (resources.empty())
167 {
168 lwm2m.objID = bind.objectId;
169 }
170
171 if (bind.objectId != lwm2m.objID)
172 {
173 DAWNERR("Wakaama object bind mixes object IDs %u and %u\n", lwm2m.objID, bind.objectId);
174 return -EINVAL;
175 }
176
177 for (const Resource &existing : resources)
178 {
179 if (existing.instanceId == bind.instanceId && existing.resourceId == bind.resourceId)
180 {
181 DAWNERR("Duplicate Wakaama resource bind %u/%u/%u\n",
182 bind.objectId,
183 bind.instanceId,
184 bind.resourceId);
185 return -EEXIST;
186 }
187 }
188
189 res.instanceId = bind.instanceId;
190 res.resourceId = bind.resourceId;
191 res.access = bind.access;
192 res.objid = bind.objid;
193 res.io = nullptr;
194 res.data = nullptr;
195 resources.push_back(res);
196
197 if (proto != nullptr)
198 {
199 proto->regObject(bind.objid);
200 }
201
202 return OK;
203}
204
206{
207 if (configStatus < 0)
208 {
209 return configStatus;
210 }
211
212 if (resources.empty())
213 {
214 return -EINVAL;
215 }
216
217 for (Resource &res : resources)
218 {
219 if (proto == nullptr)
220 {
221 return -ENODEV;
222 }
223
224 res.io = proto->getIOObject(res.objid);
225 if (res.io == nullptr)
226 {
227 return -ENOENT;
228 }
229
230 res.data = res.io->ddata_alloc(1, res.io->isSeekable() ? CProtoWakaama::IO_CHUNK_CAP : 0);
231 if (res.data == nullptr)
232 {
233 return -ENOMEM;
234 }
235 }
236
237 for (Resource &res : resources)
238 {
239 Instance *inst = findOrCreateInstance(res.instanceId);
240 if (inst == nullptr)
241 {
242 return -ENOMEM;
243 }
244
245 inst->resourceCount++;
246 }
247
248 lwm2m.userData = this;
249 lwm2m.readFunc = ObjectBinding::readCb;
250 lwm2m.writeFunc = ObjectBinding::writeCb;
251 lwm2m.discoverFunc = ObjectBinding::discoverCb;
252 lwm2m.executeFunc = ObjectBinding::executeCb;
253
254#ifdef CONFIG_DAWN_IO_NOTIFY
255 setupNotifications();
256#endif
257
258 return OK;
259}
260
262{
263#ifdef CONFIG_DAWN_IO_NOTIFY
264 destroyNotifications();
265#endif
266
267 for (Resource &res : resources)
268 {
269 delete res.data;
270 res.data = nullptr;
271 res.io = nullptr;
272 }
273
274 for (Instance *inst : instances)
275 {
276 delete inst;
277 }
278
279 instances.clear();
280 lwm2m.instanceList = nullptr;
281
282 return OK;
283}
284
285ObjectBinding::Resource *ObjectBinding::findResource(uint16_t instanceId, uint16_t resourceId)
286{
287 for (Resource &res : resources)
288 {
289 if (res.instanceId == instanceId && res.resourceId == resourceId)
290 {
291 return &res;
292 }
293 }
294
295 return nullptr;
296}
297
298ObjectBinding::Instance *ObjectBinding::findOrCreateInstance(uint16_t instanceId)
299{
300 for (Instance *inst : instances)
301 {
302 if (inst->id == instanceId)
303 {
304 return inst;
305 }
306 }
307
308 Instance *inst = new (std::nothrow) Instance();
309 if (inst == nullptr)
310 {
311 return nullptr;
312 }
313
314 inst->next = nullptr;
315 inst->id = instanceId;
316 inst->resourceCount = 0;
317 instances.push_back(inst);
318 lwm2m.instanceList = LWM2M_LIST_ADD(lwm2m.instanceList, inst);
319
320 return inst;
321}
322
323#ifdef CONFIG_DAWN_IO_NOTIFY
324void ObjectBinding::setupNotifications()
325{
326 for (Resource &res : resources)
327 {
328 NotifyContext *ctx;
329 int ret;
330
331 if (proto == nullptr || res.io == nullptr)
332 {
333 continue;
334 }
335
336 if ((res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) == 0 || !res.io->isNotify())
337 {
338 continue;
339 }
340
341 ctx = new (std::nothrow) NotifyContext();
342 if (ctx == nullptr)
343 {
344 DAWNERR("Failed to allocate Wakaama notify context\n");
345 continue;
346 }
347
348 ctx->proto = proto;
349 ctx->io = res.io;
350 ctx->objectId = lwm2m.objID;
351 ctx->instanceId = res.instanceId;
352 ctx->resourceId = res.resourceId;
353 notifyContexts.push_back(ctx);
354
355 ret = res.io->setNotifier(notifierCb, 0, ctx);
356 if (ret < 0)
357 {
358 DAWNERR("Wakaama setNotifier failed for objid=0x%" PRIx32 "\n", res.objid);
359 delete ctx;
360 notifyContexts.pop_back();
361 }
362 }
363}
364
365void ObjectBinding::destroyNotifications()
366{
367 for (NotifyContext *ctx : notifyContexts)
368 {
369 if (ctx != nullptr && ctx->io != nullptr && ctx->io->isNotify())
370 {
371 ctx->io->setNotifier(nullptr, 0, nullptr);
372 }
373
374 delete ctx;
375 }
376
377 notifyContexts.clear();
378}
379
380int ObjectBinding::notifierCb(void *priv, io_ddata_t *data)
381{
382 NotifyContext *ctx = static_cast<NotifyContext *>(priv);
383
384 UNUSED(data);
385
386 if (ctx == nullptr || ctx->proto == nullptr)
387 {
388 return -EINVAL;
389 }
390
391 ctx->proto->queueResourceChanged(ctx->objectId, ctx->instanceId, ctx->resourceId);
392
393 return OK;
394}
395#endif
396
397int ObjectBinding::readResource(Resource &res, lwm2m_data_t &data)
398{
399 CIOCommon *io;
400 void *ptr;
401 int ret;
402
403 if (proto == nullptr)
404 {
405 return -ENODEV;
406 }
407
408 io = res.io;
409 if (io == nullptr || res.data == nullptr || !io->isRead())
410 {
411 return -ENOENT;
412 }
413
414#ifdef CONFIG_DAWN_DTYPE_BLOCK
415 if (io->getDtype() == SObjectId::DTYPE_BLOCK)
416 {
417 const size_t size = io->getDataSize();
418 const size_t capacity = res.data->getBufferSize();
419
420 if (size == 0)
421 {
422 lwm2m_data_encode_opaque(nullptr, 0, &data);
423 return OK;
424 }
425
426 if (size > capacity)
427 {
428 return -EFBIG;
429 }
430
431 res.data->N = capacity;
432 ret = io->getData(*res.data, 1);
433 if (ret < 0)
434 {
435 return ret;
436 }
437
438 lwm2m_data_encode_opaque(static_cast<uint8_t *>(res.data->getDataPtr()), size, &data);
439 return data.type == LWM2M_TYPE_OPAQUE ? OK : -ENOMEM;
440 }
441#endif
442
443 ret = io->getData(*res.data, 1);
444 if (ret < 0)
445 {
446 return ret;
447 }
448
449 ptr = res.data->getDataPtr();
450 UNUSED(ptr);
451
452 switch (io->getDtype())
453 {
454#ifdef CONFIG_DAWN_DTYPE_BOOL
456 lwm2m_data_encode_bool(readScalar<uint8_t>(ptr) != 0, &data);
457 break;
458#endif
459
460#ifdef CONFIG_DAWN_DTYPE_INT8
462 lwm2m_data_encode_int(readScalar<int8_t>(ptr), &data);
463 break;
464#endif
465
466#ifdef CONFIG_DAWN_DTYPE_UINT8
468 lwm2m_data_encode_uint(readScalar<uint8_t>(ptr), &data);
469 break;
470#endif
471
472#ifdef CONFIG_DAWN_DTYPE_INT16
474 lwm2m_data_encode_int(readScalar<int16_t>(ptr), &data);
475 break;
476#endif
477
478#ifdef CONFIG_DAWN_DTYPE_UINT16
480 lwm2m_data_encode_uint(readScalar<uint16_t>(ptr), &data);
481 break;
482#endif
483
484#ifdef CONFIG_DAWN_DTYPE_INT32
486 lwm2m_data_encode_int(readScalar<int32_t>(ptr), &data);
487 break;
488#endif
489
490#ifdef CONFIG_DAWN_DTYPE_UINT32
492 lwm2m_data_encode_uint(readScalar<uint32_t>(ptr), &data);
493 break;
494#endif
495
496#ifdef CONFIG_DAWN_DTYPE_INT64
498 lwm2m_data_encode_int(readScalar<int64_t>(ptr), &data);
499 break;
500#endif
501
502#ifdef CONFIG_DAWN_DTYPE_UINT64
504 lwm2m_data_encode_uint(readScalar<uint64_t>(ptr), &data);
505 break;
506#endif
507
508#ifdef CONFIG_DAWN_DTYPE_FLOAT
510 lwm2m_data_encode_float(readScalar<float>(ptr), &data);
511 break;
512#endif
513
514#ifdef CONFIG_DAWN_DTYPE_DOUBLE
516 lwm2m_data_encode_float(readScalar<double>(ptr), &data);
517 break;
518#endif
519
520#ifdef CONFIG_DAWN_DTYPE_B16
522 lwm2m_data_encode_float(static_cast<double>(readScalar<int32_t>(ptr)) / 65536.0, &data);
523 break;
524#endif
525
526#ifdef CONFIG_DAWN_DTYPE_UB16
528 lwm2m_data_encode_float(static_cast<double>(readScalar<uint32_t>(ptr)) / 65536.0, &data);
529 break;
530#endif
531
532 default:
533 return -ENOTSUP;
534 }
535
536 return OK;
537}
538
539int ObjectBinding::writeResource(Resource &res, const lwm2m_data_t &data)
540{
541 CIOCommon *io;
542 void *ptr;
543
544 if (proto == nullptr)
545 {
546 return -ENODEV;
547 }
548
549 io = res.io;
550 if (io == nullptr || res.data == nullptr || !io->isWrite())
551 {
552 return -ENOENT;
553 }
554
555 ptr = res.data->getDataPtr();
556 UNUSED(ptr);
557
558 switch (io->getDtype())
559 {
560#ifdef CONFIG_DAWN_DTYPE_BOOL
562 {
563 bool bval = false;
564
565 if (!lwm2m_data_decode_bool(&data, &bval))
566 {
567 return -EINVAL;
568 }
569
570 *static_cast<uint8_t *>(ptr) = bval ? 1 : 0;
571 break;
572 }
573#endif
574
575#ifdef CONFIG_DAWN_DTYPE_INT8
577 {
578 int ret = decodeAndStoreSigned<int8_t>(ptr, data);
579 if (ret < 0)
580 {
581 return ret;
582 }
583
584 break;
585 }
586#endif
587
588#ifdef CONFIG_DAWN_DTYPE_UINT8
590 {
591 int ret = decodeAndStoreUnsigned<uint8_t>(ptr, data);
592 if (ret < 0)
593 {
594 return ret;
595 }
596
597 break;
598 }
599#endif
600
601#ifdef CONFIG_DAWN_DTYPE_INT16
603 {
604 int ret = decodeAndStoreSigned<int16_t>(ptr, data);
605 if (ret < 0)
606 {
607 return ret;
608 }
609
610 break;
611 }
612#endif
613
614#ifdef CONFIG_DAWN_DTYPE_UINT16
616 {
617 int ret = decodeAndStoreUnsigned<uint16_t>(ptr, data);
618 if (ret < 0)
619 {
620 return ret;
621 }
622
623 break;
624 }
625#endif
626
627#ifdef CONFIG_DAWN_DTYPE_INT32
629 {
630 int ret = decodeAndStoreSigned<int32_t>(ptr, data);
631 if (ret < 0)
632 {
633 return ret;
634 }
635
636 break;
637 }
638#endif
639
640#ifdef CONFIG_DAWN_DTYPE_UINT32
642 {
643 int ret = decodeAndStoreUnsigned<uint32_t>(ptr, data);
644 if (ret < 0)
645 {
646 return ret;
647 }
648
649 break;
650 }
651#endif
652
653#ifdef CONFIG_DAWN_DTYPE_INT64
655 {
656 int64_t sval = 0;
657
658 if (!lwm2m_data_decode_int(&data, &sval))
659 {
660 return -EINVAL;
661 }
662
663 *static_cast<int64_t *>(ptr) = sval;
664 break;
665 }
666#endif
667
668#ifdef CONFIG_DAWN_DTYPE_UINT64
670 {
671 uint64_t uval = 0;
672
673 if (!lwm2m_data_decode_uint(&data, &uval))
674 {
675 return -EINVAL;
676 }
677
678 *static_cast<uint64_t *>(ptr) = uval;
679 break;
680 }
681#endif
682
683#ifdef CONFIG_DAWN_DTYPE_FLOAT
685 {
686 double fval = 0.0;
687
688 if (!lwm2m_data_decode_float(&data, &fval))
689 {
690 return -EINVAL;
691 }
692
693 *static_cast<float *>(ptr) = static_cast<float>(fval);
694 break;
695 }
696#endif
697
698#ifdef CONFIG_DAWN_DTYPE_DOUBLE
700 {
701 double fval = 0.0;
702
703 if (!lwm2m_data_decode_float(&data, &fval))
704 {
705 return -EINVAL;
706 }
707
708 *static_cast<double *>(ptr) = fval;
709 break;
710 }
711#endif
712
713#ifdef CONFIG_DAWN_DTYPE_B16
715 {
716 double fval = 0.0;
717
718 if (!lwm2m_data_decode_float(&data, &fval))
719 {
720 return -EINVAL;
721 }
722
723 if (fval < static_cast<double>(std::numeric_limits<int32_t>::min()) / 65536.0 ||
724 fval > static_cast<double>(std::numeric_limits<int32_t>::max()) / 65536.0)
725 {
726 return -ERANGE;
727 }
728
729 *static_cast<b16_t *>(ptr) = ftob16(fval);
730 break;
731 }
732#endif
733
734#ifdef CONFIG_DAWN_DTYPE_UB16
736 {
737 double fval = 0.0;
738
739 if (!lwm2m_data_decode_float(&data, &fval))
740 {
741 return -EINVAL;
742 }
743
744 if (fval < 0.0 ||
745 fval > static_cast<double>(std::numeric_limits<uint32_t>::max()) / 65536.0)
746 {
747 return -ERANGE;
748 }
749
750 *static_cast<ub16_t *>(ptr) = static_cast<ub16_t>(fval * 65536.0);
751 break;
752 }
753#endif
754
755#ifdef CONFIG_DAWN_DTYPE_BLOCK
757 {
758 const uint8_t *buffer;
759 size_t size;
760 const size_t capacity = res.data->getBufferSize();
761
762 if (!bufferValue(data, &buffer, &size))
763 {
764 return -EINVAL;
765 }
766
767 if (size > capacity)
768 {
769 return -EFBIG;
770 }
771
772 res.data->N = size;
773 if (size > 0)
774 {
775 std::memcpy(res.data->getDataPtr(), buffer, size);
776 }
777
778 return io->setData(*res.data);
779 }
780#endif
781
782 default:
783 return -ENOTSUP;
784 }
785
786 return io->setData(*res.data);
787}
788
789int ObjectBinding::executeResource(Resource &res, const uint8_t *buffer, int length)
790{
791 CIOCommon *io;
792 uint8_t cmd = CObject::CMD_RESET;
793 int ret;
794
795 if (proto == nullptr)
796 {
797 return -ENODEV;
798 }
799
800 io = res.io;
801 if (io == nullptr)
802 {
803 return -ENOENT;
804 }
805
806 if (length > 0)
807 {
808 if (buffer == nullptr || length != 1 || buffer[0] < '0' || buffer[0] > '3')
809 {
810 return -EINVAL;
811 }
812
813 cmd = static_cast<uint8_t>(buffer[0] - '0');
814 }
815
816 ret = io->trigger(cmd);
817 if (ret != -ENOTSUP)
818 {
819 return ret;
820 }
821
822 if (res.data == nullptr || !io->isWrite())
823 {
824 return -ENOTSUP;
825 }
826
827#ifdef CONFIG_DAWN_DTYPE_UINT8
828 if (io->getDtype() == SObjectId::DTYPE_UINT8)
829 {
830 *static_cast<uint8_t *>(res.data->getDataPtr()) = cmd;
831 return io->setData(*res.data);
832 }
833#endif
834
835 return -ENOTSUP;
836}
837
838uint8_t ObjectBinding::readCb(lwm2m_context_t *ctx,
839 uint16_t instanceId,
840 int *numData,
841 lwm2m_data_t **dataArray,
842 lwm2m_object_t *object)
843{
844 ObjectBinding *self = static_cast<ObjectBinding *>(object->userData);
845
846 UNUSED(ctx);
847
848 if (self == nullptr)
849 {
850 return COAP_500_INTERNAL_SERVER_ERROR;
851 }
852
853 if (*numData == 0)
854 {
855 Instance *inst =
856 reinterpret_cast<Instance *>(lwm2m_list_find(object->instanceList, instanceId));
857 size_t idx = 0;
858 size_t count = 0;
859
860 if (inst == nullptr)
861 {
862 return COAP_404_NOT_FOUND;
863 }
864
865 for (const Resource &res : self->resources)
866 {
867 if (res.instanceId == instanceId &&
868 (res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0)
869 {
870 count++;
871 }
872 }
873
874 *numData = static_cast<int>(count);
875 *dataArray = *numData > 0 ? lwm2m_data_new(*numData) : nullptr;
876 if (*numData > 0 && *dataArray == nullptr)
877 {
878 return COAP_500_INTERNAL_SERVER_ERROR;
879 }
880
881 for (const Resource &res : self->resources)
882 {
883 if (res.instanceId == instanceId &&
884 (res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0)
885 {
886 (*dataArray)[idx++].id = res.resourceId;
887 }
888 }
889 }
890
891 for (int i = 0; i < *numData; i++)
892 {
893 Resource *res = self->findResource(instanceId, (*dataArray)[i].id);
894 if (res == nullptr || (res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) == 0)
895 {
896 return COAP_404_NOT_FOUND;
897 }
898
899 if (self->readResource(*res, (*dataArray)[i]) < 0)
900 {
901 return COAP_500_INTERNAL_SERVER_ERROR;
902 }
903 }
904
905 return COAP_205_CONTENT;
906}
907
908uint8_t ObjectBinding::discoverCb(lwm2m_context_t *ctx,
909 uint16_t instanceId,
910 int *numData,
911 lwm2m_data_t **dataArray,
912 lwm2m_object_t *object)
913{
914 ObjectBinding *self = static_cast<ObjectBinding *>(object->userData);
915
916 UNUSED(ctx);
917
918 if (self == nullptr)
919 {
920 return COAP_500_INTERNAL_SERVER_ERROR;
921 }
922
923 if (*numData == 0)
924 {
925 Instance *inst =
926 reinterpret_cast<Instance *>(lwm2m_list_find(object->instanceList, instanceId));
927 size_t idx = 0;
928
929 if (inst == nullptr)
930 {
931 return COAP_404_NOT_FOUND;
932 }
933
934 *numData = static_cast<int>(inst->resourceCount);
935 *dataArray = *numData > 0 ? lwm2m_data_new(*numData) : nullptr;
936 if (*numData > 0 && *dataArray == nullptr)
937 {
938 return COAP_500_INTERNAL_SERVER_ERROR;
939 }
940
941 for (const Resource &res : self->resources)
942 {
943 if (res.instanceId == instanceId)
944 {
945 (*dataArray)[idx++].id = res.resourceId;
946 }
947 }
948 }
949
950 return COAP_205_CONTENT;
951}
952
953uint8_t ObjectBinding::writeCb(lwm2m_context_t *ctx,
954 uint16_t instanceId,
955 int numData,
956 lwm2m_data_t *dataArray,
957 lwm2m_object_t *object,
958 lwm2m_write_type_t writeType)
959{
960 ObjectBinding *self = static_cast<ObjectBinding *>(object->userData);
961
962 UNUSED(ctx);
963 UNUSED(writeType);
964
965 if (self == nullptr)
966 {
967 return COAP_500_INTERNAL_SERVER_ERROR;
968 }
969
970 for (int i = 0; i < numData; i++)
971 {
972 Resource *res = self->findResource(instanceId, dataArray[i].id);
973 int ret;
974
975 if (res == nullptr)
976 {
977 return COAP_404_NOT_FOUND;
978 }
979
980 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_WRITE) == 0)
981 {
982 return COAP_405_METHOD_NOT_ALLOWED;
983 }
984
985 ret = self->writeResource(*res, dataArray[i]);
986 if (ret == -EINVAL || ret == -ERANGE)
987 {
988 return COAP_400_BAD_REQUEST;
989 }
990
991 if (ret == -EFBIG)
992 {
993 return COAP_413_ENTITY_TOO_LARGE;
994 }
995
996 if (ret < 0)
997 {
998 return COAP_500_INTERNAL_SERVER_ERROR;
999 }
1000
1001#ifdef CONFIG_DAWN_IO_NOTIFY
1002 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0 && self->proto != nullptr)
1003 {
1004 self->proto->queueResourceChanged(self->lwm2m.objID, instanceId, res->resourceId);
1005 }
1006#endif
1007 }
1008
1009 return COAP_204_CHANGED;
1010}
1011
1012uint8_t ObjectBinding::executeCb(lwm2m_context_t *ctx,
1013 uint16_t instanceId,
1014 uint16_t resourceId,
1015 uint8_t *buffer,
1016 int length,
1017 lwm2m_object_t *object)
1018{
1019 ObjectBinding *self = static_cast<ObjectBinding *>(object->userData);
1020 Resource *res;
1021 int ret;
1022
1023 UNUSED(ctx);
1024
1025 if (self == nullptr)
1026 {
1027 return COAP_500_INTERNAL_SERVER_ERROR;
1028 }
1029
1030 res = self->findResource(instanceId, resourceId);
1031 if (res == nullptr)
1032 {
1033 return COAP_404_NOT_FOUND;
1034 }
1035
1036 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_EXECUTE) == 0)
1037 {
1038 return COAP_405_METHOD_NOT_ALLOWED;
1039 }
1040
1041 ret = self->executeResource(*res, buffer, length);
1042 if (ret == -EINVAL || ret == -ERANGE)
1043 {
1044 return COAP_400_BAD_REQUEST;
1045 }
1046
1047 if (ret == -ENOENT || ret == -ENOTSUP)
1048 {
1049 return COAP_405_METHOD_NOT_ALLOWED;
1050 }
1051
1052 if (ret < 0)
1053 {
1054 return COAP_500_INTERNAL_SERVER_ERROR;
1055 }
1056
1057 return COAP_204_CHANGED;
1058}
Base class for all I/O objects.
Definition common.hxx:27
virtual bool isWrite() const =0
Check if IO supports write operations.
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
Definition common.hxx:411
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
Definition common.hxx:372
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 size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
virtual int trigger(uint8_t cmd)
Execute a trigger command.
Definition object.hxx:195
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
@ CMD_RESET
Reset object internal state.
Definition object.hxx:42
Wakaama LwM2M client protocol implementation.
Definition wakaama.hxx:52
Runtime binding between one LwM2M object and Dawn IO resources.
~ObjectBinding()
Destroy binding state and release allocated Wakaama resources.
Definition object.cxx:117
lwm2m_object_t * object()
Return the Wakaama object exposed by this binding.
ObjectBinding(const SObjectCfg::SObjectCfgItem *item, CProtoWakaama *proto)
Construct binding state from one protocol object descriptor item.
Definition object.cxx:109
int deinit()
Release runtime allocations owned by the binding.
Definition object.cxx:261
int init()
Resolve Dawn IOs and build the Wakaama object instance list.
Definition object.cxx:205
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).
@ DTYPE_FLOAT
IEEE 754 single-precision floating point (32-bit).
Definition objectid.hxx:112
@ DTYPE_INT32
Signed 32-bit integer (-2147483648 to 2147483647).
Definition objectid.hxx:92
@ DTYPE_UINT8
Unsigned 8-bit integer (0 to 255).
Definition objectid.hxx:80
@ DTYPE_INT16
Signed 16-bit integer (-32768 to 32767).
Definition objectid.hxx:84
@ DTYPE_INT8
Signed 8-bit integer (-128 to 127).
Definition objectid.hxx:76
@ DTYPE_BLOCK
Opaque block/byte-stream data type.
Definition objectid.hxx:153
@ DTYPE_UINT64
Unsigned 64-bit integer.
Definition objectid.hxx:104
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
Definition objectid.hxx:88
@ DTYPE_UB16
Unsigned 16.16 fixed-point (32-bit).
Definition objectid.hxx:132
@ DTYPE_DOUBLE
IEEE 754 double-precision floating point (64-bit).
Definition objectid.hxx:120
@ DTYPE_INT64
Signed 64-bit integer.
Definition objectid.hxx:100
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
Definition objectid.hxx:96
@ DTYPE_BOOL
Boolean data type (stored in 32-bit container).
Definition objectid.hxx:72
@ DTYPE_B16
Signed 16.16 fixed-point (32-bit).
Definition objectid.hxx:128
Descriptor binding for one LwM2M resource.
Definition wakaama.hxx:34
Heap-allocated dynamic I/O data buffer.
Definition ddata.hxx:21
Wakaama instance node used in the object instance list.
Descriptor-backed mapping for one object instance resource.
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.