Latester update
authorMichal Sojka <sojkam1@fel.cvut.cz>
Mon, 29 Nov 2010 14:43:19 +0000 (15:43 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Mon, 29 Nov 2010 14:43:19 +0000 (15:43 +0100)
latester/Makefile.omk
latester/latester.c

index b91f16e..0b9029d 100644 (file)
@@ -2,7 +2,7 @@
 
 bin_PROGRAMS += latester
 latester_SOURCES = latester.c
-latester_LIBS = rt pthread m #ulut
+latester_LIBS = rt pthread m talloc popt #ulut
 
 INCLUDES = -DSO_RXQ_OVFL=40 \
           -DPF_CAN=29 \
index 6b5c7ed..469b794 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/can.h>
 #include <linux/can/raw.h>
 #include <poll.h>
+#include <talloc.h>
+#include <popt.h>
 
 #include "histogram.h"
 
 volatile sig_atomic_t finish_flag = 0; /* Threads should terminate. */
 sem_t finish_sem;              /* Thread signals a termination */
 
-#define MAX_INTERFACES 4
-
 /* Command line options */
-char *option_interface[MAX_INTERFACES];
+struct options {
+       char **interface;
+       canid_t id;
+       unsigned period_us;
+       unsigned timeout_ms;
+       unsigned count;
+       unsigned oneattime;
+} opt = {
+       .id = 10,
+       .period_us = 0,
+       .timeout_ms = 1000,
+       
+};
+
 int num_interfaces = 0;
-canid_t option_id;
-unsigned option_period_us = 100000;
 
 struct msg_info {
        canid_t id;
@@ -78,23 +89,37 @@ static inline struct msg_info *frame2info(struct can_frame *frame)
        return &msg_infos[idx];
 }
 
-static inline char *tstamp_str(char *buf, struct timespec *tstamp)
+static inline char *tstamp_str(const void *ctx, struct timespec *tstamp)
 {
-       sprintf(buf, "%ld.%06ld", tstamp->tv_sec, tstamp->tv_nsec/1000);
+       return talloc_asprintf(ctx, "%ld.%06ld",
+                              tstamp->tv_sec, tstamp->tv_nsec/1000);
 }
 
 void print_msg_info(struct msg_info *mi)
 {
-       struct timespec ts_diff1, ts_diff2;
-       char str_sent[32], str_kern[32], str_user[32], str_diff1[32], str_diff2[32];
-       timespec_subtract(&ts_diff1, &mi->ts_rx_final_kern, &mi->ts_sent);
-       timespec_subtract(&ts_diff2, &mi->ts_rx_final,      &mi->ts_sent);
-       tstamp_str(str_sent, &mi->ts_sent);
-       tstamp_str(str_kern, &mi->ts_rx_final_kern);
-       tstamp_str(str_user, &mi->ts_rx_final);
-       tstamp_str(str_diff1, &ts_diff1);
-       tstamp_str(str_diff2, &ts_diff2);
-       printf("%s -> %s (%s) = %s (%s)\n", str_sent, str_user, str_kern, str_diff1, str_diff2);
+       struct timespec diff;
+       void *local = talloc_new (NULL);
+       
+#define S(ts) tstamp_str(local, &ts)
+#define DIFF(a, b) (timespec_subtract(&diff, &b, &a), S(diff))
+       
+       if (num_interfaces == 2) 
+               printf("%s -> %s (%s) = %s (%s)\n",
+                      S(mi->ts_sent), S(mi->ts_rx_final_kern), S(mi->ts_rx_final),
+                      DIFF(mi->ts_sent, mi->ts_rx_onwire_kern),
+                      DIFF(mi->ts_sent, mi->ts_rx_onwire));
+       else
+               printf("%s -> %s (%s) -> %s (%s) = %s (%s), %s (%s)\n",
+                      S(mi->ts_sent),
+                      S(mi->ts_rx_onwire_kern), S(mi->ts_rx_onwire),
+                      S(mi->ts_rx_final_kern), S(mi->ts_rx_final),
+                      DIFF(mi->ts_sent, mi->ts_rx_onwire_kern),
+                      DIFF(mi->ts_sent, mi->ts_rx_onwire),
+                      DIFF(mi->ts_rx_onwire_kern, mi->ts_rx_final_kern),
+                      DIFF(mi->ts_rx_onwire, mi->ts_rx_final));
+#undef S
+#undef DIFF
+       talloc_free (local);
 }
 
 
@@ -159,7 +184,7 @@ static inline int sock_get_if_index(int s, const char *if_name)
        
        strcpy(ifr.ifr_name, if_name);
        if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
-               error(1, errno, "SIOCGIFINDEX");
+               error(1, errno, "SIOCGIFINDEX '%s'", if_name);
        return ifr.ifr_ifindex;
 }
 
