Allow build with original radio driver using $make RF230BB=0
[contiki-2.x.git] / tools / sky / motelist-linux
blobf1b0d9931b34356e40649be1912fe481c70f8ba2
1 #!/usr/bin/perl -w
2 use strict;
3 # $Id: motelist-linux,v 1.1 2007/05/29 19:34:30 adam Exp $
4 # @author Cory Sharp <cory@moteiv.com>
5 # @author Joe Polastre
7 my $help = <<'EOF';
8 usage: motelist [options]
10 $Revision: 1.1 $
12 options:
13 -h display this help
14 -c compact format, not pretty but easier for parsing
15 -f specify the usb-serial file (for smote.cs)
16 -k kernel version: 2.4, 2.6, auto (default)
17 -m method to scan usb: procfs, sysfs, auto (default)
18 -dev_prefix force the device prefix for the serial device
19 -usb display extra usb information
20 EOF
22 my %Opt = (
23 compact => 0,
24 usb => 0,
25 method => "auto",
26 kernel => "auto",
27 dev_prefix => [ "/dev/usb/tts/", "/dev/ttyUSB", "/dev/tts/USB" ],
28 usbserial => "sudo cat /proc/tty/driver/usbserial |",
31 while (@ARGV) {
32 last unless $ARGV[0] =~ /^-/;
33 my $opt = shift @ARGV;
34 if( $opt eq "-h" ) { print "$help\n"; exit 0; }
35 elsif( $opt eq "-c" ) { $Opt{compact} = 1; }
36 elsif( $opt eq "-f" ) { $Opt{usbserial} = shift @ARGV; }
37 elsif( $opt eq "-k" ) { $Opt{kernel} = shift @ARGV; }
38 elsif( $opt eq "-m" ) { $Opt{method} = shift @ARGV; }
39 elsif( $opt eq "-dev_prefix" ) { $Opt{dev_prefix} = shift @ARGV; }
40 elsif( $opt eq "-usb" ) { $Opt{usb} = 1; }
41 else { print STDERR "$help\nerror, unknown command line option $opt\n"; exit 1; }
44 if( $Opt{kernel} eq "auto" ) {
45 $Opt{kernel} = "unknown";
46 $Opt{kernel} = $1 if snarf("/proc/version") =~ /\bLinux version (\d+\.\d+)/;
49 if( $Opt{method} eq "auto" ) {
50 $Opt{method} = ($Opt{kernel} eq "2.4") ? "procfs" : "sysfs";
53 my @devs = $Opt{method} eq "procfs" ? scan_procfs() : scan_sysfs();
54 print_motelist( sort { cmp_usbdev($a,$b) } @devs );
58 # SysFS
60 sub scan_sysfs {
62 # Scan /sys/bus/usb/drivers/usb for FTDI devices
63 my @ftdidevs =
64 grep { ($_->{UsbVendor}||"") eq "0403" && ($_->{UsbProduct}||"") eq "6001" }
65 map { {
66 SysPath => $_,
67 UsbVendor => snarf("$_/idVendor",1),
68 UsbProduct => snarf("$_/idProduct",1),
69 } }
70 glob("/sys/bus/usb/drivers/usb/*");
72 # Gather information about each FTDI device
73 for my $f (@ftdidevs) {
74 my $syspath = $f->{SysPath};
76 $f->{InfoManufacturer} = snarf("$syspath/manufacturer",1);
77 $f->{InfoProduct} = snarf("$syspath/product",1);
78 $f->{InfoSerial} = snarf("$syspath/serial",1);
79 $f->{UsbDevNum} = snarf("$syspath/devnum",1);
81 my $devstr = readlink($syspath);
82 if( $devstr =~ m{([^/]+)/usb(\d+)/.*-([^/]+)$} ) {
83 $f->{UsbPath} = "usb-$1-$3";
84 $f->{UsbBusNum} = $2;
86 ($f->{SysDev} = $syspath) =~ s{^.*/}{};
88 my $port = "$syspath/$f->{SysDev}:1.0";
89 ($f->{DriverName} = readlink("$port/driver")) =~ s{^.*/}{} if -l "$port/driver";
90 ($f->{SerialDevName} = (glob("$port/tty*"),undef)[0]) =~ s{^.*/}{};
91 $f->{SerialDevNum} = $1 if $f->{SerialDevName} =~ /(\d+)/;
92 $f->{SerialDevName} = getSerialDevName( $f->{SerialDevNum} ) || " (none)";
95 return @ftdidevs;
100 # Scan Procfs
102 sub scan_procfs {
104 my $text_devs = snarf("< /proc/bus/usb/devices");
105 my $text_serial = snarf($Opt{usbserial});
107 my @usbdevs = map { {parse_usb_devices_text($_)} }
108 grep { !/^\s*$/ } split /\n+(?=T:)/, $text_devs;
109 my %usbtree = build_usb_tree( @usbdevs );
110 my %usbserialtree = build_usbserial_tree( $text_serial );
111 for my $tts ( values %usbserialtree ) {
112 $usbtree{usbkey($tts->{path})}{usbserial} = $tts if defined $tts->{path};
115 my @ftdidevs = map { {
116 UsbVendor => $_->{Vendor},
117 UsbProduct => $_->{ProdID},
118 InfoManufacturer => $_->{Manufacturer},
119 InfoProduct => $_->{Product},
120 InfoSerial => $_->{SerialNumber},
121 UsbBusNum => $_->{nbus},
122 UsbDevNum => $_->{ndev},
123 UsbPath => (($Opt{kernel} eq "2.4") ? $_->{usbserial}{path} : $_->{usbpath}),
124 DriverName => $_->{driver},
125 SerialDevNum => $_->{usbserial}{tts},
126 SerialDevName => getSerialDevName($_->{usbserial}{tts}) || " (none)",
128 grep { ($_->{Vendor}||"") eq "0403" && ($_->{ProdID}||"") eq "6001" }
129 values %usbtree;
131 return @ftdidevs;
134 sub build_usb_tree {
135 my @devs = @_;
136 my %tree = ();
137 for my $dev (sort { $a->{Lev} <=> $b->{Lev} } @devs) {
138 my ($bus,$lev,$prnt) = ( $dev->{Bus}+0, $dev->{Lev}+0, $dev->{Prnt}+0 );
139 my $devnum = $dev->{"Dev#"}+0;
140 $dev->{nbus} = $bus;
141 $dev->{ndev} = $devnum;
142 $tree{"bus$bus"} = {} unless exists $tree{"bus$bus"};
143 $tree{"bus$bus"}{"dev$devnum"} = $dev;
144 if( $lev == 0 ) {
145 $dev->{usbpath} = "usb-$dev->{SerialNumber}";
146 } else {
147 my $sep = ($lev==1) ? "-" : ".";
148 $dev->{parent} = $tree{"bus$bus"}{"dev$prnt"};
149 $dev->{usbpath} = $dev->{parent}{usbpath} . $sep . ($dev->{Port}+1);
151 $tree{usbkey($dev->{usbpath})} = $dev;
153 return %tree;
156 sub parse_usb_devices_text {
157 my $text = shift;
158 $text =~ s/^\S+\s*//gm;
159 $text =~ s/\s*(\S+=)/\001$1/g;
160 return map { m/(.*?)=(.*)/ } split /\001/, $text;
163 sub build_usbserial_tree {
164 my $text = shift;
165 my %tree = ();
166 while( $text =~ /^([^:]+):(.*)/mg ) {
167 my ($tts,$params) = ($1,$2);
168 $tree{$tts} = { tts => $tts };
169 while ($params =~ m/\s+([^:]+):(?:"([^"]*)"|(\S+))/g) {
170 $tree{$tts}{$1} = $2||$3;
173 return %tree;
176 sub usbkey {
177 if( $Opt{kernel} eq "2.4" ) {
178 (my $key = $_[0]) =~ s/^.*-//;
179 return $key;
181 return $_[0];
186 # getSerialDevName
188 # For each device, force to use dev_prefix if it's not an array. Otherwise,
189 # assume it's a list of candidate prefixes. Check them and commit to the
190 # first one that actually exists.
192 sub getSerialDevName {
193 my $devnum = shift;
194 my $devname = undef;
195 if( defined $devnum ) {
196 if( ref($Opt{dev_prefix}) eq "ARRAY" ) {
197 $devname = $devnum;
198 for my $prefix (@{$Opt{dev_prefix}}) {
199 my $file = $prefix . $devnum;
200 if( -e $file ) { $devname = $file; last; }
202 } else {
203 $devname = $Opt{dev_prefix} . $devnum;
206 return $devname;
211 # Print motelist
213 sub print_motelist {
214 my @devs = @_;
216 # If none were found, quit
217 if( @devs == 0 ) {
218 print "No devices found.\n";
219 return;
222 # Print a header
223 if( !$Opt{compact} ) {
224 if( $Opt{usb} ) {
225 print << "EOF" unless $Opt{compact};
226 Bus Dev USB Path Reference Device Description
227 --- --- ------------------------ ---------- ---------------- -------------------------------------
229 } else {
230 print << "EOF" unless $Opt{compact};
231 Reference Device Description
232 ---------- ---------------- ---------------------------------------------
237 # Print the usb information
238 for my $dev (sort { cmp_usbdev($a,$b) } @devs) {
239 my $desc = join( " ", $dev->{InfoManufacturer}||"", $dev->{InfoProduct}||"" ) || " (none)";
240 my @output = ( $dev->{InfoSerial}||" (none)", $dev->{SerialDevName}, $desc );
241 @output = ( $dev->{UsbBusNum}, $dev->{UsbDevNum}, $dev->{UsbPath}, @output ) if $Opt{usb};
242 if( $Opt{compact} ) {
243 print join(",",@output) . "\n";
244 } else {
245 printf( ($Opt{usb}?"%3d %3d %-24s ":"")."%-10s %-16s %s\n", @output );
252 # Cmp Usbdev's
254 sub cmp_usbdev {
255 my ($a,$b) = @_;
256 if( defined $a->{SerialDevNum} ) {
257 if( defined $b->{SerialDevNum} ) {
258 return $a->{SerialDevNum} <=> $b->{SerialDevNum};
260 return -1;
262 return 1 if defined $b->{SerialDevNum};
263 return ($a->{InfoSerial}||"") cmp ($b->{InfoSerial}||"");
267 # Read a file in
269 sub snarf {
270 open my $fh, $_[0] or return undef;
271 my $text = do{local $/;<$fh>};
272 close $fh;
273 $text =~ s/\s+$// if $_[1];
274 return $text;