First pass at a device-independent find-device-port-macos

pull/764/head
Jesse Vincent 5 years ago
parent 9417e0bc31
commit e5558eaf90
No known key found for this signature in database
GPG Key ID: CC228463465E40BC

@ -2,103 +2,94 @@
# Based on listArduinos.pl from https://github.com/todbot/usbSearch (License: MIT) # Based on listArduinos.pl from https://github.com/todbot/usbSearch (License: MIT)
# Original (C) 2012, Tod E. Kurt, http://todbot.com/blog/ # Original (C) 2012, Tod E. Kurt, http://todbot.com/blog/
# This version by Michael Richters <gedankenexperimenter@gmail.com> # This version by Michael Richters <gedankenexperimenter@gmail.com> and Jesse Vincent <jesse@keyboard.io>
use warnings; use warnings;
use strict; use strict;
my $vid = shift @ARGV;
my $pid = shift @ARGV;
# ioreg might be more machine-readable than system_profiler, but I haven't been able to # ioreg might be more machine-readable than system_profiler, but I haven't been able to
# get it to produce useful output # get it to produce useful output
my @output = qx(/usr/sbin/system_profiler SPUSBDataType); my @output = qx(/usr/sbin/system_profiler SPUSBDataType);
my $parse_state = 0; my $serial = "";
my $device = {}; my $location = "";
LINE: foreach my $line (@output) {
chomp $line;
if ( $parse_state == 0 ) { my $output = join('', @output);
if ( $line =~ m/Model 01/ ) {
$parse_state = 1;
next LINE;
}
}
if ( $parse_state == 1 ) { my @stanzas = split(/\n\n/, $output);
if ( $line =~ m/^\s*$/ ) { foreach my $stanza (@stanzas) {
$parse_state = 2; if ($stanza =~ /Product ID: ${pid}/ && $stanza =~ /Vendor ID: ${vid}/) {
next LINE; if ($stanza =~ /Serial Number: (.*?)$/m) {
$serial = $1;
} }
if ($stanza =~ /Location ID: (.*?)$/m) {
$location = $1;
} }
if ( $parse_state == 2 ) { if ($serial) {
if ( $line =~ m/Serial Number: (.+)$/ ) { try_for_raw_serialnum($serial);
$device->{'serial_number'} = $1;
next LINE;
}
if ( $line =~ m/Location ID: (.+)$/ ) {
$device->{'location_id'} = $1;
next LINE;
}
if ( $line =~ m/Product ID: (.+)$/ ) {
$device->{'product_id'} = $1;
next LINE;
} }
if ( $line =~ m/Vendor ID: (.+)$/ ) { if ($location) {
$device->{'vendor_id'} = $1; try_for_location_id($location);
next LINE;
}
if ( $line =~ m/^\s*$/ ) {
last LINE;
} }
if ($serial) {
try_for_sn_prefix($serial);
} }
} }
}
die "Can't find Model 01" if ( $device == {} ); sub try_for_raw_serialnum {
my $sn = shift;
my $serial_port_name = ""; my $serial_port_name = "/dev/cu.usbmodem" . $sn;
exit_with_port_if_exists($serial_port_name);
if ( exists( $device->{'serial_number'} ) ) {
$serial_port_name = "/dev/cu.usbmodem" . $device->{'serial_number'};
if ( -e $serial_port_name ) {
print $serial_port_name;
exit 0;
}
# High Sierra sometimes has a mismatch between the serial number and the device # High Sierra sometimes has a mismatch between the serial number and the device
# filename. I'm not sure why, but system_profiler has a serial number ending in "E", # filename. I'm not sure why, but system_profiler has a serial number ending in "E",
# whereas the device filename ends in "1". In fact, when I change HID.getShortName() # whereas the device filename ends in "1". In fact, when I change HID.getShortName()
# to return "kbio02", the final character is replaced with a "1", so we should do the # to return "kbio02", the final character is replaced with a "1", so we should do the
# same here. # same here. If the serial number doesn't end in a digit, however, we may want to append
# rather than replace the last character with a 1.
if ($serial_port_name =~ /\d$/) {
$serial_port_name =~ s/.$/1/; $serial_port_name =~ s/.$/1/;
if ( -e $serial_port_name ) { } else {
print $serial_port_name; $serial_port_name .= "1";
exit 0;
} }
exit_with_port_if_exists($serial_port_name);
} }
sub try_for_location_id {
my $location_id = shift;
# Here, also, the final character is always a "1", so if macOS ever stops doing that, this # Here, also, the final character is always a "1", so if macOS ever stops doing that, this
# will need an update, as well. # will need an update, as well.
if ( exists( $device->{'location_id'} ) ) { my $loc = substr($location_id, 2, 3);
my $loc = substr( $device->{'location_id'}, 2, 3 ); exit_with_port_if_exists("/dev/cu.usbmodem" . $loc . 1);
$serial_port_name = "/dev/cu.usbmodem" . $loc . 1;
if ( -e $serial_port_name ) {
print $serial_port_name;
exit 0;
}
} }
sub try_for_sn_prefix {
my $sn = shift;
# If none of the above tests succeeds, just list the directory and see if there are any # If none of the above tests succeeds, just list the directory and see if there are any
# files that have the device shortname that we expect: # files that have the device shortname that we expect:
foreach my $line (qx(ls /dev/cu.usbmodem*)) { foreach my $line (qx(ls /dev/cu.usbmodem*)) {
# If this script gets used for the Model 02 (or anything else that won't end it "1"), if ($line =~ /${sn}/) {
# the line below should probably drop the final character (see above):
if ( $line =~ m/kbio01/ ) {
chomp $line; chomp $line;
print $line; print $line;
exit 0; exit 0;
} }
} }
}
sub exit_with_port_if_exists {
my $serial_port_name = shift;
die "Can't find Model 01 serial port name"; if (-e $serial_port_name) {
print $serial_port_name;
exit 0;
}
}

Loading…
Cancel
Save