Migrated user-space example to use clock_nanosleep().
authorFlorian Pose <fp@igh-essen.com>
Thu, 09 Jun 2016 13:52:22 +0200
changeset 2649 717c331cc227
parent 2647 5a70ffc4644b
child 2650 0dc0873d4aed
Migrated user-space example to use clock_nanosleep().
examples/user/Makefile.am
examples/user/main.c
--- a/examples/user/Makefile.am	Wed May 04 11:17:20 2016 +0200
+++ b/examples/user/Makefile.am	Thu Jun 09 13:52:22 2016 +0200
@@ -31,6 +31,6 @@
 
 ec_user_example_SOURCES = main.c
 ec_user_example_CFLAGS = -I$(top_srcdir)/include -Wall
-ec_user_example_LDFLAGS = -L$(top_builddir)/lib/.libs -lethercat
+ec_user_example_LDFLAGS = -L$(top_builddir)/lib/.libs -lethercat -lrt
 
 #------------------------------------------------------------------------------
--- a/examples/user/main.c	Wed May 04 11:17:20 2016 +0200
+++ b/examples/user/main.c	Thu Jun 09 13:52:22 2016 +0200
@@ -35,6 +35,8 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <time.h> /* clock_gettime() */
+#include <sys/mman.h> /* mlockall() */
 
 /****************************************************************************/
 
@@ -42,13 +44,18 @@
 
 /****************************************************************************/
 
-// Application parameters
-#define FREQUENCY 100
-#define PRIORITY 1
-
-// Optional features
-#define CONFIGURE_PDOS  1
-#define SDO_ACCESS      0
+/** Task period in ns. */
+#define PERIOD_NS   (1000000)
+
+#define MAX_SAFE_STACK (8 * 1024) /* The maximum stack size which is
+                                     guranteed safe to access without
+                                     faulting */
+
+/****************************************************************************/
+
+/* Constants */
+#define NSEC_PER_SEC (1000000000)
+#define FREQUENCY (NSEC_PER_SEC / PERIOD_NS)
 
 /****************************************************************************/
 
@@ -62,10 +69,6 @@
 static ec_slave_config_t *sc_ana_in = NULL;
 static ec_slave_config_state_t sc_ana_in_state = {};
 
-// Timer
-static unsigned int sig_alarms = 0;
-static unsigned int user_alarms = 0;
-
 /****************************************************************************/
 
 // process data
@@ -102,8 +105,6 @@
 
 /*****************************************************************************/
 
-#if CONFIGURE_PDOS
-
 // Analog in --------------------------
 
 static ec_pdo_entry_info_t el3102_pdo_entries[] = {
@@ -165,13 +166,6 @@
     {1, EC_DIR_INPUT},
     {0xff}
 };
-#endif
-
-/*****************************************************************************/
-
-#if SDO_ACCESS
-static ec_sdo_request_t *sdo;
-#endif
 
 /*****************************************************************************/
 
@@ -181,10 +175,12 @@
 
     ecrt_domain_state(domain1, &ds);
 
-    if (ds.working_counter != domain1_state.working_counter)
+    if (ds.working_counter != domain1_state.working_counter) {
         printf("Domain1: WC %u.\n", ds.working_counter);
-    if (ds.wc_state != domain1_state.wc_state)
+    }
+    if (ds.wc_state != domain1_state.wc_state) {
         printf("Domain1: State %u.\n", ds.wc_state);
+    }
 
     domain1_state = ds;
 }
@@ -197,12 +193,15 @@
 
     ecrt_master_state(master, &ms);
 
-    if (ms.slaves_responding != master_state.slaves_responding)
+    if (ms.slaves_responding != master_state.slaves_responding) {
         printf("%u slave(s).\n", ms.slaves_responding);
-    if (ms.al_states != master_state.al_states)
+    }
+    if (ms.al_states != master_state.al_states) {
         printf("AL states: 0x%02X.\n", ms.al_states);
-    if (ms.link_up != master_state.link_up)
+    }
+    if (ms.link_up != master_state.link_up) {
         printf("Link is %s.\n", ms.link_up ? "up" : "down");
+    }
 
     master_state = ms;
 }
