Add example for out of band rpmsg demo atop RPMsg. This demo shows a
simple proof concept for an echo-test like application.
Instead of the default rpmsg echo-test demo, this application shows
uses a structure within the payload that denotes whether a
rpmsg packet holds data or a pointer.
Signed-off-by: Ben Levinsky <
ben.le...@xilinx.com>
---
apps/examples/CMakeLists.txt | 1 +
apps/examples/oob_echo/CMakeLists.txt | 47 +++++++
apps/examples/oob_echo/rpmsg-echo.h | 6 +
apps/examples/oob_echo/rpmsg-oob-echo.c | 141 ++++++++++++++++++++
apps/examples/oob_echo/rpmsg-oob-ping.c | 223 ++++++++++++++++++++++++++++++++
5 files changed, 418 insertions(+)
create mode 100644 apps/examples/oob_echo/CMakeLists.txt
create mode 100644 apps/examples/oob_echo/rpmsg-echo.h
create mode 100644 apps/examples/oob_echo/rpmsg-oob-echo.c
create mode 100644 apps/examples/oob_echo/rpmsg-oob-ping.c
diff --git a/apps/examples/CMakeLists.txt b/apps/examples/CMakeLists.txt
index 319f01e..f0ae8cd 100644
--- a/apps/examples/CMakeLists.txt
+++ b/apps/examples/CMakeLists.txt
@@ -2,6 +2,7 @@
option (WITH_LOAD_FW "Include loading firmware example" OFF)
add_subdirectory (echo)
+add_subdirectory (oob_echo)
add_subdirectory (rpmsg_sample_echo)
add_subdirectory (matrix_multiply)
if (WITH_LOAD_FW)
diff --git a/apps/examples/oob_echo/CMakeLists.txt b/apps/examples/oob_echo/CMakeLists.txt
new file mode 100644
index 0000000..eab1dbf
--- /dev/null
+++ b/apps/examples/oob_echo/CMakeLists.txt
@@ -0,0 +1,47 @@
+
+set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS} -fdata-sections -ffunction-sections")
+set (_fw_dir "${APPS_SHARE_DIR}")
+
+collector_list (_list PROJECT_INC_DIRS)
+collector_list (_app_list APP_INC_DIRS)
+include_directories (${_list} ${_app_list} ${CMAKE_CURRENT_SOURCE_DIR})
+
+collector_list (_list PROJECT_LIB_DIRS)
+collector_list (_app_list APP_LIB_DIRS)
+link_directories (${_list} ${_app_list})
+
+get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
+collector_list (_deps PROJECT_LIB_DEPS)
+
+set (OPENAMP_LIB open_amp)
+
+foreach (_app rpmsg-oob-echo-ping rpmsg-oob-echo)
+ collector_list (_sources APP_COMMON_SOURCES)
+ if (${_app} STREQUAL "rpmsg-oob-echo-ping")
+ list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-oob-ping.c")
+ elseif (${_app} STREQUAL "rpmsg-oob-echo")
+ list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/rpmsg-oob-echo.c")
+ endif (${_app} STREQUAL "rpmsg-oob-echo-ping")
+
+ if (WITH_SHARED_LIB)
+ add_executable (${_app}-shared ${_sources})
+ target_link_libraries (${_app}-shared ${OPENAMP_LIB}-shared ${_deps})
+ install (TARGETS ${_app}-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif (WITH_SHARED_LIB)
+
+ if (WITH_STATIC_LIB)
+ if (${PROJECT_SYSTEM} STREQUAL "linux")
+ add_executable (${_app}-static ${_sources})
+ target_link_libraries (${_app}-static ${OPENAMP_LIB}-static ${_deps})
+ install (TARGETS ${_app}-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ else (${PROJECT_SYSTEM})
+ add_executable (${_app}.out ${_sources})
+ set_source_files_properties(${_sources} PROPERTIES COMPILE_FLAGS "${_cflags}")
+
+ target_link_libraries(${_app}.out -Wl,-Map=${_app}.map -Wl,--gc-sections ${_linker_opt} -Wl,--start-group ${OPENAMP_LIB}-static ${_deps} -Wl,--end-group)
+
+ install (TARGETS ${_app}.out RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif (${PROJECT_SYSTEM} STREQUAL "linux" )
+ endif (WITH_STATIC_LIB)
+endforeach(_app)
+
diff --git a/apps/examples/oob_echo/rpmsg-echo.h b/apps/examples/oob_echo/rpmsg-echo.h
new file mode 100644
index 0000000..d15eb56
--- /dev/null
+++ b/apps/examples/oob_echo/rpmsg-echo.h
@@ -0,0 +1,6 @@
+#ifndef RPMSG_ECHO_H
+#define RPMSG_ECHO_H
+
+#define RPMSG_SERVICE_NAME "rpmsg-openamp-demo-channel"
+
+#endif /* RPMSG_ECHO_H */
diff --git a/apps/examples/oob_echo/rpmsg-oob-echo.c b/apps/examples/oob_echo/rpmsg-oob-echo.c
new file mode 100644
index 0000000..8c92df3
--- /dev/null
+++ b/apps/examples/oob_echo/rpmsg-oob-echo.c
@@ -0,0 +1,141 @@
+/* This is a sample demonstration application that showcases usage of rpmsg
+This application is meant to run on the remote CPU running baremetal code.
+This application echoes back data that was sent to it by the master core. */
+
+#include <stdio.h>
+#include <openamp/open_amp.h>
+#include <metal/alloc.h>
+#include "platform_info.h"
+#include "rpmsg-echo.h"
+//#include "xil_printf.h"
+
+#define OUT_OF_BAND (0x1UL<<31)
+#define INIT_MSG 0x2UL
+#define ACK_MSG 0X3UL
+#define DATA_MSG 0x4UL
+#define SHUTDOWN_MSG 0x5UL
+
+#define TABLE_BASE_ADDRESS 0x3ee20000UL
+#define BUFFER_SIZE 0x10000UL //64K.. can change to 65K as needed
+#define NUM_BUFFERS 16
+#define NUM_MESSAGES_TO_SEND 32
+
+static struct packet {
+ unsigned packet_type;
+ unsigned buffer_index;
+ unsigned packet_length;
+};
+
+static int demo_status = 0;
+
+#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
+//#define LPRINTF(format, ...)
+#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
+
+static struct rpmsg_endpoint lept;
+static int shutdown_req = 0;
+
+/*-----------------------------------------------------------------------------*
+ * RPMSG endpoint callbacks
+ *-----------------------------------------------------------------------------*/
+static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
+ uint32_t src, void *priv)
+{
+
+ struct packet * p = (struct packet *)data;
+ struct packet ack_packet;
+
+ (void)priv;
+ (void)src;
+ (void)len;
+ LPRINTF("RPU message is received.\r\n" );
+ LPRINTF("RPU message contents : packet_type %x buffer_index %x packet_length %x\r\n",
+ p->packet_type, p->buffer_index, p->packet_length );
+
+ LPRINTF("RPU: Data location at %x \r\n", (unsigned)(TABLE_BASE_ADDRESS+ (BUFFER_SIZE * p->buffer_index)));
+ LPRINTF("RPU: contents of message %x \r\n", *(char*)((TABLE_BASE_ADDRESS+ (BUFFER_SIZE * p->buffer_index))));
+ /* notify remote that message is received */
+ ack_packet.packet_type = OUT_OF_BAND | ACK_MSG;
+ if (rpmsg_send(ept, &ack_packet, sizeof(struct packet)) < 0){
+ LPERROR("RPU rpmsg_send failed\r\n");
+ return RPMSG_ERR_PARAM;
+ }
+
+ return RPMSG_SUCCESS;
+}
+
+static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
+{
+ (void)ept;
+ LPRINTF("RPU unexpected Remote endpoint destroy\r\n");
+ shutdown_req = 1;
+}
+
+/*-----------------------------------------------------------------------------*
+ * Application
+ *-----------------------------------------------------------------------------*/
+int app(struct rpmsg_device *rdev, void *priv)
+{
+ int ret;
+
+ /* Initialize RPMSG framework */
+ LPRINTF("Try to create rpmsg endpoint.\r\n");
+
+ ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
+ 0, RPMSG_ADDR_ANY, rpmsg_endpoint_cb,
+ rpmsg_service_unbind);
+ if (ret) {
+ LPERROR("Failed to create endpoint.\r\n");
+ return -1;
+ }
+
+ LPRINTF("Successfully created rpmsg endpoint.\r\n");
+ while(1) {
+ platform_poll(priv);
+ /* err or INIT */
+ if (shutdown_req ) {
+ LPRINTF("got shutdown request \r\n");
+ break;
+ }
+ }
+ LPRINTF("destroying rpmsg endpoint \r\n");
+ rpmsg_destroy_ept(&lept);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------*
+ * Application entry point
+ *-----------------------------------------------------------------------------*/
+int main(int argc, char *argv[])
+{
+ void *platform;
+ struct rpmsg_device *rpdev;
+ int ret;
+
+ LPRINTF("Starting application...\r\n");
+
+ /* Initialize platform */
+ ret = platform_init(argc, argv, &platform);
+ if (ret) {
+ LPERROR("Failed to initialize platform.\r\n");
+ ret = -1;
+ } else {
+ rpdev = platform_create_rpmsg_vdev(platform, 0,
+ VIRTIO_DEV_SLAVE,
+ NULL, NULL);
+ if (!rpdev) {
+ LPERROR("Failed to create rpmsg virtio device.\r\n");
+ ret = -1;
+ } else {
+ app(rpdev, platform);
+ platform_release_rpmsg_vdev(rpdev);
+ ret = 0;
+ }
+ }
+
+ LPRINTF("Stopping application...\r\n");
+ platform_cleanup(platform);
+
+ return ret;
+}
diff --git a/apps/examples/oob_echo/rpmsg-oob-ping.c b/apps/examples/oob_echo/rpmsg-oob-ping.c
new file mode 100644
index 0000000..8dc6a3b
--- /dev/null
+++ b/apps/examples/oob_echo/rpmsg-oob-ping.c
@@ -0,0 +1,223 @@
+/* This is a sample demonstration application that showcases usage of rpmsg
+This application is meant to run on the remote CPU running baremetal code.
+This application echoes back data that was sent to it by the master core. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <openamp/open_amp.h>
+#include <metal/alloc.h>
+#include "platform_info.h"
+#include "rpmsg-echo.h"
+#include <metal/io.h>
+#include <metal/device.h>
+
+#define APP_EPT_ADDR 0
+#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
+#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
+
+
+#define OUT_OF_BAND (0x1UL<<31)
+#define INIT_MSG 0x2UL
+#define ACK_MSG 0X3UL
+#define DATA_MSG 0x4UL
+#define SHUTDOWN_MSG 0x5UL
+
+#define TABLE_BASE_ADDRESS 0x3ee20000UL
+#define BUFFER_SIZE 0x10000UL //64K.. can change to 65K as needed
+#define NUM_BUFFERS 16
+#define NUM_MESSAGES_TO_SEND 32
+
+#define DEV_BUS_NAME "platform"
+
+
+static struct packet {
+ unsigned packet_type;
+ unsigned buffer_index;
+ unsigned packet_length;
+};
+
+
+static void* large_buffer;
+
+static char data_to_send[BUFFER_SIZE];
+/* Globals */
+static struct rpmsg_endpoint lept;
+static int ept_deleted = 0;
+
+static struct metal_device *large_buffer_shm_device;
+static struct metal_io_region * large_buffer_io;
+
+static int setup_buffer(struct packet * p, unsigned buffer_index, unsigned packet_length, void * data){
+ int ret;
+
+ if (buffer_index > NUM_BUFFERS || packet_length > BUFFER_SIZE || !data)
+ LPERROR("send_buffer failed\r\n");
+ p->packet_type = OUT_OF_BAND | DATA_MSG;
+ p->buffer_index = buffer_index;
+ p->packet_length = packet_length;
+ ret = metal_io_block_write(large_buffer_io, (BUFFER_SIZE * buffer_index), data, packet_length);
+ if (ret < 0){
+ LPERROR("Unable to metal_io_block_write()\n");
+ return -1;
+ }
+ LPRINTF("APU copied to large buffer \r\n");
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------*
+ * RPMSG endpoint callbacks
+ *-----------------------------------------------------------------------------*/
+static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
+ uint32_t src, void *priv)
+{
+ (void)priv;
+ (void)src;
+ (void)len;
+ (void)ept;
+
+ struct packet * p = (struct packet *)data;
+
+ LPRINTF("APU message is received.\r\n" );
+ LPRINTF("APU message contents : packet_type %x buffer_index %x packet_length %x\r\n",
+ p->packet_type, p->buffer_index, p->packet_length );
+ if (p->packet_type & ACK_MSG){
+ LPRINTF("APU received ACK_MSG");
+ }
+ return RPMSG_SUCCESS;
+
+}
+
+static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
+{
+ (void)ept;
+ rpmsg_destroy_ept(&lept);
+ LPRINTF("echo test: service is destroyed\r\n");
+ ept_deleted = 1;
+}
+
+static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
+ const char *name, uint32_t dest)
+{
+ LPRINTF("new endpoint notification is received.\r\n");
+ if (strcmp(name, RPMSG_SERVICE_NAME))
+ LPERROR("Unexpected name service %s.\r\n", name);
+ else
+ (void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
+ APP_EPT_ADDR, dest,
+ rpmsg_endpoint_cb,
+ rpmsg_service_unbind);
+
+}
+
+/*-----------------------------------------------------------------------------*
+ * Application
+ *-----------------------------------------------------------------------------*/
+int app (struct rpmsg_device *rdev, void *priv)
+{
+ int ret;
+
+
+ /* Create RPMsg endpoint */
+ ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
+ RPMSG_ADDR_ANY,
+ rpmsg_endpoint_cb, rpmsg_service_unbind);
+
+ if (ret) {
+ LPERROR("Failed to create RPMsg endpoint.\r\n");
+ return ret;
+ }
+ while (!is_rpmsg_ept_ready(&lept))
+ platform_poll(priv);
+
+ struct packet * p;
+ p = (struct packet *)metal_allocate_memory(sizeof(struct packet));
+ if (!p){
+ LPERROR("memory allocation failed for packet.\r\n");
+ return -1;
+ }
+
+ large_buffer = metal_allocate_memory(sizeof(BUFFER_SIZE*sizeof(char)));
+ if (!large_buffer){
+ LPERROR("memory allocation failed for packet.\r\n");
+ return -1;
+ }
+
+ LPRINTF("APU begin demo \r\n");
+ for(int number_messages_sent = 0; number_messages_sent < 3; number_messages_sent++) {
+ *data_to_send = number_messages_sent;
+ LPRINTF("APU: contents of message %i \r\n", number_messages_sent);
+
+ ret = setup_buffer(p, number_messages_sent % NUM_BUFFERS, sizeof(data_to_send), data_to_send);
+ if (ret){
+ LPERROR("setup_buffer failed \r\n");
+ return RPMSG_ERR_PARAM;
+ }
+
+ if (rpmsg_send(&lept, p, sizeof(struct packet)) < 0){
+ LPERROR("rpmsg_send failed\r\n");
+ return RPMSG_ERR_PARAM;
+ }
+ sleep(2);
+
+ }
+ LPRINTF("APU side ending demo \r\n");
+ metal_free_memory(p);
+
+ rpmsg_destroy_ept(&lept);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ void *platform;
+ struct rpmsg_device *rpdev;
+ int ret;
+
+ ret = platform_init(argc, argv, &platform);
+ if (ret) {
+ LPERROR("Failed to initialize platform.\r\n");
+ ret = -1;
+ } else {
+ /* Initialize platform */
+ printf("try to open device \r\n");
+ ret = metal_device_open(DEV_BUS_NAME, "3ee20000.shm", &large_buffer_shm_device);
+ if (ret) {
+ fprintf(stderr, "ERROR: failed to open large_buffer_shm_device device: %d.\r\n", ret);
+ return -1;
+ }
+
+ printf("able to open device. now try to get io region from device \r\n");
+ printf("large_buffer_shm_device->num_regions %u \r\n", large_buffer_shm_device->num_regions);
+ large_buffer_io = metal_device_io_region(large_buffer_shm_device, 0);
+ if (!large_buffer_io){
+ fprintf(stderr, "ERROR: failed to open large_buffer_io \r\n");
+ return -1;
+ }
+
+ printf("able to get io region from device \r\n");
+
+ rpdev = platform_create_rpmsg_vdev(platform, 0,
+ VIRTIO_DEV_MASTER,
+ NULL,
+ rpmsg_name_service_bind_cb);
+ if (!rpdev) {
+ LPERROR("Failed to create rpmsg virtio device.\r\n");
+ ret = -1;
+ } else {
+ app(rpdev, platform);
+ platform_release_rpmsg_vdev(rpdev);
+ ret = 0;
+ }
+ }
+
+ LPRINTF("Stopping application...\r\n");
+ platform_cleanup(platform);
+
+ return ret;
+}
+
--
2.7.4