@@ -174,7 +199,7 @@ int send_frame(int socket)
        struct msg_info *mi;
        int ret;
 
-       frame.can_id = option_id;
+       frame.can_id = opt.id;
        frame.can_dlc = 2;
        memcpy(frame.data, &curr_msg, sizeof(curr_msg));
        mi = frame2info(&frame);
@@ -193,13 +218,19 @@ static inline void get_next_timeout(struct timespec *timeout)
        
        if (last.tv_sec == -1)
                last = now;
-       last.tv_sec += option_period_us/1000000;
-       last.tv_nsec += (option_period_us%1000000)*1000;
-       while (last.tv_nsec >= 1000000000) {
-               last.tv_nsec -= 1000000000;
-               last.tv_sec++;
-       }               
-       timespec_subtract(timeout, &last, &now);
+       if (opt.period_us != 0) {
+               last.tv_sec += opt.period_us/1000000;
+               last.tv_nsec += (opt.period_us%1000000)*1000;
+               while (last.tv_nsec >= 1000000000) {
+                       last.tv_nsec -= 1000000000;
+                       last.tv_sec++;
+               }               
+               timespec_subtract(timeout, &last, &now);
+       } else if (opt.timeout_ms != 0) {
+               timeout->tv_sec = opt.timeout_ms/1000;
+               timeout->tv_nsec = (opt.timeout_ms%1000)*1000000;
+       } else
+               error(1, 0, "Timeout and period cannot be both zero");
 }
 
 void receive(int s, struct can_frame *frame, struct timespec *ts_kern, struct timespec *ts_user)
@@ -251,7 +282,13 @@ void process_tx(int s)
 
 void process_on_wire_rx(int s)
 {
-       error(1, 0, "%s: not implemented", __FUNCTION__);
+       struct timespec ts_kern, ts_user, ts_diff;
+       struct can_frame frame;
+       struct msg_info *mi;
+       receive(s, &frame, &ts_kern, &ts_user);
+       mi = frame2info(&frame);
+       mi->ts_rx_onwire_kern = ts_kern;
+       mi->ts_rx_onwire = ts_user;
 }
 
 
