examples: Add rpmsg_char_simple example
authorSuman Anna <s-anna@ti.com>
Fri, 16 Oct 2020 04:29:46 +0000 (23:29 -0500)
committerSuman Anna <s-anna@ti.com>
Fri, 16 Oct 2020 23:28:14 +0000 (18:28 -0500)
Add a very basic example application demonstrating the usage
of the rpmsg_char API provided by the ti-rpmsg-char library.
The application is a single-threaded application, communicating
with a single rpmsg device on a remote processor using one local
endpoint device.

The example is added in a new 'examples' directory. An README file
is also added in the examples folder with the usage instructions.

The examples folder is not built automatically using top-level make,
and requires a specific command to be built. The top-level README
is also updated accordingly.

Signed-off-by: Suman Anna <s-anna@ti.com>
README
configure.ac
examples/.gitignore [new file with mode: 0644]
examples/Makefile.am [new file with mode: 0644]
examples/README [new file with mode: 0644]
examples/rpmsg_char_simple.c [new file with mode: 0644]

diff --git a/README b/README
index d42989b00028c7618bc436614b1bee93ba9eb500..94de97a1bf51a42d2e94b7397e14cae9430bbbe3 100644 (file)
--- a/README
+++ b/README
@@ -66,7 +66,15 @@ examples:
       cd <ti-rpmsg-char-dir>
       autoreconf -i
       ./configure --host=aarch64-none-linux-gnu --prefix=<target-dir>
- 4. Build and Install
+ 4. Build and Install Library
+      make
+      make install
+ 5. Build Examples, the top-level Makefile builds only the library by
+    default
+      make -C examples
+      make -C examples install
+              or
+      cd examples
       make
       make install
 
@@ -75,5 +83,11 @@ examples:
        make clean      : Erase the files built by make
        make distclean  : clean + Erase the files created by the configure step
        make uninstall  : Erase the installed libraries and executables
-  2. Use git clean to get the repo back to a pristine state
+  2. Cleaning up examples specifically needs separate commands. It is all
+     similar to the commands in #1, but invoked with -C examples, or invoke
+     normally from within the examples folder
+       eg: make -C examples uninstall
+                     or
+           cd examples; make uninstall
+  3. Use git clean to get the repo back to a pristine state
        git clean -dfx
