blob: 0f060b51fdfeb7496a58c0958a23be5004d4bf18 [file] [log] [blame]
/*
* Copyright (c) 2018-2021 mcumgr authors
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/util.h>
#include <assert.h>
#include <string.h>
#include <zephyr.h>
#include <debug/object_tracing.h>
#include <kernel_structs.h>
#include <util/mcumgr_util.h>
#include "tinycbor/cbor.h"
#include "cborattr/cborattr.h"
#include "mgmt/mgmt.h"
#include "os_mgmt/os_mgmt.h"
#include "os_mgmt/os_mgmt_impl.h"
/**
* Command handler: os echo
*/
#if CONFIG_OS_MGMT_ECHO
static int
os_mgmt_echo(struct mgmt_ctxt *ctxt)
{
char echo_buf[CONFIG_OS_MGMT_ECHO_LENGTH + 1];
CborError err;
const struct cbor_attr_t attrs[2] = {
[0] = {
.attribute = "d",
.type = CborAttrTextStringType,
.addr.string = echo_buf,
.nodefault = 1,
.len = CONFIG_OS_MGMT_ECHO_LENGTH,
},
[1] = {
.attribute = NULL
}
};
echo_buf[0] = '\0';
err = cbor_read_object(&ctxt->it, attrs);
if (err != 0) {
return mgmt_err_from_cbor(err);
}
echo_buf[sizeof(echo_buf) - 1] = '\0';
err = cbor_encode_text_stringz(&ctxt->encoder, "r") ||
cbor_encode_text_stringz(&ctxt->encoder, echo_buf);
return (err == 0) ? 0 : MGMT_ERR_ENOMEM;
}
#endif
#if CONFIG_OS_MGMT_TASKSTAT
#if defined(CONFIG_OS_MGMT_TASKSTAT_USE_THREAD_NAME_FOR_NAME)
static inline CborError
os_mgmt_taskstat_encode_thread_name(struct CborEncoder *encoder, int idx,
const struct k_thread *thread)
{
size_t name_len = strlen(thread->name);
ARG_UNUSED(idx);
if (name_len > CONFIG_OS_MGMT_TASKSTAT_THREAD_NAME_LEN) {
name_len = CONFIG_OS_MGMT_TASKSTAT_THREAD_NAME_LEN;
}
return cbor_encode_text_string(encoder, thread->name, name_len);
}
#else
static inline CborError
os_mgmt_taskstat_encode_thread_name(struct CborEncoder *encoder, int idx,
const struct k_thread *thread)
{
CborError err = 0;
char thread_name[CONFIG_OS_MGMT_TASKSTAT_THREAD_NAME_LEN + 1];
#if defined(CONFIG_OS_MGMT_TASKSTAT_USE_THREAD_PRIO_FOR_NAME)
idx = (int)thread->base.prio;
#elif defined(CONFIG_OS_MGMT_TASKSTAT_USE_THREAD_IDX_FOR_NAME)
ARG_UNUSED(thread);
#else
#error Unsupported option for taskstat thread name
#endif
ll_to_s(idx, sizeof(thread_name) - 1, thread_name);
thread_name[sizeof(thread_name) - 1] = 0;
err = cbor_encode_text_stringz(encoder, thread_name);
return err;
}
#endif
static inline int
os_mgmt_taskstat_encode_stack_info(struct CborEncoder *thread_map,
const struct k_thread *thread)
{
#ifdef CONFIG_OS_MGMT_TASKSTAT_STACK_INFO
ssize_t stack_size = 0;
ssize_t stack_used = 0;
int err = 0;
#ifdef CONFIG_THREAD_STACK_INFO
stack_size = thread->stack_info.size / 4;
#ifdef CONFIG_INIT_STACKS
unsigned int stack_unused;
if (k_thread_stack_space_get(thread, &stack_unused) == 0) {
stack_used = (thread->stack_info.size - stack_unused) / 4;
}
#endif /* CONFIG_INIT_STACKS */
#endif /* CONFIG_THREAD_STACK_INFO */
err = cbor_encode_text_stringz(thread_map, "stksiz") ||
cbor_encode_uint(thread_map, stack_size) ||
cbor_encode_text_stringz(thread_map, "stkuse") ||
cbor_encode_uint(thread_map, stack_used);
return err;
#else
return 0;
#endif /* CONFIG_OS_MGMT_TASKSTAT_STACK_INFO */
}
static inline int
os_mgmt_taskstat_encode_unsupported(struct CborEncoder *thread_map)
{
int err = 0;
if (!IS_ENABLED(CONFIG_OS_MGMT_TASKSTAT_ONLY_SUPPORTED_STATS)) {
err = cbor_encode_text_stringz(thread_map, "runtime") ||
cbor_encode_uint(thread_map, 0) ||
cbor_encode_text_stringz(thread_map, "cswcnt") ||
cbor_encode_uint(thread_map, 0) ||
cbor_encode_text_stringz(thread_map, "last_checkin") ||
cbor_encode_uint(thread_map, 0) ||
cbor_encode_text_stringz(thread_map, "next_checkin") ||
cbor_encode_uint(thread_map, 0);
} else {
ARG_UNUSED(thread_map);
}
return err;
}
static inline int
os_mgmt_taskstat_encode_priority(struct CborEncoder *thread_map, const struct k_thread *thread)
{
return IS_ENABLED(CONFIG_OS_MGMT_TASKSTAT_SIGNED_PRIORITY) ?
cbor_encode_int(thread_map, (int)thread->base.prio) :
cbor_encode_uint(thread_map, (unsigned int)thread->base.prio & 0xff);
}
/**
* Encodes a single taskstat entry.
*/
static int
os_mgmt_taskstat_encode_one(struct CborEncoder *encoder, int idx, const struct k_thread *thread)
{
CborEncoder thread_map;
CborError err;
/*
* Threads are sent as map where thread name is key and value is map
* of thread parameters
*/
err = os_mgmt_taskstat_encode_thread_name(encoder, idx, thread) ||
cbor_encoder_create_map(encoder, &thread_map, CborIndefiniteLength) ||
cbor_encode_text_stringz(&thread_map, "prio") ||
os_mgmt_taskstat_encode_priority(&thread_map, thread) ||
cbor_encode_text_stringz(&thread_map, "tid") ||
cbor_encode_uint(&thread_map, idx) ||
cbor_encode_text_stringz(&thread_map, "state") ||
cbor_encode_uint(&thread_map, thread->base.thread_state) ||
os_mgmt_taskstat_encode_stack_info(&thread_map, thread) ||
os_mgmt_taskstat_encode_unsupported(&thread_map) ||
cbor_encoder_close_container(encoder, &thread_map);
return err;
}
/**
* Command handler: os taskstat
*/
static int os_mgmt_taskstat_read(struct mgmt_ctxt *ctxt)
{
struct CborEncoder tasks_map;
const struct k_thread *thread;
int err;
int thread_idx;
err = cbor_encode_text_stringz(&ctxt->encoder, "tasks") ||
cbor_encoder_create_map(&ctxt->encoder, &tasks_map, CborIndefiniteLength);
/* If could not create map just exit here */
if (err != 0) {
return MGMT_ERR_ENOMEM;
}
/* Iterate the list of tasks, encoding each. */
thread = SYS_THREAD_MONITOR_HEAD;
thread_idx = 0;
while (thread != NULL) {
err = os_mgmt_taskstat_encode_one(&tasks_map, thread_idx, thread);
if (err != 0) {
break;
}
thread = SYS_THREAD_MONITOR_NEXT(thread);
++thread_idx;
}
err |= cbor_encoder_close_container(&ctxt->encoder, &tasks_map);
return (err != 0) ? MGMT_ERR_ENOMEM : 0;
}
#endif /* CONFIG_OS_MGMT_TASKSTAT */
/**
* Command handler: os reset
*/
static int
os_mgmt_reset(struct mgmt_ctxt *ctxt)
{
return os_mgmt_impl_reset(CONFIG_OS_MGMT_RESET_MS);
}
static const struct mgmt_handler os_mgmt_group_handlers[] = {
#if CONFIG_OS_MGMT_ECHO
[OS_MGMT_ID_ECHO] = {
os_mgmt_echo, os_mgmt_echo
},
#endif
#if CONFIG_OS_MGMT_TASKSTAT
[OS_MGMT_ID_TASKSTAT] = {
os_mgmt_taskstat_read, NULL
},
#endif
[OS_MGMT_ID_RESET] = {
NULL, os_mgmt_reset
},
};
#define OS_MGMT_GROUP_SZ ARRAY_SIZE(os_mgmt_group_handlers)
static struct mgmt_group os_mgmt_group = {
.mg_handlers = os_mgmt_group_handlers,
.mg_handlers_count = OS_MGMT_GROUP_SZ,
.mg_group_id = MGMT_GROUP_ID_OS,
};
void
os_mgmt_register_group(void)
{
mgmt_register_group(&os_mgmt_group);
}
void
os_mgmt_module_init(void)
{
os_mgmt_register_group();
}