Friendly LWM2M client
Instance.cpp
Go to the documentation of this file.
1 /*
2  * Instnace.cpp
3  *
4  * Created on: 17 Jul 2023
5  * Author: valentin
6  */
7 
8 #include "Instance.h"
9 #include "WppLogs.h"
10 #include "WppClient.h"
11 
12 #define IS_PTR_VALID_AND_RES_EXISTS(resPtr) (resPtr && resPtr->instCount())
13 #define IS_RES_PTR_VALID(resPtr) (resPtr != NULL)
14 
15 namespace wpp {
16 
17 void Instance::notifyResChanged(ID_T resId, ID_T resInstId) {
18  if (_context.state <= STATE_BOOTSTRAPPING) return;
19  WPP_LOGD(TAG_WPP_INST, "Notify value changed: objID=%d, instID=%d, resID=%d, resInstID=%d", getObjectID(), getInstanceID(), resId, resInstId);
20  lwm2m_uri_t uri = {getObjectID(), getInstanceID(), resId, resInstId};
21  lwm2m_resource_value_changed(&_context, &uri);
22 }
23 
24 std::vector<Resource *> Instance::getInstantiatedResList() {
25  std::vector<Resource *> list;
26  for (auto &res : resources()) {
27  if (res.instCount()) list.push_back(&res);
28  }
29  return list;
30 }
31 
32 std::vector<Resource *> Instance::getInstantiatedResList(const ItemOp& filter) {
33  std::vector<Resource *> list;
34  for (auto &res : resources()) {
35  if (res.instCount() && filter.isCompatible(res.getOperation())) list.push_back(&res);
36  }
37  return list;
38 }
39 
40 std::vector<Resource *> Instance::getResList() {
41  std::vector<Resource *> list;
42  for (auto &res : resources()) list.push_back(&res);
43  return list;
44 }
45 
47  userOperationNotifier(type, {resId, resInstId});
48 }
49 
50 lwm2m_context_t& Instance::getContext() {
51  return _context;
52 }
53 
55  return *static_cast<wpp::WppClient *>(getContext().userData);
56 }
57 
59  return static_cast<wpp::WppClient *>(getContext().userData)->registry();
60 }
61 
62 Instance* Instance::getSecurityInst(lwm2m_server_t *server) {
63  if (!server) return NULL;
64  return getRegistry().object(OBJ_ID::LWM2M_SECURITY)->instance(server->secObjInstID);
65 }
66 
67 bool Instance::resourceToLwm2mData(Resource &res, ID_T instanceId, lwm2m_data_t &data) {
68  if (!res.isExist(instanceId)) {
69  WPP_LOGE(TAG_WPP_INST, "Resource instance does not exist: %d:%d:%d:%d", _id.objId, _id.objInstId, res.getId(), instanceId);
70  return false;
71  }
72 
73  switch(res.getTypeId()) {
74  case TYPE_ID::BOOL: {
75  BOOL_T value = res.get<BOOL_T>(instanceId);
76  lwm2m_data_encode_bool(value, &data);
77  break;
78  }
79  case TYPE_ID::TIME: {
80  TIME_T value = res.get<TIME_T>(instanceId);
81  lwm2m_data_encode_time(value, &data);
82  break;
83  }
84  case TYPE_ID::INT: {
85  INT_T value = res.get<INT_T>(instanceId);
86  lwm2m_data_encode_int(value, &data);
87  break;
88  }
89  case TYPE_ID::UINT: {
90  UINT_T value = res.get<UINT_T>(instanceId);
91  lwm2m_data_encode_uint(value, &data);
92  break;
93  }
94  case TYPE_ID::FLOAT: {
95  FLOAT_T value = res.get<FLOAT_T>(instanceId);
96  lwm2m_data_encode_float(value, &data);
97  break;
98  }
99  case TYPE_ID::OBJ_LINK: {
100  OBJ_LINK_T value = res.get<OBJ_LINK_T>(instanceId);
101  lwm2m_data_encode_objlink(value.objId, value.objInstId, &data);
102  break;
103  }
104  case TYPE_ID::OPAQUE: {
105  OPAQUE_T value = res.get<OPAQUE_T>(instanceId);
106  lwm2m_data_encode_opaque(value.data(), value.size(), &data);
107  break;
108  }
109  case TYPE_ID::STRING: {
110  STRING_T value = res.get<STRING_T>(instanceId);
111  lwm2m_data_encode_string(value.c_str(), &data);
112  break;
113  }
114  case TYPE_ID::CORE_LINK: {
115  CORE_LINK_T value = res.get<CORE_LINK_T>(instanceId);
116  lwm2m_data_encode_corelink(value.c_str(), &data);
117  break;
118  }
119  default: return false;
120  }
121 
122  return true;
123 }
124 
125 bool Instance::lwm2mDataToResource(const lwm2m_data_t &data, Resource &res, ID_T instanceId) {
126  switch (res.getTypeId()) {
127  case TYPE_ID::BOOL: {
128  BOOL_T value;
129  if (!lwm2m_data_decode_bool(&data, &value) || !res.set(value, instanceId)) return false;
130  break;
131  }
132  case TYPE_ID::TIME:{
133  TIME_T value;
134  if (!lwm2m_data_decode_time(&data, &value) || !res.set(value, instanceId)) return false;
135  break;
136  }
137  case TYPE_ID::INT: {
138  INT_T value;
139  if (!lwm2m_data_decode_int(&data, &value) || !res.set(value, instanceId)) return false;
140  break;
141  }
142  case TYPE_ID::UINT: {
143  UINT_T value;
144  if (!lwm2m_data_decode_uint(&data, &value) || !res.set(value, instanceId)) return false;
145  break;
146  }
147  case TYPE_ID::FLOAT: {
148  FLOAT_T value;
149  if (!lwm2m_data_decode_float(&data, &value) || !res.set(value, instanceId)) return false;
150  break;
151  }
152  case TYPE_ID::OBJ_LINK: {
153  OBJ_LINK_T value;
154  if (!lwm2m_data_decode_objlink(&data, &value.objId, &value.objInstId) || !res.set(std::move(value), instanceId)) return false;
155  break;
156  }
157  case TYPE_ID::OPAQUE: {
158  if (data.type != LWM2M_TYPE_OPAQUE && data.type != LWM2M_TYPE_STRING) return false;
159  size_t len = 0;
160  uint8_t *buffer = NULL;
161  if (!lwm2m_data_decode_opaque(&data, &buffer, &len) || !res.set(OPAQUE_T(buffer, buffer+len), instanceId)) {
162  if (len) lwm2m_free(buffer);
163  return false;
164  }
165  if (len) lwm2m_free(buffer);
166  break;
167  }
168  case TYPE_ID::STRING: {
169  if (data.type != LWM2M_TYPE_OPAQUE && data.type != LWM2M_TYPE_STRING) return false;
170  size_t len = data.value.asBuffer.length;
171  uint8_t *buffer = data.value.asBuffer.buffer;
172  if (!res.set(STRING_T(buffer, buffer+len), instanceId)) return false;
173  break;
174  }
175  case TYPE_ID::CORE_LINK: {
176  if (data.type != LWM2M_TYPE_OPAQUE && data.type != LWM2M_TYPE_STRING && data.type != LWM2M_TYPE_CORE_LINK) return false;
177  size_t len = data.value.asBuffer.length;
178  uint8_t *buffer = data.value.asBuffer.buffer;
179  if (!res.set(CORE_LINK_T(buffer, buffer + len), instanceId)) return false;
180  break;
181  }
182  default: return false;
183  }
184 
185  return true;
186 }
187 
188 Resource* Instance::getValidatedResForWrite(const lwm2m_data_t &data, lwm2m_write_type_t writeType, uint8_t &errCode) {
189  auto res = resource(data.id);
190  if (!IS_RES_PTR_VALID(res)) {
191  WPP_LOGW(TAG_WPP_INST, "Resource does not exist: %d:%d:%d", _id.objId, _id.objInstId, data.id);
192  errCode = COAP_404_NOT_FOUND;
193  return NULL;
194  }
195  // Check resource type (single/multiple) matches with data type
196  if ((data.type == LWM2M_TYPE_MULTIPLE_RESOURCE && res->isSingle()) ||
197  (data.type != LWM2M_TYPE_MULTIPLE_RESOURCE && res->isMultiple())) {
198  WPP_LOGW(TAG_WPP_INST, "Server can not write multiple resource to single and vise verse: %d:%d:%d", _id.objId, _id.objInstId, data.id);
199  errCode = COAP_400_BAD_REQUEST;
200  return NULL;
201  }
202  return &(*res);
203 }
204 
205 uint8_t Instance::resourceWrite(lwm2m_server_t *server, Resource &res, const lwm2m_data_t &data, lwm2m_write_type_t writeType) {
206  bool isReplace = (writeType == LWM2M_WRITE_REPLACE_INSTANCE || writeType == LWM2M_WRITE_REPLACE_RESOURCES);
207  Resource resBackup;
208 
209  // Check if data is not empty
210  if (data.type == LWM2M_TYPE_MULTIPLE_RESOURCE && data.value.asChildren.count == 0) {
211  WPP_LOGW(TAG_WPP_INST, "Resource write: %d:%d:%d, empty data", _id.objId, _id.objInstId, data.id);
212  return COAP_400_BAD_REQUEST;
213  }
214 
215  // Clear resource data if we need to replace it
216  if (isReplace) {
217  WPP_LOGD(TAG_WPP_INST, "Clear resource before write: %d:%d:%d", _id.objId, _id.objInstId, data.id);
218  resBackup = std::move(res);
219  }
220 
221  size_t count = 1;
222  const lwm2m_data_t *data_ptr = &data;
223  if (data.type == LWM2M_TYPE_MULTIPLE_RESOURCE) {
224  count = data.value.asChildren.count;
225  data_ptr = data.value.asChildren.array;
226  }
227 
228  // If resource is single then this loop execute only once
229  for (size_t i = 0; i < count; i++) {
230  ID_T resInstId = res.isSingle()? SINGLE_INSTANCE_ID : data_ptr[i].id;
231  WPP_LOGD(TAG_WPP_INST, "Resource write: %d:%d:%d:%d", _id.objId, _id.objInstId, data.id, resInstId);
232  if (!lwm2mDataToResource(data_ptr[i], res, resInstId)) {
233  WPP_LOGE(TAG_WPP_INST, "Problem with converting lwm2mData to resource: %d:%d:%d:%d", _id.objId, _id.objInstId, data.id, resInstId);
234  // Restore resource state
235  if (isReplace) res = std::move(resBackup);
236  return COAP_400_BAD_REQUEST;
237  }
238  // Notify implementation about update operation
239  if (writeType == LWM2M_WRITE_PARTIAL_UPDATE) serverOperationNotifier(getSecurityInst(server), ItemOp::WRITE, {res.getId(), (res.isSingle()? ID_T_MAX_VAL : resInstId)});
240  }
241  // Notify implementation about replace resource operation
242  if (writeType == LWM2M_WRITE_REPLACE_RESOURCES) serverOperationNotifier(getSecurityInst(server), ItemOp::WRITE, {res.getId(), ID_T_MAX_VAL});
243 
244  return COAP_NO_ERROR;
245 }
246 
247 Resource* Instance::getValidatedResForRead(const lwm2m_data_t &data, uint8_t &errCode) {
248  auto res = resource(data.id);
249  if (!IS_PTR_VALID_AND_RES_EXISTS(res)) {
250  WPP_LOGW(TAG_WPP_INST, "Resource does not exist: %d:%d:%d", _id.objId, _id.objInstId, data.id);
251  errCode = COAP_404_NOT_FOUND;
252  return NULL;
253  }
254  // Check the server operation permission for resource
255  if (!res->getOperation().isRead()) {
256  WPP_LOGE(TAG_WPP_INST, "Server does not have permission for read resource: %d:%d:%d", _id.objId, _id.objInstId, data.id);
257  errCode = COAP_400_BAD_REQUEST;
258  return NULL;
259  }
260  // Check resource type (single/multiple) matches with data type
261  if (data.type == LWM2M_TYPE_MULTIPLE_RESOURCE && res->isSingle()) {
262  WPP_LOGW(TAG_WPP_INST, "Server can not read single resource to multiple: %d:%d:%d", _id.objId, _id.objInstId, data.id);
263  errCode = COAP_400_BAD_REQUEST;
264  return NULL;
265  }
266  // If resource is multile then we should check that all instances are exists
267  if (data.type == LWM2M_TYPE_MULTIPLE_RESOURCE) {
268  for (size_t i = 0; i < data.value.asChildren.count; i++) {
269  if (!res->isExist(data.value.asChildren.array[i].id)) {
270  WPP_LOGW(TAG_WPP_INST, "Resource instance does not exist: %d:%d:%d:%d", _id.objId, _id.objInstId, data.id, data.value.asChildren.array[i].id);
271  errCode = COAP_404_NOT_FOUND;
272  return NULL;
273  }
274  }
275  }
276 
277  return &(*res);
278 }
279 
280 uint8_t Instance::resourceRead(lwm2m_server_t *server, lwm2m_data_t &data, Resource &res) {
281  // if has been received data for multiple resource with not allocated memory
282  // then we ourselves allocate memory for instances
283  if (res.isMultiple() && data.type != LWM2M_TYPE_MULTIPLE_RESOURCE) {
284  lwm2m_data_t *subData = lwm2m_data_new(res.instCount());
285  lwm2m_data_t *dataCnt = subData;
286  for (auto id : res.instIds()) (dataCnt++)->id = id;
287  lwm2m_data_encode_instances(subData, res.instCount(), &data);
288  }
289 
290  size_t count = 1;
291  lwm2m_data_t *data_ptr = &data;
292  if (data.type == LWM2M_TYPE_MULTIPLE_RESOURCE) {
293  count = data.value.asChildren.count;
294  data_ptr = data.value.asChildren.array;
295  }
296 
297  // If resource is single then this loop execute only once
298  for (size_t j = 0; j < count; j++) {
299  ID_T resInstId = res.isSingle()? SINGLE_INSTANCE_ID : data_ptr[j].id;
300  WPP_LOGD(TAG_WPP_INST, "Resource read: %d:%d:%d:%d", _id.objId, _id.objInstId, data.id, resInstId);
301  if (!resourceToLwm2mData(res, resInstId, data_ptr[j])) {
302  WPP_LOGE(TAG_WPP_INST, "Problem with converting resource to lwm2mData: %d:%d:%d:%d", _id.objId, _id.objInstId, data.id, resInstId);
303  return COAP_400_BAD_REQUEST;
304  }
305  }
306 
307  return COAP_NO_ERROR;
308 }
309 
310 Resource* Instance::getValidatedResForExecute(ID_T resId, uint8_t &errCode) {
311  auto res = resource(resId);
312  if (!IS_RES_PTR_VALID(res)) {
313  WPP_LOGW(TAG_WPP_INST, "Resource does not exist: %d:%d:%d", _id.objId, _id.objInstId, resId);
314  errCode = COAP_404_NOT_FOUND;
315  return NULL;
316  }
317  // Check the server operation permission for resource
318  if (!res->getOperation().isExecute()) {
319  WPP_LOGE(TAG_WPP_INST, "Server does not have permission for execute resource: %d:%d:%d", _id.objId, _id.objInstId, resId);
320  errCode = COAP_405_METHOD_NOT_ALLOWED;
321  return NULL;
322  }
323  return &(*res);
324 }
325 
326 uint8_t Instance::createEmptyLwm2mDataArray(std::vector<Resource*> resources, lwm2m_data_t **dataArray, int *numData) {
327  lwm2m_data_t *arr = lwm2m_data_new(resources.size());
328  if (!arr) return COAP_500_INTERNAL_SERVER_ERROR;
329 
330  lwm2m_data_t *arrCnt = arr;
331  for (auto &resource : resources) (arrCnt++)->id = resource->getId();
332  *dataArray = arr;
333  *numData = resources.size();
334 
335  return COAP_NO_ERROR;
336 }
337 
338 bool Instance::isAllMandatoryResourcesPresent(int numData, lwm2m_data_t *data){
339  // During the replace instance operation, request should contains all
340  // mandatory resources for write
341  std::vector<Resource *> mandatoryResources;
342  for (auto &res : resources()) {
343  if (!res.isMandatory() || !res.getOperation().isWrite()) continue;
344  bool found = false;
345  for (int i = 0; i < numData; i++) {
346  if (data[i].id == res.getId()) {
347  found = true;
348  break;
349  }
350  }
351  if (!found) {
352  WPP_LOGE(TAG_WPP_INST, "Mandatory resource %d:%d:%d does not found", _id.objId, _id.objInstId, res.getId());
353  return false;
354  }
355  }
356  return true;
357 }
358 
359 uint8_t Instance::replaceInstance(lwm2m_server_t *server, int numData, lwm2m_data_t *dataArray) {
360  // Container with updated resources that is used during
361  // replace instance operation we do not want to change
362  // the original resources to avoid data corruption. After
363  // successful writing, we will replace the original resources.
364  std::vector<Resource> replaceInstResources;
365  // During the replace instance operation, request should contains all
366  // mandatory resources for write
367  if (_context.state > STATE_BOOTSTRAPPING && !isAllMandatoryResourcesPresent(numData, dataArray)) return COAP_400_BAD_REQUEST;
368 
369  for (int i = 0; i < numData; i++) {
370  uint8_t errCode = COAP_NO_ERROR;
371  Resource *res = getValidatedResForWrite(dataArray[i], LWM2M_WRITE_REPLACE_INSTANCE, errCode);
372  if (!res) {
373  // If resource does not exist that means it is optional resource
374  // and optional resources can be missing during write operation
375  if (errCode != COAP_404_NOT_FOUND) {
376  WPP_LOGW(TAG_WPP_INST, "Resource %d:%d:%d write not possible, error: %d", _id.objId, _id.objInstId, dataArray[i].id, errCode);
377  return errCode;
378  }
379  continue;
380  }
381  replaceInstResources.push_back(*res);
382  errCode = resourceWrite(server, replaceInstResources.back(), dataArray[i], LWM2M_WRITE_REPLACE_INSTANCE);
383  if (errCode != COAP_NO_ERROR) {
384  WPP_LOGE(TAG_WPP_INST, "Resource %d:%d:%d write error: %d", _id.objId, _id.objInstId, dataArray[i].id, errCode);
385  return errCode;
386  }
387  }
388 
389  // Replace original resources with updated resources
390  for (auto &res : replaceInstResources) {
391  *resource(res.getId()) = std::move(res);
392  serverOperationNotifier(getSecurityInst(server), ItemOp::WRITE, {res.getId(), ID_T_MAX_VAL});
393  }
394 
395  return COAP_NO_ERROR;
396 }
397 
398 uint8_t Instance::replaceResource(lwm2m_server_t *server, int numData, lwm2m_data_t *dataArray, lwm2m_write_type_t writeType) {
399  for (int i = 0; i < numData; i++) {
400  uint8_t errCode = COAP_NO_ERROR;
401  Resource *res = getValidatedResForWrite(dataArray[i], writeType, errCode);
402  if (!res) {
403  // TODO: According to the documentation, optional resources can be missing when a write
404  // or read attempt is made, allowing us to ignore a request to read/write these
405  // resources, but wakaama is implemented in such a way that the behavior of ignoring
406  // optional resources results in an incorrect internal registration system state.
407  if (server == NULL || errCode != COAP_404_NOT_FOUND) {
408  WPP_LOGW(TAG_WPP_INST, "Resource %d:%d:%d write not possible, error: %d", _id.objId, _id.objInstId, dataArray[i].id, errCode);
409  return errCode;
410  }
411  continue;
412  }
413  errCode = resourceWrite(server, *res, dataArray[i], writeType);
414  if (errCode != COAP_NO_ERROR) {
415  WPP_LOGE(TAG_WPP_INST, "Resource %d:%d:%d write error: %d", _id.objId, _id.objInstId, dataArray[i].id, errCode);
416  return errCode;
417  }
418  }
419 
420  return COAP_NO_ERROR;
421 }
422 
423 uint8_t Instance::readAsServer(lwm2m_server_t *server, int *numData, lwm2m_data_t **dataArray) {
424  // TODO: Read-Composite Operation for now not supported
425  if (numData == NULL || dataArray == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
426 
427  bool readAllAvailableRes = *numData == 0;
428  WPP_LOGD(TAG_WPP_INST, "Read %d:%d, readAllAvailableRes: %d, numData: %d", _id.objId, _id.objInstId, readAllAvailableRes, *numData);
429  if (readAllAvailableRes) {
430  std::vector<Resource *> readResources = getInstantiatedResList(ItemOp(ItemOp::READ));
431  uint8_t errCode = createEmptyLwm2mDataArray(readResources, dataArray, numData);
432  if (errCode != COAP_NO_ERROR) {
433  WPP_LOGE(TAG_WPP_INST, "Error during creating lwm2m_data_t for read instance %d:%d", _id.objId, _id.objInstId);
434  return errCode;
435  }
436  }
437 
438  uint8_t result = COAP_404_NOT_FOUND;
439  for (int i = 0; i < *numData; i++) {
440  uint8_t errCode = COAP_NO_ERROR;
441  lwm2m_data_t *data = (*dataArray) + i;
442  Resource *res = getValidatedResForRead(*data, errCode);
443  if (!res) {
444  // TODO: According to the documentation, optional resources can be missing when a write
445  // or read attempt is made, allowing us to ignore a request to read/write these
446  // resources, but wakaama is implemented in such a way that the behavior of ignoring
447  // optional resources results in an incorrect internal registration system state.
448  if (server == NULL || errCode != COAP_404_NOT_FOUND) {
449  WPP_LOGW(TAG_WPP_INST, "Resource %d:%d:%d read not possible, error: %d", _id.objId, _id.objInstId, data->id, errCode);
450  return errCode;
451  }
452  continue;
453  }
454 
455  errCode = resourceRead(server, *data, *res);
456  if (errCode != COAP_NO_ERROR) {
457  WPP_LOGE(TAG_WPP_INST, "Resource %d:%d:%d read error: %d", _id.objId, _id.objInstId, data->id, errCode);
458  return errCode;
459  }
460  // For successful read operation we should read at least one resource
461  result = COAP_205_CONTENT;
462  }
463 
464  return result;
465 }
466 
467 uint8_t Instance::writeAsServer(lwm2m_server_t *server, int numData, lwm2m_data_t *dataArray, lwm2m_write_type_t writeType) {
468  // TODO: Write-Composite Operation for now not supported
469  if (!numData) return COAP_204_CHANGED;
470  if (dataArray == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
471  WPP_LOGD(TAG_WPP_INST, "Write %d:%d, numData: %d, write type %d", _id.objId, _id.objInstId, numData, writeType);
472 
473  // Check the server operation permission for resource.
474  // Bootstrap server can write even if resource is not writable.
475  for (int i = 0; i < numData; i++) {
476  auto res = resource(dataArray[i].id);
477  if (!IS_RES_PTR_VALID(res)) continue;
478  if (!res->getOperation().isWrite() && (_context.state > STATE_BOOTSTRAPPING) && server != NULL) {
479  WPP_LOGE(TAG_WPP_INST, "Trying to write read-only resource %d:%d:%d", _id.objId, _id.objInstId, dataArray[i].id);
480  return COAP_405_METHOD_NOT_ALLOWED;
481  }
482  }
483 
484  uint8_t errCode = COAP_NO_ERROR;
485  if (writeType == LWM2M_WRITE_REPLACE_INSTANCE) errCode = replaceInstance(server, numData, dataArray);
486  else errCode = replaceResource(server, numData, dataArray, writeType);
487 
488  return (errCode == COAP_NO_ERROR)? COAP_204_CHANGED : errCode;
489 }
490 
491 uint8_t Instance::executeAsServer(lwm2m_server_t *server, ID_T resId, uint8_t * buffer, int length) {
492  WPP_LOGD(TAG_WPP_INST, "Execute %d:%d:%d, buffer length: %d", _id.objId, _id.objInstId, resId, length);
493  uint8_t errCode = COAP_NO_ERROR;
494  Resource *res = getValidatedResForExecute(resId, errCode);
495  if (!res) {
496  WPP_LOGE(TAG_WPP_INST, "Resource %d:%d:%d execute not possible", _id.objId, _id.objInstId, resId);
497  return errCode;
498  }
499 
500  EXECUTE_T execute = res->get<EXECUTE_T>();
501  if (!execute) {
502  WPP_LOGE(TAG_WPP_INST, "Resource value is not set: %d:%d:%d", _id.objId, _id.objInstId, resId);
503  return COAP_404_NOT_FOUND;
504  }
505 
506  // Notify implementation about execute resource operation
507  serverOperationNotifier(getSecurityInst(server), ItemOp::EXECUTE, {res->getId(), ID_T_MAX_VAL});
508 
509  WPP_LOGD(TAG_WPP_INST, "Resource execute: %d:%d:%d, buffer length: %d", _id.objId, _id.objInstId, resId, length);
510  return execute(*this, resId, OPAQUE_T(buffer, buffer + length))? COAP_204_CHANGED : COAP_405_METHOD_NOT_ALLOWED;
511 }
512 
513 uint8_t Instance::discoverAsServer(lwm2m_server_t *server, int * numData, lwm2m_data_t ** dataArray) {
514  if (numData == NULL || dataArray == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
515 
516  bool discoverAllAvailableRes = *numData == 0;
517  WPP_LOGD(TAG_WPP_INST, "Discover %d:%d, discoverAllAvailableRes: %d, numData: %d", _id.objId, _id.objInstId, discoverAllAvailableRes, *numData);
518  if (discoverAllAvailableRes) {
519  std::vector<Resource *> resources = getResList();
520  uint8_t errCode = createEmptyLwm2mDataArray(resources, dataArray, numData);
521  if (errCode != COAP_NO_ERROR) {
522  WPP_LOGE(TAG_WPP_INST, "Error during creating lwm2m_data_t for discover instance %d:%d", _id.objId, _id.objInstId);
523  return errCode;
524  }
525  }
526 
527  for (int i = 0; i < *numData; i++) {
528  lwm2m_data_t *data = (*dataArray) + i;
529  auto res = resource(data->id);
530  if (!IS_RES_PTR_VALID(res)) {
531  WPP_LOGE(TAG_WPP_INST, "Resource does not exist: %d:%d:%d", _id.objId, _id.objInstId, data->id);
532  return COAP_404_NOT_FOUND;
533  }
534 
535  // if has been received data for multiple resource with not allocated memory
536  // then we ourselves allocate memory for instances
537  if (res->isMultiple() && res->instCount() && data->type != LWM2M_TYPE_MULTIPLE_RESOURCE) {
538  lwm2m_data_t *subData = lwm2m_data_new(res->instCount());
539  lwm2m_data_t *dataCnt = subData;
540  for (auto id : res->instIds()) {
541  (dataCnt++)->id = id;
542  WPP_LOGD(TAG_WPP_INST, "Resource instance discover: %d:%d:%d:%d", _id.objId, _id.objInstId, data->id, id);
543  }
544  lwm2m_data_encode_instances(subData, res->instCount(), data);
545  } else {
546  WPP_LOGD(TAG_WPP_INST, "Resource discover: %d:%d:%d", _id.objId, _id.objInstId, data->id);
547  }
548  }
549  return COAP_205_CONTENT;
550 }
551 
552 } // namespcae wpp
553 
#define IS_PTR_VALID_AND_RES_EXISTS(resPtr)
Definition: Instance.cpp:12
#define IS_RES_PTR_VALID(resPtr)
Definition: Instance.cpp:13
#define TAG_WPP_INST
Definition: WppLogs.h:12
#define WPP_LOGE(TAG, FMT,...)
Definition: WppLogs.h:49
#define WPP_LOGW(TAG, FMT,...)
Definition: WppLogs.h:43
#define WPP_LOGD(TAG, FMT,...)
Definition: WppLogs.h:31
void lwm2m_free(void *p)
Definition: WppPlatform.cpp:36
#define SINGLE_INSTANCE_ID
Definition: WppTypes.h:13
#define ID_T_MAX_VAL
Definition: WppTypes.h:16
Instance is interface class that implements manipulation with derived class resources....
Definition: Instance.h:40
void resourceOperationNotifier(ItemOp::TYPE type, ID_T resId, ID_T resInstId) override
Handle information about resource operation (WRITE, DELETE). Called by ResourceContainer after resour...
Definition: Instance.cpp:46
uint8_t readAsServer(lwm2m_server_t *server, int *numDataP, lwm2m_data_t **dataArray)
This methods is called by the core when the server wants to read, write, discover,...
Definition: Instance.cpp:423
OBJ_ID getObjectID() const
Definition: Instance.h:52
virtual void serverOperationNotifier(Instance *securityInst, ItemOp::TYPE type, const ResLink &resLink)=0
This method must be implemented by the derived class, and handle information about resource operation...
uint8_t discoverAsServer(lwm2m_server_t *server, int *numDataP, lwm2m_data_t **dataArray)
Definition: Instance.cpp:513
virtual void userOperationNotifier(ItemOp::TYPE type, const ResLink &resLink)=0
This method must be implemented by the derived class, and handle information about resource operation...
std::vector< Resource * > getInstantiatedResList()
This method return list with resources that has been instantiated. If resources does not exist then r...
Definition: Instance.cpp:24
WppRegistry & getRegistry()
Helpfull methods to get registry instances.
Definition: Instance.cpp:58
WppClient & getClient()
Helpfull methods to get client instances.
Definition: Instance.cpp:54
uint8_t executeAsServer(lwm2m_server_t *server, ID_T resId, uint8_t *buffer, int length)
Definition: Instance.cpp:491
lwm2m_context_t & getContext()
Return context that can be used by derived class.
Definition: Instance.cpp:50
void notifyResChanged(ID_T resId, ID_T resInstId=ID_T_MAX_VAL)
Notify server about resource value change.
Definition: Instance.cpp:17
ID_T getInstanceID() const
Definition: Instance.h:53
std::vector< Resource * > getResList()
This method return list with all resources that has been defined. If resources does not exist then re...
Definition: Instance.cpp:40
uint8_t writeAsServer(lwm2m_server_t *server, int numData, lwm2m_data_t *dataArray, lwm2m_write_type_t writeType)
Definition: Instance.cpp:467
Instance * instance(ID_T instanceID=ID_T_MAX_VAL)
Gets an instance of the object.
Definition: Object.cpp:102
Resource * resource(ID_T resId)
This method return resource ptr if it exists. If resources does not exist then return NULL.
std::vector< Resource > & resources()
This method return list with all resources that has been defined.
The Resource class in the wpp namespace is a comprehensive and flexible class designed to handle diff...
Definition: Resource.h:49
ID_T getId() const
Definition: Resource.cpp:72
const T & get(ID_T resInstId=SINGLE_INSTANCE_ID)
Definition: Resource.h:290
Represents a client interface for Wpp library.
Definition: WppClient.h:37
The WppRegistry class represents a registry for managing LWM2M objects.
Definition: WppRegistry.h:53
Object * object(OBJ_ID objId)
Retrieves a pointer to the Object with the given objId.
Definition: WppRegistry.cpp:64
The WppConnection class represents a connection interface for the Wpp library.
Definition: WppClient.cpp:14
std::string CORE_LINK_T
CoreLink - </3/0> or </1/0/>;ssid=101 or </5>,</4>,</55>;ver=1.9,</55/0>. Represent as string in lwm2...
Definition: WppTypes.h:62
bool BOOL_T
Wpp data types bindings.
Definition: WppTypes.h:40
std::function< bool(Instance &, ID_T, const OPAQUE_T &)> EXECUTE_T
Definition: WppTypes.h:72
int64_t INT_T
Definition: WppTypes.h:41
uint16_t ID_T
Definition: WppTypes.h:15
uint64_t UINT_T
Definition: WppTypes.h:42
std::string STRING_T
Definition: WppTypes.h:45
INT_T TIME_T
Definition: WppTypes.h:44
std::vector< uint8_t > OPAQUE_T
Opaque - represent buffer or string as lwm2m_data_t.value.asBuffer.
Definition: WppTypes.h:49
@ LWM2M_SECURITY
Definition: ObjectID.h:23
double FLOAT_T
Definition: WppTypes.h:43
The ItemOp struct represents the operations that can be performed on a instance/resource.
Definition: ItemOp.h:24
bool isCompatible(const ItemOp &operation) const
Checks if the ItemOp object is compatible with another ItemOp object.
Definition: ItemOp.h:63
TYPE
Enum representing the different types of operations.
Definition: ItemOp.h:29
@ EXECUTE
Definition: ItemOp.h:33