In case lwm2m_get_engine_obj_field() fails to find a corresponding object field when iterating resource instances, simply skip that resource instance when printing object instance contents. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
861 lines
21 KiB
C
861 lines
21 KiB
C
/*
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#define LOG_MODULE_NAME net_lwm2m_shell
|
|
#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/net/lwm2m.h>
|
|
#include <zephyr/shell/shell.h>
|
|
#include <zephyr/sys/crc.h>
|
|
|
|
#include <lwm2m_engine.h>
|
|
#include <lwm2m_util.h>
|
|
|
|
#define LWM2M_HELP_CMD "LwM2M commands"
|
|
#define LWM2M_HELP_SEND "send PATHS\nLwM2M SEND operation\n"
|
|
#define LWM2M_HELP_EXEC "exec PATH [PARAM]\nExecute a resource\n"
|
|
#define LWM2M_HELP_READ "read PATH [OPTIONS]\nRead value from LwM2M resource\n" \
|
|
"-x \tRead value as hex stream (default)\n" \
|
|
"-s \tRead value as string\n" \
|
|
"-b \tRead value as bool (1/0)\n" \
|
|
"-uX\tRead value as uintX_t\n" \
|
|
"-sX\tRead value as intX_t\n" \
|
|
"-f \tRead value as float\n" \
|
|
"-t \tRead value as time_t\n" \
|
|
"-crc32\tCalculate CRC32 of the content\n"
|
|
#define LWM2M_HELP_WRITE "write PATH [OPTIONS] VALUE\nWrite into LwM2M resource\n" \
|
|
"-s \tWrite value as string (default)\n" \
|
|
"-b \tWrite value as bool\n" \
|
|
"-uX\tWrite value as uintX_t\n" \
|
|
"-sX\tWrite value as intX_t\n" \
|
|
"-f \tWrite value as float\n" \
|
|
"-t \tWrite value as time_t\n"
|
|
#define LWM2M_HELP_CREATE "create PATH\nCreate object or resource instance\n"
|
|
#define LWM2M_HELP_DELETE "delete PATH\nDelete object or resource instance\n"
|
|
#define LWM2M_HELP_START "start EP_NAME [BOOTSTRAP FLAG]\n" \
|
|
"Start the LwM2M RD (Registration / Discovery) Client\n" \
|
|
"-b \tSet the bootstrap flag (default 0)\n"
|
|
#define LWM2M_HELP_STOP "stop [OPTIONS]\nStop the LwM2M RD (De-register) Client\n" \
|
|
"-f \tForce close the connection\n"
|
|
#define LWM2M_HELP_UPDATE "Trigger Registration Update of the LwM2M RD Client\n"
|
|
#define LWM2M_HELP_PAUSE "LwM2M engine thread pause"
|
|
#define LWM2M_HELP_RESUME "LwM2M engine thread resume"
|
|
#define LWM2M_HELP_LOCK "Lock the LwM2M registry"
|
|
#define LWM2M_HELP_UNLOCK "Unlock the LwM2M registry"
|
|
#define LWM2M_HELP_OBSERV "List observations"
|
|
#define LWM2M_HELP_CACHE "cache PATH NUM\nEnable data cache for resource\n" \
|
|
"PATH is LwM2M path\n" \
|
|
"NUM how many elements to cache\n"
|
|
#define LWM2M_HELP_LS "ls [PATH]\nList objects, instances, resources\n"
|
|
|
|
static void send_cb(enum lwm2m_send_status status)
|
|
{
|
|
LOG_INF("SEND status: %d", status);
|
|
}
|
|
|
|
static int cmd_send(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
int ret = 0;
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
int path_cnt = argc - 1;
|
|
struct lwm2m_obj_path lwm2m_path_list[CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE];
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (argc < 2) {
|
|
shell_error(sh, "no path(s)");
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (path_cnt > CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE) {
|
|
return -E2BIG;
|
|
}
|
|
|
|
for (int i = 0; i < path_cnt; i++) {
|
|
const char *p = argv[1 + i];
|
|
/* translate path -> path_obj */
|
|
ret = lwm2m_string_to_path(p, &lwm2m_path_list[i], '/');
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = lwm2m_send_cb(ctx, lwm2m_path_list, path_cnt, send_cb);
|
|
|
|
if (ret < 0) {
|
|
shell_error(sh, "can't do send operation, request failed (%d)", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_exec(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
const char *pathstr = argv[1];
|
|
struct lwm2m_obj_path path;
|
|
int ret = lwm2m_string_to_path(pathstr, &path, '/'); /* translate path -> path_obj */
|
|
|
|
if (ret < 0) {
|
|
shell_error(sh, "Illegal path (PATH %s)", pathstr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
struct lwm2m_engine_res *res = lwm2m_engine_get_res(&path);
|
|
|
|
if (res == NULL) {
|
|
shell_error(sh, "Resource not found");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!res->execute_cb) {
|
|
shell_error(sh, "No execute callback!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* 0: exec, 1:<path> 2:[<param>] */
|
|
char *param = (argc == 3) ? argv[2] : NULL;
|
|
size_t param_len = param ? strlen(param) + 1 : 0;
|
|
|
|
ret = res->execute_cb(path.obj_inst_id, param, param_len);
|
|
if (ret < 0) {
|
|
shell_error(sh, "returned (err %d)", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_read(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (argc < 2) {
|
|
shell_error(sh, "no arguments or path(s)");
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
const char *dtype = "-x"; /* default */
|
|
const char *pathstr = argv[1];
|
|
int ret = 0;
|
|
struct lwm2m_obj_path path;
|
|
|
|
ret = lwm2m_string_to_path(pathstr, &path, '/');
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (argc > 2) { /* read + path + options(data type) */
|
|
dtype = argv[2];
|
|
}
|
|
if (strcmp(dtype, "-x") == 0) {
|
|
const char *buff;
|
|
uint16_t buff_len = 0;
|
|
|
|
ret = lwm2m_get_res_buf(&path, (void **)&buff,
|
|
NULL, &buff_len, NULL);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_hexdump(sh, buff, buff_len);
|
|
} else if (strcmp(dtype, "-crc32") == 0) {
|
|
const char *buff;
|
|
uint16_t buff_len = 0;
|
|
|
|
ret = lwm2m_get_res_buf(&path, (void **)&buff,
|
|
NULL, &buff_len, NULL);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
|
|
uint32_t crc = crc32_ieee(buff, buff_len);
|
|
|
|
shell_print(sh, "%u", crc);
|
|
} else if (strcmp(dtype, "-s") == 0) {
|
|
const char *buff;
|
|
uint16_t buff_len = 0;
|
|
|
|
ret = lwm2m_get_res_buf(&path, (void **)&buff,
|
|
NULL, &buff_len, NULL);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%.*s", buff_len, buff);
|
|
} else if (strcmp(dtype, "-s8") == 0) {
|
|
int8_t temp = 0;
|
|
|
|
ret = lwm2m_get_s8(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-s16") == 0) {
|
|
int16_t temp = 0;
|
|
|
|
ret = lwm2m_get_s16(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-s32") == 0) {
|
|
int32_t temp = 0;
|
|
|
|
ret = lwm2m_get_s32(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-s64") == 0) {
|
|
int64_t temp = 0;
|
|
|
|
ret = lwm2m_get_s64(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%lld", temp);
|
|
} else if (strcmp(dtype, "-u8") == 0) {
|
|
uint8_t temp = 0;
|
|
|
|
ret = lwm2m_get_u8(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-u16") == 0) {
|
|
uint16_t temp = 0;
|
|
|
|
ret = lwm2m_get_u16(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-u32") == 0) {
|
|
uint32_t temp = 0;
|
|
|
|
ret = lwm2m_get_u32(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-f") == 0) {
|
|
double temp = 0;
|
|
|
|
ret = lwm2m_get_f64(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%f", temp);
|
|
} else if (strcmp(dtype, "-b") == 0) {
|
|
bool temp;
|
|
|
|
ret = lwm2m_get_bool(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%d", temp);
|
|
} else if (strcmp(dtype, "-t") == 0) {
|
|
time_t temp;
|
|
|
|
ret = lwm2m_get_time(&path, &temp);
|
|
if (ret != 0) {
|
|
goto out;
|
|
}
|
|
shell_print(sh, "%lld", temp);
|
|
} else {
|
|
shell_error(sh, "can't recognize data type %s", dtype);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
out:
|
|
shell_error(sh, "can't do read operation, request failed (err %d)", ret);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int cmd_write(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (argc < 3) {
|
|
shell_error(sh, "no arguments or path(s)");
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
|
|
int ret = 0;
|
|
const char *pathstr = argv[1];
|
|
const char *dtype;
|
|
char *value;
|
|
struct lwm2m_obj_path path;
|
|
|
|
ret = lwm2m_string_to_path(pathstr, &path, '/');
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (argc == 4) { /* write path options value */
|
|
dtype = argv[2];
|
|
value = argv[3];
|
|
} else { /* write path value */
|
|
dtype = "-s";
|
|
value = argv[2];
|
|
}
|
|
|
|
if (strcmp(dtype, "-s") == 0) {
|
|
ret = lwm2m_set_string(&path, value);
|
|
} else if (strcmp(dtype, "-f") == 0) {
|
|
double new = 0;
|
|
|
|
ret = lwm2m_atof(value, &new); /* Convert string -> float */
|
|
if (ret == 0) {
|
|
ret = lwm2m_set_f64(&path, new);
|
|
}
|
|
} else { /* All the types using stdlib funcs*/
|
|
char *e;
|
|
|
|
if (strcmp(dtype, "-s8") == 0) {
|
|
ret = lwm2m_set_s8(&path, strtol(value, &e, 10));
|
|
} else if (strcmp(dtype, "-s16") == 0) {
|
|
ret = lwm2m_set_s16(&path, strtol(value, &e, 10));
|
|
} else if (strcmp(dtype, "-s32") == 0) {
|
|
ret = lwm2m_set_s32(&path, strtol(value, &e, 10));
|
|
} else if (strcmp(dtype, "-s64") == 0) {
|
|
ret = lwm2m_set_s64(&path, strtoll(value, &e, 10));
|
|
} else if (strcmp(dtype, "-u8") == 0) {
|
|
ret = lwm2m_set_u8(&path, strtoul(value, &e, 10));
|
|
} else if (strcmp(dtype, "-u16") == 0) {
|
|
ret = lwm2m_set_u16(&path, strtoul(value, &e, 10));
|
|
} else if (strcmp(dtype, "-u32") == 0) {
|
|
ret = lwm2m_set_u32(&path, strtoul(value, &e, 10));
|
|
} else if (strcmp(dtype, "-b") == 0) {
|
|
ret = lwm2m_set_bool(&path, strtoul(value, &e, 10));
|
|
} else if (strcmp(dtype, "-t") == 0) {
|
|
ret = lwm2m_set_time(&path, strtoll(value, &e, 10));
|
|
} else {
|
|
shell_error(sh, "can't recognize data type %s",
|
|
dtype);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
if (*e != '\0') {
|
|
shell_error(sh, "Invalid number: %s", value);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (ret < 0) {
|
|
shell_error(
|
|
sh,
|
|
"can't do write operation, request failed (err %d)",
|
|
ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_create_or_delete(const struct shell *sh, bool delete, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_obj_path path;
|
|
int ret;
|
|
|
|
if (argc < 2) {
|
|
shell_error(sh, "No object ID given");
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = lwm2m_string_to_path(argv[1], &path, '/');
|
|
if (ret < 0) {
|
|
shell_error(sh, "failed to read path (%d)", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (delete) {
|
|
switch (path.level) {
|
|
case LWM2M_PATH_LEVEL_RESOURCE_INST:
|
|
ret = lwm2m_delete_res_inst(&path);
|
|
break;
|
|
case LWM2M_PATH_LEVEL_OBJECT_INST:
|
|
ret = lwm2m_delete_object_inst(&path);
|
|
break;
|
|
default:
|
|
return -ENOEXEC;
|
|
}
|
|
} else {
|
|
switch (path.level) {
|
|
case LWM2M_PATH_LEVEL_RESOURCE_INST:
|
|
ret = lwm2m_create_res_inst(&path);
|
|
break;
|
|
case LWM2M_PATH_LEVEL_OBJECT_INST:
|
|
ret = lwm2m_create_object_inst(&path);
|
|
break;
|
|
default:
|
|
return -ENOEXEC;
|
|
}
|
|
}
|
|
|
|
if (ret < 0) {
|
|
shell_error(sh, "operation failed, %d", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_create(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
return cmd_create_or_delete(sh, false, argc, argv);
|
|
}
|
|
|
|
static int cmd_delete(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
return cmd_create_or_delete(sh, true, argc, argv);
|
|
}
|
|
|
|
static int cmd_start(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
uint32_t bootstrap_flag = 0;
|
|
|
|
if (argc == 3) {
|
|
shell_error(sh, "no specifier or value");
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
} else if (argc == 4) {
|
|
if (strcmp(argv[2], "-b") != 0) {
|
|
shell_error(sh, "unknown specifier %s", argv[2]);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
|
|
char *e;
|
|
|
|
bootstrap_flag = strtol(argv[3], &e, 10);
|
|
if (*e != '\0') {
|
|
shell_error(sh, "Invalid number: %s", argv[3]);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
int ret = lwm2m_rd_client_start(ctx, argv[1], bootstrap_flag,
|
|
ctx->event_cb, ctx->observe_cb);
|
|
if (ret < 0) {
|
|
shell_error(
|
|
sh,
|
|
"can't do start operation, request failed (err %d)",
|
|
ret);
|
|
return -ENOEXEC;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_stop(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
bool forcefully = true;
|
|
|
|
if (argc == 2) {
|
|
if (strcmp(argv[1], "-f") != 0) {
|
|
shell_error(sh, "can't recognize specifier %s",
|
|
argv[1]);
|
|
shell_help(sh);
|
|
return -EINVAL;
|
|
}
|
|
forcefully = false;
|
|
}
|
|
int ret = lwm2m_rd_client_stop(ctx, ctx->event_cb, forcefully);
|
|
|
|
if (ret < 0) {
|
|
shell_error(
|
|
sh,
|
|
"can't do stop operation, request failed (err %d)",
|
|
ret);
|
|
return -ENOEXEC;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_update(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
struct lwm2m_ctx *ctx = lwm2m_rd_client_ctx();
|
|
|
|
if (!ctx) {
|
|
shell_error(sh, "no lwm2m context yet");
|
|
return -ENOEXEC;
|
|
}
|
|
lwm2m_rd_client_update();
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_pause(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
ARG_UNUSED(sh);
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
return lwm2m_engine_pause();
|
|
}
|
|
|
|
static int cmd_resume(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
ARG_UNUSED(sh);
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
return lwm2m_engine_resume();
|
|
}
|
|
|
|
static int cmd_lock(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
ARG_UNUSED(sh);
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
lwm2m_registry_lock();
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_unlock(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
ARG_UNUSED(sh);
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
lwm2m_registry_unlock();
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_cache(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
#if (K_HEAP_MEM_POOL_SIZE > 0)
|
|
int rc;
|
|
int elems;
|
|
struct lwm2m_time_series_elem *cache;
|
|
struct lwm2m_obj_path obj_path;
|
|
|
|
if (argc != 3) {
|
|
shell_error(sh, "wrong parameters");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* translate path -> path_obj */
|
|
rc = lwm2m_string_to_path(argv[1], &obj_path, '/');
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
if (obj_path.level < 3) {
|
|
shell_error(sh, "Path string not correct");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (lwm2m_cache_entry_get_by_object(&obj_path)) {
|
|
shell_error(sh, "Cache already enabled for %s", argv[1]);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
elems = atoi(argv[2]);
|
|
if (elems < 1) {
|
|
shell_error(sh, "Size must be 1 or more (given %d)", elems);
|
|
return -EINVAL;
|
|
}
|
|
|
|
cache = k_malloc(sizeof(struct lwm2m_time_series_elem) * elems);
|
|
if (!cache) {
|
|
shell_error(sh, "Out of memory");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
rc = lwm2m_enable_cache(&obj_path, cache, elems);
|
|
if (rc) {
|
|
shell_error(sh, "lwm2m_enable_cache(%u/%u/%u/%u, %p, %d) returned %d",
|
|
obj_path.obj_id, obj_path.obj_inst_id, obj_path.res_id,
|
|
obj_path.res_inst_id, cache, elems, rc);
|
|
k_free(cache);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
shell_error(sh, "No heap configured");
|
|
return -ENOEXEC;
|
|
#endif
|
|
}
|
|
|
|
static void shell_print_attr(const struct shell *sh, void *ref)
|
|
{
|
|
struct lwm2m_attr *attr = NULL;
|
|
bool found;
|
|
|
|
for (uint8_t type = 0; type < NR_LWM2M_ATTR; type++) {
|
|
found = false;
|
|
while ((attr = lwm2m_engine_get_next_attr(ref, attr)) != NULL) {
|
|
if (attr->type == type) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
switch (type) {
|
|
case LWM2M_ATTR_PMIN:
|
|
/* fall through */
|
|
case LWM2M_ATTR_PMAX:
|
|
shell_fprintf(sh, SHELL_NORMAL, "%10u", attr->int_val);
|
|
break;
|
|
case LWM2M_ATTR_GT:
|
|
/* fall through */
|
|
case LWM2M_ATTR_LT:
|
|
/* fall through */
|
|
case LWM2M_ATTR_STEP:
|
|
shell_fprintf(sh, SHELL_NORMAL, "%10f", attr->float_val);
|
|
break;
|
|
}
|
|
} else {
|
|
shell_fprintf(sh, SHELL_NORMAL, "%10s", "");
|
|
}
|
|
}
|
|
}
|
|
|
|
static int cmd_observations(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
char buf[LWM2M_MAX_PATH_STR_SIZE];
|
|
struct lwm2m_obj_path_list *o_p;
|
|
struct observe_node *obs;
|
|
uint32_t i = 0, path_i;
|
|
struct lwm2m_ctx *ctx;
|
|
void *ref;
|
|
int ret;
|
|
|
|
ctx = lwm2m_rd_client_ctx();
|
|
if (ctx == NULL) {
|
|
shell_error(sh, "no lwm2m context yet\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
shell_fprintf(sh, SHELL_INFO, " # %10s %18s", "composite", "path");
|
|
for (i = 0; i < NR_LWM2M_ATTR; i++) {
|
|
shell_fprintf(sh, SHELL_INFO, "%10s", lwm2m_attr_to_str(i));
|
|
}
|
|
shell_print(sh, "");
|
|
|
|
lwm2m_registry_lock();
|
|
i = 0;
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) {
|
|
shell_fprintf(sh, SHELL_NORMAL, "%2u %10c ", i, obs->composite ? 'y' : 'n');
|
|
path_i = 0;
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&obs->path_list, o_p, node) {
|
|
if (path_i > 0) {
|
|
shell_fprintf(sh, SHELL_NORMAL, "%14s", "");
|
|
}
|
|
shell_fprintf(sh, SHELL_NORMAL, "%-18s",
|
|
lwm2m_path_log_buf(buf, &o_p->path));
|
|
ret = lwm2m_get_path_reference_ptr(NULL, &o_p->path, &ref);
|
|
if (ret < 0) {
|
|
continue;
|
|
}
|
|
shell_print_attr(sh, ref);
|
|
path_i++;
|
|
shell_print(sh, "");
|
|
}
|
|
i++;
|
|
|
|
}
|
|
lwm2m_registry_unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_object_instance(const struct shell *sh, struct lwm2m_engine_obj_inst *oi)
|
|
{
|
|
struct lwm2m_engine_obj *obj;
|
|
|
|
if (!oi) {
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
obj = oi->obj;
|
|
|
|
for (int i = 0; i < oi->resource_count; i++) {
|
|
struct lwm2m_engine_res *re = &oi->resources[i];
|
|
|
|
for (int j = 0; j < re->res_inst_count; j++) {
|
|
struct lwm2m_engine_res_inst *ri = &re->res_instances[j];
|
|
|
|
if (ri->data_ptr && ri->data_len > 0 &&
|
|
ri->res_inst_id != RES_INSTANCE_NOT_CREATED) {
|
|
struct lwm2m_engine_obj_field *field =
|
|
lwm2m_get_engine_obj_field(obj, re->res_id);
|
|
char path[LWM2M_MAX_PATH_STR_SIZE];
|
|
|
|
if (field == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (re->multi_res_inst) {
|
|
snprintf(path, sizeof(path), "%hu/%hu/%hu/%hu", obj->obj_id,
|
|
oi->obj_inst_id, re->res_id, ri->res_inst_id);
|
|
} else {
|
|
snprintf(path, sizeof(path), "%hu/%hu/%hu", obj->obj_id,
|
|
oi->obj_inst_id, re->res_id);
|
|
}
|
|
switch (field->data_type) {
|
|
case LWM2M_RES_TYPE_STRING:
|
|
shell_print(sh, "%s : %s", path, (char *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_U8:
|
|
case LWM2M_RES_TYPE_S8:
|
|
case LWM2M_RES_TYPE_BOOL:
|
|
shell_print(sh, "%s : %u", path, *(uint8_t *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_U16:
|
|
case LWM2M_RES_TYPE_S16:
|
|
shell_print(sh, "%s : %u", path, *(uint16_t *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_U32:
|
|
case LWM2M_RES_TYPE_S32:
|
|
shell_print(sh, "%s : %u", path, *(uint32_t *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_S64:
|
|
case LWM2M_RES_TYPE_TIME:
|
|
shell_print(sh, "%s : %lld", path,
|
|
*(int64_t *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_FLOAT:
|
|
shell_print(sh, "%s : %lf", path, *(double *)ri->data_ptr);
|
|
break;
|
|
case LWM2M_RES_TYPE_OPAQUE:
|
|
shell_print(sh, "%s : OPAQUE(%hu/%hu)", path, ri->data_len,
|
|
ri->max_data_len);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int print_object(const struct shell *sh, struct lwm2m_engine_obj *obj)
|
|
{
|
|
if (!obj) {
|
|
return -ENOEXEC;
|
|
}
|
|
struct lwm2m_engine_obj_inst *oi = next_engine_obj_inst(obj->obj_id, -1);
|
|
|
|
for (int i = 0; i < obj->instance_count; i++) {
|
|
print_object_instance(sh, oi);
|
|
oi = next_engine_obj_inst(obj->obj_id, oi->obj_inst_id);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int print_all_objs(const struct shell *sh)
|
|
{
|
|
struct lwm2m_engine_obj *obj;
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(lwm2m_engine_obj_list(), obj, node) {
|
|
print_object(sh, obj);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_ls(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct lwm2m_obj_path path;
|
|
int ret;
|
|
|
|
if (argc < 2) {
|
|
return print_all_objs(sh);
|
|
}
|
|
|
|
ret = lwm2m_string_to_path(argv[1], &path, '/');
|
|
if (ret < 0) {
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (path.level == LWM2M_PATH_LEVEL_NONE) {
|
|
return print_all_objs(sh);
|
|
} else if (path.level == LWM2M_PATH_LEVEL_OBJECT) {
|
|
struct lwm2m_engine_obj *obj = lwm2m_engine_get_obj(&path);
|
|
|
|
return print_object(sh, obj);
|
|
} else if (path.level == LWM2M_PATH_LEVEL_OBJECT_INST) {
|
|
struct lwm2m_engine_obj_inst *oi = lwm2m_engine_get_obj_inst(&path);
|
|
|
|
return print_object_instance(sh, oi);
|
|
} else if (path.level == LWM2M_PATH_LEVEL_RESOURCE) {
|
|
return cmd_read(sh, argc, argv);
|
|
}
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(
|
|
sub_lwm2m,
|
|
SHELL_COND_CMD_ARG(CONFIG_LWM2M_VERSION_1_1, send, NULL,
|
|
LWM2M_HELP_SEND, cmd_send, 1, 9),
|
|
SHELL_CMD_ARG(exec, NULL, LWM2M_HELP_EXEC, cmd_exec, 2, 1),
|
|
SHELL_CMD_ARG(read, NULL, LWM2M_HELP_READ, cmd_read, 2, 1),
|
|
SHELL_CMD_ARG(write, NULL, LWM2M_HELP_WRITE, cmd_write, 3, 1),
|
|
SHELL_CMD_ARG(create, NULL, LWM2M_HELP_CREATE, cmd_create, 2, 0),
|
|
SHELL_CMD_ARG(delete, NULL, LWM2M_HELP_DELETE, cmd_delete, 2, 0),
|
|
SHELL_CMD_ARG(cache, NULL, LWM2M_HELP_CACHE, cmd_cache, 3, 0),
|
|
SHELL_CMD_ARG(start, NULL, LWM2M_HELP_START, cmd_start, 2, 2),
|
|
SHELL_CMD_ARG(stop, NULL, LWM2M_HELP_STOP, cmd_stop, 1, 1),
|
|
SHELL_CMD_ARG(update, NULL, LWM2M_HELP_UPDATE, cmd_update, 1, 0),
|
|
SHELL_CMD_ARG(pause, NULL, LWM2M_HELP_PAUSE, cmd_pause, 1, 0),
|
|
SHELL_CMD_ARG(resume, NULL, LWM2M_HELP_RESUME, cmd_resume, 1, 0),
|
|
SHELL_CMD_ARG(lock, NULL, LWM2M_HELP_LOCK, cmd_lock, 1, 0),
|
|
SHELL_CMD_ARG(unlock, NULL, LWM2M_HELP_UNLOCK, cmd_unlock, 1, 0),
|
|
SHELL_CMD_ARG(obs, NULL, LWM2M_HELP_OBSERV, cmd_observations, 1, 0),
|
|
SHELL_CMD_ARG(ls, NULL, LWM2M_HELP_LS, cmd_ls, 1, 1),
|
|
SHELL_SUBCMD_SET_END);
|
|
SHELL_COND_CMD_ARG_REGISTER(CONFIG_LWM2M_SHELL, lwm2m, &sub_lwm2m,
|
|
LWM2M_HELP_CMD, NULL, 1, 0);
|