@@ -215,51 +214,28 @@
 
     ecrt_slave_config_state(sc_ana_in, &s);
 
-    if (s.al_state != sc_ana_in_state.al_state)
+    if (s.al_state != sc_ana_in_state.al_state) {
         printf("AnaIn: State 0x%02X.\n", s.al_state);
-    if (s.online != sc_ana_in_state.online)
+    }
+    if (s.online != sc_ana_in_state.online) {
         printf("AnaIn: %s.\n", s.online ? "online" : "offline");
-    if (s.operational != sc_ana_in_state.operational)
-        printf("AnaIn: %soperational.\n",
-                s.operational ? "" : "Not ");
+    }
+    if (s.operational != sc_ana_in_state.operational) {
+        printf("AnaIn: %soperational.\n", s.operational ? "" : "Not ");
+    }
 
     sc_ana_in_state = s;
 }
 
 /*****************************************************************************/
 
-#if SDO_ACCESS
-void read_sdo(void)
-{
-    switch (ecrt_sdo_request_state(sdo)) {
-        case EC_REQUEST_UNUSED: // request was not used yet
-            ecrt_sdo_request_read(sdo); // trigger first read
-            break;
-        case EC_REQUEST_BUSY:
-            fprintf(stderr, "Still busy...\n");
-            break;
-        case EC_REQUEST_SUCCESS:
-            fprintf(stderr, "SDO value: 0x%04X\n",
-                    EC_READ_U16(ecrt_sdo_request_data(sdo)));
-            ecrt_sdo_request_read(sdo); // trigger next read
-            break;
-        case EC_REQUEST_ERROR:
-            fprintf(stderr, "Failed to read SDO!\n");
-            ecrt_sdo_request_read(sdo); // retry reading
-            break;
-    }
-}
-#endif
-
-/****************************************************************************/
-
 void cyclic_task()
 {
     // receive process data
     ecrt_master_receive(master);
     ecrt_domain_process(domain1);
 
-    // check process data state (optional)
+    // check process data state
     check_domain1_state();
 
     if (counter) {
@@ -273,14 +249,8 @@
         // check for master state (optional)
         check_master_state();
 
-        // check for islave configuration state(s) (optional)
+        // check for slave configuration state(s) (optional)
         check_slave_config_states();
-
-#if SDO_ACCESS
-        // read process data SDO
-        read_sdo();
-#endif
-
     }
 
 #if 0
@@ -302,12 +272,11 @@
 
 /****************************************************************************/
 
-void signal_handler(int signum) {
-    switch (signum) {
-        case SIGALRM:
-            sig_alarms++;
-            break;
-    }
+void stack_prefault(void)
+{
+    unsigned char dummy[MAX_SAFE_STACK];
+
+    memset(dummy, 0, MAX_SAFE_STACK);
 }
 
 /****************************************************************************/
@@ -315,16 +284,18 @@
 int main(int argc, char **argv)
 {
     ec_slave_config_t *sc;
-    struct sigaction sa;
-    struct itimerval tv;
+    struct timespec wakeup_time;
+    int ret = 0;
 
     master = ecrt_request_master(0);
-    if (!master)
-        return -1;
+    if (!master) {
+        return -1;
+    }
 
     domain1 = ecrt_master_create_domain(master);
-    if (!domain1)
-        return -1;
+    if (!domain1) {
+        return -1;
+    }
 
     if (!(sc_ana_in = ecrt_master_slave_config(
                     master, AnaInSlavePos, Beckhoff_EL3102))) {
@@ -332,16 +303,6 @@
         return -1;
     }
 
-#if SDO_ACCESS
-    fprintf(stderr, "Creating SDO requests...\n");
-    if (!(sdo = ecrt_slave_config_create_sdo_request(sc_ana_in, 0x3102, 2, 2))) {
-        fprintf(stderr, "Failed to create SDO request.\n");
-        return -1;
-    }
-    ecrt_sdo_request_timeout(sdo, 500); // ms
-#endif
-
-#if CONFIGURE_PDOS
     printf("Configuring PDOs...\n");
     if (ecrt_slave_config_pdos(sc_ana_in, EC_END, el3102_syncs)) {
         fprintf(stderr, "Failed to configure PDOs.\n");
@@ -369,12 +330,12 @@
         fprintf(stderr, "Failed to configure PDOs.\n");
         return -1;
     }
-#endif
 
     // Create configuration for bus coupler
     sc = ecrt_master_slave_config(master, BusCouplerPos, Beckhoff_EK1100);
-    if (!sc)
-        return -1;
+    if (!sc) {
+        return -1;
+    }
 
     if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
         fprintf(stderr, "PDO entry registration failed!\n");
@@ -382,55 +343,55 @@
     }
 
     printf("Activating master...\n");
-    if (ecrt_master_activate(master))
-        return -1;
+    if (ecrt_master_activate(master)) {
+        return -1;
+    }
 
     if (!(domain1_pd = ecrt_domain_data(domain1))) {
         return -1;
     }
 
-#if PRIORITY
+    /* Set priority */
+
     pid_t pid = getpid();
-    if (setpriority(PRIO_PROCESS, pid, -19))
+    if (setpriority(PRIO_PROCESS, pid, -19)) {
         fprintf(stderr, "Warning: Failed to set priority: %s\n",
                 strerror(errno));
-#endif
-
-    sa.sa_handler = signal_handler;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    if (sigaction(SIGALRM, &sa, 0)) {
-        fprintf(stderr, "Failed to install signal handler!\n");
-        return -1;
-    }
-
-    printf("Starting timer...\n");
-    tv.it_interval.tv_sec = 0;
-    tv.it_interval.tv_usec = 1000000 / FREQUENCY;
-    tv.it_value.tv_sec = 0;
-    tv.it_value.tv_usec = 1000;
-    if (setitimer(ITIMER_REAL, &tv, NULL)) {
-        fprintf(stderr, "Failed to start timer: %s\n", strerror(errno));
-        return 1;
-    }
-
-    printf("Started.\n");
+    }
+
+    /* Lock memory */
+
+    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
+        fprintf(stderr, "Warning: Failed to lock memory: %s\n",
+                strerror(errno));
+    }
+
+    stack_prefault();
+
+    printf("Starting RT task with dt=%u ns.\n", PERIOD_NS);
+
+    clock_gettime(CLOCK_MONOTONIC, &wakeup_time);
+    wakeup_time.tv_sec += 1; /* start in future */
+    wakeup_time.tv_nsec = 0;
+
     while (1) {
-        pause();
-
-#if 0
-        struct timeval t;
-        gettimeofday(&t, NULL);
-        printf("%u.%06u\n", t.tv_sec, t.tv_usec);
-#endif
-
-        while (sig_alarms != user_alarms) {
-            cyclic_task();
-            user_alarms++;
+        ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
+                &wakeup_time, NULL);
+        if (ret) {
+            fprintf(stderr, "clock_nanosleep(): %s\n", strerror(ret));
+            break;
         }
-    }
-
-    return 0;
-}
-
-/****************************************************************************/
+
+        cyclic_task();
+
+        wakeup_time.tv_nsec += PERIOD_NS;
+        while (wakeup_time.tv_nsec >= NSEC_PER_SEC) {
+            wakeup_time.tv_nsec -= NSEC_PER_SEC;
+            wakeup_time.tv_sec++;
+        }
+    }
+
+    return ret;
+}
+
+/****************************************************************************/