mgmt: mcumgr: lib: cmd: os: Add device information handler

The device information handler can be used to retrieve information about
the configuration of the configured device such as board name, board
revision, firmware version and build date.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
Jamie McCrae 2022-10-17 10:27:08 +01:00 committed by Fabio Baltieri
parent ae97971a61
commit 656a910b1e
6 changed files with 571 additions and 0 deletions

View file

@ -22,6 +22,66 @@ extern "C" {
#define OS_MGMT_ID_DATETIME_STR 4
#define OS_MGMT_ID_RESET 5
#define OS_MGMT_ID_MCUMGR_PARAMS 6
#define OS_MGMT_ID_INFO 7
/* Bitmask values used by the os info command handler. Note that the width of this variable is
* 32-bits, allowing 32 flags, custom user-level implementations should start at
* OS_MGMT_INFO_FORMAT_USER_CUSTOM_START and reference that directly as additional format
* specifiers might be added to this list in the future.
*/
enum os_mgmt_info_formats {
OS_MGMT_INFO_FORMAT_KERNEL_NAME = BIT(0),
OS_MGMT_INFO_FORMAT_NODE_NAME = BIT(1),
OS_MGMT_INFO_FORMAT_KERNEL_RELEASE = BIT(2),
OS_MGMT_INFO_FORMAT_KERNEL_VERSION = BIT(3),
OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME = BIT(4),
OS_MGMT_INFO_FORMAT_MACHINE = BIT(5),
OS_MGMT_INFO_FORMAT_PROCESSOR = BIT(6),
OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM = BIT(7),
OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM = BIT(8),
OS_MGMT_INFO_FORMAT_USER_CUSTOM_START = BIT(9),
};
/* Structure provided in the MGMT_EVT_OP_OS_MGMT_INFO_CHECK notification callback */
struct os_mgmt_info_check {
/* Input format string from the mcumgr client */
struct zcbor_string *format;
/* Bitmask of values specifying which outputs should be present */
uint32_t *format_bitmask;
/* Number of valid format characters parsed, must be incremented by 1 for each valid
* character
*/
uint16_t *valid_formats;
/* Needs to be set to true if the OS name is being provided by external code */
bool *custom_os_name;
};
/* Structure provided in the MGMT_EVT_OP_OS_MGMT_INFO_APPEND notification callback */
struct os_mgmt_info_append {
/* The format bitmask from the processed commands, the bits should be cleared once
* processed, note that if all_format_specified is specified, the corrisponding bits here
* will not be set
*/
uint32_t *format_bitmask;
/* Will be true if the all 'a' specifier was provided */
bool all_format_specified;
/* The output buffer which the responses should be appended to. If prior_output is true, a
* space must be added prior to the output response
*/
uint8_t *output;
/* The current size of the output response in the output buffer, must be updated to be the
* size of the output response after appending data
*/
uint16_t *output_length;
/* The size of the output buffer, including null terminator character, if the output
* response would exceed this size, the function must abort and return false to return a
* memory error to the client
*/
uint16_t buffer_size;
/* If there has been prior output, must be set to true if a response has been output */
bool *prior_output;
};
/**
* @brief Registers the OS management command handler group.

View file

@ -146,6 +146,12 @@ enum os_mgmt_group_events {
/** Callback when a reset command has been received. */
MGMT_EVT_OP_OS_MGMT_RESET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 0),
/** Callback when an info command is processed, data is os_mgmt_info_check. */
MGMT_EVT_OP_OS_MGMT_INFO_CHECK = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 1),
/** Callback when an info command needs to output data, data is os_mgmt_info_append. */
MGMT_EVT_OP_OS_MGMT_INFO_APPEND = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 2),
/** Used to enable all os_mgmt_group events. */
MGMT_EVT_OP_OS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_OS),
};

View file

