/* * 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 LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include #include #include #include #include #include #include #include #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: 2:[] */ 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);