1

Xenomai マシンで RT から NRT への通信を実行する必要があります。

私は実際にここでpthreads提案された例をコンパイルして実行することができますが、次のようにを に置き換えようとするとstd::thread:

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <malloc.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <rtdk.h>
#include <rtdm/rtipc.h>
#include <iostream>
#include <thread>


#define XDDP_PORT_LABEL  "xddp-demo"
static const char *msg[] = {
    "Surfing With The Alien",
    "Lords of Karma",
    "Banana Mango",
    "Psycho Monkey",
    "Luminous Flesh Giants",
    "Moroccan Sunset",
    "Satch Boogie",
    "Flying In A Blue Dream",
    "Ride",
    "Summer Song",
    "Speed Of Light",
    "Crystal Planet",
    "Raspberry Jam Delta-V",
    "Champagne?",
    "Clouds Race Across The Sky",
    "Engines Of Creation"
};
static void fail(const char *reason) {
    perror(reason);
    exit(EXIT_FAILURE);
}
void realtime_thread1() {
    struct rtipc_port_label plabel;
    struct sockaddr_ipc saddr;
    char buf[128];
    int ret, s;
    /*
     * Get a datagram socket to bind to the RT endpoint. Each
     * endpoint is represented by a port number within the XDDP
     * protocol namespace.
     */
    s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP);
    if (s < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    /*
     * Set a port label. This name will be registered when
     * binding, in addition to the port number (if given).
     */
    strcpy(plabel.label, XDDP_PORT_LABEL);
    ret = setsockopt(s, SOL_XDDP, XDDP_LABEL,
                     &plabel, sizeof(plabel));
    if (ret)
        fail("setsockopt");
    /*
     * Bind the socket to the port, to setup a proxy to channel
     * traffic to/from the Linux domain. Assign that port a label,
     * so that peers may use a descriptive information to locate
     * it. For instance, the pseudo-device matching our RT
     * endpoint will appear as
     * /proc/xenomai/registry/rtipc/xddp/<XDDP_PORT_LABEL> in the
     * Linux domain, once the socket is bound.
     *
     * saddr.sipc_port specifies the port number to use. If -1 is
     * passed, the XDDP driver will auto-select an idle port.
     */
    memset(&saddr, 0, sizeof(saddr));
    saddr.sipc_family = AF_RTIPC;
    saddr.sipc_port = -1;
    ret = bind(s, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret)
        fail("bind");
    for (;;) {
        /* Get packets relayed by the regular thread */
        ret = recvfrom(s, buf, sizeof(buf), 0, NULL, 0);
        if (ret <= 0)
            fail("recvfrom");
        rt_printf("%s: \"%.*s\" relayed by peer\n", __FUNCTION__, ret, buf);
    }
}
void realtime_thread2() {
    struct rtipc_port_label plabel;
    struct sockaddr_ipc saddr;
    int ret, s, n = 0, len;
    struct timespec ts;
    struct timeval tv;
    socklen_t addrlen;
    s = socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP);
    if (s < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    /*
     * Set the socket timeout; it will apply when attempting to
     * connect to a labeled port, and to recvfrom() calls.  The
     * following setup tells the XDDP driver to wait for at most
     * one second until a socket is bound to a port using the same
     * label, or return with a timeout error.
     */
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
                     &tv, sizeof(tv));
    if (ret)
        fail("setsockopt");
    /*
     * Set a port label. This name will be used to find the peer
     * when connecting, instead of the port number.
     */
    strcpy(plabel.label, XDDP_PORT_LABEL);
    ret = setsockopt(s, SOL_XDDP, XDDP_LABEL,
                     &plabel, sizeof(plabel));
    if (ret)
        fail("setsockopt");
    memset(&saddr, 0, sizeof(saddr));
    saddr.sipc_family = AF_RTIPC;
    saddr.sipc_port = -1;   /* Tell XDDP to search by label. */
    ret = connect(s, (struct sockaddr *)&saddr, sizeof(saddr));
    if (ret)
        fail("connect");
    /*
     * We succeeded in making the port our default destination
     * address by using its label, but we don't know its actual
     * port number yet. Use getpeername() to retrieve it.
     */
    addrlen = sizeof(saddr);
    ret = getpeername(s, (struct sockaddr *)&saddr, &addrlen);
    if (ret || addrlen != sizeof(saddr))
        fail("getpeername");
    rt_printf("%s: NRT peer is reading from /dev/rtp%d\n",
              __FUNCTION__, saddr.sipc_port);
    for (;;) {
        len = strlen(msg[n]);
        /*
         * Send a datagram to the NRT endpoint via the proxy.
         * We may pass a NULL destination address, since the
         * socket was successfully assigned the proper default
         * address via connect(2).
         */
        ret = sendto(s, msg[n], len, 0, NULL, 0);
        if (ret != len)
            fail("sendto");
        rt_printf("%s: sent %d bytes, \"%.*s\"\n",
                  __FUNCTION__, ret, ret, msg[n]);
        n = (n + 1) % (sizeof(msg) / sizeof(msg[0]));
        /*
         * We run in full real-time mode (i.e. primary mode),
         * so we have to let the system breathe between two
         * iterations.
         */
        ts.tv_sec = 0;
        ts.tv_nsec = 500000000; /* 500 ms */
        clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL);
    }
}
void regular_thread() {
    char buf[128], *devname;
    int fd, ret;
    if (asprintf(&devname,
                 "/proc/xenomai/registry/rtipc/xddp/%s",
                 XDDP_PORT_LABEL) < 0)
        fail("asprintf");
    fd = open(devname, O_RDWR);
    std::cout << "File descriptor regular thread: " << fd << std::endl;
    free(devname);
    if (fd < 0)
        fail("open");
    for (;;) {
        /* Get the next message from realtime_thread2. */
        ret = read(fd, buf, sizeof(buf));
        if (ret <= 0)
            fail("read");
        /* Relay the message to realtime_thread1. */
        ret = write(fd, buf, ret);
        if (ret <= 0)
            fail("write");
    }
}
int main(int argc, char **argv) {
    std::thread rt1(realtime_thread1);
    std::thread rt2(realtime_thread2);
    std::thread regth(regular_thread);

    rt1.join();
    rt2.join();
    regth.join();
    return 0;
}

