blob: 0bd174d1c97812669db7ed5c7d4368b353ef593e [file] [log] [blame]
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zcbor_common.h>
#include <zcbor_decode.h>
#include <zcbor_encode.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/net/buf.h>
#include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
#include <zephyr/mgmt/mcumgr/smp/smp.h>
#include <zephyr/mgmt/mcumgr/smp/smp_client.h>
#include <zephyr/mgmt/mcumgr/transport/smp.h>
#include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h>
#include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h>
#include <mgmt/mcumgr/util/zcbor_bulk.h>
#include <mgmt/mcumgr/transport/smp_internal.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(mcumgr_grp_os_client, CONFIG_MCUMGR_GRP_OS_CLIENT_LOG_LEVEL);
static struct os_mgmt_client *active_client;
static K_SEM_DEFINE(mcummgr_os_client_grp_sem, 0, 1);
static K_MUTEX_DEFINE(mcummgr_os_client_grp_mutex);
void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client)
{
client->smp_client = smp_client;
}
#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_RESET
static int reset_res_fn(struct net_buf *nb, void *user_data)
{
if (!nb) {
active_client->status = MGMT_ERR_ETIMEOUT;
} else {
active_client->status = MGMT_ERR_EOK;
}
k_sem_give(user_data);
return 0;
}
int os_mgmt_client_reset(struct os_mgmt_client *client)
{
struct net_buf *nb;
int rc;
k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER);
active_client = client;
/* allocate buffer */
nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS,
OS_MGMT_ID_RESET, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
if (!nb) {
active_client->status = MGMT_ERR_ENOMEM;
goto end;
}
k_sem_reset(&mcummgr_os_client_grp_sem);
rc = smp_client_send_cmd(active_client->smp_client, nb, reset_res_fn,
&mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
if (rc) {
active_client->status = rc;
smp_packet_free(nb);
goto end;
}
/* Wait for process end update event */
k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER);
end:
rc = active_client->status;
active_client = NULL;
k_mutex_unlock(&mcummgr_os_client_grp_mutex);
return rc;
}
#endif /* CONFIG_MCUMGR_GRP_OS_CLIENT_RESET */
#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO
static int echo_res_fn(struct net_buf *nb, void *user_data)
{
struct zcbor_string val = {0};
zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
size_t decoded;
bool ok;
int rc;
struct zcbor_map_decode_key_val echo_response[] = {
ZCBOR_MAP_DECODE_KEY_DECODER("r", zcbor_tstr_decode, &val)
};
if (!nb) {
LOG_ERR("Echo command timeout");
active_client->status = MGMT_ERR_ETIMEOUT;
goto end;
}
/* Init ZCOR decoder state */
zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0);
ok = zcbor_map_decode_bulk(zsd, echo_response, ARRAY_SIZE(echo_response), &decoded) == 0;
if (!ok) {
active_client->status = MGMT_ERR_ECORRUPT;
goto end;
}
active_client->status = MGMT_ERR_EOK;
end:
rc = active_client->status;
k_sem_give(user_data);
return rc;
}
int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string, size_t max_len)
{
struct net_buf *nb;
int rc;
bool ok;
zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS];
k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER);
active_client = client;
nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, OS_MGMT_ID_ECHO,
MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
if (!nb) {
rc = active_client->status = MGMT_ERR_ENOMEM;
goto end;
}
zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0);
ok = zcbor_map_start_encode(zse, 2) &&
zcbor_tstr_put_lit(zse, "d") &&
zcbor_tstr_put_term(zse, echo_string, max_len) &&
zcbor_map_end_encode(zse, 2);
if (!ok) {
smp_packet_free(nb);
rc = active_client->status = MGMT_ERR_ENOMEM;
goto end;
}
nb->len = zse->payload - nb->data;
LOG_DBG("Echo Command packet len %d", nb->len);
k_sem_reset(&mcummgr_os_client_grp_sem);
rc = smp_client_send_cmd(active_client->smp_client, nb, echo_res_fn,
&mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
if (rc) {
smp_packet_free(nb);
} else {
k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER);
/* Take response status */
rc = active_client->status;
}
end:
active_client = NULL;
k_mutex_unlock(&mcummgr_os_client_grp_mutex);
return rc;
}
#endif