48
48
#include <string.h>
49
49
#include <time.h>
50
50
#include <unistd.h>
51
+ #include <stdbool.h>
51
52
52
53
#include <linux/can.h>
53
54
#include <linux/can/raw.h>
@@ -89,6 +90,12 @@ const int canfx_on = 1;
89
90
90
91
extern int optind , opterr , optopt ;
91
92
93
+ struct sleep {
94
+ struct timeval * sleep_vector ;
95
+ size_t idx ;
96
+ size_t size ;
97
+ };
98
+
92
99
static void print_usage (char * prg )
93
100
{
94
101
fprintf (stderr , "%s - replay a compact CAN frame logfile to CAN devices.\n" , prg );
@@ -117,6 +124,8 @@ static void print_usage(char *prg)
117
124
"loopback of sent CAN frames)\n" );
118
125
fprintf (stderr , " -v (verbose: print "
119
126
"sent CAN frames)\n" );
127
+ fprintf (stderr , " -r (real-time: send "
128
+ "CAN frames in real-time)\n" );
120
129
fprintf (stderr , " -h (show "
121
130
"this help message)\n\n" );
122
131
fprintf (stderr , "Interface assignment:\n" );
@@ -254,6 +263,53 @@ static int add_assignment(char *mode, int socket, char *txname,
254
263
return 0 ;
255
264
}
256
265
266
+ static void load_gaps_from_file (FILE * fp , struct sleep * timestamps )
267
+ {
268
+ char * line = NULL ;
269
+ size_t len = 0 ;
270
+ ssize_t read ;
271
+ struct timeval * current ;
272
+ struct timeval init_offset ;
273
+ init_offset .tv_sec = 0 ;
274
+ init_offset .tv_usec = 0 ;
275
+
276
+ while ((read = getline (& line , & len , fp )) != -1 ) {
277
+ if (timestamps -> idx == timestamps -> size ) {
278
+ timestamps -> size *= 2 ;
279
+ timestamps -> sleep_vector = realloc (timestamps -> sleep_vector , timestamps -> size * sizeof (* (timestamps -> sleep_vector )));
280
+ if (!timestamps -> sleep_vector ) {
281
+ fprintf (stderr , "Failed to realloc the timestamps vector!\n" );
282
+ exit (1 );
283
+ }
284
+ }
285
+ current = & timestamps -> sleep_vector [timestamps -> idx ];
286
+ sscanf (line , "(%lu.%lu)" , & (current -> tv_sec ), & (current -> tv_usec ));
287
+
288
+ if (timestamps -> idx == 0 && (current -> tv_sec != 0 || current -> tv_usec != 0 )){
289
+ init_offset .tv_sec = current -> tv_sec ;
290
+ init_offset .tv_usec = current -> tv_usec ;
291
+ }
292
+
293
+ if (timestamps -> idx > 0 && (init_offset .tv_sec > 0 || init_offset .tv_usec > 0 )){
294
+ current -> tv_sec -= init_offset .tv_sec ;
295
+ current -> tv_usec -= init_offset .tv_usec ;
296
+ }
297
+
298
+ timestamps -> idx ++ ;
299
+ }
300
+ free (line );
301
+ }
302
+
303
+ static void init_timestamps (struct sleep * timestamps , size_t init_size )
304
+ {
305
+ timestamps -> size = init_size ;
306
+ timestamps -> sleep_vector = calloc (init_size , sizeof (* (timestamps -> sleep_vector )));
307
+ if (!timestamps -> sleep_vector ) {
308
+ fprintf (stderr , "Failed to create the timestamps vector!\n" );
309
+ exit (1 );
310
+ }
311
+ }
312
+
257
313
int main (int argc , char * * argv )
258
314
{
259
315
static char buf [BUFSZ ], device [DEVSZ ], afrbuf [AFRSZ ];
@@ -280,8 +336,11 @@ int main(int argc, char **argv)
280
336
int eof , txmtu , i , j ;
281
337
char * fret ;
282
338
unsigned long long sec , usec ;
339
+ bool gap_from_file = false;
340
+ struct sleep timestamps ;
341
+ struct timeval send_time , act_time , init_time ;
283
342
284
- while ((opt = getopt (argc , argv , "I:l:tin:g:s:xvh " )) != -1 ) {
343
+ while ((opt = getopt (argc , argv , "I:l:tin:g:s:xvrh " )) != -1 ) {
285
344
switch (opt ) {
286
345
case 'I' :
287
346
infile = fopen (optarg , "r" );
@@ -336,6 +395,17 @@ int main(int argc, char **argv)
336
395
verbose ++ ;
337
396
break ;
338
397
398
+ case 'r' :
399
+ if (isatty (fileno (infile ))) {
400
+ fprintf (stderr , "Specify an input file for option -r !\n" );
401
+ exit (EXIT_FAILURE );
402
+ }
403
+ gap_from_file = true; /* using time delta from file */
404
+ init_timestamps (& timestamps , 1 );
405
+ load_gaps_from_file (infile , & timestamps );
406
+ timestamps .idx = 0 ; /*to avoid warning accessing idx variable*/
407
+ break ;
408
+
339
409
case 'h' :
340
410
print_usage (basename (argv [0 ]));
341
411
exit (EXIT_SUCCESS );
@@ -368,8 +438,10 @@ int main(int argc, char **argv)
368
438
printf ("interactive mode: press ENTER to process next CAN frame ...\n" );
369
439
}
370
440
371
- sleep_ts .tv_sec = gap / 1000 ;
372
- sleep_ts .tv_nsec = (gap % 1000 ) * 1000000 ;
441
+ if (!gap_from_file ) {
442
+ sleep_ts .tv_sec = gap / 1000 ;
443
+ sleep_ts .tv_nsec = (gap % 1000 ) * 1000000 ;
444
+ }
373
445
374
446
/* open socket */
375
447
if ((s = socket (PF_CAN , SOCK_RAW , CAN_RAW )) < 0 ) {
@@ -513,6 +585,23 @@ int main(int argc, char **argv)
513
585
addr .can_family = AF_CAN ;
514
586
addr .can_ifindex = txidx ; /* send via this interface */
515
587
588
+ if (gap_from_file && timestamps .idx > 0 ) {
589
+ send_time = timestamps .sleep_vector [timestamps .idx ];
590
+ gettimeofday (& act_time , NULL );
591
+ timersub (& act_time , & init_time , & act_time );
592
+
593
+ while (timercmp (& act_time , & send_time , < )){
594
+ gettimeofday (& act_time , NULL );
595
+ timersub (& act_time , & init_time , & act_time );
596
+ }
597
+ }
598
+ if (gap_from_file && timestamps .idx == 0 ) {
599
+ gettimeofday (& init_time , NULL );
600
+ gettimeofday (& act_time , NULL );
601
+ timersub (& act_time , & init_time , & act_time );
602
+ }
603
+ timestamps .idx ++ ;
604
+
516
605
if (sendto (s , & cu , txmtu , 0 , (struct sockaddr * )& addr , sizeof (addr )) != txmtu ) {
517
606
perror ("sendto" );
518
607
return 1 ;
@@ -570,7 +659,7 @@ int main(int argc, char **argv)
570
659
571
660
} /* while frames_to_send ... */
572
661
573
- if (nanosleep (& sleep_ts , NULL ))
662
+ if (! gap_from_file && nanosleep (& sleep_ts , NULL ))
574
663
return 1 ;
575
664
576
665
delay_loops ++ ; /* private statistics */
0 commit comments