-1 を返す open 関数でエラーが発生しました。

使用したい理由std::threadは、コードを C++ で実装する必要があり、pthread がメンバー関数を理解できないためです。また、グローバル変数を使用したくありません。

また、RT および NRT (xenomai ライブラリなし) マシンで同じコードを実行する必要があり、そのためのコードを既に準備しています (便利な場所に配置され#ifdefた .

4

1 に答える 1

2

私はそれを理解しました。Xenomai の posix スキンでバイナリをラップする必要があります。

CMAKE で:

    set(xeno_cflags_params "--skin=posix" "--cflags")
execute_process(
    COMMAND xeno-config ${xeno_cflags_params}
    OUTPUT_VARIABLE xeno_cflags
    OUTPUT_STRIP_TRAILING_WHITESPACE)

set(xeno_ldflags_params "--skin=posix" "--ldflags")
execute_process(
    COMMAND xeno-config ${xeno_ldflags_params}
    OUTPUT_VARIABLE xeno_ldflags
    OUTPUT_STRIP_TRAILING_WHITESPACE)

# Compiler and linker options
set(CMAKE_C_FLAGS          "${CMAKE_CXX_FLAGS} ${xeno_cflags}")
set(CMAKE_CXX_FLAGS        "${CMAKE_CXX_FLAGS} ${xeno_cflags}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${xeno_ldflags}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${xeno_ldflags}")
于 2016-02-15T11:56:16.010 に答える