* apps/examples/rpmsgchar/rpmsgchar_main.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 <debug.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <nuttx/rpmsg/rpmsg.h>
* Private types
****************************************************************************/
struct rpmsg_char_arg_s
{
const char *type;
const char *ctrl;
const char *name;
uint32_t src;
uint32_t dst;
int ctrl_fd;
};
* Private Functions
****************************************************************************/
static void rpmsg_char_usage(const char *progname)
{
printf("Usage: %s [-t <type>] [-c <ctrl>] [-n <name>] [-s <src>] "
"[-d <dst>]\n"
" type: the test type, now we support: echo, destroy\n"
" ctrl: the rpmsg ctrl char device name, e.g, /dev/rpmsg/ap\n"
" name: the rpmsg char device name you want to create, will\n"
" append \"rpmsg-raw-\" or \"rpmsg-\", e.g, if set\n"
" to \"test\", the rpmsg char device name will be\n"
" /dev/rpmsgX (Linux) or /dev/rpmsg-test (NuttX)\n"
" src : the rpmsg char device source address, default is ANY\n"
" dst : the rpmsg char device destination address, default is\n"
" ANY\n",
progname);
}
static int rpmsg_char_arg_prase(struct rpmsg_char_arg_s *args,
int argc, char *argv[])
{
int opt;
memset(args, 0, sizeof(*args));
args->src = RPMSG_ADDR_ANY;
args->dst = RPMSG_ADDR_ANY;
args->type = "echo";
while ((opt = getopt(argc, argv, "h:t:c:n:s:d")) != -1)
{
switch (opt)
{
case 'h':
rpmsg_char_usage(argv[0]);
return 0;
case 't':
args->type = optarg;
break;
case 'c':
args->ctrl = optarg;
break;
case 'n':
args->name = optarg;
break;
case 's':
args->src = strtoul(optarg, NULL, 0);
break;
case 'd':
args->dst = strtoul(optarg, NULL, 0);
break;
default:
printf("ERROR: arguments are error, print usage:\n");
rpmsg_char_usage(argv[0]);
return ERROR;
}
}
if (!((args->src == RPMSG_ADDR_ANY && args->dst == RPMSG_ADDR_ANY) ||
(args->src != RPMSG_ADDR_ANY && args->dst != RPMSG_ADDR_ANY)))
{
printf("Invalid src:0x%" PRIx32 " dst:0x%" PRIx32 " name: %s\n",
args->src, args->dst, args->name);
return ERROR;
}
return 0;
}
static ssize_t rpmsg_char_echo_test(struct rpmsg_char_arg_s *args)
{
struct rpmsg_endpoint_info eptinfo;
char devname[32];
char buf[12];
ssize_t ret;
int count;
int fd;
eptinfo.src = args->src;
eptinfo.dst = args->dst;
strlcpy(eptinfo.name, args->name, sizeof(eptinfo.name));
if (args->src == RPMSG_ADDR_ANY && args->dst == RPMSG_ADDR_ANY)
{
ret = ioctl(args->ctrl_fd, RPMSG_CREATE_DEV_IOCTL, &eptinfo);
}
else
{
ret = ioctl(args->ctrl_fd, RPMSG_CREATE_EPT_IOCTL, &eptinfo);
}
assert(ret >= 0);
snprintf(devname, sizeof(devname), "/dev/rpmsg-%s", args->name);
fd = open(devname, O_RDWR);
assert(fd >= 0);
printf("Start the echo test\n");
for (count = 0; count < 1000; count++)
{
ret = write(fd, "Hello World\n", 12);
assert(ret == 12);
ret = read(fd, buf, 12);
assert(ret == 12);
assert(memcmp(buf, "Hello World\n", 12) == 0);
}
printf("Finish the echo test\n");
if (args->src == RPMSG_ADDR_ANY && args->dst == RPMSG_ADDR_ANY)
{
ret = ioctl(args->ctrl_fd, RPMSG_RELEASE_DEV_IOCTL, &eptinfo);
}
else
{
ret = ioctl(fd, RPMSG_DESTROY_EPT_IOCTL, 0);
}
assert(ret >= 0);
close(fd);
return OK;
}
static ssize_t rpmsg_char_destroy_test(struct rpmsg_char_arg_s *args)
{
struct rpmsg_endpoint_info eptinfo;
char devname[32];
ssize_t ret;
char buf;
int fd;
int i;
printf("Start the destroy test\n");
eptinfo.src = RPMSG_ADDR_ANY;
eptinfo.dst = RPMSG_ADDR_ANY;
for (i = 0; i < 100; i++)
{
snprintf(eptinfo.name, sizeof(eptinfo.name), "%s%d", args->name, i);
ret = ioctl(args->ctrl_fd, RPMSG_CREATE_EPT_IOCTL, &eptinfo);
if (ret < 0)
{
printf("Failed to create endpoint i=%d %d\n", i, errno);
return ret;
}
}
for (i = 0; i < 100; i++)
{
snprintf(devname, sizeof(devname), "/dev/rpmsg-%s%d", args->name, i);
fd = open(devname, O_RDWR);
assert(fd >= 0);
buf = 0xaa;
ret = write(fd, &buf, 1);
assert(ret == 1);
ret = read(fd, &buf, 1);
assert(ret == 1 && buf == 0xaa);
ret = ioctl(fd, RPMSG_DESTROY_EPT_IOCTL, 0);
assert(ret >= 0);
close(fd);
}
printf("End the destroy test\n");
return ret;
}
* Public Functions
****************************************************************************/
int main(int argc, char *argv[])
{
struct rpmsg_char_arg_s args;
int ret;
if (rpmsg_char_arg_prase(&args, argc, argv) < 0)
{
return ERROR;
}
args.ctrl_fd = open(args.ctrl, O_RDWR);
if (args.ctrl_fd < 0)
{
printf("Failed to open %s %d\n", args.ctrl, errno);
return ERROR;
}
if (strcmp(args.type, "echo") == 0)
{
ret = rpmsg_char_echo_test(&args);
}
else if (strcmp(args.type, "destroy") == 0)
{
ret = rpmsg_char_destroy_test(&args);
}
else
{
printf("Invalid test type %s\n", args.type);
rpmsg_char_usage(argv[0]);
ret = ERROR;
}
close(args.ctrl_fd);
return ret;
}