| /* |
| * 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 |