#! /usr/bin/perl 
#
# extracts firmware from usbsnoop dump
# 

open(MYINPUTFILE,"<usbsnoop.log");
open(MYOUTPUTFILE,">fw.bin");
my(@lines) = <MYINPUTFILE>;
my($size) = 0;

# controlling the state 
# is the driver loading the firmware yet ?
my($started) = 0;
# has the driver ended the firmware upload ?
my($last) = 0;

# how many lines we skip
my($skip) = 1;

for (my $i = 0 ; ($i < @lines) && ($last == 0); $i+=$skip) 
{
$line = $lines[$i];
$ctrl = $lines[$i+2];
$length = $lines[$i+4];
if ( 	
	$line =~ "going down" && 
 	$ctrl =~ "endpoint 0x00000001" &&
	( $length =~ "00000200" || $started == 1 )
   ) 

# this is the filter against the chunk size. The beginning of the firmware
# is sent in 512kB chunks, and the end chunk is variable in size (depends on the
# firmware total length, obviously. We assume this last chunk is *not* 512 bytes
# in size
	{
	if ($length =~ "00000200")
	{
		# we hit a non-last chunk, assuming the last chunk will not be 512 bytes,
		# which seems a reasonable enough assumption
		$started = 1;
		$last = 0;
	}
	else
	{
		# we hit a chunk of size != 512 bytes, we assume this is the last chunk
		# of the firmware
		$last = 1;
	}

	$line =~ "URB ([0-9]+)";
	my $count = $1;
	while(! ($line =~ "TransferBufferLength = ([0123456789abcdefABCDEF]*)\$"))
	{
		$i++;
		$line = @lines[$i];
	}
	$line =~ "TransferBufferLength = ([0-9a-fA-F]+)";
	my $chunksize = hex($1);
	print("URB ".$count." ");
	print("buffer length ".$chunksize." bytes\n");
	while(! ($line =~ m/[0-9]+:/))
	{
		$i++;
		$line = @lines[$i];
	}
	do {
	    $line =~ "([0-9]+): *([^:]*) *\$";
	    process_line($2);
	    $i++;
	    $line = @lines[$i];
	}
	while ($line =~ m/[0-9]+:/);
	$size += $chunksize; 
}
}

print($size." bytes total\n");

sub process_line
{
    my $line = shift;
    @elems = split(/ /, $line);
    for (my $i = 0 ; $i < @elems ; $i++) 
    {
	$num = hex(@elems[$i]);
	printf MYOUTPUTFILE ("%c",$num);
	#print ".".$elems[$i];
    }
}

