6#include "object_binding.hxx"
14#if defined(CONFIG_DAWN_DTYPE_B16) || defined(CONFIG_DAWN_DTYPE_UB16)
15# include "dawn/porting/fixedmath.hxx"
19using namespace dawn::wakaama_internal;
24T readScalar(
const void *ptr)
28 std::memcpy(&val, ptr,
sizeof(T));
33int storeSigned(
void *ptr, int64_t val)
35 if (val <
static_cast<int64_t
>(std::numeric_limits<T>::min()) ||
36 val >
static_cast<int64_t
>(std::numeric_limits<T>::max()))
41 *
static_cast<T *
>(ptr) =
static_cast<T
>(val);
46int storeUnsigned(
void *ptr, uint64_t val)
48 if (val >
static_cast<uint64_t
>(std::numeric_limits<T>::max()))
53 *
static_cast<T *
>(ptr) =
static_cast<T
>(val);
58int decodeAndStoreSigned(
void *ptr,
const lwm2m_data_t &data)
62 if (!lwm2m_data_decode_int(&data, &val))
67 return storeSigned<T>(ptr, val);
71int decodeAndStoreUnsigned(
void *ptr,
const lwm2m_data_t &data)
75 if (!lwm2m_data_decode_uint(&data, &val))
80 return storeUnsigned<T>(ptr, val);
83#ifdef CONFIG_DAWN_DTYPE_BLOCK
84bool bufferValue(
const lwm2m_data_t &data,
const uint8_t **buffer,
size_t *length)
86 if (buffer ==
nullptr || length ==
nullptr)
93 case LWM2M_TYPE_STRING:
94 case LWM2M_TYPE_OPAQUE:
95 case LWM2M_TYPE_CORE_LINK:
102 *buffer = data.value.asBuffer.buffer;
103 *length = data.value.asBuffer.length;
104 return *length == 0 || *buffer !=
nullptr;
114 configStatus = configureDesc(item);
139 std::memset(&lwm2m, 0,
sizeof(lwm2m));
144 for (
size_t i = 0; i < count; i++)
146 int ret = allocObject(bind[i]);
160 if ((bind.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_RWE) == 0 ||
161 (bind.access & ~CProtoWakaama::PROTO_WAKAAMA_ACCESS_RWE) != 0)
166 if (resources.empty())
168 lwm2m.objID = bind.objectId;
171 if (bind.objectId != lwm2m.objID)
173 DAWNERR(
"Wakaama object bind mixes object IDs %u and %u\n", lwm2m.objID, bind.objectId);
177 for (
const Resource &existing : resources)
179 if (existing.instanceId == bind.instanceId && existing.resourceId == bind.resourceId)
181 DAWNERR(
"Duplicate Wakaama resource bind %u/%u/%u\n",
189 res.instanceId = bind.instanceId;
190 res.resourceId = bind.resourceId;
191 res.access = bind.access;
192 res.objid = bind.objid;
195 resources.push_back(res);
197 if (proto !=
nullptr)
199 proto->regObject(bind.objid);
207 if (configStatus < 0)
212 if (resources.empty())
219 if (proto ==
nullptr)
224 res.io = proto->getIOObject(res.objid);
225 if (res.io ==
nullptr)
230 res.data = res.io->
ddata_alloc(1, res.io->isSeekable() ? CProtoWakaama::IO_CHUNK_CAP : 0);
231 if (res.data ==
nullptr)
239 Instance *inst = findOrCreateInstance(res.instanceId);
245 inst->resourceCount++;
248 lwm2m.userData =
this;
249 lwm2m.readFunc = ObjectBinding::readCb;
250 lwm2m.writeFunc = ObjectBinding::writeCb;
251 lwm2m.discoverFunc = ObjectBinding::discoverCb;
252 lwm2m.executeFunc = ObjectBinding::executeCb;
254#ifdef CONFIG_DAWN_IO_NOTIFY
255 setupNotifications();
263#ifdef CONFIG_DAWN_IO_NOTIFY
264 destroyNotifications();
280 lwm2m.instanceList =
nullptr;
287 for (Resource &res : resources)
289 if (res.instanceId == instanceId && res.resourceId == resourceId)
300 for (Instance *inst : instances)
302 if (inst->id == instanceId)
308 Instance *inst =
new (std::nothrow) Instance();
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);
323#ifdef CONFIG_DAWN_IO_NOTIFY
324void ObjectBinding::setupNotifications()
326 for (Resource &res : resources)
331 if (proto ==
nullptr || res.io ==
nullptr)
336 if ((res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) == 0 || !res.io->isNotify())
341 ctx =
new (std::nothrow) NotifyContext();
344 DAWNERR(
"Failed to allocate Wakaama notify context\n");
350 ctx->objectId = lwm2m.objID;
351 ctx->instanceId = res.instanceId;
352 ctx->resourceId = res.resourceId;
353 notifyContexts.push_back(ctx);
355 ret = res.io->setNotifier(notifierCb, 0, ctx);
358 DAWNERR(
"Wakaama setNotifier failed for objid=0x%" PRIx32
"\n", res.objid);
360 notifyContexts.pop_back();
365void ObjectBinding::destroyNotifications()
367 for (NotifyContext *ctx : notifyContexts)
369 if (ctx !=
nullptr && ctx->io !=
nullptr && ctx->io->isNotify())
371 ctx->io->setNotifier(
nullptr, 0,
nullptr);
377 notifyContexts.clear();
380int ObjectBinding::notifierCb(
void *priv,
io_ddata_t *data)
382 NotifyContext *ctx =
static_cast<NotifyContext *
>(priv);
386 if (ctx ==
nullptr || ctx->proto ==
nullptr)
391 ctx->proto->queueResourceChanged(ctx->objectId, ctx->instanceId, ctx->resourceId);
397int ObjectBinding::readResource(Resource &res, lwm2m_data_t &data)
403 if (proto ==
nullptr)
409 if (io ==
nullptr || res.data ==
nullptr || !io->
isRead())
414#ifdef CONFIG_DAWN_DTYPE_BLOCK
418 const size_t capacity = res.data->getBufferSize();
422 lwm2m_data_encode_opaque(
nullptr, 0, &data);
431 res.data->N = capacity;
432 ret = io->
getData(*res.data, 1);
438 lwm2m_data_encode_opaque(
static_cast<uint8_t *
>(res.data->getDataPtr()), size, &data);
439 return data.type == LWM2M_TYPE_OPAQUE ? OK : -ENOMEM;
443 ret = io->
getData(*res.data, 1);
449 ptr = res.data->getDataPtr();
454#ifdef CONFIG_DAWN_DTYPE_BOOL
456 lwm2m_data_encode_bool(readScalar<uint8_t>(ptr) != 0, &data);
460#ifdef CONFIG_DAWN_DTYPE_INT8
462 lwm2m_data_encode_int(readScalar<int8_t>(ptr), &data);
466#ifdef CONFIG_DAWN_DTYPE_UINT8
468 lwm2m_data_encode_uint(readScalar<uint8_t>(ptr), &data);
472#ifdef CONFIG_DAWN_DTYPE_INT16
474 lwm2m_data_encode_int(readScalar<int16_t>(ptr), &data);
478#ifdef CONFIG_DAWN_DTYPE_UINT16
480 lwm2m_data_encode_uint(readScalar<uint16_t>(ptr), &data);
484#ifdef CONFIG_DAWN_DTYPE_INT32
486 lwm2m_data_encode_int(readScalar<int32_t>(ptr), &data);
490#ifdef CONFIG_DAWN_DTYPE_UINT32
492 lwm2m_data_encode_uint(readScalar<uint32_t>(ptr), &data);
496#ifdef CONFIG_DAWN_DTYPE_INT64
498 lwm2m_data_encode_int(readScalar<int64_t>(ptr), &data);
502#ifdef CONFIG_DAWN_DTYPE_UINT64
504 lwm2m_data_encode_uint(readScalar<uint64_t>(ptr), &data);
508#ifdef CONFIG_DAWN_DTYPE_FLOAT
510 lwm2m_data_encode_float(readScalar<float>(ptr), &data);
514#ifdef CONFIG_DAWN_DTYPE_DOUBLE
516 lwm2m_data_encode_float(readScalar<double>(ptr), &data);
520#ifdef CONFIG_DAWN_DTYPE_B16
522 lwm2m_data_encode_float(
static_cast<double>(readScalar<int32_t>(ptr)) / 65536.0, &data);
526#ifdef CONFIG_DAWN_DTYPE_UB16
528 lwm2m_data_encode_float(
static_cast<double>(readScalar<uint32_t>(ptr)) / 65536.0, &data);
539int ObjectBinding::writeResource(Resource &res,
const lwm2m_data_t &data)
544 if (proto ==
nullptr)
550 if (io ==
nullptr || res.data ==
nullptr || !io->
isWrite())
555 ptr = res.data->getDataPtr();
560#ifdef CONFIG_DAWN_DTYPE_BOOL
565 if (!lwm2m_data_decode_bool(&data, &bval))
570 *
static_cast<uint8_t *
>(ptr) = bval ? 1 : 0;
575#ifdef CONFIG_DAWN_DTYPE_INT8
578 int ret = decodeAndStoreSigned<int8_t>(ptr, data);
588#ifdef CONFIG_DAWN_DTYPE_UINT8
591 int ret = decodeAndStoreUnsigned<uint8_t>(ptr, data);
601#ifdef CONFIG_DAWN_DTYPE_INT16
604 int ret = decodeAndStoreSigned<int16_t>(ptr, data);
614#ifdef CONFIG_DAWN_DTYPE_UINT16
617 int ret = decodeAndStoreUnsigned<uint16_t>(ptr, data);
627#ifdef CONFIG_DAWN_DTYPE_INT32
630 int ret = decodeAndStoreSigned<int32_t>(ptr, data);
640#ifdef CONFIG_DAWN_DTYPE_UINT32
643 int ret = decodeAndStoreUnsigned<uint32_t>(ptr, data);
653#ifdef CONFIG_DAWN_DTYPE_INT64
658 if (!lwm2m_data_decode_int(&data, &sval))
663 *
static_cast<int64_t *
>(ptr) = sval;
668#ifdef CONFIG_DAWN_DTYPE_UINT64
673 if (!lwm2m_data_decode_uint(&data, &uval))
678 *
static_cast<uint64_t *
>(ptr) = uval;
683#ifdef CONFIG_DAWN_DTYPE_FLOAT
688 if (!lwm2m_data_decode_float(&data, &fval))
693 *
static_cast<float *
>(ptr) =
static_cast<float>(fval);
698#ifdef CONFIG_DAWN_DTYPE_DOUBLE
703 if (!lwm2m_data_decode_float(&data, &fval))
708 *
static_cast<double *
>(ptr) = fval;
713#ifdef CONFIG_DAWN_DTYPE_B16
718 if (!lwm2m_data_decode_float(&data, &fval))
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)
729 *
static_cast<b16_t *
>(ptr) = ftob16(fval);
734#ifdef CONFIG_DAWN_DTYPE_UB16
739 if (!lwm2m_data_decode_float(&data, &fval))
745 fval >
static_cast<double>(std::numeric_limits<uint32_t>::max()) / 65536.0)
750 *
static_cast<ub16_t *
>(ptr) =
static_cast<ub16_t
>(fval * 65536.0);
755#ifdef CONFIG_DAWN_DTYPE_BLOCK
758 const uint8_t *buffer;
760 const size_t capacity = res.data->getBufferSize();
762 if (!bufferValue(data, &buffer, &size))
775 std::memcpy(res.data->getDataPtr(), buffer, size);
789int ObjectBinding::executeResource(Resource &res,
const uint8_t *buffer,
int length)
795 if (proto ==
nullptr)
808 if (buffer ==
nullptr || length != 1 || buffer[0] <
'0' || buffer[0] >
'3')
813 cmd =
static_cast<uint8_t
>(buffer[0] -
'0');
822 if (res.data ==
nullptr || !io->
isWrite())
827#ifdef CONFIG_DAWN_DTYPE_UINT8
830 *
static_cast<uint8_t *
>(res.data->getDataPtr()) = cmd;
838uint8_t ObjectBinding::readCb(lwm2m_context_t *ctx,
841 lwm2m_data_t **dataArray,
842 lwm2m_object_t *
object)
850 return COAP_500_INTERNAL_SERVER_ERROR;
856 reinterpret_cast<Instance *
>(lwm2m_list_find(
object->instanceList, instanceId));
862 return COAP_404_NOT_FOUND;
865 for (
const Resource &res : self->resources)
867 if (res.instanceId == instanceId &&
868 (res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0)
874 *numData =
static_cast<int>(count);
875 *dataArray = *numData > 0 ? lwm2m_data_new(*numData) : nullptr;
876 if (*numData > 0 && *dataArray ==
nullptr)
878 return COAP_500_INTERNAL_SERVER_ERROR;
881 for (
const Resource &res : self->resources)
883 if (res.instanceId == instanceId &&
884 (res.access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0)
886 (*dataArray)[idx++].id = res.resourceId;
891 for (
int i = 0; i < *numData; i++)
893 Resource *res = self->findResource(instanceId, (*dataArray)[i].
id);
894 if (res ==
nullptr || (res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) == 0)
896 return COAP_404_NOT_FOUND;
899 if (self->readResource(*res, (*dataArray)[i]) < 0)
901 return COAP_500_INTERNAL_SERVER_ERROR;
905 return COAP_205_CONTENT;
908uint8_t ObjectBinding::discoverCb(lwm2m_context_t *ctx,
911 lwm2m_data_t **dataArray,
912 lwm2m_object_t *
object)
920 return COAP_500_INTERNAL_SERVER_ERROR;
926 reinterpret_cast<Instance *
>(lwm2m_list_find(
object->instanceList, instanceId));
931 return COAP_404_NOT_FOUND;
934 *numData =
static_cast<int>(inst->resourceCount);
935 *dataArray = *numData > 0 ? lwm2m_data_new(*numData) : nullptr;
936 if (*numData > 0 && *dataArray ==
nullptr)
938 return COAP_500_INTERNAL_SERVER_ERROR;
941 for (
const Resource &res : self->resources)
943 if (res.instanceId == instanceId)
945 (*dataArray)[idx++].id = res.resourceId;
950 return COAP_205_CONTENT;
953uint8_t ObjectBinding::writeCb(lwm2m_context_t *ctx,
956 lwm2m_data_t *dataArray,
957 lwm2m_object_t *
object,
958 lwm2m_write_type_t writeType)
967 return COAP_500_INTERNAL_SERVER_ERROR;
970 for (
int i = 0; i < numData; i++)
972 Resource *res = self->findResource(instanceId, dataArray[i].
id);
977 return COAP_404_NOT_FOUND;
980 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_WRITE) == 0)
982 return COAP_405_METHOD_NOT_ALLOWED;
985 ret = self->writeResource(*res, dataArray[i]);
986 if (ret == -EINVAL || ret == -ERANGE)
988 return COAP_400_BAD_REQUEST;
993 return COAP_413_ENTITY_TOO_LARGE;
998 return COAP_500_INTERNAL_SERVER_ERROR;
1001#ifdef CONFIG_DAWN_IO_NOTIFY
1002 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_READ) != 0 && self->proto !=
nullptr)
1004 self->proto->queueResourceChanged(self->lwm2m.objID, instanceId, res->resourceId);
1009 return COAP_204_CHANGED;
1012uint8_t ObjectBinding::executeCb(lwm2m_context_t *ctx,
1013 uint16_t instanceId,
1014 uint16_t resourceId,
1017 lwm2m_object_t *
object)
1025 if (self ==
nullptr)
1027 return COAP_500_INTERNAL_SERVER_ERROR;
1030 res = self->findResource(instanceId, resourceId);
1033 return COAP_404_NOT_FOUND;
1036 if ((res->access & CProtoWakaama::PROTO_WAKAAMA_ACCESS_EXECUTE) == 0)
1038 return COAP_405_METHOD_NOT_ALLOWED;
1041 ret = self->executeResource(*res, buffer, length);
1042 if (ret == -EINVAL || ret == -ERANGE)
1044 return COAP_400_BAD_REQUEST;
1047 if (ret == -ENOENT || ret == -ENOTSUP)
1049 return COAP_405_METHOD_NOT_ALLOWED;
1054 return COAP_500_INTERNAL_SERVER_ERROR;
1057 return COAP_204_CHANGED;
Base class for all I/O objects.
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).
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
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.
uint8_t getDtype() const
Get data type field.
@ CMD_RESET
Reset object internal state.
Wakaama LwM2M client protocol implementation.
Runtime binding between one LwM2M object and Dawn IO resources.
~ObjectBinding()
Destroy binding state and release allocated Wakaama resources.
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.
int deinit()
Release runtime allocations owned by the binding.
int init()
Resolve Dawn IOs and build the Wakaama object instance list.
Out-of-tree user-extension hooks for Dawn.
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).
@ DTYPE_INT32
Signed 32-bit integer (-2147483648 to 2147483647).
@ DTYPE_UINT8
Unsigned 8-bit integer (0 to 255).
@ DTYPE_INT16
Signed 16-bit integer (-32768 to 32767).
@ DTYPE_INT8
Signed 8-bit integer (-128 to 127).
@ DTYPE_BLOCK
Opaque block/byte-stream data type.
@ DTYPE_UINT64
Unsigned 64-bit integer.
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
@ DTYPE_UB16
Unsigned 16.16 fixed-point (32-bit).
@ DTYPE_DOUBLE
IEEE 754 double-precision floating point (64-bit).
@ DTYPE_INT64
Signed 64-bit integer.
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
@ DTYPE_BOOL
Boolean data type (stored in 32-bit container).
@ DTYPE_B16
Signed 16.16 fixed-point (32-bit).
Descriptor binding for one LwM2M resource.
Heap-allocated dynamic I/O data buffer.
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.