Xenomai XDDP example and Posix Compling

xenomai

RTDM

1 firstly we give the function:

/* realtime_thread1—————————–>———-+

* => get socket |

* => bind socket to port “xddp-demo |

* => read traffic from NRT domain via recvfrom() <–+–+

* | |

* realtime_thread2—————————————-+ |

* => get socket | |

* => connect socket to port “xddp-demo” | |

* => write traffic to NRT domain via sendto() v |

* | ^

* regular_thread——————————————+ |

* => open /proc/xenomai/registry/rtipc/xddp/xddp-demo | |

* => read traffic from RT domain via read() | |

* => mirror traffic to RT domain via write() +–+

*/

2 The codes are as follows:

#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 <rtdm/ipc.h>
pthread_t rt1, rt2, nrt;
#define XDDP_PORT_LABEL  "rt_arm"
static const char *msg[] = {
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9",
        "10",
        "A",
        "B",
        "C",
        "D",
        "E",
        "F"
};
static void fail(const char *reason)
{
        perror(reason);
        exit(EXIT_FAILURE);
}
static void *realtime_thread1(void *arg) //sensor data
{
        struct rtipc_port_label plabel;
        struct sockaddr_ipc saddr;
        char buf[128];
        int ret, s;
    int err;

    struct timespec next_period;
    struct timespec time;
    clock_gettime(CLOCK_MONOTONIC, &next_period);
    //err=rt_task_set_periodic(1000);

        /*
         * 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 */
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_period, NULL);
                ret = recvfrom(s, buf, sizeof(buf), 0, NULL, 0);
            

            clock_gettime(CLOCK_MONOTONIC, &time);
                if (ret <= 0)
                        fail("recvfrom");
                rt_printf("%s: \"%.*s\" relayed by peer\n", __FUNCTION__, ret, buf);
        }
        return NULL;
}


static void *realtime_thread2(void *arg)  // Loop
{
        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 pee
         * 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);

        }
        return NULL;
}
static void *regular_thread(void *arg)
{
        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);
        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");
        }
        return NULL;
}
int main(int argc, char **argv)
{
        struct sched_param rtparam = { .sched_priority = 42 };
        pthread_attr_t rtattr, regattr;
        sigset_t set;
        int sig;
        sigemptyset(&set);
        sigaddset(&set, SIGINT);
        sigaddset(&set, SIGTERM);
        sigaddset(&set, SIGHUP);
        pthread_sigmask(SIG_BLOCK, &set, NULL);
        pthread_attr_init(&rtattr);
        pthread_attr_setdetachstate(&rtattr, PTHREAD_CREATE_JOINABLE);
        pthread_attr_setinheritsched(&rtattr, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setschedpolicy(&rtattr, SCHED_FIFO);
        pthread_attr_setschedparam(&rtattr, &rtparam);
        /* Both real-time threads have the same attribute set. */
        errno = pthread_create(&rt1, &rtattr, &realtime_thread1, NULL);
        if (errno)
                fail("pthread_create");
        errno = pthread_create(&rt2, &rtattr, &realtime_thread2, NULL);
        if (errno)
                fail("pthread_create");
        pthread_attr_init(&regattr);
        pthread_attr_setdetachstate(&regattr, PTHREAD_CREATE_JOINABLE);
        pthread_attr_setinheritsched(&regattr, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setschedpolicy(&regattr, SCHED_OTHER);
        errno = pthread_create(&nrt, &regattr, &regular_thread, NULL);
        if (errno)
                fail("pthread_create");
        sigwait(&set, &sig);
        pthread_cancel(rt1);
        pthread_cancel(rt2);
        pthread_cancel(nrt);
        pthread_join(rt1, NULL);
        pthread_join(rt2, NULL);
        pthread_join(nrt, NULL);
        return 0;
}

3 The compiler, Makefile

target = rt_p1
skin = posix
#skin = vxworks
CC := $(shell /usr/xenomai/bin/xeno-config --cc)
CFLAGS := $(shell /usr/xenomai/bin/xeno-config --skin=$(skin) --cflags)
LDFLAGS := $(shell /usr/xenomai/bin/xeno-config --skin=$(skin) --ldflags)
$(target): $(target).c
    $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS)
clean:
    @rm $(target)

4 the previous configuration

sudo chmod  777  /dev/rtdm/memdev-shared
sudo chmod  777  /dev/rtdm/memdev-private
sudo chmod 777  /dev/rtp0

5 run

sudo su
./rt_p1

The results are

realtime_thread2: NRT peer is reading from /dev/rtp0

realtime_thread2: sent 1 bytes, “1”

realtime_thread1: “1” relayed by pee

realtime_thread2: sent 1 bytes, “2”

realtime_thread1: “2” relayed by pee

realtime_thread2: sent 1 bytes, “3”

realtime_thread1: “3” relayed by pee

realtime_thread2: sent 1 bytes, “4”

realtime_thread1: “4” relayed by pee

realtime_thread2: sent 1 bytes, “5”

realtime_thread1: “5” relayed by pee

realtime_thread2: sent 1 bytes, “6”

realtime_thread1: “6” relayed by pee

realtime_thread2: sent 1 bytes, “7”

realtime_thread1: “7” relayed by pee

realtime_thread2: sent 1 bytes, “8”

realtime_thread1: “8” relayed by pee

realtime_thread2: sent 1 bytes, “9”

realtime_thread1: “9” relayed by pee

realtime_thread2: sent 2 bytes, “10”

realtime_thread1: “10” relayed by pee

^Crealtime_thread2: sent 1 bytes, “A”

realtime_thread1: “A” relayed by pee

realtime_thread2: sent 1 bytes, “B”

realtime_thread1: “B” relayed by pee

realtime_thread2: sent 1 bytes, “C”

realtime_thread1: “C” relayed by pee

realtime_thread2: sent 1 bytes, “D”

realtime_thread1: “D” relayed by pee

User space

6 Have a good fun!

正文完