diff --git a/drivers/note/CMakeLists.txt b/drivers/note/CMakeLists.txt index e2651cd9813..ff3807bcaeb 100644 --- a/drivers/note/CMakeLists.txt +++ b/drivers/note/CMakeLists.txt @@ -40,5 +40,13 @@ if(CONFIG_DRIVERS_NOTESNAP) list(APPEND SRCS notesnap_driver.c) endif() +if(CONFIG_DRIVERS_NOTERPMSG_SERVER) + list(APPEND SRCS noterpmsg_server.c) +endif() + +if(CONFIG_DRIVERS_NOTERPMSG) + list(APPEND SRCS noterpmsg_driver.c) +endif() + target_sources(drivers PRIVATE ${SRCS}) target_include_directories(drivers PRIVATE ${NUTTX_DIR}/sched) diff --git a/drivers/note/Kconfig b/drivers/note/Kconfig index 49248bd121c..a9b296862dd 100644 --- a/drivers/note/Kconfig +++ b/drivers/note/Kconfig @@ -106,4 +106,40 @@ config DRIVERS_NOTESNAP_NBUFFERS Number of last scheduling information buffers. endif +config DRIVERS_NOTERPMSG_SERVER + bool "Enable RPMSG server for NOTE" + default n + depends on RPTUN + ---help--- + Use rpmsg to receive message from remote proc. + +config DRIVERS_NOTERPMSG + bool "Note to RPMSG" + depends on RPTUN + depends on SCHED_WORKQUEUE + default n + ---help--- + Use the rpmsg as a Note output device, send message to remote proc. + +if DRIVERS_NOTERPMSG + +config DRIVERS_NOTERPMSG_BUFSIZE + int "Note RPMSG client buffer size" + default 1024 + ---help--- + The size of the client buffer (in bytes) + +config DRIVERS_NOTERPMSG_SERVER_NAME + string "The name of Note Rpmsg Server" + default "ap" + ---help--- + The proc name of rpmsg server. Client sends message to + specified name of remote proc. + +config DRIVERS_NOTERPMSG_WORK_DELAY + int "NOTE RPMSG work delay(ms)" + default 100 + +endif + endif # DRIVERS_NOTE diff --git a/drivers/note/Make.defs b/drivers/note/Make.defs index 096063aa42a..02a14ee1c9a 100644 --- a/drivers/note/Make.defs +++ b/drivers/note/Make.defs @@ -41,5 +41,13 @@ ifeq ($(CONFIG_DRIVERS_NOTESNAP),y) CSRCS += notesnap_driver.c endif +ifeq ($(CONFIG_DRIVERS_NOTERPMSG_SERVER),y) + CSRCS += noterpmsg_server.c +endif + +ifeq ($(CONFIG_DRIVERS_NOTERPMSG),y) + CSRCS += noterpmsg_driver.c +endif + DEPPATH += --dep-path note VPATH += :note diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index 74141665420..25ae513dec4 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -43,6 +43,7 @@ #include #include "sched/sched.h" +#include "noterpmsg.h" /**************************************************************************** * Pre-processor Definitions @@ -193,6 +194,9 @@ FAR static struct note_driver_s * #endif #ifdef CONFIG_DRIVERS_NOTELOG &g_notelog_driver, +#endif +#ifdef CONFIG_DRIVERS_NOTERPMSG + (FAR struct note_driver_s *)&g_noterpmsg_driver, #endif NULL }; diff --git a/drivers/note/note_initialize.c b/drivers/note/note_initialize.c index 5d507289255..475dafa444f 100644 --- a/drivers/note/note_initialize.c +++ b/drivers/note/note_initialize.c @@ -31,6 +31,8 @@ #include #include +#include "noterpmsg.h" + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -121,5 +123,23 @@ int note_initialize(void) } #endif +#ifdef CONFIG_DRIVERS_NOTERPMSG_SERVER + ret = noterpmsg_server_init(); + if (ret < 0) + { + serr("noterpmsg_server_init failed %d\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_DRIVERS_NOTERPMSG + ret = noterpmsg_init(); + if (ret < 0) + { + serr("noterpmsg_init failed %d\n", ret); + return ret; + } +#endif + return ret; } diff --git a/drivers/note/noterpmsg.h b/drivers/note/noterpmsg.h new file mode 100644 index 00000000000..3eb2af1ed0f --- /dev/null +++ b/drivers/note/noterpmsg.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * drivers/note/noterpmsg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_NOTE_NOTERPMSG_H +#define __DRIVERS_NOTE_NOTERPMSG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +#define NOTERPMSG_EPT_NAME "rpmsg-note" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_DRIVERS_NOTERPMSG +extern struct noterpmsg_driver_s g_noterpmsg_driver; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_DRIVERS_NOTERPMSG_SERVER +int noterpmsg_server_init(void); +#endif + +#ifdef CONFIG_DRIVERS_NOTERPMSG +int noterpmsg_init(void); +#endif + +#endif /* __DRIVERS_NOTE_NOTERPMSG_H */ diff --git a/drivers/note/noterpmsg_driver.c b/drivers/note/noterpmsg_driver.c new file mode 100644 index 00000000000..67fbbcc9d41 --- /dev/null +++ b/drivers/note/noterpmsg_driver.c @@ -0,0 +1,286 @@ +/**************************************************************************** + * drivers/note/noterpmsg_driver.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "noterpmsg.h" + +/**************************************************************************** + * Pre-processor definitions + ****************************************************************************/ + +#define NOTE_RPMSG_WORK_DELAY MSEC2TICK(CONFIG_DRIVERS_NOTERPMSG_WORK_DELAY) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct noterpmsg_driver_s +{ + struct note_driver_s driver; + volatile size_t head; + volatile size_t tail; + uint8_t buffer[CONFIG_DRIVERS_NOTERPMSG_BUFSIZE]; + struct work_s work; + struct rpmsg_endpoint ept; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void noterpmsg_add(FAR struct note_driver_s *driver, + FAR const void *note, size_t notelen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct note_driver_ops_s g_noterpmsg_ops = +{ + noterpmsg_add +}; + +struct noterpmsg_driver_s g_noterpmsg_driver = +{ + {&g_noterpmsg_ops}, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline size_t noterpmsg_next(FAR struct noterpmsg_driver_s *drv, + size_t pos, size_t offset) +{ + pos += offset; + if (pos >= CONFIG_DRIVERS_NOTERPMSG_BUFSIZE) + { + pos -= CONFIG_DRIVERS_NOTERPMSG_BUFSIZE; + } + + return pos; +} + +static inline size_t noterpmsg_length(FAR struct noterpmsg_driver_s *drv) +{ + size_t head = drv->head; + size_t tail = drv->tail; + + if (tail > head) + { + head += CONFIG_DRIVERS_NOTERPMSG_BUFSIZE; + } + + return head - tail; +} + +static inline void noterpmsg_remove(FAR struct noterpmsg_driver_s *drv) +{ + size_t tail = drv->tail; + uint8_t notelen = drv->buffer[tail]; + + DEBUGASSERT(notelen <= noterpmsg_length(drv)); + drv->tail = noterpmsg_next(drv, tail, notelen); +} + +static bool noterpmsg_transfer(FAR struct noterpmsg_driver_s *drv, + bool wait) +{ + for (; ; ) + { + FAR uint8_t *buffer; + uint32_t space; + size_t len; + + len = noterpmsg_length(drv); + if (len == 0) + { + return true; + } + + buffer = rpmsg_get_tx_payload_buffer(&drv->ept, &space, wait); + if (buffer == NULL) + { + return false; + } + + if (space < len) + { + /* Find the len of large entire note data */ + + size_t pos = drv->tail; + uint8_t notelen = drv->buffer[pos]; + + len = 0; + while (len + notelen <= space) + { + pos = noterpmsg_next(drv, pos, notelen); + len += notelen; + notelen = drv->buffer[pos]; + } + } + + space = CONFIG_DRIVERS_NOTERPMSG_BUFSIZE - drv->tail; + space = space < len ? space : len; + + memcpy(buffer, drv->buffer + drv->tail, space); + memcpy(buffer + space, drv->buffer, len - space); + + rpmsg_send_nocopy(&drv->ept, buffer, len); + drv->tail = noterpmsg_next(drv, drv->tail, len); + } +} + +static void noterpmsg_work(FAR void *priv) +{ + FAR struct noterpmsg_driver_s *drv = priv; + irqstate_t flags = enter_critical_section(); + + if (!noterpmsg_transfer(drv, false)) + { + work_queue(HPWORK, &drv->work, noterpmsg_work, drv, + NOTE_RPMSG_WORK_DELAY); + } + + leave_critical_section(flags); +} + +static void noterpmsg_add(FAR struct note_driver_s *driver, + FAR const void *note, size_t notelen) +{ + FAR struct noterpmsg_driver_s *drv = + (FAR struct noterpmsg_driver_s *)driver; + irqstate_t flags; + size_t space; + + flags = enter_critical_section(); + + space = CONFIG_DRIVERS_NOTERPMSG_BUFSIZE - noterpmsg_length(drv); + if (space < notelen) + { + if (!up_interrupt_context() && !sched_idletask()) + { + noterpmsg_transfer(drv, true); + } + else + { + /* Overwrite */ + + do + { + noterpmsg_remove(drv); + space = CONFIG_DRIVERS_NOTERPMSG_BUFSIZE - + noterpmsg_length(drv); + } + while (space < notelen); + } + } + + space = CONFIG_DRIVERS_NOTERPMSG_BUFSIZE - drv->head; + space = space < notelen ? space : notelen; + + memcpy(drv->buffer + drv->head, note, space); + memcpy(drv->buffer, note + space, notelen - space); + + drv->head = noterpmsg_next(drv, drv->head, notelen); + + if (work_available(&drv->work)) + { + work_queue(HPWORK, &drv->work, noterpmsg_work, drv, + NOTE_RPMSG_WORK_DELAY); + } + + leave_critical_section(flags); +} + +static int noterpmsg_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, uint32_t src, + FAR void *priv) +{ + return 0; +} + +static void noterpmsg_device_created(FAR struct rpmsg_device *rdev, + FAR void *priv) +{ + FAR struct noterpmsg_driver_s *drv = priv; + int ret; + + if (strcmp(CONFIG_DRIVERS_NOTERPMSG_SERVER_NAME, + rpmsg_get_cpuname(rdev)) == 0) + { + drv->ept.priv = drv; + + ret = rpmsg_create_ept(&drv->ept, rdev, NOTERPMSG_EPT_NAME, + RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, + noterpmsg_ept_cb, NULL); + if (ret >= 0) + { + work_queue(HPWORK, &drv->work, noterpmsg_work, drv, 0); + } + } +} + +static void noterpmsg_device_destroy(FAR struct rpmsg_device *rdev, + FAR void *priv) +{ + FAR struct noterpmsg_driver_s *drv = priv; + + if (strcmp(CONFIG_DRIVERS_NOTERPMSG_SERVER_NAME, + rpmsg_get_cpuname(rdev)) == 0) + { + rpmsg_destroy_ept(&drv->ept); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: noterpmsg_init + * + * Description: + * Register a rmpsg channel to note. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero on success. A negated errno value is returned on a failure. + * + ****************************************************************************/ + +int noterpmsg_init(void) +{ + return rpmsg_register_callback(&g_noterpmsg_driver, + noterpmsg_device_created, + noterpmsg_device_destroy, + NULL, + NULL); +} diff --git a/drivers/note/noterpmsg_server.c b/drivers/note/noterpmsg_server.c new file mode 100644 index 00000000000..43e4f6ac572 --- /dev/null +++ b/drivers/note/noterpmsg_server.c @@ -0,0 +1,129 @@ +/**************************************************************************** + * drivers/note/noterpmsg_server.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "noterpmsg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct noterpmsg_server_s +{ + struct rpmsg_endpoint ept; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int noterpmsg_ept_cb(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + /* The client ensures that the packet sent is the correct note + * data packet. + */ + + sched_note_add(data, len); + + return 0; +} + +static void noterpmsg_ns_unbind(FAR struct rpmsg_endpoint *ept) +{ + FAR struct noterpmsg_server_s *srv = ept->priv; + + rpmsg_destroy_ept(ept); + kmm_free(srv); +} + +static bool noterpmsg_ns_match(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + return !strcmp(name, NOTERPMSG_EPT_NAME); +} + +static void noterpmsg_ns_bind(FAR struct rpmsg_device *rdev, + FAR void *priv, FAR const char *name, + uint32_t dest) +{ + FAR struct noterpmsg_server_s *srv; + int ret; + + srv = kmm_zalloc(sizeof(struct noterpmsg_server_s)); + if (srv == NULL) + { + return; + } + + srv->ept.priv = srv; + + ret = rpmsg_create_ept(&srv->ept, rdev, NOTERPMSG_EPT_NAME, + RPMSG_ADDR_ANY, dest, + noterpmsg_ept_cb, noterpmsg_ns_unbind); + if (ret < 0) + { + kmm_free(srv); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: noterpmsg_server_init + * + * Description: + * Register a rmpsg channel to note. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero on success. A negated errno value is returned on a failure. + * + ****************************************************************************/ + +int noterpmsg_server_init(void) +{ + return rpmsg_register_callback(NULL, + NULL, + NULL, + noterpmsg_ns_match, + noterpmsg_ns_bind); +}