@ -20,3 +20,10 @@ if (CONFIG_REBOOT)
endif()
target_link_libraries(mgmt_mcumgr INTERFACE mgmt_mcumgr_grp_os)
if(DEFINED CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME)
set(MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR ${PROJECT_BINARY_DIR}/os_mgmt_auto)
file(MAKE_DIRECTORY ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR})
file(WRITE ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c "/* Auto generated file, do not edit */\n#include <stdint.h>\nuint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME = __TIMESTAMP__;")
zephyr_library_sources(${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c)
endif()

View file

@ -123,4 +123,39 @@ config OS_MGMT_ECHO
config OS_MGMT_MCUMGR_PARAMS
bool "MCUMGR Parameters retrieval command"
config MCUMGR_GRP_OS_INFO
bool "Support for info command"
help
Can be used similarly to the unix/linux uname command for retrieving system information
including kernel version, processor architecture and board name.
if MCUMGR_GRP_OS_INFO
config MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE
int "Maximum response size for info command"
default 256
range 32 512
help
The maximum size of the response to the info command, will use a stack buffer of this
size to store the data in. If the output response is too big then the output will not be
present in the response, which will just contain the result code (rc) of memory error.
config MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
bool "Custom info hooks"
depends on MCUMGR_MGMT_NOTIFICATION_HOOKS
help
Supports adding custom command/character processing to the info command by using
registered callbacks. Data can be appended to the struct provided in the callback.
config MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
bool "Show build date and time"
help
Will allow returning the build date and time of the firmware by using the info with
format option 'b' (will also be returned with all responses by using 'a').
Note: This will invalidate reproducible builds of the firmware as it will embed the
build date/time in the output firmware image.
endif
endif

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2022 Zephyr authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_OS_MGMT_PROCESSOR_
#define H_OS_MGMT_PROCESSOR_
#ifdef __cplusplus
extern "C" {
#endif
/**
* Processor name (used in uname output command)
* Will be unknown if processor type is not listed
* (List extracted from /cmake/gcc-m-cpu.cmake)
*/
#if defined(CONFIG_ARM)
#if defined(CONFIG_CPU_CORTEX_M0)
#define PROCESSOR_NAME "cortex-m0"
#elif defined(CONFIG_CPU_CORTEX_M0PLUS)
#define PROCESSOR_NAME "cortex-m0plus"
#elif defined(CONFIG_CPU_CORTEX_M1)
#define PROCESSOR_NAME "cortex-m1"
#elif defined(CONFIG_CPU_CORTEX_M3)
#define PROCESSOR_NAME "cortex-m3"
#elif defined(CONFIG_CPU_CORTEX_M4)
#define PROCESSOR_NAME "cortex-m4"
#elif defined(CONFIG_CPU_CORTEX_M7)
#define PROCESSOR_NAME "cortex-m7"
#elif defined(CONFIG_CPU_CORTEX_M23)
#define PROCESSOR_NAME "cortex-m23"
#elif defined(CONFIG_CPU_CORTEX_M33)
#if defined(CONFIG_ARMV8_M_DSP)
#define PROCESSOR_NAME "cortex-m33"
#else
#define PROCESSOR_NAME "cortex-m33+nodsp"
#endif
#elif defined(CONFIG_CPU_CORTEX_M55)
#if defined(CONFIG_ARMV8_1_M_MVEF)
#define PROCESSOR_NAME "cortex-m55"
#elif defined(CONFIG_ARMV8_1_M_MVEI)
#define PROCESSOR_NAME "cortex-m55+nomve.fp"
#elif defined(CONFIG_ARMV8_M_DSP)
#define PROCESSOR_NAME "cortex-m55+nomve"
#else
#define PROCESSOR_NAME "cortex-m55+nodsp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R4)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#define PROCESSOR_NAME "cortex-r4f"
#else
#define PROCESSOR_NAME "cortex-r4"
#endif
#elif defined(CONFIG_CPU_CORTEX_R5)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r5+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r5"
#endif
#else
#define PROCESSOR_NAME "cortex-r5+nofp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R7)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r7+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r7"
#endif
#else
#define PROCESSOR_NAME "cortex-r7+nofp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R52)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r52+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r52"
#endif
#else
#define PROCESSOR_NAME "cortex-r52"
#endif
#elif defined(CONFIG_CPU_CORTEX_A9)
#define PROCESSOR_NAME "cortex-a9"
#endif
#elif defined(CONFIG_ARM64)
#if defined(CONFIG_CPU_CORTEX_A53)
#define PROCESSOR_NAME "cortex-a53"
#if defined(CONFIG_CPU_CORTEX_A55)
#define PROCESSOR_NAME "cortex-a55"
#elif defined(CONFIG_CPU_CORTEX_A72)
#define PROCESSOR_NAME "cortex-a72"
#elif defined(CONFIG_CPU_CORTEX_R82)
#define PROCESSOR_NAME "armv8.4-a+nolse"
#endif
#endif
#elif defined(CONFIG_ARC)
#if defined(CONFIG_CPU_EM4_FPUS)
#define PROCESSOR_NAME "em4_fpus"
#elif defined(CONFIG_CPU_EM4_DMIPS)
#define PROCESSOR_NAME "em4_dmips"
#elif defined(CONFIG_CPU_EM4_FPUDA)
#define PROCESSOR_NAME "em4_fpuda"
#elif defined(CONFIG_CPU_HS3X)
#define PROCESSOR_NAME "archs"
#elif defined(CONFIG_CPU_HS5X)
#define PROCESSOR_NAME "hs5x"
#elif defined(CONFIG_CPU_HS6X)
#define PROCESSOR_NAME "hs6x"
#elif defined(CONFIG_CPU_EM4)
#define PROCESSOR_NAME "arcem"
#elif defined(CONFIG_CPU_EM6)
#define PROCESSOR_NAME "arcem"
#endif
#elif defined(CONFIG_X86)
#if defined(CONFIG_X86_64)
#define PROCESSOR_NAME "x86_64"
#else
#define PROCESSOR_NAME "x86"
#endif
#elif defined(CONFIG_RISCV)
#define PROCESSOR_NAME "riscv"
#endif
#ifndef PROCESSOR_NAME
#warning "Processor type could not be determined"
#define PROCESSOR_NAME "unknown"
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_OS_MGMT_PROCESSOR_ */

View file

@ -28,6 +28,18 @@
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
#include <stdio.h>
#include <version.h>
#include <os_mgmt_processor.h>
#include <mgmt/mcumgr/util/zcbor_bulk.h>
#if defined(CONFIG_NET_HOSTNAME_ENABLE)
#include <zephyr/net/hostname.h>
#elif defined(CONFIG_BT)
#include <zephyr/bluetooth/bluetooth.h>
#endif
#endif
#ifdef CONFIG_REBOOT
static void os_mgmt_reset_work_handler(struct k_work *work);
static void os_mgmt_reset_cb(struct k_timer *timer);
@ -54,6 +66,19 @@ struct thread_iterator_info {
};
#endif
/* Specifies what the "all" ('a') of info parameter shows */
#define OS_MGMT_INFO_FORMAT_ALL \
OS_MGMT_INFO_FORMAT_KERNEL_NAME | OS_MGMT_INFO_FORMAT_NODE_NAME | \
OS_MGMT_INFO_FORMAT_KERNEL_RELEASE | OS_MGMT_INFO_FORMAT_KERNEL_VERSION | \
(IS_ENABLED(CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME) ? \
OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME : 0) | \
OS_MGMT_INFO_FORMAT_MACHINE | OS_MGMT_INFO_FORMAT_PROCESSOR | \
OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM | OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
extern uint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME;
#endif
/**
* Command handler: os echo
*/
@ -318,6 +343,302 @@ os_mgmt_mcumgr_params(struct smp_streamer *ctxt)
}
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
/**
* Command handler: os info
*/
static int os_mgmt_info(struct smp_streamer *ctxt)
{
struct zcbor_string format = { 0 };
uint8_t output[CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE] = { 0 };
zcbor_state_t *zse = ctxt->writer->zs;
zcbor_state_t *zsd = ctxt->reader->zs;
uint32_t format_bitmask = 0;
bool prior_output = false;
size_t i = 0;
size_t decoded;
bool custom_os_name = false;
int rc;
uint16_t output_length = 0;
uint16_t valid_formats = 0;
struct zcbor_map_decode_key_val fs_info_decode[] = {
ZCBOR_MAP_DECODE_KEY_VAL(format, zcbor_tstr_decode, &format),
};
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
struct os_mgmt_info_check check_data = {
.format = &format,
.format_bitmask = &format_bitmask,
.valid_formats = &valid_formats,
.custom_os_name = &custom_os_name,
};
struct os_mgmt_info_append append_data = {
.format_bitmask = &format_bitmask,
.all_format_specified = false,
.output = output,
.output_length = &output_length,
.buffer_size = sizeof(output),
.prior_output = &prior_output,
};
#endif
if (zcbor_map_decode_bulk(zsd, fs_info_decode, ARRAY_SIZE(fs_info_decode), &decoded)) {
return MGMT_ERR_EINVAL;
}
/* Process all input characters in format value */
while (i < format.len) {
switch (format.value[i]) {
case 'a': {
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
append_data.all_format_specified = true;
#endif
format_bitmask = OS_MGMT_INFO_FORMAT_ALL;
++valid_formats;
break;
}
case 's': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_NAME;
++valid_formats;
break;
}
case 'n': {
format_bitmask |= OS_MGMT_INFO_FORMAT_NODE_NAME;
++valid_formats;
break;
}
case 'r': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
++valid_formats;
break;
}
case 'v': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
++valid_formats;
break;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
case 'b': {
format_bitmask |= OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
++valid_formats;
break;
}
#endif
case 'm': {
format_bitmask |= OS_MGMT_INFO_FORMAT_MACHINE;
++valid_formats;
break;
}
case 'p': {
format_bitmask |= OS_MGMT_INFO_FORMAT_PROCESSOR;
++valid_formats;
break;
}
case 'i': {
format_bitmask |= OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
++valid_formats;
break;
}
case 'o': {
format_bitmask |= OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
++valid_formats;
break;
}
default: {
break;
}
}
++i;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
/* Run callbacks to see if any additional handlers will add options */
(void)mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_CHECK, &check_data,
sizeof(check_data));
#endif
if (valid_formats != format.len) {
/* A provided format specifier is not valid */
return MGMT_ERR_EINVAL;
} else if (format_bitmask == 0) {
/* If no value is provided, use default of kernel name */
format_bitmask = OS_MGMT_INFO_FORMAT_KERNEL_NAME;
}
/* Process all options in order and append to output string */
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_NAME) {
rc = snprintf(output, (sizeof(output) - output_length), "Zephyr");
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_NODE_NAME) {
/* Get hostname, if enabled */
#if defined(CONFIG_NET_HOSTNAME_ENABLE)
/* From network */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), net_hostname_get());
#elif defined(CONFIG_BT)
/* From Bluetooth */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), bt_get_name());
#else
/* Not available */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sunknown", (prior_output == true ? " " : ""));
#endif
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_NODE_NAME;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_RELEASE) {
#ifdef BUILD_VERSION
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), STRINGIFY(BUILD_VERSION));
#else
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sunknown", (prior_output == true ? " " : ""));
#endif
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_VERSION) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), KERNEL_VERSION_STRING);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
if (format_bitmask & OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"),
MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
}
#endif
if (format_bitmask & OS_MGMT_INFO_FORMAT_MACHINE) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), CONFIG_ARCH);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_MACHINE;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_PROCESSOR) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), PROCESSOR_NAME);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_PROCESSOR;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s%s%s" : "%s%s%s"), CONFIG_BOARD,
(sizeof(CONFIG_BOARD_REVISION) > 1 ? "@" : ""),
CONFIG_BOARD_REVISION);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
}
/* If custom_os_name is not set (by extension code) then return the default OS name of
* Zephyr
*/
if (format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM && custom_os_name == false) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sZephyr", (prior_output == true ? " " : ""));
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
/* Call custom handler command for additional output/processing */
rc = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_APPEND, &append_data,
sizeof(append_data));
if (rc != MGMT_ERR_EOK) {
return rc;
}
#endif
if (zcbor_tstr_put_lit(zse, "output") &&
zcbor_tstr_encode_ptr(zse, output, output_length)) {
return MGMT_ERR_EOK;
}
fail:
return MGMT_ERR_EMSGSIZE;
}
#endif
static const struct mgmt_handler os_mgmt_group_handlers[] = {
#ifdef CONFIG_OS_MGMT_ECHO
[OS_MGMT_ID_ECHO] = {
@ -339,6 +660,11 @@ static const struct mgmt_handler os_mgmt_group_handlers[] = {
os_mgmt_mcumgr_params, NULL
},
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
[OS_MGMT_ID_INFO] = {
os_mgmt_info, NULL
},
#endif
};
#define OS_MGMT_GROUP_SZ ARRAY_SIZE(os_mgmt_group_handlers)