#!/usr/bin/env perl

# Based on listArduinos.pl from https://github.com/todbot/usbSearch (License: MIT)
# Original (C) 2012, Tod E. Kurt, http://todbot.com/blog/
# This version by Michael Richters <gedankenexperimenter@gmail.com>

use warnings;
use strict;

# ioreg might be more machine-readable than system_profiler, but I haven't been able to
# get it to produce useful output
my @output = qx(/usr/sbin/system_profiler SPUSBDataType);

my $parse_state = 0;
my $device      = {};

LINE: foreach my $line (@output) {

    chomp $line;

    if ( $parse_state == 0 ) {
        if ( $line =~ m/Model 01/ ) {
            $parse_state = 1;
            next LINE;
        }
    }

    if ( $parse_state == 1 ) {
        if ( $line =~ m/^\s*$/ ) {
            $parse_state = 2;
            next LINE;
        }
    }

    if ( $parse_state == 2 ) {
        if ( $line =~ m/Serial Number: (.+)$/ ) {
            $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: (.+)$/ ) {
            $device->{'vendor_id'} = $1;
            next LINE;
        }
        if ( $line =~ m/^\s*$/ ) {
            last LINE;
        }
    }

}

die "Can't find Model 01" if ( $device == {} );

my $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
    # 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()
    # to return "kbio02", the final character is replaced with a "1", so we should do the
    # same here.
    $serial_port_name =~ s/.$/1/;
    if ( -e $serial_port_name ) {
        print $serial_port_name;
        exit 0;
    }
}

# Here, also, the final character is always a "1", so if macOS ever stops doing that, this
# will need an update, as well.
if ( exists( $device->{'location_id'} ) ) {
    my $loc = substr( $device->{'location_id'}, 2, 3 );
    $serial_port_name = "/dev/cu.usbmodem" . $loc . 1;
    if ( -e $serial_port_name ) {
        print $serial_port_name;
        exit 0;
    }
}

# 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:
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"),
    # the line below should probably drop the final character (see above):
    if ( $line =~ m/kbio01/ ) {
	chomp $line;
	print $line;
	exit 0;
    }
}

die "Can't find Model 01 serial port name";