summaryrefslogtreecommitdiff
path: root/src/ivyreplay
diff options
context:
space:
mode:
Diffstat (limited to 'src/ivyreplay')
-rwxr-xr-xsrc/ivyreplay768
1 files changed, 768 insertions, 0 deletions
diff --git a/src/ivyreplay b/src/ivyreplay
new file mode 100755
index 0000000..8d34b61
--- /dev/null
+++ b/src/ivyreplay
@@ -0,0 +1,768 @@
+#!/usr/bin/perl
+
+
+#=================================================================================
+#
+# M A I N
+#
+#=================================================================================
+
+use Tk;
+use Tk::Font;
+use Tk::ErrorDialog;
+use Tk::Dialog;
+use Tk::ProgressBar;
+use Time::HiRes qw(gettimeofday);
+use Ivy;
+use Carp;
+use strict;
+use Getopt::Long;
+use Tk::CmdLine;
+use vars qw/$opt_help $opt_b $opt_bus
+ $opt_size $opt_undersize $opt_autostart
+ $opt_repeat $opt_startregexp
+ $opt_stopregexp $opt_timegranularity $opt_debug/;
+
+# geometry
+my $minW = 1024;
+my $minH = 768;
+my $smallsized = 0;
+my $coef = 1;
+
+my $ivy_port; # undef:=> default value is treated by ivy-perl
+my $appname = 'IvyReplay';
+$appname =~ s/ /_/g;
+
+
+# replay
+my $replay_current_t0;
+my $replay_current_t;
+my $replay_data_t0;
+my $replay_data_t;
+my $replay_maxgap = 0.2; # sec
+my $replay_regulpct = [50, 20]; # %
+my $replay_factor = 1000; # msec
+my $replay_current_factor = $replay_factor;
+
+my $replay_speed = 1;
+my $replay_runnable = 1;
+my $replay_running = 0;
+my $replay_time_granularity = 1;
+my $replay_time_decimalplaces = 0;
+my $replay_timer;
+my $mw;
+my $replay_text;
+my $replay_repeat;
+my %replay_msg;
+my $replay_time;
+my $replay_min_time;
+my $replay_max_time;
+my $replay_last_time;
+my $replay_stepbystep;
+my $replay_bg = 'gray75';
+my $replay_fg = 'black';
+my $replay_bg_orig;
+my $replay_fg_orig;
+my $replay_hour;
+
+
+#----------------------------------------------------------------------------------
+# command line options management
+#----------------------------------------------------------------------------------
+
+Tk::CmdLine::SetArguments(-font => '7x14');
+Tk::CmdLine::SetArguments();
+
+if (not GetOptions('-help', '-b=s', '-bus=s', '-size=s', '-undersize',
+ '-repeat', '-startregexp=s', '-debug', '-timegranularity=s',
+ '-autostart', '-stopregexp=s') or $opt_help) {
+
+ print "\n";
+ print "Usage: ivyreplay [-b[us] bus] [-help]\n";
+ print " [-size size] [-undersize] [-autostart]\n";
+ print " [-repeat] [-timegranularity float>0]\n";
+ print " [-startregexp regexp] [-stopregexp regexp]\n";
+ print " [standard X11 options...]\n";
+ print " inputfile\n";
+ print "\n";
+ print "Options :\n";
+ print " -b <[addr]:port> Ivy bus (\$IVYBUS by default)\n";
+ print " -size <VGA|SVGA|XGA|SXGA|UXGA> Size of the main window\n";
+ print " -undersize If set, slightly reduces the main window\n";
+ print " -autostart If set, messages are replayed as soon as the\n";
+ print " -repeat If set, repeat infinitely the replay sequence\n";
+ print " -timegranularity Time granularity (in second) for replaying\n";
+ print " messages (1 by default)\n";
+ print " -startregexp <regexp> Regexp to match for starting replay\n";
+ print " ('^ClockStart\$'' by default)\n";
+ print " -stopregexp <regexp> Regexp to match for stopping replay\n";
+ print " ('^ClockStop\$'' by default)\n";
+ print "\n";
+
+ exit ;
+
+}
+
+croak "Error : an input file is expected\n" unless @ARGV > 0;
+
+$replay_repeat = $opt_repeat;
+if ($opt_bus) {
+ $ivy_port = $opt_bus;
+} elsif ($opt_b) {
+ $ivy_port = $opt_b;
+}
+my $title;
+my $ivy_version = $Ivy::VERSION;
+my $ivy_cvsrevision = 0;
+my $ivy_versionstring = "v$ivy_version";
+if ($ivy_version =~ s/Revision: (.*)//) {
+ $ivy_version = $1;
+ $ivy_cvsrevision = 1;
+ $ivy_versionstring = "v$ivy_version (cvs revision)";
+}
+if ($ivy_port) {
+ $title = "Ivyreplay ($ivy_port) - Ivy $ivy_versionstring";
+} else {
+ $title = "Ivyreplay (default port) - Ivy $ivy_versionstring";
+}
+$replay_time_granularity = $opt_timegranularity if $opt_timegranularity > 0;
+if ($replay_time_granularity >= 1) {
+ $replay_time_decimalplaces = 0;
+} else {
+ $replay_time_decimalplaces = $replay_time_granularity;
+ $replay_time_decimalplaces =~ s/^\+?\d*\.//;
+ $replay_time_decimalplaces = length($replay_time_decimalplaces);
+}
+$replay_hour = &replayTime();
+
+
+#===================================
+#
+# Size options
+
+if($opt_size eq "UXGA" || $opt_size eq "1600") {
+ $minW = 1600;
+ $minH = 1200;
+ $smallsized = 0;
+ $coef = 1.2;
+ Tk::CmdLine::SetArguments(-font => '10x20');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "SXGA" || $opt_size eq "1280") {
+ $minW = 1280;
+ $minH = 1024;
+ $smallsized = 0;
+ $coef = 1.1;
+ Tk::CmdLine::SetArguments(-font => '8x13');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "XGA" || $opt_size eq "1024") {
+ $minW = 1024;
+ $minH = 768;
+ $smallsized = 1;
+ $coef = 1;
+ Tk::CmdLine::SetArguments(-font => '7x14');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "SVGA" || $opt_size eq "800") {
+ $minW = 800;
+ $minH = 600;
+ $smallsized = 1;
+ $coef = 0.64;
+ Tk::CmdLine::SetArguments(-font => '6x10');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "VGA" || $opt_size eq "640"){
+ $minW = 640;
+ $minH = 480;
+ $smallsized = 1;
+ $coef = 0.48;
+ Tk::CmdLine::SetArguments(-font => '5x7');
+ Tk::CmdLine::SetArguments();
+}
+
+if ($opt_undersize) {
+ $minW -= 10;
+ $minH -= 30;
+}
+
+#=================================================================================
+#
+# H M I
+#
+#=================================================================================
+my $mw = MainWindow->new();
+
+# Set default min size
+$mw->geometry($minW."x".$minH);
+$mw->minsize($minW, $minH);
+$mw->title($title);
+
+# Key-Tab binding is deactivated, because this event will be used by entries
+# for completion functionality
+$mw->bind('<Key-Tab>', sub {Tk->break});
+my $focusedtext;
+$mw->bind("Tk::Text", "<FocusIn>", [sub {
+ &clearSearch() if $_[1] ne $focusedtext;
+ $focusedtext = $_[1];}, Ev('W')]);
+
+
+#----------------------------------------------------------------------------------
+# Progress bar
+#----------------------------------------------------------------------------------
+my $tpl = $mw->Toplevel;
+$tpl->Popup;
+$tpl->raise($mw);
+$tpl->title("");
+$tpl->geometry("300x50");
+my $progressbar =
+ $tpl->ProgressBar(-from => 0,
+ -length => 200,
+ -borderwidth => 2,
+ -colors => [ 0 => 'yellow'],
+ -relief => 'sunken',
+ -resolution => 0,
+ -anchor => 'w',
+ )->pack(-fill => 'both',
+ -expand => 1,
+ );
+$progressbar->value(0);
+$tpl->withdraw;
+
+
+
+#=================================================================================
+#
+# Ivy initialisation and Ivy bindings
+#
+#=================================================================================
+
+# init Ivy bus and start it.
+Ivy->init(-loopMode => 'TK',
+ -appName => $appname,
+ -ivyBus => $ivy_port,
+ -onDieFunc => [\&quit],
+ );
+my $ivy = Ivy->new();
+$ivy->start;
+
+
+#=================================================================================
+#
+# Options and arguments test
+#
+#=================================================================================
+
+&build();
+
+# load input files
+my $file = $ARGV[0];
+
+if (not open(IN, $file)) {
+ $mw->Tk::Error("Can't open file '$file' ($!)");
+} else {
+ &showProgressbar();
+ my ($step, $timefound) = &stepsnumber;
+ if ($timefound) {
+ &loadfileForReplay($step);
+ } else {
+ $mw->Tk::Error("No time information in file '$file'. ".
+ "Can't be replayed.");
+ }
+ &replayStart() if $opt_autostart;
+ &hideProgressbar();
+ close(IN);
+}
+
+MainLoop;
+
+#==================================================================================
+#
+# Functions
+#
+#==================================================================================
+
+
+#----------------------------------------------------------------------------------
+# Functions related to input/output files
+#----------------------------------------------------------------------------------
+
+sub stepsnumber {
+
+ my $step = 0;
+ my $timefound;
+ my $lc = 0;
+
+ # get lines number and test if exists time field
+ while(<IN>) {
+ chomp;
+ next if (/^applications=/ or /^(marker\d+)$/ or /^(messages_number=)/
+ or /^\#/);
+ my ($sender, $message) = split(/\s+/, $_, 2);
+ if ($message =~ /^(\d[\d\.]+\d)\s+.*/) {
+ $timefound = 1;
+ }
+ $lc++;
+ }
+ $step = int($lc/10);
+ $progressbar->configure(-to => $step*10);
+ seek(IN, 0, 0);
+ return ($step, $timefound);
+
+} # end stepsnumber
+
+sub build {
+
+ %replay_msg = ();
+ $replay_time = undef;
+ # build replay window
+ my $ctrl_fm = $mw->Frame()->pack(-side => 'bottom', -pady => 5);
+ $replay_text = $mw->Scrolled('Text',
+ -scrollbars => 'e',
+ -spacing1 => 2,
+ -spacing2 => 0,
+ -spacing3 => 2,
+ )->pack(-fill => 'both',
+ -expand => 1,
+ -side => 'bottom');
+ # colors
+ $replay_bg_orig = $replay_text->cget(-background);
+ $replay_fg_orig = $replay_text->cget(-foreground);
+ &wheelmousebindings($replay_text);
+ # build speed control buttons
+ my $realspeedrate = 1;
+ my $ctrl_fm1 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ $ctrl_fm1->Radiobutton(-text => "x0.1", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 0.1,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x0.5", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 0.5,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x1", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 1,
+ -variable => \$replay_speed,
+ -command => sub {
+ return if $realspeedrate == 1;
+ $realspeedrate = 1;
+ &regulationReset();
+ },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x2", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 2,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x5", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 5,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x10", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 10,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ # build hour label
+ my $ctrl_fm2 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ my $hour_lab = $ctrl_fm2->Label(-borderwidth => 1, -relief => 'ridge',
+ -height => 2,
+ -width => ($replay_time_decimalplaces > 0) ?
+ 10 + $replay_time_decimalplaces : 9,
+ -textvariable => \$replay_hour,
+ )->pack(-side => 'left');
+
+ # build control buttons
+ my $ctrl_fm3 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ $ctrl_fm3->Radiobutton(-text => "Play", -indicatoron => 0,
+ -width => 6,
+ -height => 2,
+ -value => 0,
+ -command => \&replayStart,
+ -variable => \$replay_runnable,
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm3->Radiobutton(-text => "Pause", -indicatoron => 0,
+ -width => 6,
+ -height => 2,
+ -value => 1,
+ -command => \&replayStop,
+ -variable => \$replay_runnable,
+ -selectcolor => 'white')->pack(-side => 'left');
+ # build loop and step by step checkbuttons
+ my $ctrl_fm4 =
+ $ctrl_fm->Frame(-relief => 'ridge', -borderwidth => 1
+ )->pack(-side => 'left', -padx => 10, -fill => 'y',
+ -expand => 1);
+ $ctrl_fm4->Checkbutton(-text => "Repeat",
+ -variable => \$replay_repeat,
+ )->pack(-side => 'left');
+
+ $ctrl_fm4->Checkbutton(-text => "Step by\nstep",
+ -variable => \$replay_stepbystep,
+ -command => \&replayStop,
+ )->pack(-side => 'left', -padx => 10);
+
+ # build close button
+ $ctrl_fm->Button(-text => "Close",
+ -command => \&replayClose,
+ -height => 1)->pack(-side => 'left', -padx => 10, -fill => 'y',
+ -expand => 1);
+ $mw->update;
+ $mw->minsize($mw->width, $mw->height);
+
+} # end build
+
+
+sub loadfileForReplay {
+
+ my $step = shift;
+ my $line = 0;
+
+ # display messsages to replay
+ my ($sender, $time, $message);
+ while(<IN>) {
+ chomp;
+ next if /^\#/ or /^applications=/ or /^messages_number=/
+ or /^\s*$/ or /^(marker\d+)$/;
+ ($sender, $time, $message) = split(/\s+/, $_, 3);
+ if ($replay_time_granularity >= 1) {
+ $time = int($time);
+ } else {
+ $time = sprintf("%.".$replay_time_decimalplaces."f", $time);
+ }
+ if (defined $replay_max_time) {
+ $replay_max_time = $time if $time > $replay_max_time;
+ } else {
+ $replay_max_time = $time;
+ }
+ if (defined $replay_min_time) {
+ $replay_min_time = $time if $time < $replay_min_time;
+ } else {
+ $replay_min_time = $time;
+ }
+ $line++;
+ $message =~ s/^\"//;
+ $message =~ s/\"$//;
+ push(@{$replay_msg{$time}}, $message);
+ $replay_text->insert('end', &replayTime($time)." ".$message."\n", $time);
+ # when user click on a message the begin time changes.
+ $replay_text->tagBind($time, '<1>', [sub {
+ my $ti = $_[1];
+ my $replay_was_running;
+ if ($replay_running) {
+ $replay_was_running = 1;
+ &replayStop;
+ }
+ $replay_text->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $replay_text->tagConfigure($ti,
+ -foreground => $replay_fg,
+ -background => $replay_bg);
+ $replay_last_time = $ti;
+ $replay_hour = &replayTime($ti);
+ $replay_time = $ti;
+ &regulationReset();
+ &replayStart if $replay_was_running;
+ }, $time]);
+ &setProgressbar($line, $step);
+ }
+ $mw->raise;
+ $replay_time = $replay_min_time;
+ $replay_text->configure(-state => 'disabled');
+ # ivy bindings
+ $ivy->bindRegexp($opt_startregexp, [\&replayStart]);
+ $ivy->bindRegexp($opt_stopregexp, [\&replayStop]);
+
+
+} # end loadfileForReplay
+
+
+
+sub showProgressbar {
+
+ $progressbar->value(0);
+ $progressbar->toplevel->deiconify;
+ $progressbar->toplevel->raise($mw);
+
+} # end showProgressbar
+
+
+sub hideProgressbar {
+
+ $progressbar->toplevel->withdraw;
+
+} # end hideProgressbar
+
+
+sub setProgressbar {
+
+ my ($line, $step) = @_;
+ $progressbar->value($line);
+ $progressbar->toplevel->raise($mw);
+ return unless defined $step;
+ $progressbar->update if ($step == 0 or $line % $step == 0);
+
+} # end setProgressbar
+
+
+#----------------------------------------------------------------------------------
+# Functions related to replay
+#----------------------------------------------------------------------------------
+sub replayStart {
+
+ my $loopflag = ($_[0] == 1) ? 1 : undef;
+ $replay_data_t0 = $replay_time unless defined $replay_data_t0;
+ $replay_current_t0 = gettimeofday() unless defined $replay_current_t0;
+ my $t = $replay_text;
+ return if $replay_running and not $loopflag;
+ return if $loopflag and not $replay_running;
+ $replay_runnable = 0;
+ $replay_running = 1;
+ if ($replay_time > $replay_max_time) {
+ if ($replay_repeat == 1) {
+ $replay_time = $replay_min_time;
+ } else {
+ $t->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $replay_running = 0;
+ $replay_runnable = 1;
+ return;
+ }
+ }
+ $replay_hour = &replayTime($replay_time);
+ my $data_dt = $replay_time - $replay_data_t0;
+ if (defined $replay_msg{$replay_time}) {
+ for my $msg (@{$replay_msg{$replay_time}}) {
+ $ivy->sendMsgs($msg);
+ $t->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $t->tagConfigure($replay_time,
+ -foreground => $replay_fg,
+ -background => $replay_bg);
+ }
+ $replay_last_time = $replay_time;
+ my $i = $t->tagRanges($replay_time);
+ $t->see($i) if defined $i;
+ }
+ $replay_time += $replay_time_granularity;
+ $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
+ $replay_time_decimalplaces > 0;
+ # step by step mode
+ if ($replay_stepbystep) {
+ while (not defined $replay_msg{$replay_time}) {
+ $replay_time += $replay_time_granularity;
+ $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
+ $replay_time_decimalplaces > 0;
+ last if $replay_time > $replay_max_time;
+ }
+ $replay_running = 0;
+ $replay_runnable = 1;
+
+ # continuous mode
+ } else {
+ my $dt = gettimeofday() - $replay_current_t0;
+ my $dt2 = sprintf("%.2f", $dt);
+ my $d = sprintf("%.3f", $dt-$data_dt);
+
+ # if speed rate != 1, time regulation is deactivated
+ if ($replay_speed != 1) {
+ $replay_current_factor = $replay_factor;
+ print "replay_speed=$replay_speed => time regulation deactivated\n"
+ if $opt_debug;
+
+ # if replay is running behind schedule (retard)
+ } elsif ($dt > $data_dt + $replay_maxgap and
+ $replay_current_factor <= $replay_factor) {
+ $replay_current_factor *= (1 - $replay_regulpct->[0]/100);
+ print "data_dt=$data_dt dt=$dt2 delay=$d [--] ".
+ "replay_factor=$replay_current_factor\n" if $opt_debug;
+
+ # if replay is getting ahead of schedule (avance)
+ } elsif ($dt < $data_dt - $replay_maxgap and
+ $replay_current_factor >= $replay_factor) {
+ $replay_current_factor *= (1 + $replay_regulpct->[1]/100);
+ print "data_dt=$data_dt dt=$dt2 delay=$d [++] ".
+ "replay_factor=$replay_current_factor\n" if $opt_debug;
+
+ # if replay is on time
+ } else {
+ print "data_dt=$data_dt dt=$dt2 delay=$d\n" if $opt_debug;
+ $replay_current_factor = $replay_factor;
+ }
+
+ $replay_timer =
+ $mw->after($replay_current_factor*$replay_time_granularity/$replay_speed,
+ [\&replayStart, 1]);
+ }
+
+} # end replayStart
+
+sub replayStop {
+
+ $replay_running = 0;
+ $replay_runnable = 1;
+ $replay_text->afterCancel($replay_timer) if defined $replay_timer;
+ &regulationReset();
+
+} # end replayStop
+
+sub replayClose {
+
+ $ivy->bindRegexp($opt_startregexp);
+ $ivy->bindRegexp($opt_stopregexp);
+ &replayStop();
+ $replay_text->after(400, sub {$mw->destroy});
+ $replay_speed = 1;
+ $replay_repeat = $opt_repeat;
+ $replay_stepbystep = undef;
+ $replay_hour = '--:--:--';
+
+} # end replayClose
+
+sub replayTime {
+
+ my $time = shift;
+ if (defined $time) {
+ my ($s, $m, $h) = localtime($time);
+ if ($replay_time_decimalplaces > 0) {
+ my $dec =
+ substr($time, -$replay_time_decimalplaces, $replay_time_decimalplaces);
+ return sprintf("%02d:%02d:%02d.%s", $h, $m, $s, $dec);
+ } else {
+ return sprintf("%02d:%02d:%02d", $h, $m, $s);
+ }
+ } elsif ($replay_time_decimalplaces > 0) {
+ return "--:--:--."."-" x $replay_time_decimalplaces;
+ } else {
+ return "--:--:--";
+ }
+
+} # end replayTime
+
+#----------------------------------------------------------------------------------
+# General functions
+#----------------------------------------------------------------------------------
+
+sub regulationReset {
+
+ $replay_data_t0 = undef;
+ $replay_current_t0 = undef;
+
+} # end regulationReset
+
+
+sub wheelmousebindings {
+
+ my $w = shift;
+ my $count = shift;
+ my $count = 3 unless $count > 0;
+ $w->bind('<Control-ButtonPress-4>', sub {$w->yview('scroll', -1, 'page')});
+ $w->bind('<Shift-ButtonPress-4>', sub {$w->yview('scroll', -1, 'unit')});
+ $w->bind('<ButtonPress-4>', sub {$w->yview('scroll', -$count, 'unit')});
+
+ $w->bind('<Control-ButtonPress-5>', sub {$w->yview('scroll', 1, 'page')});
+ $w->bind('<Shift-ButtonPress-5>', sub {$w->yview('scroll', 1, 'unit')});
+ $w->bind('<ButtonPress-5>', sub {$w->yview('scroll', $count, 'unit')});
+
+} # end wheelmousebindings
+
+
+sub quit {
+
+ print "Quit\n";
+ exit;
+
+} # end quit
+
+
+__END__
+
+=head1 NAME
+
+ivyreplay - a graphical application for replaying Ivy messages
+
+
+=head1 SYNOPSIS
+
+B<ivyreplay> [B<-b> ivybus] [B<-help>]
+ [B<-size> window size] [B<-undersize>]
+ [B<-autostart>] [B<-repeat>]
+ [B<-timegranularity> float>0]
+ [B<-startregexp> regexp]
+ [B<-stopregexp> regexp]
+ [standard X11 options...]
+ inputfile
+
+=head1 DESCRIPTION
+
+IvyReplay is dedicated to replay Ivy messages. Input file must have been generated with ivymon v1.6 or later (it must contain time information).
+
+
+=head1 OPTIONS
+
+=over
+
+=item B<-b> ip:port
+
+Set the bus domain and port number to be used. Use $IVYBUS variable if defined. Default is 127.255.255.255:2010.
+
+=item B<-help>
+
+Get some help
+
+
+=item B<-size> window size
+
+Set the size of the IvyMon window. Can be VGA or 640, SVGA or 800, XGA or 1024, SXGA or 1280, UXGA or 1600. Default is XGA (1024x768).
+
+=item B<-undersize>
+
+Slightly reduce the IvyMon window to fit it in screen with borders of the window manager. Option not set by default.
+
+
+=item B<-repeat>
+
+If set, the replay sequence will be repetitive.
+
+=item B<-timegranularity> float>0
+
+Specify the time granularity in second for replaying messages. Set to 1 by default.
+
+=item B<-startregexp> regexp
+
+Specify the ivy regular expression to match in order to start the replay sequence. Default is '^ClockStart'. You can do manually the same using the B<Play> button of the Replay window.
+
+=item B<-stopregexp> regexp
+
+Specify the ivy regular expression to match in order to stop the replay sequence. Default is '^ClockStop'. You can do manually the same using the B<Pause> button of the Replay window.
+
+
+=back
+
+
+=head1 EXAMPLE
+
+ivyreplay -b 10.192.36.255:3456 -repeat -startregexp '^ReplayOn' -stopregexp '^ReplayOff' /my/dir/log.ivy
+
+
+=head1 AUTHORS
+
+Daniel Etienne <etienne@cena.fr>
+