@@ -271,10 +308,12 @@ void process_final_rx(int s)
 void *measure_thread(void *arg)
 {
        int s, i, ret;
-       struct pollfd pfd[MAX_INTERFACES];
+       struct pollfd pfd[3];
        struct timespec timeout;
        struct sockaddr_can addr;
        sigset_t set;
+       int count = 0;
+       unsigned msg_in_progress = 0;
 
        MEMSET_ZERO(pfd);
        
@@ -283,7 +322,7 @@ void *measure_thread(void *arg)
                        error(1, errno, "socket");
 
                addr.can_family = AF_CAN;
-               addr.can_ifindex = sock_get_if_index(s, option_interface[i]);
+               addr.can_ifindex = sock_get_if_index(s, opt.interface[i]);
 
                if (i == 0) {   /* TX socket */
                        /* disable default receive filter on this RAW socket */
@@ -308,36 +347,66 @@ void *measure_thread(void *arg)
 //                     error(1, errno, "setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
 
                pfd[i].fd = s;
-               pfd[i].events = (i == 0) ? POLLERR : POLLIN;
+               if (i == 0)
+                       pfd[i].events = POLLIN | POLLERR | (opt.period_us == 0 ? POLLOUT : 0);
+               else
+                       pfd[i].events = POLLIN;
        }
 
        set_sched_policy_and_prio(SCHED_FIFO, 99);
 
-       while (!finish_flag) {
+#define SEND()                                         \
+       do {                                            \
+               ret = send_frame(pfd[0].fd);            \
+               if (ret != sizeof(struct can_frame))    \
+                       error(1, errno, "send_frame");  \
+               msg_in_progress++;                      \
+       } while (0)
+
+       while (!finish_flag &&
+              (opt.count == 0 || count < opt.count || msg_in_progress != 0)) {
                get_next_timeout(&timeout);
                ret = ppoll(pfd, num_interfaces, &timeout, NULL);
                switch (ret) {
-               case -1:
+               case -1: // Error
                        if (!INTERRUPTED_SYSCALL(errno))
                                error(1, errno, "ppoll");
                        break;
-               case 0:
-                       ret = send_frame(pfd[0].fd);
-                       if (ret != sizeof(struct can_frame))
-                               error(1, errno, "send_frame");
+               case 0: // Timeout
+                       if (opt.period_us) {
+                               if (opt.count == 0 || count++ < opt.count) {
+                                       SEND();
+                               } else {
+                                       error(1, 0, "poll timeout");
+                               }
+                       }
                        break;
-               default:
-                       if (pfd[0].revents != 0) {
+               default: // Event
+                       if (pfd[0].revents & (POLLIN|POLLERR)) {
                                process_tx(pfd[0].fd);
                        }
-                       if (pfd[1].revents != 0) {
-                               switch (num_interfaces) {
-                               case 2: process_final_rx(pfd[1].fd); break;
-                               case 3: process_on_wire_rx(pfd[1].fd); break;
+                       if (pfd[0].revents & POLLOUT) {
+                               if ((opt.count == 0 || count++ < opt.count) &&
+                                   !opt.oneattime) {
+                                       SEND();
                                }
                        }
-                       if (pfd[2].revents != 0) {
-                               process_final_rx(pfd[2].fd);
+                       pfd[0].revents = 0;
+
+                       if (num_interfaces == 3 && pfd[1].revents != 0) {
+                               process_on_wire_rx(pfd[1].fd);
+                               pfd[1].revents = 0;
+                       }
+
+                       i = (num_interfaces == 2) ? 1 : 2;
+                       if (pfd[i].revents != 0) {
+                               process_final_rx(pfd[i].fd);
+                               msg_in_progress--;
+                               pfd[i].revents = 0;
+                               if ((opt.count == 0 || count++ < opt.count) &&
+                                   opt.oneattime) {
+                                       SEND();
+                               }
                        }
                }
        }
@@ -348,54 +417,56 @@ void *measure_thread(void *arg)
        return NULL;
 }
 
-void print_help(void)
-{
-       printf("Usage: latester -d <interface> -d <interface> ... [other options]\n"
-              "Other options:\n"
-              "  -d <interface> Interface to use. Must be given two times (tx, rx) or three times (tx, rx1, rx2).\n"
-               );
-}
-     
-int parse_options(int argc, char *argv[])
+struct poptOption optionsTable[] = {
+       { "device", 'd', POPT_ARG_ARGV, &opt.interface, 'd', "Interface to use. Must be given two times (tx, rx) or three times (tx, rx1, rx2)", "interface" },
+       { "count",  'c', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.count,   0,   "The count of messages to send, zero corresponds to infinity", "num"},
+       { "id",     'i', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.id,      0,   "CAN ID of sent messages", "id"},
+       { "period", 'p', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.period_us, 0,   "Period for sending messages or zero (default) to send as fast as possible", "us"},
+       { "timeout",'t', POPT_ARG_INT|POPT_ARGFLAG_SHOW_DEFAULT,  &opt.timeout_ms,0,   "Timeout when period is zero", "ms"},
+       { "oneattime",'o', POPT_ARG_NONE,                         &opt.oneattime,0,   "Send the next message only when the previous was finally received"},
+       { "verbose",'v', POPT_ARG_NONE,                           NULL, 'v',   "Send the next message only when the previous was finally received"},
+       POPT_AUTOHELP
+       { NULL, 0, 0, NULL, 0 }
+};
+
+int parse_options(int argc, const char *argv[])
 {
        int c;
+       poptContext optCon;   /* context for parsing command-line options */
        
-       opterr = 0;
-       while ((c = getopt (argc, argv, "d:h")) != -1)
-               switch (c)
-               {
+       optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
+       //poptSetOtherOptionHelp(optCon, "[OPTIONS]* <port>");
+
+       /* Now do options processing */
+       while ((c = poptGetNextOpt(optCon)) >= 0) {
+               switch (c) {
                case 'd':
-                       if (num_interfaces < MAX_INTERFACES) {
-                               option_interface[num_interfaces] = optarg;
-                               num_interfaces++;
-                       } else
-                               error(1, 0, "error: Too many -d options");
-                       break;
-               case 'h':
-                       print_help();
-                       exit(0);
+                       num_interfaces++;
                        break;
-               case '?':
-                       if (isprint (optopt))
-                               error (1, 0, "Unknown option `-%c'.\n", optopt);
-                       else
-                               error (1, 0, "Unknown option character `\\x%x'.\n", optopt);
-               default:
-                       error(1, 0, "Unhandled parameter");
                }
+       }
+       if (c < -1)
+               error(1, 0, "%s: %s\n",
+                     poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+                     poptStrerror(c));
+       
        if (num_interfaces < 2 || num_interfaces > 3)
                error(1, 0, "-d option must be given exactly 2 or 3 times");
+
+       poptFreeContext(optCon);
+
        return 0;
 }
 
-int main(int argc, char *argv[])
+
+int main(int argc, const char *argv[])
 {
        pthread_t thread;
        sigset_t set;
        int ret;
-                          
-       parse_options(argc, argv);
 
+       parse_options(argc, argv);
+                          
        mlockall(MCL_CURRENT | MCL_FUTURE);
 
        signal(SIGINT, term_handler);