6#include "dawn/proto/wakaama/wakaama.hxx"
9#include "object_binding.hxx"
10#include "transport.hxx"
19using namespace dawn::wakaama_internal;
23void assignDescriptorString(std::string &dst,
27int hexNibble(
char ch);
28bool parseHexKey(
const char *hex,
size_t len, std::vector<uint8_t> &key);
31#ifdef CONFIG_DAWN_PROTO_WAKAAMA_QUEUE_MODE
32# define WAKAAMA_QUEUE_MODE_DEFAULT (true)
34# define WAKAAMA_QUEUE_MODE_DEFAULT (false)
41 , endpoint(CONFIG_DAWN_PROTO_WAKAAMA_ENDPOINT)
42 , serverHost(CONFIG_DAWN_PROTO_WAKAAMA_SERVER_HOST)
43 , manufacturer(CONFIG_DAWN_PROTO_WAKAAMA_DEVICE_MANUFACTURER)
44 , modelNumber(CONFIG_DAWN_PROTO_WAKAAMA_DEVICE_MODEL_NUMBER)
45 , serialNumber(CONFIG_DAWN_PROTO_WAKAAMA_DEVICE_SERIAL_NUMBER)
46 , firmwareVersion(CONFIG_DAWN_PROTO_WAKAAMA_DEVICE_FIRMWARE_VERSION)
47 , serverPort(CONFIG_DAWN_PROTO_WAKAAMA_SERVER_PORT)
48 , localPort(CONFIG_DAWN_PROTO_WAKAAMA_LOCAL_PORT)
49 , lifetime(CONFIG_DAWN_PROTO_WAKAAMA_LIFETIME)
50 , shortServerId(CONFIG_DAWN_PROTO_WAKAAMA_SHORT_SERVER_ID)
51 , queueMode(WAKAAMA_QUEUE_MODE_DEFAULT)
52#ifdef CONFIG_DAWN_IO_NOTIFY
53 , changedResourcesCapacity(0)
54 , acceptChangedResources(false)
59CProtoWakaama::~CProtoWakaama()
71int CProtoWakaama::configureDesc(
const CDescObject &desc)
76 for (
size_t i = 0; i < desc.
getSize(); i++)
82 DAWNERR(
"Unsupported Wakaama config 0x%08" PRIx32
"\n", item->
cfgid.
v);
88 case PROTO_WAKAAMA_CFG_ENDPOINT:
90 assignDescriptorString(endpoint, item, 0, item->
cfgid.
s.
size);
94 case PROTO_WAKAAMA_CFG_SERVER_HOST:
96 assignDescriptorString(serverHost, item, 0, item->
cfgid.
s.
size);
100 case PROTO_WAKAAMA_CFG_SERVER_PORT:
102 serverPort =
static_cast<uint16_t
>(item->
data[0]);
106 case PROTO_WAKAAMA_CFG_LOCAL_PORT:
108 localPort =
static_cast<uint16_t
>(item->
data[0]);
112 case PROTO_WAKAAMA_CFG_LIFETIME:
114 lifetime = item->
data[0];
118 case PROTO_WAKAAMA_CFG_QUEUE_MODE:
120 queueMode = (item->
data[0] != 0);
124 case PROTO_WAKAAMA_CFG_IOBIND:
141#ifdef CONFIG_DAWN_IO_NOTIFY
142 changedResourcesCapacity +=
145 objects.push_back(obj);
149 case PROTO_WAKAAMA_CFG_DEVICE_MANUFACTURER:
151 assignDescriptorString(manufacturer, item, 0, item->
cfgid.
s.
size);
155 case PROTO_WAKAAMA_CFG_DEVICE_MODEL_NUMBER:
157 assignDescriptorString(modelNumber, item, 0, item->
cfgid.
s.
size);
161 case PROTO_WAKAAMA_CFG_DEVICE_SERIAL_NUMBER:
163 assignDescriptorString(serialNumber, item, 0, item->
cfgid.
s.
size);
167 case PROTO_WAKAAMA_CFG_DEVICE_FIRMWARE_VERSION:
169 assignDescriptorString(firmwareVersion, item, 0, item->
cfgid.
s.
size);
173 case PROTO_WAKAAMA_CFG_DEVICE_BATTERY_VOLTAGE:
179 case PROTO_WAKAAMA_CFG_DEVICE_BATTERY_LEVEL:
185 case PROTO_WAKAAMA_CFG_DEVICE_BATTERY_STATUS:
191 case PROTO_WAKAAMA_CFG_SERVER:
193 int ret = configureServer(item);
204 DAWNERR(
"Unsupported Wakaama config 0x%08" PRIx32
"\n", item->
cfgid.
v);
217 ret = configureDesc(
getDesc());
220 DAWNERR(
"Wakaama configure failed (error %d)\n", ret);
229 for (
const ServerConfig &server : servers)
231 if (server.scheme == WAKAAMA_SERVER_SCHEME_COAPS ||
232 server.securityMode == LWM2M_SECURITY_MODE_PRE_SHARED_KEY)
234#ifndef CONFIG_DAWN_PROTO_WAKAAMA_DTLS_PSK
235 DAWNERR(
"Wakaama coaps/PSK server requires CONFIG_DAWN_PROTO_WAKAAMA_DTLS_PSK\n");
240 if (server.bootstrap)
242#ifndef CONFIG_WAKAAMA_BOOTSTRAP
243 DAWNERR(
"Wakaama bootstrap server requires CONFIG_WAKAAMA_BOOTSTRAP\n");
258 if (item ==
nullptr || item->
cfgid.
s.
size < 3)
263 server.host = serverHost;
264 server.pskIdentity.clear();
265 server.pskKey.clear();
266 server.port =
static_cast<uint16_t
>(item->
data[1] & 0xffff);
267 server.lifetime = item->
data[2];
268 server.shortServerId =
static_cast<uint16_t
>((item->
data[1] >> 16) & 0xffff);
269 server.securityInstanceId =
static_cast<uint16_t
>((item->
data[0] >> 16) & 0xffff);
270 server.serverInstanceId =
static_cast<uint16_t
>(item->
data[0] & 0xffff);
272 server.bootstrapTimeout = 0;
273 server.scheme = WAKAAMA_SERVER_SCHEME_COAP;
274 server.securityMode = LWM2M_SECURITY_MODE_NONE;
275 server.binding = queueMode ? BINDING_UQ : BINDING_U;
276 server.bootstrap =
false;
278 if (item->
cfgid.
s.
size > 3 && item->
data[3] == WAKAAMA_SERVER_EXT_MAGIC)
280 size_t identityWords;
283 const char *identity;
291 flags = item->
data[4];
292 server.scheme = (flags & WAKAAMA_SERVER_FLAG_COAPS) != 0 ? WAKAAMA_SERVER_SCHEME_COAPS
293 : WAKAAMA_SERVER_SCHEME_COAP;
294 server.securityMode =
static_cast<uint8_t
>((flags >> WAKAAMA_SERVER_FLAG_SECURITY_SHIFT) &
295 WAKAAMA_SERVER_FLAG_SECURITY_MASK);
296 server.bootstrap = (flags & WAKAAMA_SERVER_FLAG_BOOTSTRAP) != 0;
297 server.holdoff = item->
data[5];
298 server.bootstrapTimeout = item->
data[6];
299 identityWords = item->
data[7];
300 keyWords = item->
data[8];
304 if (item->
cfgid.
s.
size < pos + identityWords + keyWords + hostWords)
309 identity =
reinterpret_cast<const char *
>(&item->
data[pos]);
310 server.pskIdentity.assign(identity, identityWords *
sizeof(uint32_t));
311 server.pskIdentity = server.pskIdentity.c_str();
312 pos += identityWords;
314 key =
reinterpret_cast<const char *
>(&item->
data[pos]);
315 if (!parseHexKey(key, keyWords *
sizeof(uint32_t), server.pskKey))
323 assignDescriptorString(server.host, item, pos, hostWords);
328 assignDescriptorString(server.host, item, 3, item->
cfgid.
s.
size - 3);
331 if (server.securityMode == LWM2M_SECURITY_MODE_PRE_SHARED_KEY &&
332 (server.pskIdentity.empty() || server.pskKey.empty()))
337 servers.push_back(server);
341void CProtoWakaama::addDefaultServer()
345 server.host = serverHost;
346 server.pskIdentity.clear();
347 server.pskKey.clear();
348 server.port = serverPort;
349 server.lifetime = lifetime;
350 server.shortServerId = shortServerId;
351 server.securityInstanceId = 0;
352 server.serverInstanceId = 0;
354 server.bootstrapTimeout = 0;
355 server.scheme = WAKAAMA_SERVER_SCHEME_COAP;
356 server.securityMode = LWM2M_SECURITY_MODE_NONE;
357 server.binding = queueMode ? BINDING_UQ : BINDING_U;
358 server.bootstrap =
false;
359 servers.push_back(server);
362size_t CProtoWakaama::serverPoolCapacity()
const
364 size_t capacity = servers.size();
366 for (
const ServerConfig &server : servers)
368 if (server.bootstrap)
377std::string CProtoWakaama::serverUri(
const ServerConfig &server)
const
379 return std::string(server.scheme == WAKAAMA_SERVER_SCHEME_COAPS ?
"coaps://" :
"coap://") +
380 server.host +
":" + std::to_string(server.port);
383const CProtoWakaama::ServerConfig *CProtoWakaama::findServer(uint16_t securityInstanceId)
const
385 for (
const ServerConfig &server : servers)
387 if (server.securityInstanceId == securityInstanceId)
396#ifdef CONFIG_DAWN_IO_NOTIFY
397void CProtoWakaama::queueResourceChanged(uint16_t objectId,
401 std::lock_guard<std::mutex> lock(changedResourcesMutex);
403 if (!acceptChangedResources.load())
408 for (
const ChangedResource &res : changedResources)
410 if (res.objectId == objectId && res.instanceId == instanceId && res.resourceId == resourceId)
416 if (changedResources.size() >= changedResources.capacity())
418 DAWNERR(
"Wakaama changed resource queue full\n");
422 changedResources.push_back({objectId, instanceId, resourceId});
425void CProtoWakaama::processChangedResources()
427 if (runtime ==
nullptr || runtime->
context() ==
nullptr || !acceptChangedResources.load())
432 std::lock_guard<std::mutex> lock(changedResourcesMutex);
434 for (
const ChangedResource &res : changedResources)
438 LWM2M_URI_RESET(&uri);
439 uri.objectId = res.objectId;
440 uri.instanceId = res.instanceId;
441 uri.resourceId = res.resourceId;
442 lwm2m_resource_value_changed(runtime->
context(), &uri);
445 changedResources.clear();
453 case WAKAAMA_DEVICE_RESOURCE_POWER_SOURCE_VOLTAGE:
454 return &devBattVoltage;
455 case WAKAAMA_DEVICE_RESOURCE_BATTERY_LEVEL:
456 return &devBattLevel;
457 case WAKAAMA_DEVICE_RESOURCE_BATTERY_STATUS:
458 return &devBattStatus;
476int CProtoWakaama::buildObjects()
479 if (runtime ==
nullptr)
484 return runtime->
build(objects);
487void CProtoWakaama::destroyObjects()
489#ifdef CONFIG_DAWN_IO_NOTIFY
490 acceptChangedResources.store(
false);
493 if (runtime !=
nullptr)
500#ifdef CONFIG_DAWN_IO_NOTIFY
502 std::lock_guard<std::mutex> lock(changedResourcesMutex);
503 changedResources.clear();
515 ret = buildObjects();
522 ret = initConnectionPool();
550 ret = runtime->
configure(endpoint.c_str());
553 DAWNERR(
"lwm2m_configure failed: %d\n", ret);
558#ifdef CONFIG_DAWN_IO_NOTIFY
559 changedResources.reserve(changedResourcesCapacity);
562#ifdef CONFIG_DAWN_IO_NOTIFY
563 acceptChangedResources.store(
true);
573 destroyConnectionPool();
592 DAWNERR(
"failed to start Wakaama thread %d\n", ret);
613void assignDescriptorString(std::string &dst,
618 dst.assign(
reinterpret_cast<const char *
>(&item->
data[wordOffset]), wordCount *
sizeof(uint32_t));
619 size_t nul = dst.find(
'\0');
620 if (nul != std::string::npos)
626int hexNibble(
char ch)
628 if (ch >=
'0' && ch <=
'9')
633 ch =
static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
634 if (ch >=
'a' && ch <=
'f')
636 return ch -
'a' + 10;
642bool parseHexKey(
const char *hex,
size_t len, std::vector<uint8_t> &key)
644 while (len > 0 && hex[len - 1] ==
'\0')
661 key.reserve(len / 2);
662 for (
size_t i = 0; i < len; i += 2)
664 int hi = hexNibble(hex[i]);
665 int lo = hexNibble(hex[i + 1]);
667 if (hi < 0 || lo < 0)
673 key.push_back(
static_cast<uint8_t
>((hi << 4) | lo));
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemNext(size_t &offset) const
Get config item at current offset and advance past it.
CDescObject & getDesc()
Get descriptor object for this object.
Base class for all protocol implementations.
@ PROTO_CLASS_WAKAAMA
LwM2M protocol using Eclipse Wakaama.
void setDeviceBatteryBind(uint16_t resourceId, SObjectId::ObjectId objid)
Record a battery IO binding for a Device resource (7/9/20).
int doStop()
Stop implementation hook.
int deinit()
De-initialize object.
int doStart()
Start implementation hook.
int init()
One-time initialize object after bindings are resolved.
SDeviceIoBind * deviceBatteryBind(uint16_t resourceId)
Return the battery binding for a Device resource id, or nullptr.
int configure()
Configure object from descriptor data.
bool hasThread() const
Check if a background thread is active.
void setThreadStackSize(size_t stackSize)
Configure worker thread stack size.
bool workerThreadRunning() const
Check if the worker thread is running.
int stopWorkerThread()
Stop the worker thread.
int startWorkerThread(Func &&func)
Start the worker thread with a given function.
Wakaama client context and object registry runtime.
int configure(const char *endpoint)
Configure the Wakaama client endpoint and registered objects.
int build(const std::vector< ObjectBinding * > &objects)
Build built-in and descriptor-backed LwM2M objects.
void destroy(const std::vector< ObjectBinding * > &objects)
Release built-in and descriptor-backed LwM2M objects.
lwm2m_context_t * context() const
Return the underlying Wakaama client context.
int openContext(void *userdata)
Open the Wakaama client context with transport callback userdata.
Runtime binding between one LwM2M object and Dawn IO resources.
int configureStatus() const
Return descriptor parsing status captured by the constructor.
Out-of-tree user-extension hooks for Dawn.
Device-object resource backed by a descriptor IO.
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.
Descriptor binding for one LwM2M resource.
ObjectCfgId v
Raw 32-bit ConfigID value (for storage, comparison).
uint32_t cls
Object class (bits 21-29, max 511).
uint32_t id
Configuration identifier (bits 0-4, max 31).
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.