4848#include <string.h>
4949#include <time.h>
5050#include <unistd.h>
51+ #include <stdbool.h>
5152
5253#include <linux/can.h>
5354#include <linux/can/raw.h>
@@ -89,6 +90,12 @@ const int canfx_on = 1;
8990
9091extern int optind , opterr , optopt ;
9192
93+ struct sleep {
94+ struct timeval * sleep_vector ;
95+ size_t idx ;
96+ size_t size ;
97+ };
98+
9299static void print_usage (char * prg )
93100{
94101 fprintf (stderr , "%s - replay a compact CAN frame logfile to CAN devices.\n" , prg );
@@ -117,6 +124,8 @@ static void print_usage(char *prg)
117124 "loopback of sent CAN frames)\n" );
118125 fprintf (stderr , " -v (verbose: print "
119126 "sent CAN frames)\n" );
127+ fprintf (stderr , " -r (real-time: send "
128+ "CAN frames in real-time)\n" );
120129 fprintf (stderr , " -h (show "
121130 "this help message)\n\n" );
122131 fprintf (stderr , "Interface assignment:\n" );
@@ -254,6 +263,53 @@ static int add_assignment(char *mode, int socket, char *txname,
254263 return 0 ;
255264}
256265
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+
257313int main (int argc , char * * argv )
258314{
259315 static char buf [BUFSZ ], device [DEVSZ ], afrbuf [AFRSZ ];
@@ -280,8 +336,11 @@ int main(int argc, char **argv)
280336 int eof , txmtu , i , j ;
281337 char * fret ;
282338 unsigned long long sec , usec ;
339+ bool gap_from_file = false;
340+ struct sleep timestamps ;
341+ struct timeval send_time , act_time , init_time ;
283342
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 ) {
285344 switch (opt ) {
286345 case 'I' :
287346 infile = fopen (optarg , "r" );
@@ -336,6 +395,17 @@ int main(int argc, char **argv)
336395 verbose ++ ;
337396 break ;
338397
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+
339409 case 'h' :
340410 print_usage (basename (argv [0 ]));
341411 exit (EXIT_SUCCESS );
@@ -368,8 +438,10 @@ int main(int argc, char **argv)
368438 printf ("interactive mode: press ENTER to process next CAN frame ...\n" );
369439 }
370440
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+ }
373445
374446 /* open socket */
375447 if ((s = socket (PF_CAN , SOCK_RAW , CAN_RAW )) < 0 ) {
@@ -513,6 +585,23 @@ int main(int argc, char **argv)
513585 addr .can_family = AF_CAN ;
514586 addr .can_ifindex = txidx ; /* send via this interface */
515587
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+
516605 if (sendto (s , & cu , txmtu , 0 , (struct sockaddr * )& addr , sizeof (addr )) != txmtu ) {
517606 perror ("sendto" );
518607 return 1 ;
@@ -570,7 +659,7 @@ int main(int argc, char **argv)
570659
571660 } /* while frames_to_send ... */
572661
573- if (nanosleep (& sleep_ts , NULL ))
662+ if (! gap_from_file && nanosleep (& sleep_ts , NULL ))
574663 return 1 ;
575664
576665 delay_loops ++ ; /* private statistics */
0 commit comments