working on #223: Auto-detection of serial ports. Mac version ready even if a bit slow

This commit is contained in:
Federico Fissore 2013-01-28 18:21:41 +01:00
parent 776952762f
commit 0d47f22787
11 changed files with 365 additions and 23 deletions

View File

@ -134,18 +134,18 @@ public class Platform {
}
}
public String resolveDeviceAttachedTo(String device, Map<String, TargetPackage> packages) {
public String resolveDeviceAttachedTo(String serial, Map<String, TargetPackage> packages) {
return null;
}
public String resolveDeviceByVendorIdProductId(Map<String, TargetPackage> packages, String vendorId, String productId) {
protected String resolveDeviceByVendorIdProductId(Map<String, TargetPackage> packages, String readVIDPID) {
for (TargetPackage targetPackage : packages.values()) {
for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) {
for (PreferencesMap board : targetPlatform.getBoards().values()) {
if (board.containsKey("vid_pid")) {
String[] vidPids = board.get("vid_pid").split(",");
for (String vidPid : vidPids) {
if (vidPid.toUpperCase().equals(vendorId + "_" + productId)) {
if (vidPid.toUpperCase().equals(readVIDPID)) {
return board.get("name");
}
}

View File

@ -22,12 +22,6 @@
package processing.app.linux;
import java.io.*;
import java.util.Map;
import java.util.Properties;
import javax.swing.UIManager;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteStreamHandler;
@ -36,6 +30,9 @@ import processing.app.Preferences;
import processing.app.debug.TargetPackage;
import processing.core.PConstants;
import java.io.*;
import java.util.Map;
/**
* Used by Base for platform-specific tweaking, for instance finding the
@ -171,11 +168,15 @@ public class Platform extends processing.app.Platform {
baos.reset();
CommandLine commandLine = CommandLine.parse("udevadm info --query=property -p " + devicePath);
executor.execute(commandLine);
Properties properties = new Properties();
properties.load(new ByteArrayInputStream(baos.toByteArray()));
return super.resolveDeviceByVendorIdProductId(packages, properties.get("ID_VENDOR_ID").toString().toUpperCase(), properties.get("ID_MODEL_ID").toString().toUpperCase());
String vidPid = new UDevAdmParser().extractVIDAndPID(new String(baos.toByteArray()));
if (vidPid == null) {
return super.resolveDeviceAttachedTo(serial, packages);
}
return super.resolveDeviceByVendorIdProductId(packages, vidPid);
} catch (IOException e) {
return null;
return super.resolveDeviceAttachedTo(serial, packages);
}
}
}

View File

@ -0,0 +1,16 @@
package processing.app.linux;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
public class UDevAdmParser {
public String extractVIDAndPID(String output) throws IOException {
Properties properties = new Properties();
properties.load(new StringReader(output));
return properties.get("ID_VENDOR_ID").toString().toUpperCase() + "_" + properties.get("ID_MODEL_ID").toString().toUpperCase();
}
}

View File

@ -22,20 +22,23 @@
package processing.app.macosx;
import java.awt.Insets;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.net.URI;
import javax.swing.UIManager;
import com.apple.eio.FileManager;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteStreamHandler;
import org.apache.commons.exec.Executor;
import processing.app.Base;
import processing.app.debug.TargetPackage;
import processing.core.PApplet;
import processing.core.PConstants;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Map;
/**
* Platform handler for Mac OS X.
@ -202,4 +205,52 @@ public class Platform extends processing.app.Platform {
return PConstants.platformNames[PConstants.MACOSX];
}
@Override
public String resolveDeviceAttachedTo(String serial, Map<String, TargetPackage> packages) {
Executor executor = new DefaultExecutor();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
executor.setStreamHandler(new ExecuteStreamHandler() {
@Override
public void setProcessInputStream(OutputStream outputStream) throws IOException {
}
@Override
public void setProcessErrorStream(InputStream inputStream) throws IOException {
}
@Override
public void setProcessOutputStream(InputStream inputStream) throws IOException {
byte[] buf = new byte[4096];
int bytes = -1;
while ((bytes = inputStream.read(buf)) != -1) {
baos.write(buf, 0, bytes);
}
}
@Override
public void start() throws IOException {
}
@Override
public void stop() {
}
});
try {
CommandLine toDevicePath = CommandLine.parse("/usr/sbin/system_profiler SPUSBDataType");
executor.execute(toDevicePath);
String output = new String(baos.toByteArray());
String vidPid = new SystemProfilerParser().extractVIDAndPID(output, serial);
if (vidPid == null) {
return super.resolveDeviceAttachedTo(serial, packages);
}
return super.resolveDeviceByVendorIdProductId(packages, vidPid);
} catch (IOException e) {
return super.resolveDeviceAttachedTo(serial, packages);
}
}
}

View File

@ -0,0 +1,62 @@
package processing.app.macosx;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SystemProfilerParser {
private final Pattern vidRegex;
private final Pattern serialNumberRegex;
private final Pattern locationRegex;
private final Pattern pidRegex;
public SystemProfilerParser() {
serialNumberRegex = Pattern.compile("^Serial Number: (.+)$");
locationRegex = Pattern.compile("^Location ID: (.+)$");
pidRegex = Pattern.compile("^Product ID: (.+)$");
vidRegex = Pattern.compile("^Vendor ID: (.+)$");
}
public String extractVIDAndPID(String output, String serial) throws IOException {
BufferedReader reader = new BufferedReader(new StringReader(output));
String devicePrefix;
if (serial.startsWith("/dev/tty.")) {
devicePrefix = "/dev/tty.usbmodem";
} else {
devicePrefix = "/dev/cu.usbmodem";
}
Map<String, String> device = new HashMap<String, String>();
String line;
Matcher matcher;
while ((line = reader.readLine()) != null) {
line = line.trim();
line = line.replaceAll("\\s+", " ");
if ((matcher = serialNumberRegex.matcher(line)).matches()) {
device.put("serial_number", matcher.group(1));
} else if ((matcher = locationRegex.matcher(line)).matches()) {
device.put("device_path", devicePrefix + matcher.group(1).substring(2, 6) + "1");
} else if ((matcher = pidRegex.matcher(line)).matches()) {
device.put("pid", matcher.group(1));
} else if ((matcher = vidRegex.matcher(line)).matches()) {
device.put("vid", matcher.group(1));
} else if (line.equals("")) {
if (device.containsKey("serial_number") && device.get("device_path").equals(serial)) {
return device.get("vid").substring(2).toUpperCase() + "_" + device.get("pid").substring(2).toUpperCase();
}
device = new HashMap<String, String>();
}
}
return null;
}
}

View File

@ -0,0 +1,21 @@
package processing.app;
import java.io.*;
public class TestHelper {
public static String inputStreamToString(InputStream is) throws IOException {
StringWriter sw = new StringWriter();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
try {
while ((line = reader.readLine()) != null) {
sw.append(line).append('\n');
}
return sw.toString();
} finally {
is.close();
}
}
}

View File

@ -0,0 +1,16 @@
package processing.app.linux;
import org.junit.Test;
import processing.app.TestHelper;
import static org.junit.Assert.assertEquals;
public class UDevAdmParserTest {
@Test
public void shouldCorrectlyParse() throws Exception {
String output = TestHelper.inputStreamToString(UDevAdmParserTest.class.getResourceAsStream("udev_output.txt"));
assertEquals("2341_0036", new UDevAdmParser().extractVIDAndPID(output));
}
}

View File

@ -0,0 +1,24 @@
DEVLINKS=/dev/arduino_leonardo /dev/serial/by-id/usb-Arduino_LLC_Arduino_Leonardo-if00 /dev/serial/by-path/pci-0000:00:14.0-usb-0:2.3:1.0
DEVNAME=/dev/ttyACM0
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.3/3-2.3:1.0/tty/ttyACM0
ID_BUS=usb
ID_MM_CANDIDATE=1
ID_MODEL=Arduino_Leonardo
ID_MODEL_ENC=Arduino\x20Leonardo
ID_MODEL_ID=0036
ID_PATH=pci-0000:00:14.0-usb-0:2.3:1.0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_3_1_0
ID_REVISION=0001
ID_SERIAL=Arduino_LLC_Arduino_Leonardo
ID_TYPE=generic
ID_USB_DRIVER=cdc_acm
ID_USB_INTERFACES=:020201:0a0000:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=Arduino_LLC
ID_VENDOR_ENC=Arduino\x20LLC
ID_VENDOR_ID=2341
MAJOR=166
MINOR=0
SUBSYSTEM=tty
UDEV_LOG=3
USEC_INITIALIZED=21035594802

View File

@ -0,0 +1,17 @@
package processing.app.macosx;
import org.junit.Test;
import processing.app.TestHelper;
import static org.junit.Assert.assertEquals;
public class SystemProfilerParserTest {
@Test
public void shouldCorrectlyParse() throws Exception {
String output = TestHelper.inputStreamToString(SystemProfilerParserTest.class.getResourceAsStream("system_profiler_output.txt"));
assertEquals("2341_0044", new SystemProfilerParser().extractVIDAndPID(output, "/dev/cu.usbmodemfa121"));
assertEquals("2341_0044", new SystemProfilerParser().extractVIDAndPID(output, "/dev/tty.usbmodemfa121"));
}
}

View File

@ -0,0 +1,134 @@
USB:
USB High-Speed Bus:
Host Controller Location: Built-in USB
Host Controller Driver: AppleUSBEHCI
PCI Device ID: 0x1c2d
PCI Revision ID: 0x0005
PCI Vendor ID: 0x8086
Bus Number: 0xfa
Hub:
Product ID: 0x2513
Vendor ID: 0x0424 (SMSC)
Version: b.b3
Speed: Up to 480 Mb/sec
Location ID: 0xfa100000 / 2
Current Available (mA): 500
Current Required (mA): 2
Trans-It Drive:
Capacity: 3.99 GB (3,992,977,408 bytes)
Removable Media: Yes
Detachable Drive: Yes
BSD Name: disk1
Product ID: 0x0622
Vendor ID: 0x0718 (Imation Corp.)
Version: 1.10
Serial Number: 0792181A2BDD
Speed: Up to 480 Mb/sec
Manufacturer: TDKMedia
Location ID: 0xfa130000 / 6
Current Available (mA): 500
Current Required (mA): 300
Partition Map Type: MBR (Master Boot Record)
S.M.A.R.T. status: Not Supported
Volumes:
Untitled:
Capacity: 3.99 GB (3,990,379,520 bytes)
Available: 1.99 GB (1,986,838,528 bytes)
Writable: Yes
File System: MS-DOS FAT32
BSD Name: disk1s1
Mount Point: /Volumes/Untitled
Content: Windows_FAT_32
Arduino Mega ADK:
Product ID: 0x0044
Vendor ID: 0x2341
Version: 0.01
Serial Number: 64936333936351500000
Speed: Up to 12 Mb/sec
Manufacturer: Arduino (www.arduino.cc)
Location ID: 0xfa120000 / 5
Current Available (mA): 500
Current Required (mA): 100
BRCM20702 Hub:
Product ID: 0x4500
Vendor ID: 0x0a5c (Broadcom Corp.)
Version: 1.00
Speed: Up to 12 Mb/sec
Manufacturer: Apple Inc.
Location ID: 0xfa110000 / 3
Current Available (mA): 500
Current Required (mA): 94
Bluetooth USB Host Controller:
Product ID: 0x8281
Vendor ID: 0x05ac (Apple Inc.)
Version: 0.97
Speed: Up to 12 Mb/sec
Manufacturer: Apple Inc.
Location ID: 0xfa113000 / 4
Current Available (mA): 500
Current Required (mA): 0
USB High-Speed Bus:
Host Controller Location: Built-in USB
Host Controller Driver: AppleUSBEHCI
PCI Device ID: 0x7ffc00001c26
PCI Revision ID: 0x7ffc00000005
PCI Vendor ID: 0x7ffc00008086
Bus Number: 0xfd
Hub:
Product ID: 0x2513
Vendor ID: 0x0424 (SMSC)
Version: b.b3
Speed: Up to 480 Mb/sec
Location ID: 0xfd100000 / 2
Current Available (mA): 500
Current Required (mA): 2
USB Multimedia Keyboard:
Product ID: 0xc311
Vendor ID: 0x046d (Logitech Inc.)
Version: 1.30
Speed: Up to 1.5 Mb/sec
Manufacturer: BTC
Location ID: 0xfd120000 / 5
Current Available (mA): 500
Current Required (mA): 100
USB-PS/2 Optical Mouse:
Product ID: 0xc050
Vendor ID: 0x046d (Logitech Inc.)
Version: 27.20
Speed: Up to 1.5 Mb/sec
Manufacturer: Logitech
Location ID: 0xfd130000 / 4
Current Available (mA): 500
Current Required (mA): 98
IR Receiver:
Product ID: 0x8242
Vendor ID: 0x05ac (Apple Inc.)
Version: 0.16
Speed: Up to 1.5 Mb/sec
Manufacturer: Apple Computer, Inc.
Location ID: 0xfd110000 / 3
Current Available (mA): 500
Current Required (mA): 100

View File

@ -76,7 +76,7 @@
<!-- In 0149, removed /System/Library/Java from the CLASSPATH because
it can cause problems if users have installed weird files there.
http://dev.processing.org/bugs/show_bug.cgi?id=1045 -->
<string>$JAVAROOT/pde.jar:$JAVAROOT/core.jar:$JAVAROOT/antlr.jar:$JAVAROOT/ecj.jar:$JAVAROOT/registry.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/RXTXcomm.jar</string>
<string>$JAVAROOT/pde.jar:$JAVAROOT/core.jar:$JAVAROOT/antlr.jar:$JAVAROOT/ecj.jar:$JAVAROOT/registry.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/RXTXcomm.jar:$JAVAROOT/commons-exec-1.1.jar</string>
<key>JVMArchs</key>
<array>