]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tools/platforms/msp430/motelist/motelist-linux
Merge devel code into the trunk.
[tinyos-2.x.git] / tools / platforms / msp430 / motelist / motelist-linux
diff --git a/tools/platforms/msp430/motelist/motelist-linux b/tools/platforms/msp430/motelist/motelist-linux
new file mode 100755 (executable)
index 0000000..b6f1c40
--- /dev/null
@@ -0,0 +1,275 @@
+#!/usr/bin/perl -w
+use strict;
+# $Id$
+# @author Cory Sharp <cory@moteiv.com>
+# @author Joe Polastre
+
+my $help = <<'EOF';
+usage: motelist [options]
+
+  $Revision$
+
+options:
+  -h  display this help
+  -c  compact format, not pretty but easier for parsing
+  -f  specify the usb-serial file (for smote.cs)
+  -k  kernel version: 2.4, 2.6, auto (default)
+  -m  method to scan usb: procfs, sysfs, auto (default)
+  -dev_prefix  force the device prefix for the serial device
+  -usb  display extra usb information
+EOF
+
+my %Opt = (
+  compact => 0,
+  usb => 0,
+  method => "auto",
+  kernel => "auto",
+  dev_prefix => [ "/dev/usb/tts/", "/dev/ttyUSB", "/dev/tts/USB" ],
+  usbserial => "sudo cat /proc/tty/driver/usbserial |",
+);
+
+while (@ARGV) {
+  last unless $ARGV[0] =~ /^-/;
+  my $opt = shift @ARGV;
+  if( $opt eq "-h" ) { print "$help\n"; exit 0; }
+  elsif( $opt eq "-c" ) { $Opt{compact} = 1; }
+  elsif( $opt eq "-f" ) { $Opt{usbserial} = shift @ARGV; }
+  elsif( $opt eq "-k" ) { $Opt{kernel} = shift @ARGV; }
+  elsif( $opt eq "-m" ) { $Opt{method} = shift @ARGV; }
+  elsif( $opt eq "-dev_prefix" ) { $Opt{dev_prefix} = shift @ARGV; }
+  elsif( $opt eq "-usb" ) { $Opt{usb} = 1; }
+  else { print STDERR "$help\nerror, unknown command line option $opt\n"; exit 1; }
+}
+
+if( $Opt{kernel} eq "auto" ) {
+  $Opt{kernel} = "unknown";
+  $Opt{kernel} = $1 if snarf("/proc/version") =~ /\bLinux version (\d+\.\d+)/;
+}
+
+if( $Opt{method} eq "auto" ) {
+  $Opt{method} = ($Opt{kernel} eq "2.4") ? "procfs" : "sysfs";
+}
+
+my @devs = $Opt{method} eq "procfs" ? scan_procfs() : scan_sysfs();
+print_motelist( sort { cmp_usbdev($a,$b) } @devs );
+
+
+#
+#  SysFS
+#
+sub scan_sysfs {
+
+  #  Scan /sys/bus/usb/drivers/usb for FTDI devices
+  my @ftdidevs =
+    grep { ($_->{UsbVendor}||"") eq "0403" && ($_->{UsbProduct}||"") eq "6001" }
+    map { {
+      SysPath => $_,
+      UsbVendor => snarf("$_/idVendor",1),
+      UsbProduct => snarf("$_/idProduct",1),
+    } }
+    glob("/sys/bus/usb/drivers/usb/*");
+
+  #  Gather information about each FTDI device
+  for my $f (@ftdidevs) {
+    my $syspath = $f->{SysPath};
+
+    $f->{InfoManufacturer} = snarf("$syspath/manufacturer",1);
+    $f->{InfoProduct} = snarf("$syspath/product",1);
+    $f->{InfoSerial} = snarf("$syspath/serial",1);
+    $f->{UsbDevNum} = snarf("$syspath/devnum",1);
+
+    my $devstr = readlink($syspath);
+    if( $devstr =~ m{([^/]+)/usb(\d+)/.*-([^/]+)$} ) {
+      $f->{UsbPath} = "usb-$1-$3";
+      $f->{UsbBusNum} = $2;
+    }
+    ($f->{SysDev} = $syspath) =~ s{^.*/}{};
+
+    my $port = "$syspath/$f->{SysDev}:1.0";
+    ($f->{DriverName} = readlink("$port/driver")) =~ s{^.*/}{} if -l "$port/driver";
+    ($f->{SerialDevName} = (glob("$port/tty*"),undef)[0]) =~ s{^.*/}{};
+    $f->{SerialDevNum} = $1 if $f->{SerialDevName} =~ /(\d+)/;
+    $f->{SerialDevName} = getSerialDevName( $f->{SerialDevNum} ) || "  (none)";
+  }
+
+  return @ftdidevs;
+}
+
+
+#
+#  Scan Procfs
+#
+sub scan_procfs {
+
+  my $text_devs = snarf("< /proc/bus/usb/devices");
+  my $text_serial = snarf($Opt{usbserial});
+
+  my @usbdevs = map { {parse_usb_devices_text($_)} }
+                grep { !/^\s*$/ } split /\n+(?=T:)/, $text_devs;
+  my %usbtree = build_usb_tree( @usbdevs );
+  my %usbserialtree = build_usbserial_tree( $text_serial );
+  for my $tts ( values %usbserialtree ) {
+    $usbtree{usbkey($tts->{path})}{usbserial} = $tts if defined $tts->{path};
+  }
+
+  my @ftdidevs = map { {
+      UsbVendor => $_->{Vendor},
+      UsbProduct => $_->{ProdID},
+      InfoManufacturer => $_->{Manufacturer},
+      InfoProduct => $_->{Product},
+      InfoSerial => $_->{SerialNumber},
+      UsbBusNum => $_->{nbus},
+      UsbDevNum => $_->{ndev},
+      UsbPath => (($Opt{kernel} eq "2.4") ? $_->{usbserial}{path} : $_->{usbpath}),
+      DriverName => $_->{driver},
+      SerialDevNum => $_->{usbserial}{tts},
+      SerialDevName => getSerialDevName($_->{usbserial}{tts}) || "  (none)",
+    } }
+    grep { ($_->{Vendor}||"") eq "0403" && ($_->{ProdID}||"") eq "6001" }
+    values %usbtree;
+
+  return @ftdidevs;
+}
+
+sub build_usb_tree {
+  my @devs = @_;
+  my %tree = ();
+  for my $dev (sort { $a->{Lev} <=> $b->{Lev} } @devs) {
+    my ($bus,$lev,$prnt) = ( $dev->{Bus}+0, $dev->{Lev}+0, $dev->{Prnt}+0 );
+    my $devnum = $dev->{"Dev#"}+0;
+    $dev->{nbus} = $bus;
+    $dev->{ndev} = $devnum;
+    $tree{"bus$bus"} = {} unless exists $tree{"bus$bus"};
+    $tree{"bus$bus"}{"dev$devnum"} = $dev;
+    if( $lev == 0 ) {
+      $dev->{usbpath} = "usb-$dev->{SerialNumber}";
+    } else {
+      my $sep = ($lev==1) ? "-" : ".";
+      $dev->{parent} = $tree{"bus$bus"}{"dev$prnt"};
+      $dev->{usbpath} = $dev->{parent}{usbpath} . $sep . ($dev->{Port}+1);
+    }
+    $tree{usbkey($dev->{usbpath})} = $dev;
+  }
+  return %tree;
+}
+
+sub parse_usb_devices_text {
+  my $text = shift;
+  $text =~ s/^\S+\s*//gm;
+  return ($text =~ m/([^\s=]+)=\s*(.*?\S)\s*(?=[^\s=]+=|$)/mg);
+}
+
+sub build_usbserial_tree {
+  my $text = shift;
+  my %tree = ();
+  while( $text =~ /^([^:]+):(.*)/mg ) {
+    my ($tts,$params) = ($1,$2);
+    $tree{$tts} = { tts => $tts };
+    while ($params =~ m/\s+([^:]+):(?:"([^"]*)"|(\S+))/g) {
+      $tree{$tts}{$1} = $2||$3;
+    }
+  }
+  return %tree;
+}
+
+sub usbkey {
+  if( $Opt{kernel} eq "2.4" ) {
+    (my $key = $_[0]) =~ s/^.*-//;
+    return $key;
+  }
+  return $_[0];
+}
+
+
+#
+#  getSerialDevName
+#
+#  For each device, force to use dev_prefix if it's not an array.  Otherwise,
+#  assume it's a list of candidate prefixes.  Check them and commit to the
+#  first one that actually exists.
+#
+sub getSerialDevName {
+  my $devnum = shift;
+  my $devname = undef;
+  if( defined $devnum ) {
+    if( ref($Opt{dev_prefix}) eq "ARRAY" ) {
+      $devname = $devnum;
+      for my $prefix (@{$Opt{dev_prefix}}) {
+        my $file = $prefix . $devnum;
+        if( -e $file ) { $devname = $file; last; }
+      }
+    } else {
+      $devname = $Opt{dev_prefix} . $devnum;
+    }
+  }
+  return $devname;
+}
+
+
+#
+#  Print motelist
+#
+sub print_motelist {
+  my @devs = @_;
+
+  #  If none were found, quit
+  if( @devs == 0 ) {
+    print "No devices found.\n";
+    return;
+  }
+
+  #  Print a header
+  if( !$Opt{compact} ) {
+    if( $Opt{usb} ) {
+      print << "EOF" unless $Opt{compact};
+Bus Dev USB Path                 Reference  Device           Description
+--- --- ------------------------ ---------- ---------------- -------------------------------------
+EOF
+    } else {
+      print << "EOF" unless $Opt{compact};
+Reference  Device           Description
+---------- ---------------- ---------------------------------------------
+EOF
+    }
+  }
+
+  #  Print the usb information
+  for my $dev (sort { cmp_usbdev($a,$b) } @devs) {
+    my $desc = join( " ", $dev->{InfoManufacturer}||"", $dev->{InfoProduct}||"" ) || " (none)";
+    my @output = ( $dev->{InfoSerial}||" (none)", $dev->{SerialDevName}, $desc );
+    @output = ( $dev->{UsbBusNum}, $dev->{UsbDevNum}, $dev->{UsbPath}, @output ) if $Opt{usb};
+    if( $Opt{compact} ) {
+      print join(",",@output) . "\n";
+    } else {
+      printf( ($Opt{usb}?"%3d %3d %-24s ":"")."%-10s %-16s %s\n", @output );
+    }
+  }
+}
+
+
+#
+#  Cmp Usbdev's
+#
+sub cmp_usbdev {
+  my ($a,$b) = @_;
+  if( defined $a->{SerialDevNum} ) {
+    if( defined $b->{SerialDevNum} ) {
+      return $a->{SerialDevNum} <=> $b->{SerialDevNum};
+    }
+    return -1;
+  }
+  return 1 if defined $b->{SerialDevNum};
+  return ($a->{InfoSerial}||"") cmp ($b->{InfoSerial}||"");
+}
+
+#
+#  Read a file in
+#
+sub snarf {
+  open my $fh, $_[0] or return undef;
+  my $text = do{local $/;<$fh>};
+  close $fh;
+  $text =~ s/\s+$// if $_[1];
+  return $text;
+}
+