1 #include <posix/unistd.h>
2 #include <linux/module.h>
3 #include <asm/atomic.h>
7 #include <linux/time.h>
11 /* TODO osetrit vicero pongu */
13 /* Defines for better compatibility with user-space version */
14 #define option_device device
15 #define option_masters masters
16 #define option_first_id first_id
17 #define option_slaves slaves
18 #define option_verbose verbose
19 #define option_length length
20 #define option_count count
21 #define option_wait_ms wait_ms
22 #define option_timeout timeout
23 #define option_open_once open_once
24 #define option_synch_start synch_start
26 #define printf rtl_printf
27 #define fprintf(file, fmt, arg...) printf(fmt, ## arg)
28 #define perror(s) printf("%s: error %d\n", s, errno);
29 #define exit(retval) pthread_exit((void *)retval)
30 #define select(NFDS, READFDS, WRITEFDS, EXCEPTFDS, TIMEOUT) (1)
31 #define malloc(size) kmalloc(size, GFP_KERNEL)
32 #define free(what) kfree(what)
33 #define sqrt(val) (0.0)
36 #define siginterrupt(a, b)
37 #define gettimeofday(a, b) do {;} while (0) //do_gettimeofday(a)
40 #define dbg(level, fmt, arg...) do {} while (0)
42 #define dbg(level, fmt, arg...) do { if (level <= DEBUG) { printf("candping: " fmt, ## arg); } } while (0)
45 #define NOT_INTERRUPTED_SYSCALL (errno != EINTR && errno != ERESTART)
46 #define IS_FINISH_FLAG() (atomic_read(&finish_flag) != 0)
50 #define EXIT_BAD_PARAM 1
51 #define EXIT_CANNOT_OPEN 2
52 #define EXIT_FILTER_ERROR 3
54 #define EXIT_READ_ERROR 5
55 #define EXIT_WRITE_ERROR 6
56 #define EXIT_SELECT_ERROR 7
57 #define EXIT_FLUSH_ERROR 8
59 /* Global variables */
60 atomic_t finish_flag = ATOMIC_INIT(0); /* Threads should terminate. */
61 sem_t finish_sem; /* Thread signals a termination */
65 int total_timeout = 0;
67 pthread_mutex_t mut_start = PTHREAD_MUTEX_INITIALIZER;
68 pthread_cond_t cond_start = PTHREAD_COND_INITIALIZER;
70 sem_t ready_sem; /* Thread is ready for execution */
73 /* Command line options */
74 char *option_device = "/dev/can0";
75 int option_masters = 0;
76 long int option_first_id = 1000;
77 int option_slaves = 0;
78 int option_verbose = 0; /* 0 - nothing, 1 - only global
79 * statistics, 2 - simple times, 3 -
81 int option_length = 8;
83 int option_wait_ms = 1000;
84 int option_timeout = 4;
85 int option_open_once = 0;
86 int option_synch_start = 0;
88 MODULE_PARM_DESC(option_device,"name of CAN device [/dev/can0]");
89 MODULE_PARM(option_device,"1s");
91 MODULE_PARM_DESC(option_first_id,"lowest ID of generated messages [1000]");
92 MODULE_PARM(option_first_id,"1i");
94 MODULE_PARM_DESC(option_masters,"how many master threads to start");
95 MODULE_PARM(option_masters,"1i");
97 MODULE_PARM_DESC(option_slaves,"how many slave threads to start");
98 MODULE_PARM(option_slaves,"1i");
100 MODULE_PARM_DESC(option_verbose,"verbosity level");
101 MODULE_PARM(option_verbose,"1i");
103 MODULE_PARM_DESC(option_count,"number of messages to send");
104 MODULE_PARM(option_count,"1i");
106 MODULE_PARM_DESC(option_wait_ms,"miliseconds to wait between sent messages");
107 MODULE_PARM(option_wait_ms,"1i");
109 MODULE_PARM_DESC(option_synch_start,"synchronize threads before start");
110 MODULE_PARM(option_synch_start,"1i");
113 MODULE_SUPPORTED_DEVICE("canping");
114 MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");
115 MODULE_DESCRIPTION("canping: RT-Linux LinCAN test application");
116 MODULE_LICENSE("GPL");
119 typedef struct threads {
123 typedef struct thread_data {
128 double mean; /* mean value of responses */
129 double moment2nd; /* used to compute variance of
131 int min, max; /* min/max response times */
132 int timeout; /* number of timeouts */
137 UL_LIST_CUST_DEC(thread_list, threads_t, thread_data_t, head, node);
139 threads_t master_threads;
140 threads_t slave_threads;
142 /* Subtract the `struct timeval' values X and Y, storing the result in
143 RESULT. Return 1 if the difference is negative, otherwise 0. */
145 int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
147 /* Perform the carry for the later subtraction by updating Y. */
148 if (x->tv_usec < y->tv_usec) {
149 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
150 y->tv_usec -= 1000000 * nsec;
153 if (x->tv_usec - y->tv_usec > 1000000) {
154 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
155 y->tv_usec += 1000000 * nsec;
159 /* Compute the time remaining to wait.
160 `tv_usec' is certainly positive. */
161 result->tv_sec = x->tv_sec - y->tv_sec;
162 result->tv_usec = x->tv_usec - y->tv_usec;
164 /* Return 1 if result is negative. */
165 return x->tv_sec < y->tv_sec;
168 void dbg_print_timeval(char *msg, struct timeval *tv)
171 printf("%s sec=%ld usec=%ld\n", msg, tv->tv_sec, tv->tv_usec);
173 void kill_all_threads(int signum)
177 ul_list_for_each(thread_list, &master_threads, td) {
178 pthread_kill(td->tid, signum);
180 ul_list_for_each(thread_list, &slave_threads, td) {
181 pthread_kill(td->tid, signum);
184 void term_handler(int signum)
186 dbg(1, "Thread %p got a signal %d\n", (void *)pthread_self(), signum);
187 if (!IS_FINISH_FLAG()) {
188 dbg(1, "Terminating threads\n");
189 atomic_set(&finish_flag, 1);
191 kill_all_threads(signum);
195 void *master_thread(void *arg)
197 thread_data_t *td = (thread_data_t *)arg;
198 int ping_id = td->canid;
199 int pong_id = ping_id + 1;
200 struct canmsg_t pingmsg, pongmsg;
203 int canfd; /* File descriptor of CAN driver. */
205 fd_set rdset; /* read set for select syscall */
206 struct timeval to, pingtime, pongtime;
207 struct canfilt_t canfilt; /* filter for received messages */
209 if (!option_open_once) {
210 /* Open can driver */
211 if ((canfd = open(option_device, O_RDWR)) < 0) {
213 fprintf(stderr, "Error opening %s (for id %d)\n", option_device, ping_id);
214 exit(EXIT_CANNOT_OPEN);
217 canfd = global_canfd;
220 /* setup filtering of received messages */
221 memset(&canfilt, 0, sizeof(canfilt));
222 canfilt.mask = 0xfffffff;
223 canfilt.id = pong_id; /* pong responces with increased id */
224 ret = ioctl(canfd, CANQUE_FILTER, &canfilt);
226 perror("ioctl CANQUE_FILTER");
227 exit(EXIT_FILTER_ERROR);
229 ret = ioctl(canfd, CANQUE_FLUSH, NULL);
231 perror("ioctl CANQUE_QUEUE_FLUSH");
232 exit(EXIT_FLUSH_ERROR);
235 /* Prepare data structures for the select syscall. */
238 /* Signal that I'm ready */
239 sem_post(&ready_sem);
241 if (option_synch_start) {
242 /* Wait for other threads to initialize */
243 pthread_mutex_lock(&mut_start);
244 while (!start_flag) pthread_cond_wait(&cond_start, &mut_start);
245 pthread_mutex_unlock(&mut_start);
248 while (!IS_FINISH_FLAG() && (option_count == 0 || ping_count++ < option_count)) {
249 /* Send a ping message */
252 pingmsg.length = option_length;
253 for (i=0; i < option_length; i++) pingmsg.data[i] = i;
254 gettimeofday(&pingtime, NULL);
256 ret = write(canfd, &pingmsg, sizeof(pingmsg));
258 if (NOT_INTERRUPTED_SYSCALL) {
260 exit(EXIT_WRITE_ERROR);
264 /* Wait for a pong responce */
265 FD_SET (canfd, &rdset);
267 to.tv_sec = option_timeout;
270 ret = select(FD_SETSIZE, &rdset, NULL, NULL, &to);
272 /* Read the message */
274 ret = read(canfd, &pongmsg, sizeof(pongmsg));
276 if (NOT_INTERRUPTED_SYSCALL) {
278 exit(EXIT_READ_ERROR);
281 else { /* A pong message received */
283 gettimeofday(&pongtime, NULL);
285 fprintf(stderr, "read returned zero\n");
286 exit(EXIT_READ_ERROR);
288 if (pongmsg.id != pong_id) {
289 fprintf(stderr, "Filter error (expected: %d, received %ld)\n", pong_id, pongmsg.id);
290 exit(EXIT_FILTER_ERROR);
292 timeval_subtract(&pongtime, &pongtime, &pingtime);
293 time = pongtime.tv_sec*1000000 + pongtime.tv_usec;
294 switch (option_verbose) {
296 printf("%d:%ld\n", ping_id, time);
299 printf("Pong response for id %d received in %ld us\n", ping_id, time);
302 /* Update statistics */
305 td->mean * ((double)(td->count - 1) / td->count) +
306 (double)time / td->count;
308 td->moment2nd * ((double)(td->count - 1) / td->count) +
309 (double)time*time / td->count;
310 if (time > td->max) td->max = time;
311 if (time < td->min) td->min = time;
314 } else if (ret == 0) { /* select */
315 if (option_verbose >= 2)
316 printf("Timeout encountered (id %d)\n", ping_id);
320 if (NOT_INTERRUPTED_SYSCALL) {
322 exit(EXIT_SELECT_ERROR);
325 usleep(option_wait_ms * 1000);
328 if (!option_open_once) {
329 /* Close the can driver */
333 sem_post(&finish_sem);
337 void start_masters(int masters, int first_id)
342 dbg(1, "Starting %d master threads\n", masters);
344 for (i = 0; i < masters; i++, id += 2) {
347 td = malloc(sizeof(*td));
349 printf("Can't allocate memory");
352 memset(td, 0, sizeof(*td));
354 td->min = 0x7fffffff;
355 /* TODO use mutexes and signal blocking */
356 thread_list_ins_tail(&master_threads, td);
357 pthread_create(&td->tid, NULL, master_thread, (void *)td);
358 dbg(2, "Master thread: %p\n", (void *)td->tid);
362 /* Wait for all threads beeing ready */
363 for (i = 0; i < masters; i++) sem_wait(&ready_sem);
366 pthread_mutex_lock(&mut_start);
368 pthread_cond_broadcast(&cond_start);
369 pthread_mutex_unlock(&mut_start);
372 void *slave_thread(void *arg)
374 thread_data_t *td = (thread_data_t *)arg;
375 int ping_id = td->canid;
376 int pong_id = ping_id + 1;
377 struct canmsg_t pingmsg, pongmsg;
379 int canfd; /* File descriptor of CAN driver. */
381 struct canfilt_t canfilt; /* filter for received messages */
383 if (!option_open_once) {
384 /* Open the CAN driver */
385 if ((canfd = open(option_device, O_RDWR)) < 0) {
387 printf("Error opening %s (for id %d)\n", option_device, ping_id);
388 exit(EXIT_CANNOT_OPEN);
391 canfd = global_canfd;
394 /* setup filtering of received messages */
395 memset(&canfilt, 0, sizeof(canfilt));
396 canfilt.mask = 0xfffffff;
397 canfilt.id = ping_id; /* receive only our ping messages */
398 ret = ioctl(canfd, CANQUE_FILTER, &canfilt);
400 perror("ioctl CANQUE_FILTER");
401 exit(EXIT_FILTER_ERROR);
403 /* If there are some messages already, delete them. These may
404 * not processed by our filter and thus may have a wrong
406 ret = ioctl(canfd, CANQUE_FLUSH, NULL);
408 perror("ioctl CANQUE_QUEUE_FLUSH");
409 exit(EXIT_FLUSH_ERROR);
412 /* Prepare a pong message */
414 pongmsg.id = pong_id;
415 pongmsg.length = option_length;
416 for (i=0; i < option_length; i++) pongmsg.data[i] = i;
418 while (!IS_FINISH_FLAG()) {
419 /* Receive a ping message */
421 ret = read(canfd, &pingmsg, sizeof(pingmsg));
423 if (NOT_INTERRUPTED_SYSCALL) {
424 printf("%d\n", errno);
426 exit(EXIT_READ_ERROR);
429 if (NOT_INTERRUPTED_SYSCALL && pingmsg.id != ping_id) {
430 fprintf(stderr, "Filter error (expected: %d, received %ld)\n", ping_id, pingmsg.id);
431 exit(EXIT_FILTER_ERROR);
433 /* Answer immendiately with a pong message */
434 if (NOT_INTERRUPTED_SYSCALL) {
435 ret = write(canfd, &pongmsg, sizeof(pongmsg));
437 if (NOT_INTERRUPTED_SYSCALL) {
439 exit(EXIT_WRITE_ERROR);
444 if (ret >= 0) total_count++;
446 if (option_verbose >= 2)
447 /* This drasticly slows down the pong
448 * response. Why??? */
449 printf("Replying to ping id %lu\n", pingmsg.id);
453 if (!option_open_once) {
454 /* Close can driver */
458 sem_post(&finish_sem);
462 void start_slaves(int slaves, int first_id)
467 dbg(1, "Starting %d slave threads\n", slaves);
469 for (i = 0; i < slaves; i++, id += 2) {
472 td = malloc(sizeof(*td));
474 printf("Can't allocate memory");
477 memset(td, 0, sizeof(*td));
479 /* TODO use mutexes and signal blocking */
480 thread_list_ins_tail(&slave_threads, td);
481 pthread_create(&td->tid, NULL, slave_thread, (void *)td);
482 dbg(2, "Slave thread: %p\n", (void *)td->tid);
486 void print_help(void)
488 printf("Usage: canping -m <master threads> [other options]\n"
489 " canping -s <slave threads> [other options]\n\n"
491 " -c count how many messages each master sends\n"
492 " -d dev device (e.g. /dev/can1)\n"
493 " -h print this help\n"
494 " -i id id of first master message\n"
495 " -l length length of the messages (0..8)\n"
496 " -o open a device only once for all threads (doesn't work)\n" /* due to filters */
497 " -t timeout timeout in seconds (default 4 s)\n"
498 " -v be verbose (use more than once to increase verbosity)\n"
499 " -w ms wait ms miliseconds between sending pings\n"
500 " -y synchronize threads before start (doesn't test race conditions\n"
501 " between open and read/write)\n"
503 "Example: canping -m 10 -vv\n"
507 void print_stats(thread_data_t *td)
510 int count = td->count + td->timeout;
512 if (td->count >= 2) {
513 snprintf(std, 19, "%7.2f", sqrt((td->count/(td->count - 1)) *
514 (td->moment2nd - td->mean*td->mean)));
516 strncpy(std, "N/A", 19);
518 printf("Id %4ld: count = %5d"
519 " mean = %7.2f stddev = %s"
520 " min = %5d max = %5d [us]"
521 " loss = %d%% (%d)\n",
522 td->canid, count, td->mean,
525 (count > 0) ? 100 * td->timeout / count : 0, td->timeout
529 void wait_for_threads(void)
533 int thread_count = option_slaves + option_masters;
534 while (thread_count > 0) {
535 if (option_verbose != 1) {
536 sem_wait(&finish_sem);
539 if (!IS_FINISH_FLAG()) {
540 printf("Total count: %6d, Timeouts: %6d\r", total_count, total_timeout);
544 while (sem_trywait(&finish_sem) == 0) thread_count--;
547 if (option_verbose == 1) {
551 ul_list_for_each(thread_list, &master_threads, td) {
552 pthread_join(td->tid, &thread_ret);
553 dbg(2, "Master thread for id %ld finished; exit code %d\n", td->canid, (int)thread_ret);
556 ul_list_for_each(thread_list, &slave_threads, td) {
557 pthread_join(td->tid, &thread_ret);
558 dbg(2, "Slave thread for id %ld finished; exit code %d\n", td->canid, (int)thread_ret);
561 if (option_masters) printf("Summary statistics:\n");
563 ul_list_for_each_cut(thread_list, &master_threads, td) {
569 ul_list_for_each_cut(thread_list, &slave_threads, td)
573 int main(int argc, char *argv[])
575 thread_list_init_head(&master_threads);
576 thread_list_init_head(&slave_threads);
578 sem_init(&finish_sem, 0, 0);
579 sem_init(&ready_sem, 0, 0);
581 siginterrupt(SIGINT, 1);
582 signal(SIGINT, term_handler);
583 siginterrupt(SIGTERM, 1);
584 signal(SIGTERM, term_handler);
586 dbg(2, "Main thread: %p\n", (void *)pthread_self());
588 if (option_open_once) {
589 /* Open the CAN driver */
590 if ((global_canfd = open(option_device, O_RDWR)) < 0) {
592 printf("Error opening %s\n", option_device);
593 exit(EXIT_CANNOT_OPEN);
597 if (option_masters) start_masters(option_masters, option_first_id);
598 if (option_slaves) start_slaves(option_slaves, option_first_id);
600 /* wait_for_threads(); */
602 /* if (option_open_once) { */
603 /* close(global_canfd); */
609 int init_module(void)
611 rtl_printf("Loading canping_rtl module...\n");
612 return main(0, NULL);
615 void cleanup_module(void)
619 rtl_printf("Module canping_rtl finished.\n");