203 lines
4.5 KiB
C
203 lines
4.5 KiB
C
|
/*
|
||
|
* Copyright (c) 2024 Basalte bv
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*/
|
||
|
|
||
|
#include <zephyr/shell/shell_rpmsg.h>
|
||
|
|
||
|
SHELL_RPMSG_DEFINE(shell_transport_rpmsg);
|
||
|
SHELL_DEFINE(shell_rpmsg, CONFIG_SHELL_PROMPT_RPMSG, &shell_transport_rpmsg,
|
||
|
CONFIG_SHELL_BACKEND_RPMSG_LOG_MESSAGE_QUEUE_SIZE,
|
||
|
CONFIG_SHELL_BACKEND_RPMSG_LOG_MESSAGE_QUEUE_TIMEOUT, SHELL_FLAG_OLF_CRLF);
|
||
|
|
||
|
static int rpmsg_shell_cb(struct rpmsg_endpoint *ept, void *data,
|
||
|
size_t len, uint32_t src, void *priv)
|
||
|
{
|
||
|
const struct shell_transport *transport = (const struct shell_transport *)priv;
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
struct shell_rpmsg_rx rx;
|
||
|
|
||
|
if (len == 0) {
|
||
|
return RPMSG_ERR_NO_BUFF;
|
||
|
}
|
||
|
|
||
|
rx.data = data;
|
||
|
rx.len = len;
|
||
|
if (k_msgq_put(&sh_rpmsg->rx_q, &rx, K_NO_WAIT) != 0) {
|
||
|
return RPMSG_ERR_NO_MEM;
|
||
|
}
|
||
|
|
||
|
rpmsg_hold_rx_buffer(ept, data);
|
||
|
sh_rpmsg->shell_handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_rpmsg->shell_context);
|
||
|
|
||
|
return RPMSG_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static int uninit(const struct shell_transport *transport)
|
||
|
{
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
|
||
|
if (!sh_rpmsg->ready) {
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
rpmsg_destroy_ept(&sh_rpmsg->ept);
|
||
|
sh_rpmsg->ready = false;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int init(const struct shell_transport *transport,
|
||
|
const void *config,
|
||
|
shell_transport_handler_t evt_handler,
|
||
|
void *context)
|
||
|
{
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
struct rpmsg_device *rdev;
|
||
|
int ret;
|
||
|
|
||
|
if (sh_rpmsg->ready) {
|
||
|
return -EALREADY;
|
||
|
}
|
||
|
|
||
|
if (config == NULL) {
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
rdev = (struct rpmsg_device *)config;
|
||
|
|
||
|
k_msgq_init(&sh_rpmsg->rx_q, (char *)sh_rpmsg->rx_buf, sizeof(struct shell_rpmsg_rx),
|
||
|
CONFIG_SHELL_RPMSG_MAX_RX);
|
||
|
|
||
|
ret = rpmsg_create_ept(&sh_rpmsg->ept, rdev, CONFIG_SHELL_RPMSG_SERVICE_NAME,
|
||
|
CONFIG_SHELL_RPMSG_SRC_ADDR, CONFIG_SHELL_RPMSG_DST_ADDR,
|
||
|
rpmsg_shell_cb, NULL);
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
sh_rpmsg->ept.priv = (void *)transport;
|
||
|
|
||
|
sh_rpmsg->shell_handler = evt_handler;
|
||
|
sh_rpmsg->shell_context = context;
|
||
|
sh_rpmsg->ready = true;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int enable(const struct shell_transport *transport, bool blocking)
|
||
|
{
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
|
||
|
if (!sh_rpmsg->ready) {
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
sh_rpmsg->blocking = blocking;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int write(const struct shell_transport *transport,
|
||
|
const void *data, size_t length, size_t *cnt)
|
||
|
{
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
int ret;
|
||
|
|
||
|
*cnt = 0;
|
||
|
|
||
|
if (!sh_rpmsg->ready) {
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
if (sh_rpmsg->blocking) {
|
||
|
ret = rpmsg_send(&sh_rpmsg->ept, data, (int)length);
|
||
|
} else {
|
||
|
ret = rpmsg_trysend(&sh_rpmsg->ept, data, (int)length);
|
||
|
}
|
||
|
|
||
|
/* Set TX ready in any case, as we have no way to recover otherwise */
|
||
|
sh_rpmsg->shell_handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_rpmsg->shell_context);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
*cnt = (size_t)ret;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int read(const struct shell_transport *transport,
|
||
|
void *data, size_t length, size_t *cnt)
|
||
|
{
|
||
|
struct shell_rpmsg *sh_rpmsg = (struct shell_rpmsg *)transport->ctx;
|
||
|
struct shell_rpmsg_rx *rx = &sh_rpmsg->rx_cur;
|
||
|
size_t read_len;
|
||
|
bool release = true;
|
||
|
|
||
|
if (!sh_rpmsg->ready) {
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
/* Check if we still have pending data */
|
||
|
if (rx->data == NULL) {
|
||
|
int ret = k_msgq_get(&sh_rpmsg->rx_q, rx, K_NO_WAIT);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
rx->data = NULL;
|
||
|
goto no_data;
|
||
|
}
|
||
|
|
||
|
__ASSERT_NO_MSG(rx->len > 0);
|
||
|
sh_rpmsg->rx_consumed = 0;
|
||
|
}
|
||
|
|
||
|
__ASSERT_NO_MSG(rx->len > sh_rpmsg->rx_consumed);
|
||
|
read_len = rx->len - sh_rpmsg->rx_consumed;
|
||
|
if (read_len > length) {
|
||
|
read_len = length;
|
||
|
release = false;
|
||
|
}
|
||
|
|
||
|
*cnt = read_len;
|
||
|
memcpy(data, &((char *)rx->data)[sh_rpmsg->rx_consumed], read_len);
|
||
|
|
||
|
if (release) {
|
||
|
rpmsg_release_rx_buffer(&sh_rpmsg->ept, rx->data);
|
||
|
rx->data = NULL;
|
||
|
} else {
|
||
|
sh_rpmsg->rx_consumed += read_len;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
no_data:
|
||
|
*cnt = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const struct shell_transport_api shell_rpmsg_transport_api = {
|
||
|
.init = init,
|
||
|
.uninit = uninit,
|
||
|
.enable = enable,
|
||
|
.read = read,
|
||
|
.write = write,
|
||
|
};
|
||
|
|
||
|
int shell_backend_rpmsg_init_transport(struct rpmsg_device *rpmsg_dev)
|
||
|
{
|
||
|
bool log_backend = CONFIG_SHELL_RPMSG_INIT_LOG_LEVEL > 0;
|
||
|
uint32_t level = (CONFIG_SHELL_RPMSG_INIT_LOG_LEVEL > LOG_LEVEL_DBG) ?
|
||
|
CONFIG_LOG_MAX_LEVEL : CONFIG_SHELL_RPMSG_INIT_LOG_LEVEL;
|
||
|
static const struct shell_backend_config_flags cfg_flags =
|
||
|
SHELL_DEFAULT_BACKEND_CONFIG_FLAGS;
|
||
|
|
||
|
return shell_init(&shell_rpmsg, rpmsg_dev, cfg_flags, log_backend, level);
|
||
|
}
|
||
|
|
||
|
const struct shell *shell_backend_rpmsg_get_ptr(void)
|
||
|
{
|
||
|
return &shell_rpmsg;
|
||
|
}
|