index 227c442abc8c9a3d8fe76bc926c1c26efa07ac3e..d3a2d45c8563eb54effa8330817a99496f0133b2 100644 (file)
@@ -49,7 +49,8 @@ AC_SUBST([AM_LDFLAGS])
 # Generate Makefile(s)
 AC_CONFIG_FILES([Makefile
                  src/Makefile
-                 src/ti_rpmsg_char.pc])
+                 src/ti_rpmsg_char.pc
+                 examples/Makefile])
 AC_OUTPUT
 
 echo \
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644 (file)
index 0000000..1973b26
--- /dev/null
@@ -0,0 +1 @@
+rpmsg_char_simple
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644 (file)
index 0000000..5a9bedb
--- /dev/null
@@ -0,0 +1,11 @@
+INCLUDE = -I${includedir}
+
+AM_CFLAGS = -Wall -g -O2 $(INCLUDE)
+
+bin_PROGRAMS = rpmsg_char_simple
+
+# rpmsg_char_simple program
+rpmsg_char_simple_SOURCES = rpmsg_char_simple.c
+rpmsg_char_simple_CPPFLAGS = $(AM_CFLAGS)
+rpmsg_char_simple_LDADD = -lpthread -lti_rpmsg_char
+rpmsg_char_simple_LDFLAGS = -L${libdir}
diff --git a/examples/README b/examples/README
new file mode 100644 (file)
index 0000000..72caec8
--- /dev/null
@@ -0,0 +1,28 @@
+rpmsg-char-simple application
+=============================
+
+rpmsg-char-simple is a very basic single-threaded application
+demonstrating the usage of the API provided by the ti-rpmsg-char
+library to communicate messages to a remote processor exercising
+the kernel rpmsg_char driver and virtio-rpmsg transport.
+
+Usage:
+  rpmsg_char_simple [-r <rproc_id>] [-n <num_msgs>] [-d <rpmsg_dev_name>] [-p <remote_endpt>]
+
+  Where:
+    -r <rproc_id>        remote processor id to be used.
+                         Valid values are 0 to RPROC_ID_MAX
+    -n <num_msgs>        Number of messages to exchange (default 100)
+    -d <rpmsg_dev_name>  rpmsg device name
+                         (defaults to NULL, translates to rpmsg_chrdev)
+    -p <remote_endpt>    remote end-point address of the rpmsg device
+                         (default 14 based on current example firmwares)
+
+Examples:
+1. rpmsg_char_simple -r 2 -d ti.ipc4.ping-pong -p 13
+     Runs the example using device "ti.ipc4.ping-pong" and remote port 13
+     with rproc_id value of 2 (R5F_MAIN0_0), exchanges 100 messages
+2. rpmsg_char_simple -r 4 -n 10
+     Runs the example using default rpmsg device "rpmsg_chrdev",
+     remote port 14 with rproc_id value of 4 (R5F_MAIN1_0), exchanges
+     10 messages
diff --git a/examples/rpmsg_char_simple.c b/examples/rpmsg_char_simple.c
new file mode 100644 (file)
index 0000000..96219b1
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * rpmsg_char_simple.c
+ *
+ * Simple Example application using rpmsg-char library
+ *
+ * Copyright (c) 2020 Texas Instruments Incorporated - https://www.ti.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdbool.h>
+#include <semaphore.h>
+
+#include <linux/rpmsg.h>
+#include <ti_rpmsg_char.h>
+
+#define NUM_ITERATIONS 100
+#define REMOTE_ENDPT   14
+
+int send_msg(int fd, char *msg, int len)
+{
+       int ret = 0;
+
+       ret = write(fd, msg, len);
+       if (ret < 0) {
+               perror("Can't write to rpmsg endpt device\n");
+               return -1;
+       }
+
+       return ret;
+}
+
+int recv_msg(int fd, int len, char *reply_msg, int *reply_len)
+{
+       int ret = 0;
+
+       /* Note: len should be max length of response expected */
+       ret = read(fd, reply_msg, len);
+       if (ret < 0) {
+               perror("Can't read from rpmsg endpt device\n");
+               return -1;
+       } else {
+               *reply_len = ret;
+       }
+
+       return 0;
+}
+
+/* single thread communicating with a single endpoint */
+int rpmsg_char_ping(int rproc_id, char *dev_name, int remote_endpt,
+                   int num_msgs)
+{
+       int ret = 0;
+       int i = 0;
+       int packet_len;
+       char eptdev_name[32] = { 0 };
+       char packet_buf[512] = { 0 };
+       rpmsg_char_dev_t *rcdev;
+       int flags = 0;
+
+        /*
+         * Open the remote rpmsg device identified by dev_name and bind the
+        * device to a local end-point used for receiving messages from
+        * remote processor
+         */
+       sprintf(eptdev_name, "rpmsg-char-%d-%d", rproc_id, getpid());
+       rcdev = rpmsg_char_open(rproc_id, dev_name, remote_endpt,
+                               eptdev_name, flags);
+        if (!rcdev) {
+               perror("Can't create an endpoint device");
+               return -EPERM;
+        }
+        printf("Created endpt device %s, fd = %d port = %d\n", eptdev_name,
+               rcdev->fd, rcdev->endpt);
+
+        printf("Exchanging %d messages with rpmsg device ti.ipc4.ping-pong on rproc id %d ...\n\n",
+               num_msgs, rproc_id);
+
+       for (i = 0; i < num_msgs; i++) {
+               memset(packet_buf, 0, sizeof(packet_buf));
+               sprintf(packet_buf, "hello there %d!", i);
+               packet_len = strlen(packet_buf);
+               printf("Sending message #%d: %s\n", i, packet_buf);
+               ret = send_msg(rcdev->fd, (char *)packet_buf, packet_len);
+               if (ret < 0) {
+                       printf("send_msg failed for iteration %d, ret = %d\n", i, ret);
+                       goto out;
+               }
+               if (ret != packet_len) {
+                       printf("bytes written does not match send request, ret = %d, packet_len = %d\n",
+                               i, ret);
+                   goto out;
+               }
+
+               printf("Receiving message #%d: ", i);
+               ret = recv_msg(rcdev->fd, 256, (char *)packet_buf, &packet_len);
+               if (ret < 0) {
+                       printf("recv_msg failed for iteration %d, ret = %d\n", i, ret);
+                       goto out;
+               }
+               /* TODO: Verify data integrity */
+
+               /* TODO: Reduce number of prints */
+               printf("%s\n", packet_buf);
+       }
+
+       printf("\nCommunicated %d messages successfully on %s\n\n",
+               num_msgs, eptdev_name);
+
+out:
+       ret = rpmsg_char_close(rcdev);
+       if (ret < 0)
+               perror("Can't delete the endpoint device\n");
+
+       return ret;
+}
+
+void usage()
+{
+       printf("Usage: rpmsg_char_simple [-r <rproc_id>] [-n <num_msgs>] [-d <rpmsg_dev_name] [-p <remote_endpt]\n");
+       printf("\t\tDefaults: rproc_id: 0 num_msgs: %d rpmsg_dev_name: NULL remote_endpt: %d\n",
+               NUM_ITERATIONS, REMOTE_ENDPT);
+}
+
+int main(int argc, char *argv[])
+{
+       int ret, status, c;
+       int rproc_id = 0;
+       int num_msgs = NUM_ITERATIONS;
+       int remote_endpt = REMOTE_ENDPT;
+       char *dev_name = NULL;
+
+       while (1) {
+               c = getopt(argc, argv, "r:n:p:d:");
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'r':
+                       rproc_id = atoi(optarg);
+                       break;
+               case 'n':
+                       num_msgs = atoi(optarg);
+                       break;
+               case 'p':
+                       remote_endpt = atoi(optarg);
+                       break;
+               case 'd':
+                       dev_name = optarg;
+                       break;
+               default:
+                       usage();
+                       exit(0);
+               }
+       }
+
+       if (rproc_id < 0 || rproc_id >= RPROC_ID_MAX) {
+               printf("Invalid rproc id %d, should be less than %d\n",
+                       rproc_id, RPROC_ID_MAX);
+               usage();
+               return 1;
+       }
+
+       /* Use auto-detection for SoC */
+       ret = rpmsg_char_init(NULL);
+       if (ret) {
+               printf("rpmsg_char_init failed, ret = %d\n", ret);
+               return ret;
+       }
+
+       status = rpmsg_char_ping(rproc_id, dev_name, remote_endpt, num_msgs);
+
+       rpmsg_char_exit();
+
+       if (status < 0) {
+               printf("TEST STATUS: FAILED\n");
+       } else {
+               printf("TEST STATUS: PASSED\n");
+       }
+
+       return 0;
+}