#!/usr/bin/perl

$file = shift ( @ARGV ) ;
open ( INDAT , '<' . $file ) ;
@scan_down = ( ) ;
@scan_back = ( ) ;
@data_down = ( ) ;
@data_back = ( ) ;
$state = 'START' ;

while ( $zeile = <INDAT> )
{
  chomp ( $zeile ) ;

  if ( $state eq 'START' )
  {
    if ( index ( $zeile , '>>>' ) >= 0 )
    {
      $state = 'DOWN' ;
      push ( @scan_down , $zeile ) ;
    }
  }
  elsif ( $state eq 'DOWN' )
  {
    if ( index ( $zeile , '<<<' ) >= 0 )
    {
      @data_down = @scan_down ;
      @scan_down = ( ) ;
      $state = 'BACK' ;
      push ( @scan_back , $zeile ) ;
    }
    else
    {
      unless ( substr ( $zeile , 0 , 1 ) eq '[' )
      {
        push ( @scan_down , $zeile ) ;
      }
    }
  }
  elsif ( $state eq 'BACK' )
  {
    if ( index ( $zeile , '>>>' ) >= 0 )
    {
      @data_back = @scan_back ;
      parse_urb ( ) ;
      @scan_back = ( ) ;
      $state = 'DOWN' ;
      push ( @scan_down , $zeile ) ;
    }
    else
    {
      unless ( substr ( $zeile , 0 , 1 ) eq '[' )
      {
        push ( @scan_back , $zeile ) ;
      }
    }
  }
}

close ( INDAT ) ;
1 ;

sub parse_urb
{
  my ( $urb_down ) = $data_down[0] =~ m!(URB \d+)! ;
  my ( $urb_back ) = $data_back[0] =~ m!(URB \d+)! ;

  unless ( $urb_down eq $urb_back )
  {
    error ( 'URB counts does not match' , $data_down[0] , $data_back[0] ) ;
  }

  my ( $type_down ) = $data_down[1] =~ m!URB_FUNCTION_(\w+)! ;
  my ( $type_back ) = $data_back[1] =~ m!URB_FUNCTION_(\w+)! ;

  if ( ( $type_down eq 'GET_DESCRIPTOR_FROM_DEVICE' ) && ( $type_back eq 'CONTROL_TRANSFER' ) )
  {
    print '# GET_DESCRIPTOR' , "\n" ;
    return();
  }
  elsif ( ( $type_down eq 'SELECT_CONFIGURATION' ) && ( $type_back eq 'SELECT_CONFIGURATION' ) )
  {
    print '# SELECT_CONFIGURATION' , "\n" ;
    return();
  }
  elsif ( ( $type_down eq 'ABORT_PIPE' ) && ( $type_back eq 'ABORT_PIPE' ) )
  {
    print '# ABORT_PIPE' , "\n" ;
    return();
  }
  elsif ( ( $type_down eq 'RESET_PIPE' ) && ( $type_back eq 'RESET_PIPE' ) )
  {
    print '# RESET_PIPE' , "\n" ;
    return();
  }
  elsif ( ( $type_down eq 'BULK_OR_INTERRUPT_TRANSFER' ) && ( $type_back eq 'BULK_OR_INTERRUPT_TRANSFER' ) )
  {
    my ( $ep_down ) = $data_down[2] =~ m!endpoint 0x000000(..)! ;
    my ( $ep_back ) = $data_back[2] =~ m!endpoint 0x000000(..)! ;

    unless ( $ep_down == $ep_back )
    {
      error ( 'URB endpoints does not match' , $data_down[2] , $data_back[2] ) ;
    }

    my $data_down = get_urb_data ( @data_down ) ;
    my $data_back = get_urb_data ( @data_back ) ;

    $ep_down = hex ( $ep_down ) ;
    $ep_down &= 0x7f ;
    $ep_down = sprintf ( '%02x' , $ep_down ) ;

    print 'BULK > ' , $ep_down , ' (' , $urb_down , ')' , "\n" ;

#    if ( substr ( $data_down_bak , 0 , 16 ) eq '    00000000: 01' )
#    {
#      print '    00000000: ...' , "\n" ;
#    }
#    else
#    {
      print $data_down , "\n" ;
#    }

    if ( $data_back )
    {
      print 'BULK < ' , $ep_back , ' (' , $urb_back , ')' , "\n" ;
      print $data_back , "\n" ;
    }

    print "\n" ;
    ( $data_down_bak , $data_back_bak ) = ( $data_down , $data_bak ) ;
  }
  else
  {
    error ( 'URB request types unhandled' , $data_down[1] , $data_back[1] ) ;
  }
}

sub get_urb_data
{
  my ( @data ) = @_ ;
  my @head = splice ( @data , 0 , 7 ) ;

  while ( @data && !( $data[-1] =~ m!\A    ........:! ) )
  {
    pop ( @data ) ;
  }

  my $data = join ( "\n" , @data ) ;

  if ( $data && ( substr ( $data , 0 , 13 ) ne '    00000000:' ) )
  {
    error ( 'URB bulk data do not start with 00000000:' , $head[0] , $data[0] ) ;
  }

  return ( $data ) ;
}

sub error
{
  my ( @msg ) = @_ ;
  $msg[0] .= ' !' ;
  print 'ERROR: ' , join ( "\n" , @msg ) , "\n" ;
  exit ;
}
