#!/bin/sh
# -*- tcl -*- \
exec tclsh "$0" ${1+"$@"}

proc usage {} {
	puts "Parse a usbmon trace
Usage:
	./parusbmon.tcl \[options\] <usbsnoop file>
Options:
	-t	Display the delta time between exchanges"
	exit
}

proc dsp_buf {b i len} {
	set b [join $b {}]
	set b [split $b {}]
	set a {}
	foreach {h1 h2} $b {
		append a " $h1$h2"
	}
	set l [string length $a]
	if {$l < $len * 3} {
		append a { ..}
	}
	if {$l <= 3 * 16} {
		return $a
	}
	set t [expr {$i / 8}]
	set i [expr {$i % 8}]
	set nl "[string range $a 0 47]\n"
	while {[incr t -1] >= 0} {
		append nl "\t"
	}
	while {[incr i -1] >= 0} {
		append nl { }
	}
	return "$nl[string range $a 49 end]"
}

proc main {argv} {
	global nowtime prevtime withtime deltatime
	set withtime 0
	set deltatime {}
	set fn {}
	foreach a $argv {
		switch -- $a {
		    -t {
			set withtime 1
		    }
		    default {
			if {[string length $fn] != 0} usage
			set fn $a
		    }
		}
	}
	if {[string length $fn] == 0} usage
	if {[catch {open $fn r} fd]} {
		puts stderr "cannot open '$fn'"
		exit 1
	}
	set nowtime 0
	set prevtime 0
	set nisoc 0
	while {[gets $fd line] >= 0} {

		set prevtime $nowtime
		set nowtime [expr {[lindex $line 1] / 1000}]
		if {[string first o: $line] > 0} {
			if {$withtime} {
				set deltatime [format "%4d " \
					[expr {$nowtime - $prevtime}]]
			} elseif {$nowtime > $prevtime + 3} {
				puts "== +[expr {$nowtime - $prevtime}] ms"
			}
		}
		if {$nowtime > $prevtime + 200} {
			puts "== \[$nowtime ms\]"
		}

		set address [split [lindex $line 3] :]
#puts "[lindex $line 2] a: $address"
		if {[lindex $address 0] == {Zi}} {
			incr nisoc
			continue
		}
		if {$nisoc > 0} {
			puts "$deltatime<isoc * $nisoc"
			set nisoc 0
		}

		switch [lindex $line 2] {
		    S {
			switch [lindex $address 0] {
			    Ci {
				set r [lindex $line 6]
				set v [lindex $line 7]
				set i [lindex $line 8]
			    }
			    Co {
				set t [lindex $line 5]
				set r [lindex $line 6]
				set v [lindex $line 7]
				if {$t == {01}} {
					if {$r == {0b}} {
						puts "intf $v"
					} else {
						puts "req $r $v"
					}
					continue
				}
				set i [lindex $line 8]
				set l [lindex $line 10]
				if {$l == 0} {
				    puts "$deltatime SET $r $v $i"
				} elseif {[lindex $line 11] == "="} {
				    set b [lrange $line 12 end]
				    puts "$deltatime SET $r $v $i[dsp_buf $b 18 $l]"
				}
			    }
			    Zo {
			    }
			    Io {
				set b [lrange $line 7 end]
				set l [lindex $line 5]
				puts "$deltatime Int OUT[dsp_buf $b 9 $l]"
			    }
			    Bo {
				set b [lrange $line 7 end]
				set l [lindex $line 5]
				puts "$deltatime Bulk OUT[dsp_buf $b 10 $l]"
			    }
			}
		    }
		    C {
			switch [lindex $address 0] {
			    Ci {
				set b [lrange $line 7 end]
				set l [lindex $line 5]
				if {[info exists r]} {
				    puts "$deltatime<GET $r $v $i[dsp_buf $b 18 $l]"
				}
			    }
			    Zi {
				puts "$deltatime<isoc"
			    }
			    Ii {
				set b [lrange $line 7 end]
				set l [lindex $line 5]
				puts "$deltatime<Int IN[dsp_buf $b 8 $l]"
			    }
			    Bi {
				set b [lrange $line 7 end]
				set l [lindex $line 5]
				puts "$deltatime<Bulk IN[dsp_buf $b 9 $l]"
			    }
			}
		    }
		    default {
			puts "$deltatime event [lindex $line 2]"
		    }
		}
	}
}

main $argv
