mirror of
https://github.com/OpenAMP/open-amp.git
synced 2026-02-06 02:54:32 +08:00
apps: add linux applications for linux rpc communication
Added linux_rpc_demo and linux_rpc_demod for rpc communication between linux master and slave configuration Signed-off-by: ViswaHarsha C <cviswa.harsha_ext@ltts.com>
This commit is contained in:
committed by
Arnaud Pouliquen
parent
413ff36118
commit
bdd4aa5d14
@@ -13,5 +13,6 @@ if (WITH_LOAD_FW)
|
||||
endif (WITH_LOAD_FW)
|
||||
if (WITH_PROXY_APPS)
|
||||
add_subdirectory (rpc_demo)
|
||||
add_subdirectory (linux_rpc_demo)
|
||||
endif (WITH_PROXY_APPS)
|
||||
endif (MACHINE MATCHES ".*microblaze.*")
|
||||
|
||||
47
apps/examples/linux_rpc_demo/CMakeLists.txt
Normal file
47
apps/examples/linux_rpc_demo/CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
set (_cflags "${CMAKE_C_FLAGS} ${APP_EXTRA_C_FLAGS}")
|
||||
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_LARGE_TEXT_OPT)
|
||||
if (NOT _linker_opt)
|
||||
get_property (_linker_opt GLOBAL PROPERTY APP_LINKER_OPT)
|
||||
endif (NOT _linker_opt)
|
||||
collector_list (_deps PROJECT_LIB_DEPS)
|
||||
|
||||
set (OPENAMP_LIB open_amp)
|
||||
|
||||
if (${PROJECT_SYSTEM} STREQUAL "linux")
|
||||
set (app_list linux_rpc_demod linux_rpc_demo)
|
||||
endif (${PROJECT_SYSTEM} STREQUAL "linux")
|
||||
|
||||
foreach (_app ${app_list})
|
||||
collector_list (_sources APP_COMMON_SOURCES)
|
||||
list (APPEND _sources "${CMAKE_CURRENT_SOURCE_DIR}/${_app}.c")
|
||||
|
||||
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)
|
||||
58
apps/examples/linux_rpc_demo/README.md
Normal file
58
apps/examples/linux_rpc_demo/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# linux_rpc_demo
|
||||
This readme is about the OpenAMP linux_rpc_demo.
|
||||
|
||||
The linux_rpc_demo is about remote procedure calls between linux master and linux
|
||||
slave using rpmsg to perform
|
||||
1. File operations such as open, read, write and close
|
||||
2. I/O operation such as printf, scanf
|
||||
|
||||
## Compilation
|
||||
|
||||
### Linux Compilation
|
||||
* Install libsysfs devel and libhugetlbfs devel packages on your Linux.
|
||||
* build libmetal library:
|
||||
|
||||
```
|
||||
$ mkdir -p build-libmetal
|
||||
$ cd build-libmetal
|
||||
$ cmake <libmetal_source>
|
||||
$ make VERBOSE=1 DESTDIR=<libmetal_install> install
|
||||
```
|
||||
|
||||
* build OpenAMP library:
|
||||
|
||||
```
|
||||
$ mkdir -p build-openamp
|
||||
$ cd build-openamp
|
||||
$ cmake <openamp_source> -DCMAKE_INCLUDE_PATH=<libmetal_built_include_dir> \
|
||||
-DCMAKE_LIBRARY_PATH=<libmetal_built_lib_dir> -DWITH_APPS=ON -DWITH_PROXY=ON
|
||||
$ make VERBOSE=1 DESTDIR=$(pwd) install
|
||||
```
|
||||
|
||||
The OpenAMP library will be generated to `build/usr/local/lib` directory, headers will be
|
||||
generated to `build/usr/local/include` directory, and the applications executable will be
|
||||
generated to `build/usr/local/bin` directory.
|
||||
|
||||
* cmake option `-DWITH_APPS=ON` is to build the demonstration applications.
|
||||
* cmake option `-DWITH_PROXY=ON` to build the linux rpc app.
|
||||
|
||||
## Run the Demo
|
||||
|
||||
### linux_rpc_demo:
|
||||
|
||||
* Start rpc demo server on one console
|
||||
```
|
||||
$ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
|
||||
build-openamp/usr/local/bin/linux_rpc_demod-shared
|
||||
```
|
||||
|
||||
* Run rpc demo client on another console to perform file and I/O operations on the server
|
||||
```
|
||||
$ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
|
||||
build-openamp/usr/local/bin/linux_rpc_demo-shared 1
|
||||
```
|
||||
Enter the inputs on the master side the same gets printed on the remote side. You will see communication between the master and remote process using rpmsg calls.
|
||||
|
||||
## Note:
|
||||
`sudo` is required to run the OpenAMP demos between Linux processes, as it doesn't work on
|
||||
some systems if you are normal users.
|
||||
79
apps/examples/linux_rpc_demo/linux-rpmsg-rpc-demo.h
Normal file
79
apps/examples/linux_rpc_demo/linux-rpmsg-rpc-demo.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2021, L&T Technology Services Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_RPC_DEMO_H
|
||||
#define RPMSG_RPC_DEMO_H
|
||||
|
||||
#define OPEN_ID 0x1UL
|
||||
#define CLOSE_ID 0x2UL
|
||||
#define WRITE_ID 0x3UL
|
||||
#define READ_ID 0x4UL
|
||||
#define ACK_STATUS_ID 0x5UL
|
||||
#define TERM_ID 0x6UL
|
||||
#define INPUT_ID 0x7UL
|
||||
#define MAX_STRING_LEN 300
|
||||
#define MAX_FILE_NAME_LEN 10
|
||||
|
||||
typedef int (*rpmsg_rpc_poll)(void *arg);
|
||||
|
||||
struct polling {
|
||||
rpmsg_rpc_poll poll;
|
||||
void *poll_arg;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_open {
|
||||
char filename[MAX_FILE_NAME_LEN];
|
||||
int flags;
|
||||
int mode;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_read {
|
||||
int fd;
|
||||
uint32_t buflen;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_input {
|
||||
uint32_t buflen;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_write {
|
||||
int fd;
|
||||
uint32_t len;
|
||||
char ptr[MAX_STRING_LEN];
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_close {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_req_term {
|
||||
int id;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_resp_open {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_resp_read {
|
||||
int bytes_read;
|
||||
char buf[MAX_STRING_LEN];
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_resp_input {
|
||||
int bytes_read;
|
||||
char buf[MAX_STRING_LEN];
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_resp_write {
|
||||
int bytes_written;
|
||||
};
|
||||
|
||||
struct rpmsg_rpc_resp_close {
|
||||
int close_ret;
|
||||
};
|
||||
|
||||
#endif /* RPMSG_RPC_DEMO_H */
|
||||
599
apps/examples/linux_rpc_demo/linux_rpc_demo.c
Normal file
599
apps/examples/linux_rpc_demo/linux_rpc_demo.c
Normal file
File diff suppressed because it is too large
Load Diff
316
apps/examples/linux_rpc_demo/linux_rpc_demod.c
Normal file
316
apps/examples/linux_rpc_demo/linux_rpc_demod.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2021, L&T Technology Services Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*This is a sample demonstration application that showcases usage of proxy
|
||||
*from the remote core.
|
||||
*This application is meant to run on the remote CPU running linux.
|
||||
*This application can print to the master console and perform file I/O through
|
||||
*rpmsg channels.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <openamp/open_amp.h>
|
||||
#include <openamp/rpmsg_rpc_client_server.h>
|
||||
#include "platform_info.h"
|
||||
#include "linux-rpmsg-rpc-demo.h"
|
||||
|
||||
#define REDEF_O_CREAT 100
|
||||
#define REDEF_O_EXCL 200
|
||||
#define REDEF_O_RDONLY 0
|
||||
#define REDEF_O_WRONLY 1
|
||||
#define REDEF_O_RDWR 2
|
||||
#define REDEF_O_APPEND 2000
|
||||
#define REDEF_O_ACCMODE 3
|
||||
|
||||
#define raw_printf(format, ...) printf(format, ##__VA_ARGS__)
|
||||
#define LPRINTF(format, ...) raw_printf("Master> " format, ##__VA_ARGS__)
|
||||
#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
|
||||
|
||||
static void *platform;
|
||||
static struct rpmsg_device *rpdev;
|
||||
static struct rpmsg_rpc_svr rpcs;
|
||||
int request_termination;
|
||||
int ept_deleted;
|
||||
|
||||
void rpmsg_service_server_unbind(struct rpmsg_endpoint *ept)
|
||||
{
|
||||
(void)ept;
|
||||
rpmsg_destroy_ept(&rpcs.ept);
|
||||
LPRINTF("Endpoint is destroyed\r\n");
|
||||
ept_deleted = 1;
|
||||
}
|
||||
|
||||
void terminate_rpc_app(void)
|
||||
{
|
||||
LPRINTF("Destroying endpoint.\r\n");
|
||||
if (!ept_deleted)
|
||||
rpmsg_destroy_ept(&rpcs.ept);
|
||||
}
|
||||
|
||||
void exit_action_handler(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
terminate_rpc_app();
|
||||
}
|
||||
|
||||
void kill_action_handler(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
LPRINTF("RPC service killed !!\r\n");
|
||||
|
||||
terminate_rpc_app();
|
||||
|
||||
if (rpdev)
|
||||
platform_release_rpmsg_vdev(rpdev, platform);
|
||||
if (platform)
|
||||
platform_cleanup(platform);
|
||||
}
|
||||
|
||||
int rpmsg_handle_open(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_open *rpc_open_req = req_ptr;
|
||||
char *buf;
|
||||
struct rpmsg_rpc_resp_open rpc_open_resp;
|
||||
int payload_size = sizeof(rpc_open_resp);
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
int fd, ret;
|
||||
|
||||
if (!rpc_open_req || !ept)
|
||||
return -EINVAL;
|
||||
buf = rpc_open_req->filename;
|
||||
|
||||
/* Open remote fd */
|
||||
fd = open(buf, rpc_open_req->flags, rpc_open_req->mode);
|
||||
|
||||
/* Construct rpc response */
|
||||
rpc_open_resp.fd = fd;
|
||||
|
||||
/* Transmit rpc response */
|
||||
ret = rpmsg_rpc_server_send(rpcs, OPEN_ID, RPMSG_RPC_OK, &rpc_open_resp,
|
||||
payload_size);
|
||||
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
int rpmsg_handle_close(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_close *rpc_close_req = req_ptr;
|
||||
struct rpmsg_rpc_resp_close rpc_close_resp;
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
int payload_size = sizeof(rpc_close_resp);
|
||||
int ret;
|
||||
|
||||
if (!rpc_close_req || !ept)
|
||||
return -EINVAL;
|
||||
|
||||
/* Close remote fd */
|
||||
ret = close(rpc_close_req->fd);
|
||||
|
||||
/* Construct rpc response */
|
||||
rpc_close_resp.close_ret = ret;
|
||||
|
||||
/* Transmit rpc response */
|
||||
ret = rpmsg_rpc_server_send(rpcs, CLOSE_ID, RPMSG_RPC_OK,
|
||||
&rpc_close_resp, payload_size);
|
||||
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
int rpmsg_handle_read(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_read *rpc_read_req = req_ptr;
|
||||
struct rpmsg_rpc_resp_read rpc_read_resp;
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
unsigned long int bytes_read;
|
||||
int payload_size = sizeof(rpc_read_resp);
|
||||
int ret;
|
||||
|
||||
if (!rpc_read_req || !ept)
|
||||
return -EINVAL;
|
||||
|
||||
if (rpc_read_req->fd == 0) {
|
||||
bytes_read = MAX_STRING_LEN;
|
||||
/* Perform read from fd for large size since this is a
|
||||
* STD/I request
|
||||
*/
|
||||
bytes_read = read(rpc_read_req->fd, rpc_read_resp.buf,
|
||||
bytes_read);
|
||||
} else {
|
||||
/* Perform read from fd */
|
||||
bytes_read = read(rpc_read_req->fd, rpc_read_resp.buf,
|
||||
rpc_read_req->buflen);
|
||||
}
|
||||
|
||||
/* Construct rpc response */
|
||||
rpc_read_resp.bytes_read = bytes_read;
|
||||
|
||||
/* Transmit rpc response */
|
||||
ret = rpmsg_rpc_server_send(rpcs, READ_ID, RPMSG_RPC_OK, &rpc_read_resp,
|
||||
payload_size);
|
||||
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
int rpmsg_handle_write(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_write *rpc_write_req = req_ptr;
|
||||
struct rpmsg_rpc_resp_write rpc_write_resp;
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
int payload_size = sizeof(rpc_write_resp);
|
||||
int bytes_written;
|
||||
int ret;
|
||||
|
||||
if (!rpc_write_req || !ept)
|
||||
return -EINVAL;
|
||||
|
||||
/* Write to remote fd */
|
||||
bytes_written = write(rpc_write_req->fd, rpc_write_req->ptr,
|
||||
rpc_write_req->len);
|
||||
|
||||
/* Construct rpc response */
|
||||
rpc_write_resp.bytes_written = bytes_written;
|
||||
|
||||
/* Transmit rpc response */
|
||||
ret = rpmsg_rpc_server_send(rpcs, WRITE_ID, RPMSG_RPC_OK,
|
||||
&rpc_write_resp, payload_size);
|
||||
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
int rpmsg_handle_input(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_input *rpc_input_req = req_ptr;
|
||||
struct rpmsg_rpc_resp_input rpc_input_resp;
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
int bytes_read;
|
||||
int payload_size = sizeof(rpc_input_resp);
|
||||
int ret;
|
||||
|
||||
if (!rpc_input_req || !ept)
|
||||
return -EINVAL;
|
||||
|
||||
/* Input from remote */
|
||||
scanf("%s", rpc_input_resp.buf);
|
||||
bytes_read = sizeof(rpc_input_resp.buf);
|
||||
|
||||
/* Construct rpc response */
|
||||
rpc_input_resp.bytes_read = bytes_read;
|
||||
|
||||
/* Transmit rpc response */
|
||||
ret = rpmsg_rpc_server_send(rpcs, INPUT_ID, RPMSG_RPC_OK,
|
||||
&rpc_input_resp, payload_size);
|
||||
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
int rpmsg_handle_term(void *data, struct rpmsg_rpc_svr *rpcs)
|
||||
{
|
||||
void *req_ptr = data + MAX_FUNC_ID_LEN;
|
||||
struct rpmsg_rpc_req_term *rpc_term_req = req_ptr;
|
||||
struct rpmsg_endpoint *ept = &rpcs->ept;
|
||||
|
||||
printf("Received termination request at id %d from endpoint %s\r\n",
|
||||
rpc_term_req->id, ept->name);
|
||||
request_termination = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Service table */
|
||||
static struct rpmsg_rpc_services rpc_table[] = {
|
||||
{OPEN_ID, &rpmsg_handle_open },
|
||||
{READ_ID, &rpmsg_handle_read },
|
||||
{WRITE_ID, &rpmsg_handle_write },
|
||||
{CLOSE_ID, &rpmsg_handle_close },
|
||||
{INPUT_ID, &rpmsg_handle_input },
|
||||
{TERM_ID, &rpmsg_handle_term }
|
||||
};
|
||||
|
||||
/* Application entry point */
|
||||
int app(struct rpmsg_device *rdev, void *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sigaction exit_action;
|
||||
struct sigaction kill_action;
|
||||
|
||||
/* Initialize signalling infrastructure */
|
||||
memset(&exit_action, 0, sizeof(struct sigaction));
|
||||
memset(&kill_action, 0, sizeof(struct sigaction));
|
||||
exit_action.sa_handler = exit_action_handler;
|
||||
kill_action.sa_handler = kill_action_handler;
|
||||
sigaction(SIGTERM, &exit_action, NULL);
|
||||
sigaction(SIGINT, &exit_action, NULL);
|
||||
sigaction(SIGKILL, &kill_action, NULL);
|
||||
sigaction(SIGHUP, &kill_action, NULL);
|
||||
|
||||
/* Initialize RPMSG framework */
|
||||
LPRINTF("Try to create rpmsg endpoint.\r\n");
|
||||
|
||||
ret = rpmsg_rpc_server_init(&rpcs, rdev, rpc_table,
|
||||
(int)sizeof(rpc_table) / sizeof(
|
||||
struct rpmsg_rpc_services),
|
||||
rpmsg_service_server_unbind);
|
||||
|
||||
if (ret) {
|
||||
LPERROR("Failed to create endpoint.\r\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LPRINTF("Successfully created rpmsg endpoint.\r\n");
|
||||
while (1) {
|
||||
platform_poll(priv);
|
||||
/* we got a shutdown request, exit */
|
||||
if (ept_deleted || request_termination) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
LPRINTF("\nRPC service exiting !!\r\n");
|
||||
|
||||
terminate_rpc_app();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
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_MASTER,
|
||||
NULL, NULL);
|
||||
if (!rpdev) {
|
||||
LPERROR("Failed to create rpmsg virtio device.\r\n");
|
||||
ret = -1;
|
||||
} else {
|
||||
app(rpdev, platform);
|
||||
platform_release_rpmsg_vdev(rpdev, platform);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LPRINTF("Stopping application...\r\n");
|
||||
platform_cleanup(platform);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user