1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #define LOG_MODULE_NAME net_lwm2m_shell
7 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
11
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <zephyr/kernel.h>
18 #include <zephyr/net/lwm2m.h>
19 #include <zephyr/shell/shell.h>
20 #include <zephyr/sys/crc.h>
21
22 #include <lwm2m_engine.h>
23 #include <lwm2m_util.h>
24
25 #define LWM2M_HELP_CMD "LwM2M commands"
26 #define LWM2M_HELP_SEND "send PATHS\nLwM2M SEND operation\n"
27 #define LWM2M_HELP_EXEC "exec PATH [PARAM]\nExecute a resource\n"
28 #define LWM2M_HELP_READ "read PATH [OPTIONS]\nRead value from LwM2M resource\n" \
29 "-x \tRead value as hex stream (default)\n" \
30 "-s \tRead value as string\n" \
31 "-b \tRead value as bool (1/0)\n" \
32 "-uX\tRead value as uintX_t\n" \
33 "-sX\tRead value as intX_t\n" \
34 "-f \tRead value as float\n" \
35 "-t \tRead value as time_t\n" \
36 "-crc32\tCalculate CRC32 of the content\n"
37 #define LWM2M_HELP_WRITE "write PATH [OPTIONS] VALUE\nWrite into LwM2M resource\n" \
38 "-s \tWrite value as string (default)\n" \
39 "-b \tWrite value as bool\n" \
40 "-uX\tWrite value as uintX_t\n" \
41 "-sX\tWrite value as intX_t\n" \
42 "-f \tWrite value as float\n" \
43 "-t \tWrite value as time_t\n"
44 #define LWM2M_HELP_CREATE "create PATH\nCreate object or resource instance\n"
45 #define LWM2M_HELP_DELETE "delete PATH\nDelete object or resource instance\n"
46 #define LWM2M_HELP_START "start EP_NAME [BOOTSTRAP FLAG]\n" \
47 "Start the LwM2M RD (Registration / Discovery) Client\n" \
48 "-b \tSet the bootstrap flag (default 0)\n"
49 #define LWM2M_HELP_STOP "stop [OPTIONS]\nStop the LwM2M RD (De-register) Client\n" \
50 "-f \tForce close the connection\n"
51 #define LWM2M_HELP_UPDATE "Trigger Registration Update of the LwM2M RD Client\n"
52 #define LWM2M_HELP_PAUSE "LwM2M engine thread pause"
53 #define LWM2M_HELP_RESUME "LwM2M engine thread resume"
54 #define LWM2M_HELP_LOCK "Lock the LwM2M registry"
55 #define LWM2M_HELP_UNLOCK "Unlock the LwM2M registry"
56 #define LWM2M_HELP_OBSERV "List observations"
57 #define LWM2M_HELP_CACHE "cache PATH NUM\nEnable data cache for resource\n" \
58 "PATH is LwM2M path\n" \
59 "NUM how many elements to cache\n"
60 #define LWM2M_HELP_LS "ls [PATH]\nList objects, instances, resources\n"
61
send_cb(enum lwm2m_send_status status)62 static void send_cb(enum lwm2m_send_status status)
63 {
64 LOG_INF("SEND status: %d", status);
65 }
66
cmd_send(const struct shell * sh,size_t argc,char ** argv)67 static int cmd_send(const struct shell *sh, size_t argc, char **argv)
68 {
69 int ret = 0;
70 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
71 int path_cnt = argc - 1;
72 struct lwm2m_obj_path lwm2m_path_list[CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE];
73
74 if (!ctx) {
75 shell_error(sh, "no lwm2m context yet");
76 return -ENOEXEC;
77 }
78
79 if (argc < 2) {
80 shell_error(sh, "no path(s)");
81 shell_help(sh);
82 return -EINVAL;
83 }
84
85 if (path_cnt > CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE) {
86 return -E2BIG;
87 }
88
89 for (int i = 0; i < path_cnt; i++) {
90 const char *p = argv[1 + i];
91 /* translate path -> path_obj */
92 ret = lwm2m_string_to_path(p, &lwm2m_path_list[i], '/');
93 if (ret < 0) {
94 return ret;
95 }
96 }
97
98 ret = lwm2m_send_cb(ctx, lwm2m_path_list, path_cnt, send_cb);
99
100 if (ret < 0) {
101 shell_error(sh, "can't do send operation, request failed (%d)", ret);
102 return -ENOEXEC;
103 }
104 return 0;
105 }
106
cmd_exec(const struct shell * sh,size_t argc,char ** argv)107 static int cmd_exec(const struct shell *sh, size_t argc, char **argv)
108 {
109 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
110
111 if (!ctx) {
112 shell_error(sh, "no lwm2m context yet");
113 return -ENOEXEC;
114 }
115
116 const char *pathstr = argv[1];
117 struct lwm2m_obj_path path;
118 int ret = lwm2m_string_to_path(pathstr, &path, '/'); /* translate path -> path_obj */
119
120 if (ret < 0) {
121 shell_error(sh, "Illegal path (PATH %s)", pathstr);
122 return -EINVAL;
123 }
124
125 struct lwm2m_engine_res *res = lwm2m_engine_get_res(&path);
126
127 if (res == NULL) {
128 shell_error(sh, "Resource not found");
129 return -EINVAL;
130 }
131
132 if (!res->execute_cb) {
133 shell_error(sh, "No execute callback!");
134 return -EINVAL;
135 }
136
137 /* 0: exec, 1:<path> 2:[<param>] */
138 char *param = (argc == 3) ? argv[2] : NULL;
139 size_t param_len = param ? strlen(param) + 1 : 0;
140
141 ret = res->execute_cb(path.obj_inst_id, param, param_len);
142 if (ret < 0) {
143 shell_error(sh, "returned (err %d)", ret);
144 return -ENOEXEC;
145 }
146
147 return 0;
148 }
149
cmd_read(const struct shell * sh,size_t argc,char ** argv)150 static int cmd_read(const struct shell *sh, size_t argc, char **argv)
151 {
152 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
153
154 if (!ctx) {
155 shell_error(sh, "no lwm2m context yet");
156 return -ENOEXEC;
157 }
158
159 if (argc < 2) {
160 shell_error(sh, "no arguments or path(s)");
161 shell_help(sh);
162 return -EINVAL;
163 }
164 const char *dtype = "-x"; /* default */
165 const char *pathstr = argv[1];
166 int ret = 0;
167 struct lwm2m_obj_path path;
168
169 ret = lwm2m_string_to_path(pathstr, &path, '/');
170 if (ret < 0) {
171 return ret;
172 }
173
174 if (argc > 2) { /* read + path + options(data type) */
175 dtype = argv[2];
176 }
177 if (strcmp(dtype, "-x") == 0) {
178 const char *buff;
179 uint16_t buff_len = 0;
180
181 ret = lwm2m_get_res_buf(&path, (void **)&buff,
182 NULL, &buff_len, NULL);
183 if (ret != 0) {
184 goto out;
185 }
186 shell_hexdump(sh, buff, buff_len);
187 } else if (strcmp(dtype, "-crc32") == 0) {
188 const char *buff;
189 uint16_t buff_len = 0;
190
191 ret = lwm2m_get_res_buf(&path, (void **)&buff,
192 NULL, &buff_len, NULL);
193 if (ret != 0) {
194 goto out;
195 }
196
197 uint32_t crc = crc32_ieee(buff, buff_len);
198
199 shell_print(sh, "%u", crc);
200 } else if (strcmp(dtype, "-s") == 0) {
201 const char *buff;
202 uint16_t buff_len = 0;
203
204 ret = lwm2m_get_res_buf(&path, (void **)&buff,
205 NULL, &buff_len, NULL);
206 if (ret != 0) {
207 goto out;
208 }
209 shell_print(sh, "%.*s", buff_len, buff);
210 } else if (strcmp(dtype, "-s8") == 0) {
211 int8_t temp = 0;
212
213 ret = lwm2m_get_s8(&path, &temp);
214 if (ret != 0) {
215 goto out;
216 }
217 shell_print(sh, "%d", temp);
218 } else if (strcmp(dtype, "-s16") == 0) {
219 int16_t temp = 0;
220
221 ret = lwm2m_get_s16(&path, &temp);
222 if (ret != 0) {
223 goto out;
224 }
225 shell_print(sh, "%d", temp);
226 } else if (strcmp(dtype, "-s32") == 0) {
227 int32_t temp = 0;
228
229 ret = lwm2m_get_s32(&path, &temp);
230 if (ret != 0) {
231 goto out;
232 }
233 shell_print(sh, "%d", temp);
234 } else if (strcmp(dtype, "-s64") == 0) {
235 int64_t temp = 0;
236
237 ret = lwm2m_get_s64(&path, &temp);
238 if (ret != 0) {
239 goto out;
240 }
241 shell_print(sh, "%lld", temp);
242 } else if (strcmp(dtype, "-u8") == 0) {
243 uint8_t temp = 0;
244
245 ret = lwm2m_get_u8(&path, &temp);
246 if (ret != 0) {
247 goto out;
248 }
249 shell_print(sh, "%d", temp);
250 } else if (strcmp(dtype, "-u16") == 0) {
251 uint16_t temp = 0;
252
253 ret = lwm2m_get_u16(&path, &temp);
254 if (ret != 0) {
255 goto out;
256 }
257 shell_print(sh, "%d", temp);
258 } else if (strcmp(dtype, "-u32") == 0) {
259 uint32_t temp = 0;
260
261 ret = lwm2m_get_u32(&path, &temp);
262 if (ret != 0) {
263 goto out;
264 }
265 shell_print(sh, "%d", temp);
266 } else if (strcmp(dtype, "-f") == 0) {
267 double temp = 0;
268
269 ret = lwm2m_get_f64(&path, &temp);
270 if (ret != 0) {
271 goto out;
272 }
273 shell_print(sh, "%f", temp);
274 } else if (strcmp(dtype, "-b") == 0) {
275 bool temp;
276
277 ret = lwm2m_get_bool(&path, &temp);
278 if (ret != 0) {
279 goto out;
280 }
281 shell_print(sh, "%d", temp);
282 } else if (strcmp(dtype, "-t") == 0) {
283 time_t temp;
284
285 ret = lwm2m_get_time(&path, &temp);
286 if (ret != 0) {
287 goto out;
288 }
289 shell_print(sh, "%lld", temp);
290 } else {
291 shell_error(sh, "can't recognize data type %s", dtype);
292 shell_help(sh);
293 return -EINVAL;
294 }
295 return 0;
296 out:
297 shell_error(sh, "can't do read operation, request failed (err %d)", ret);
298 return -EINVAL;
299 }
300
cmd_write(const struct shell * sh,size_t argc,char ** argv)301 static int cmd_write(const struct shell *sh, size_t argc, char **argv)
302 {
303 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
304
305 if (!ctx) {
306 shell_error(sh, "no lwm2m context yet");
307 return -ENOEXEC;
308 }
309
310 if (argc < 3) {
311 shell_error(sh, "no arguments or path(s)");
312 shell_help(sh);
313 return -EINVAL;
314 }
315
316 int ret = 0;
317 const char *pathstr = argv[1];
318 const char *dtype;
319 char *value;
320 struct lwm2m_obj_path path;
321
322 ret = lwm2m_string_to_path(pathstr, &path, '/');
323 if (ret < 0) {
324 return ret;
325 }
326
327 if (argc == 4) { /* write path options value */
328 dtype = argv[2];
329 value = argv[3];
330 } else { /* write path value */
331 dtype = "-s";
332 value = argv[2];
333 }
334
335 if (strcmp(dtype, "-s") == 0) {
336 ret = lwm2m_set_string(&path, value);
337 } else if (strcmp(dtype, "-f") == 0) {
338 double new = 0;
339
340 ret = lwm2m_atof(value, &new); /* Convert string -> float */
341 if (ret == 0) {
342 ret = lwm2m_set_f64(&path, new);
343 }
344 } else { /* All the types using stdlib funcs*/
345 char *e;
346
347 if (strcmp(dtype, "-s8") == 0) {
348 ret = lwm2m_set_s8(&path, strtol(value, &e, 10));
349 } else if (strcmp(dtype, "-s16") == 0) {
350 ret = lwm2m_set_s16(&path, strtol(value, &e, 10));
351 } else if (strcmp(dtype, "-s32") == 0) {
352 ret = lwm2m_set_s32(&path, strtol(value, &e, 10));
353 } else if (strcmp(dtype, "-s64") == 0) {
354 ret = lwm2m_set_s64(&path, strtoll(value, &e, 10));
355 } else if (strcmp(dtype, "-u8") == 0) {
356 ret = lwm2m_set_u8(&path, strtoul(value, &e, 10));
357 } else if (strcmp(dtype, "-u16") == 0) {
358 ret = lwm2m_set_u16(&path, strtoul(value, &e, 10));
359 } else if (strcmp(dtype, "-u32") == 0) {
360 ret = lwm2m_set_u32(&path, strtoul(value, &e, 10));
361 } else if (strcmp(dtype, "-b") == 0) {
362 ret = lwm2m_set_bool(&path, strtoul(value, &e, 10));
363 } else if (strcmp(dtype, "-t") == 0) {
364 ret = lwm2m_set_time(&path, strtoll(value, &e, 10));
365 } else {
366 shell_error(sh, "can't recognize data type %s",
367 dtype);
368 shell_help(sh);
369 return -EINVAL;
370 }
371 if (*e != '\0') {
372 shell_error(sh, "Invalid number: %s", value);
373 shell_help(sh);
374 return -EINVAL;
375 }
376 }
377
378 if (ret < 0) {
379 shell_error(
380 sh,
381 "can't do write operation, request failed (err %d)",
382 ret);
383 return -ENOEXEC;
384 }
385
386 return 0;
387 }
388
cmd_create_or_delete(const struct shell * sh,bool delete,size_t argc,char ** argv)389 static int cmd_create_or_delete(const struct shell *sh, bool delete, size_t argc, char **argv)
390 {
391 struct lwm2m_obj_path path;
392 int ret;
393
394 if (argc < 2) {
395 shell_error(sh, "No object ID given");
396 shell_help(sh);
397 return -EINVAL;
398 }
399
400 ret = lwm2m_string_to_path(argv[1], &path, '/');
401 if (ret < 0) {
402 shell_error(sh, "failed to read path (%d)", ret);
403 return -ENOEXEC;
404 }
405
406 if (delete) {
407 switch (path.level) {
408 case LWM2M_PATH_LEVEL_RESOURCE_INST:
409 ret = lwm2m_delete_res_inst(&path);
410 break;
411 case LWM2M_PATH_LEVEL_OBJECT_INST:
412 ret = lwm2m_delete_object_inst(&path);
413 break;
414 default:
415 return -ENOEXEC;
416 }
417 } else {
418 switch (path.level) {
419 case LWM2M_PATH_LEVEL_RESOURCE_INST:
420 ret = lwm2m_create_res_inst(&path);
421 break;
422 case LWM2M_PATH_LEVEL_OBJECT_INST:
423 ret = lwm2m_create_object_inst(&path);
424 break;
425 default:
426 return -ENOEXEC;
427 }
428 }
429
430 if (ret < 0) {
431 shell_error(sh, "operation failed, %d", ret);
432 return -ENOEXEC;
433 }
434
435 return 0;
436 }
437
cmd_create(const struct shell * sh,size_t argc,char ** argv)438 static int cmd_create(const struct shell *sh, size_t argc, char **argv)
439 {
440 return cmd_create_or_delete(sh, false, argc, argv);
441 }
442
cmd_delete(const struct shell * sh,size_t argc,char ** argv)443 static int cmd_delete(const struct shell *sh, size_t argc, char **argv)
444 {
445 return cmd_create_or_delete(sh, true, argc, argv);
446 }
447
cmd_start(const struct shell * sh,size_t argc,char ** argv)448 static int cmd_start(const struct shell *sh, size_t argc, char **argv)
449 {
450 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
451
452 if (!ctx) {
453 shell_error(sh, "no lwm2m context yet");
454 return -ENOEXEC;
455 }
456 uint32_t bootstrap_flag = 0;
457
458 if (argc == 3) {
459 shell_error(sh, "no specifier or value");
460 shell_help(sh);
461 return -EINVAL;
462 } else if (argc == 4) {
463 if (strcmp(argv[2], "-b") != 0) {
464 shell_error(sh, "unknown specifier %s", argv[2]);
465 shell_help(sh);
466 return -EINVAL;
467 }
468
469 char *e;
470
471 bootstrap_flag = strtol(argv[3], &e, 10);
472 if (*e != '\0') {
473 shell_error(sh, "Invalid number: %s", argv[3]);
474 shell_help(sh);
475 return -EINVAL;
476 }
477 }
478 int ret = lwm2m_rd_client_start(ctx, argv[1], bootstrap_flag,
479 ctx->event_cb, ctx->observe_cb);
480 if (ret < 0) {
481 shell_error(
482 sh,
483 "can't do start operation, request failed (err %d)",
484 ret);
485 return -ENOEXEC;
486 }
487 return 0;
488 }
489
cmd_stop(const struct shell * sh,size_t argc,char ** argv)490 static int cmd_stop(const struct shell *sh, size_t argc, char **argv)
491 {
492 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
493
494 if (!ctx) {
495 shell_error(sh, "no lwm2m context yet");
496 return -ENOEXEC;
497 }
498 bool forcefully = true;
499
500 if (argc == 2) {
501 if (strcmp(argv[1], "-f") != 0) {
502 shell_error(sh, "can't recognize specifier %s",
503 argv[1]);
504 shell_help(sh);
505 return -EINVAL;
506 }
507 forcefully = false;
508 }
509 int ret = lwm2m_rd_client_stop(ctx, ctx->event_cb, forcefully);
510
511 if (ret < 0) {
512 shell_error(
513 sh,
514 "can't do stop operation, request failed (err %d)",
515 ret);
516 return -ENOEXEC;
517 }
518 return 0;
519 }
520
cmd_update(const struct shell * sh,size_t argc,char ** argv)521 static int cmd_update(const struct shell *sh, size_t argc, char **argv)
522 {
523 ARG_UNUSED(argc);
524 ARG_UNUSED(argv);
525 struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
526
527 if (!ctx) {
528 shell_error(sh, "no lwm2m context yet");
529 return -ENOEXEC;
530 }
531 lwm2m_rd_client_update();
532 return 0;
533 }
534
cmd_pause(const struct shell * sh,size_t argc,char ** argv)535 static int cmd_pause(const struct shell *sh, size_t argc, char **argv)
536 {
537 ARG_UNUSED(sh);
538 ARG_UNUSED(argc);
539 ARG_UNUSED(argv);
540
541 return lwm2m_engine_pause();
542 }
543
cmd_resume(const struct shell * sh,size_t argc,char ** argv)544 static int cmd_resume(const struct shell *sh, size_t argc, char **argv)
545 {
546 ARG_UNUSED(sh);
547 ARG_UNUSED(argc);
548 ARG_UNUSED(argv);
549
550 return lwm2m_engine_resume();
551 }
552
cmd_lock(const struct shell * sh,size_t argc,char ** argv)553 static int cmd_lock(const struct shell *sh, size_t argc, char **argv)
554 {
555 ARG_UNUSED(sh);
556 ARG_UNUSED(argc);
557 ARG_UNUSED(argv);
558
559 lwm2m_registry_lock();
560 return 0;
561 }
562
cmd_unlock(const struct shell * sh,size_t argc,char ** argv)563 static int cmd_unlock(const struct shell *sh, size_t argc, char **argv)
564 {
565 ARG_UNUSED(sh);
566 ARG_UNUSED(argc);
567 ARG_UNUSED(argv);
568
569 lwm2m_registry_unlock();
570 return 0;
571 }
572
cmd_cache(const struct shell * sh,size_t argc,char ** argv)573 static int cmd_cache(const struct shell *sh, size_t argc, char **argv)
574 {
575 #if (K_HEAP_MEM_POOL_SIZE > 0)
576 int rc;
577 int elems;
578 struct lwm2m_time_series_elem *cache;
579 struct lwm2m_obj_path obj_path;
580
581 if (argc != 3) {
582 shell_error(sh, "wrong parameters");
583 return -EINVAL;
584 }
585
586 /* translate path -> path_obj */
587 rc = lwm2m_string_to_path(argv[1], &obj_path, '/');
588 if (rc < 0) {
589 return rc;
590 }
591
592 if (obj_path.level < 3) {
593 shell_error(sh, "Path string not correct");
594 return -EINVAL;
595 }
596
597 if (lwm2m_cache_entry_get_by_object(&obj_path)) {
598 shell_error(sh, "Cache already enabled for %s", argv[1]);
599 return -ENOEXEC;
600 }
601
602 elems = atoi(argv[2]);
603 if (elems < 1) {
604 shell_error(sh, "Size must be 1 or more (given %d)", elems);
605 return -EINVAL;
606 }
607
608 cache = k_malloc(sizeof(struct lwm2m_time_series_elem) * elems);
609 if (!cache) {
610 shell_error(sh, "Out of memory");
611 return -ENOEXEC;
612 }
613
614 rc = lwm2m_enable_cache(&obj_path, cache, elems);
615 if (rc) {
616 shell_error(sh, "lwm2m_enable_cache(%u/%u/%u/%u, %p, %d) returned %d",
617 obj_path.obj_id, obj_path.obj_inst_id, obj_path.res_id,
618 obj_path.res_inst_id, cache, elems, rc);
619 k_free(cache);
620 return -ENOEXEC;
621 }
622
623 return 0;
624 #else
625 shell_error(sh, "No heap configured");
626 return -ENOEXEC;
627 #endif
628 }
629
shell_print_attr(const struct shell * sh,void * ref)630 static void shell_print_attr(const struct shell *sh, void *ref)
631 {
632 struct lwm2m_attr *attr = NULL;
633 bool found;
634
635 for (uint8_t type = 0; type < NR_LWM2M_ATTR; type++) {
636 found = false;
637 while ((attr = lwm2m_engine_get_next_attr(ref, attr)) != NULL) {
638 if (attr->type == type) {
639 found = true;
640 break;
641 }
642 }
643 if (found) {
644 switch (type) {
645 case LWM2M_ATTR_PMIN:
646 /* fall through */
647 case LWM2M_ATTR_PMAX:
648 shell_fprintf(sh, SHELL_NORMAL, "%10u", attr->int_val);
649 break;
650 case LWM2M_ATTR_GT:
651 /* fall through */
652 case LWM2M_ATTR_LT:
653 /* fall through */
654 case LWM2M_ATTR_STEP:
655 shell_fprintf(sh, SHELL_NORMAL, "%10f", attr->float_val);
656 break;
657 }
658 } else {
659 shell_fprintf(sh, SHELL_NORMAL, "%10s", "");
660 }
661 }
662 }
663
cmd_observations(const struct shell * sh,size_t argc,char ** argv)664 static int cmd_observations(const struct shell *sh, size_t argc, char **argv)
665 {
666 char buf[LWM2M_MAX_PATH_STR_SIZE];
667 struct lwm2m_obj_path_list *o_p;
668 struct observe_node *obs;
669 uint32_t i = 0, path_i;
670 struct lwm2m_ctx *ctx;
671 void *ref;
672 int ret;
673
674 ctx = lwm2m_rd_client_ctx();
675 if (ctx == NULL) {
676 shell_error(sh, "no lwm2m context yet\n");
677 return -ENOEXEC;
678 }
679
680 ARG_UNUSED(argc);
681 ARG_UNUSED(argv);
682
683 shell_fprintf(sh, SHELL_INFO, " # %10s %18s", "composite", "path");
684 for (i = 0; i < NR_LWM2M_ATTR; i++) {
685 shell_fprintf(sh, SHELL_INFO, "%10s", lwm2m_attr_to_str(i));
686 }
687 shell_print(sh, "");
688
689 lwm2m_registry_lock();
690 i = 0;
691 SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) {
692 shell_fprintf(sh, SHELL_NORMAL, "%2u %10c ", i, obs->composite ? 'y' : 'n');
693 path_i = 0;
694 SYS_SLIST_FOR_EACH_CONTAINER(&obs->path_list, o_p, node) {
695 if (path_i > 0) {
696 shell_fprintf(sh, SHELL_NORMAL, "%14s", "");
697 }
698 shell_fprintf(sh, SHELL_NORMAL, "%-18s",
699 lwm2m_path_log_buf(buf, &o_p->path));
700 ret = lwm2m_get_path_reference_ptr(NULL, &o_p->path, &ref);
701 if (ret < 0) {
702 continue;
703 }
704 shell_print_attr(sh, ref);
705 path_i++;
706 shell_print(sh, "");
707 }
708 i++;
709
710 }
711 lwm2m_registry_unlock();
712
713 return 0;
714 }
715
print_object_instance(const struct shell * sh,struct lwm2m_engine_obj_inst * oi)716 static int print_object_instance(const struct shell *sh, struct lwm2m_engine_obj_inst *oi)
717 {
718 struct lwm2m_engine_obj *obj;
719
720 if (!oi) {
721 return -ENOEXEC;
722 }
723
724 obj = oi->obj;
725
726 for (int i = 0; i < oi->resource_count; i++) {
727 struct lwm2m_engine_res *re = &oi->resources[i];
728
729 for (int j = 0; j < re->res_inst_count; j++) {
730 struct lwm2m_engine_res_inst *ri = &re->res_instances[j];
731
732 if (ri->data_ptr && ri->data_len > 0 &&
733 ri->res_inst_id != RES_INSTANCE_NOT_CREATED) {
734 struct lwm2m_engine_obj_field *field =
735 lwm2m_get_engine_obj_field(obj, re->res_id);
736 char path[LWM2M_MAX_PATH_STR_SIZE];
737
738 if (field == NULL) {
739 continue;
740 }
741
742 if (re->multi_res_inst) {
743 snprintf(path, sizeof(path), "%hu/%hu/%hu/%hu", obj->obj_id,
744 oi->obj_inst_id, re->res_id, ri->res_inst_id);
745 } else {
746 snprintf(path, sizeof(path), "%hu/%hu/%hu", obj->obj_id,
747 oi->obj_inst_id, re->res_id);
748 }
749 switch (field->data_type) {
750 case LWM2M_RES_TYPE_STRING:
751 shell_print(sh, "%s : %s", path, (char *)ri->data_ptr);
752 break;
753 case LWM2M_RES_TYPE_U8:
754 case LWM2M_RES_TYPE_S8:
755 case LWM2M_RES_TYPE_BOOL:
756 shell_print(sh, "%s : %u", path, *(uint8_t *)ri->data_ptr);
757 break;
758 case LWM2M_RES_TYPE_U16:
759 case LWM2M_RES_TYPE_S16:
760 shell_print(sh, "%s : %u", path, *(uint16_t *)ri->data_ptr);
761 break;
762 case LWM2M_RES_TYPE_U32:
763 case LWM2M_RES_TYPE_S32:
764 shell_print(sh, "%s : %u", path, *(uint32_t *)ri->data_ptr);
765 break;
766 case LWM2M_RES_TYPE_S64:
767 case LWM2M_RES_TYPE_TIME:
768 shell_print(sh, "%s : %lld", path,
769 *(int64_t *)ri->data_ptr);
770 break;
771 case LWM2M_RES_TYPE_FLOAT:
772 shell_print(sh, "%s : %lf", path, *(double *)ri->data_ptr);
773 break;
774 case LWM2M_RES_TYPE_OPAQUE:
775 shell_print(sh, "%s : OPAQUE(%hu/%hu)", path, ri->data_len,
776 ri->max_data_len);
777 break;
778 }
779 }
780 }
781 }
782 return 0;
783 }
784
print_object(const struct shell * sh,struct lwm2m_engine_obj * obj)785 static int print_object(const struct shell *sh, struct lwm2m_engine_obj *obj)
786 {
787 if (!obj) {
788 return -ENOEXEC;
789 }
790 struct lwm2m_engine_obj_inst *oi = next_engine_obj_inst(obj->obj_id, -1);
791
792 for (int i = 0; i < obj->instance_count; i++) {
793 print_object_instance(sh, oi);
794 oi = next_engine_obj_inst(obj->obj_id, oi->obj_inst_id);
795 }
796 return 0;
797 }
798
print_all_objs(const struct shell * sh)799 static int print_all_objs(const struct shell *sh)
800 {
801 struct lwm2m_engine_obj *obj;
802
803 SYS_SLIST_FOR_EACH_CONTAINER(lwm2m_engine_obj_list(), obj, node) {
804 print_object(sh, obj);
805 }
806 return 0;
807 }
808
cmd_ls(const struct shell * sh,size_t argc,char ** argv)809 static int cmd_ls(const struct shell *sh, size_t argc, char **argv)
810 {
811 struct lwm2m_obj_path path;
812 int ret;
813
814 if (argc < 2) {
815 return print_all_objs(sh);
816 }
817
818 ret = lwm2m_string_to_path(argv[1], &path, '/');
819 if (ret < 0) {
820 return -ENOEXEC;
821 }
822
823 if (path.level == LWM2M_PATH_LEVEL_NONE) {
824 return print_all_objs(sh);
825 } else if (path.level == LWM2M_PATH_LEVEL_OBJECT) {
826 struct lwm2m_engine_obj *obj = lwm2m_engine_get_obj(&path);
827
828 return print_object(sh, obj);
829 } else if (path.level == LWM2M_PATH_LEVEL_OBJECT_INST) {
830 struct lwm2m_engine_obj_inst *oi = lwm2m_engine_get_obj_inst(&path);
831
832 return print_object_instance(sh, oi);
833 } else if (path.level == LWM2M_PATH_LEVEL_RESOURCE) {
834 return cmd_read(sh, argc, argv);
835 }
836 return -ENOEXEC;
837 }
838
839 SHELL_STATIC_SUBCMD_SET_CREATE(
840 sub_lwm2m,
841 SHELL_COND_CMD_ARG(CONFIG_LWM2M_VERSION_1_1, send, NULL,
842 LWM2M_HELP_SEND, cmd_send, 1, 9),
843 SHELL_CMD_ARG(exec, NULL, LWM2M_HELP_EXEC, cmd_exec, 2, 1),
844 SHELL_CMD_ARG(read, NULL, LWM2M_HELP_READ, cmd_read, 2, 1),
845 SHELL_CMD_ARG(write, NULL, LWM2M_HELP_WRITE, cmd_write, 3, 1),
846 SHELL_CMD_ARG(create, NULL, LWM2M_HELP_CREATE, cmd_create, 2, 0),
847 SHELL_CMD_ARG(delete, NULL, LWM2M_HELP_DELETE, cmd_delete, 2, 0),
848 SHELL_CMD_ARG(cache, NULL, LWM2M_HELP_CACHE, cmd_cache, 3, 0),
849 SHELL_CMD_ARG(start, NULL, LWM2M_HELP_START, cmd_start, 2, 2),
850 SHELL_CMD_ARG(stop, NULL, LWM2M_HELP_STOP, cmd_stop, 1, 1),
851 SHELL_CMD_ARG(update, NULL, LWM2M_HELP_UPDATE, cmd_update, 1, 0),
852 SHELL_CMD_ARG(pause, NULL, LWM2M_HELP_PAUSE, cmd_pause, 1, 0),
853 SHELL_CMD_ARG(resume, NULL, LWM2M_HELP_RESUME, cmd_resume, 1, 0),
854 SHELL_CMD_ARG(lock, NULL, LWM2M_HELP_LOCK, cmd_lock, 1, 0),
855 SHELL_CMD_ARG(unlock, NULL, LWM2M_HELP_UNLOCK, cmd_unlock, 1, 0),
856 SHELL_CMD_ARG(obs, NULL, LWM2M_HELP_OBSERV, cmd_observations, 1, 0),
857 SHELL_CMD_ARG(ls, NULL, LWM2M_HELP_LS, cmd_ls, 1, 1),
858 SHELL_SUBCMD_SET_END);
859 SHELL_COND_CMD_ARG_REGISTER(CONFIG_LWM2M_SHELL, lwm2m, &sub_lwm2m,
860 LWM2M_HELP_CMD, NULL, 1, 0);
861