diff --git a/README.md b/README.md index fbffc91..ac84f5c 100644 --- a/README.md +++ b/README.md @@ -158,9 +158,6 @@ complete license. Copyright 2011-2012, Google Inc. All Rights Reserved. -Portions of this library are based on [libftdi](http://www.intra2net.com/en/developer/libftdi). -Please see FtdiSerialDriver.java for more information. - ## Help & Discussion For common problems, see the diff --git a/usbSerialForAndroid/publishToMavenLocal.gradle b/usbSerialForAndroid/publishToMavenLocal.gradle index 3f66137..27c07d3 100644 --- a/usbSerialForAndroid/publishToMavenLocal.gradle +++ b/usbSerialForAndroid/publishToMavenLocal.gradle @@ -5,7 +5,7 @@ publishing { maven(MavenPublication) { groupId 'com.github.mik3y' artifactId 'usb-serial-for-android' - version '2.2.2a' + version '3.0.0beta' afterEvaluate { artifact androidSourcesJar artifact bundleReleaseAar diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java index bee9139..ab07212 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -383,6 +383,44 @@ public class DeviceTest { assertThat("42000/8N1", data2, equalTo(buf2)); } } + if (usbSerialDriver instanceof FtdiSerialDriver) { + try { + usbParameters(183, 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate to low expected"); + } catch (IOException ignored) { + } + usbParameters(184, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters( 960000, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1000000, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1043478, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1090909, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1142857, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1200000, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1263157, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1333333, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1411764, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(1500000, 8, 1, UsbSerialPort.PARITY_NONE); + try { + usbParameters((int)(2000000/1.04), 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate error expected"); + } catch (IOException ignored) { + } + usbParameters((int)(2000000/1.03), 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(2000000, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters((int)(2000000*1.03), 8, 1, UsbSerialPort.PARITY_NONE); + try { + usbParameters((int)(2000000*1.04), 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate error expected"); + } catch (IOException ignored) { + } + usbParameters(2000000, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(3000000, 8, 1, UsbSerialPort.PARITY_NONE); + try { + usbParameters(4000000, 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate to high expected"); + } catch (IOException ignored) { + } + } { // non matching baud rate telnet.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1366,8 +1404,6 @@ public class DeviceTest { // control lines retained over close+open boolean inputRetained = inputLinesConnected; boolean outputRetained = true; - if(usb.serialDriver instanceof FtdiSerialDriver) - outputRetained = false; // todo usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT)); usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java index bb60df9..62331da 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java @@ -1,5 +1,6 @@ /* Copyright 2011-2013 Google Inc. * Copyright 2013 mike wakerly + * Copyright 2020 kai morich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,73 +34,22 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -/** - * A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices - *

- * This driver is based on libftdi, and is - * copyright and subject to the following terms: +/* + * driver is implemented from various information scattered over FTDI documentation * - *

- *   Copyright (C) 2003 by Intra2net AG
+ * baud rate calculation https://www.ftdichip.com/Support/Documents/AppNotes/AN232B-05_BaudRates.pdf
+ * control bits https://www.ftdichip.com/Firmware/Precompiled/UM_VinculumFirmware_V205.pdf
+ * device type https://www.ftdichip.com/Support/Documents/AppNotes/AN_233_Java_D2XX_for_Android_API_User_Manual.pdf -> bvdDevice
  *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License
- *   version 2.1 as published by the Free Software Foundation;
- *
- *   opensource@intra2net.com
- *   http://www.intra2net.com/en/developer/libftdi
- * 
- * - *

- *

- * Some FTDI devices have not been tested; see later listing of supported and - * unsupported devices. Devices listed as "supported" support the following - * features: - *

- *

- *

- * Supported and tested devices: - *

- *

- *

- * Unsupported but possibly working devices (please contact the author with - * feedback or patches): - *

- *

- * - * @author mike wakerly (opensource@hoho.com) - * @see USB Serial - * for Android project page - * @see FTDI Homepage - * @see libftdi */ + public class FtdiSerialDriver implements UsbSerialDriver { + private static final String TAG = FtdiSerialPort.class.getSimpleName(); + private final UsbDevice mDevice; private final List mPorts; - /** - * FTDI chip types. - */ - private static enum DeviceType { - TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H; - } - public FtdiSerialDriver(UsbDevice device) { mDevice = device; mPorts = new ArrayList<>(); @@ -120,96 +70,35 @@ public class FtdiSerialDriver implements UsbSerialDriver { public class FtdiSerialPort extends CommonUsbSerialPort { - private static final int USB_TYPE_STANDARD = 0x00 << 5; - private static final int USB_TYPE_CLASS = 0x00 << 5; - private static final int USB_TYPE_VENDOR = 0x00 << 5; - private static final int USB_TYPE_RESERVED = 0x00 << 5; - - private static final int USB_RECIP_DEVICE = 0x00; - private static final int USB_RECIP_INTERFACE = 0x01; - private static final int USB_RECIP_ENDPOINT = 0x02; - private static final int USB_RECIP_OTHER = 0x03; - - private static final int USB_ENDPOINT_IN = 0x80; - private static final int USB_ENDPOINT_OUT = 0x00; - private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; - private static final int USB_READ_TIMEOUT_MILLIS = 5000; + private static final int READ_HEADER_LENGTH = 2; // contains MODEM_STATUS - // From ftdi.h - /** - * Reset the port. - */ - private static final int SIO_RESET_REQUEST = 0; + private static final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT; + private static final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN; - /** - * Set the modem control register. - */ - private static final int SIO_MODEM_CTRL_REQUEST = 1; + private static final int RESET_REQUEST = 0; + private static final int MODEM_CONTROL_REQUEST = 1; + private static final int SET_BAUD_RATE_REQUEST = 3; + private static final int SET_DATA_REQUEST = 4; + private static final int GET_MODEM_STATUS_REQUEST = 5; + private static final int SET_LATENCY_TIMER_REQUEST = 9; + private static final int GET_LATENCY_TIMER_REQUEST = 10; - /** - * Set flow control register. - */ - private static final int SIO_SET_FLOW_CTRL_REQUEST = 2; + private static final int MODEM_CONTROL_DTR_ENABLE = 0x0101; + private static final int MODEM_CONTROL_DTR_DISABLE = 0x0100; + private static final int MODEM_CONTROL_RTS_ENABLE = 0x0202; + private static final int MODEM_CONTROL_RTS_DISABLE = 0x0200; + private static final int MODEM_STATUS_CTS = 0x10; + private static final int MODEM_STATUS_DSR = 0x20; + private static final int MODEM_STATUS_RI = 0x40; + private static final int MODEM_STATUS_CD = 0x80; + private static final int RESET_ALL = 0; + private static final int RESET_PURGE_RX = 1; + private static final int RESET_PURGE_TX = 2; - private static final int SIO_SET_DTR_HIGH = 0x0101; - private static final int SIO_SET_DTR_LOW = 0x0100; - private static final int SIO_SET_RTS_HIGH = 0x0202; - private static final int SIO_SET_RTS_LOW = 0x0200; - - /** - * Set baud rate. - */ - private static final int SIO_SET_BAUD_RATE_REQUEST = 3; - - /** - * Set the data characteristics of the port. - */ - private static final int SIO_SET_DATA_REQUEST = 4; - - private static final int SIO_RESET_SIO = 0; - private static final int SIO_RESET_PURGE_RX = 1; // RX @ FTDI device = write @ usb-serial-for-android library - private static final int SIO_RESET_PURGE_TX = 2; - - /** - * Get modem status. - */ - private static final int SIO_GET_MODEM_STATUS_REQUEST = 5; - - private static final int SIO_MODEM_STATUS_CTS = 0x10; - private static final int SIO_MODEM_STATUS_DSR = 0x20; - private static final int SIO_MODEM_STATUS_RI = 0x40; - private static final int SIO_MODEM_STATUS_RLSD = 0x80; - - /** - * Set the latency timer. - */ - private static final int SIO_SET_LATENCY_TIMER_REQUEST = 9; - - /** - * Get the latency timer. - */ - private static final int SIO_GET_LATENCY_TIMER_REQUEST = 10; - - private static final int FTDI_DEVICE_OUT_REQTYPE = - UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT; - - private static final int FTDI_DEVICE_IN_REQTYPE = - UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN; - - /** - * Length of the modem status header, transmitted with every read. - */ - private static final int MODEM_STATUS_HEADER_LENGTH = 2; - - private final String TAG = FtdiSerialDriver.class.getSimpleName(); - - private DeviceType mType; - - private int mIndex = 0; - - private boolean mDtrState = false; - private boolean mRtsState = false; + private boolean baudRateWithPort = false; + private boolean dtr = false; + private boolean rts = false; public FtdiSerialPort(UsbDevice device, int portNumber) { super(device, portNumber); @@ -220,95 +109,38 @@ public class FtdiSerialDriver implements UsbSerialDriver { return FtdiSerialDriver.this; } - /** - * Filter FTDI status bytes from buffer - * @param buffer The source buffer (which contains status bytes) - * buffer The destination buffer to write the status bytes into (can be src) - * @param totalBytesRead Number of bytes read to src - * @return The number of payload bytes - */ - @Override - protected int readFilter(byte[] buffer, int totalBytesRead) throws IOException { - if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { - throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); - } - int maxPacketSize = mReadEndpoint.getMaxPacketSize(); - final int packetsCount = (totalBytesRead + maxPacketSize -1 )/ maxPacketSize; - for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) { - final int count = (packetIdx == (packetsCount - 1)) - ? totalBytesRead - packetIdx * maxPacketSize - MODEM_STATUS_HEADER_LENGTH - : maxPacketSize - MODEM_STATUS_HEADER_LENGTH; - if (count > 0) { - System.arraycopy(buffer, packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH, - buffer, packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH), - count); - } - } - return totalBytesRead - (packetsCount * 2); - } - - private void reset() throws IOException { - // TODO(mikey): autodetect. - mType = DeviceType.TYPE_R; - if(mDevice.getInterfaceCount() > 1) { - mIndex = mPortNumber + 1; - if (mDevice.getInterfaceCount() == 2) - mType = DeviceType.TYPE_2232H; - if (mDevice.getInterfaceCount() == 4) - mType = DeviceType.TYPE_4232H; - } - - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, - SIO_RESET_SIO, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); - if (result != 0) { - throw new IOException("Reset failed: result=" + result); - } - mDtrState = false; - mRtsState = false; - } - - public void setLatencyTimer(int latencyTime) throws IOException { - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, - latencyTime, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); - if (result != 0) { - throw new IOException("Set latency timer failed: result=" + result); - } - } - - public int getLatencyTimer() throws IOException { - byte[] data = new byte[1]; - int result = mConnection.controlTransfer(FTDI_DEVICE_IN_REQTYPE, SIO_GET_LATENCY_TIMER_REQUEST, - 0, mIndex, data, data.length, USB_WRITE_TIMEOUT_MILLIS); - if (result != 1) { - throw new IOException("Get latency timer failed: result=" + result); - } - return data[0]; - } - - private int getModemStatus() throws IOException { - byte[] data = new byte[2]; - int result = mConnection.controlTransfer(FTDI_DEVICE_IN_REQTYPE, SIO_GET_MODEM_STATUS_REQUEST, - 0, mIndex, data, data.length, USB_WRITE_TIMEOUT_MILLIS); - if (result != 2) { - throw new IOException("Get modem statusfailed: result=" + result); - } - return data[0]; - } @Override protected void openInt(UsbDeviceConnection connection) throws IOException { - if (connection.claimInterface(mDevice.getInterface(mPortNumber), true)) { - Log.d(TAG, "claimInterface " + mPortNumber + " SUCCESS"); - } else { - throw new IOException("Error claiming interface " + mPortNumber); + if (!connection.claimInterface(mDevice.getInterface(mPortNumber), true)) { + throw new IOException("Could not claim interface " + mPortNumber); } if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) { - throw new IOException("Insufficient number of endpoints (" + - mDevice.getInterface(mPortNumber).getEndpointCount() + ")"); + throw new IOException("Not enough endpoints"); } mReadEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(0); mWriteEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(1); - reset(); + + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST, + RESET_ALL, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); + if (result != 0) { + throw new IOException("Reset failed: result=" + result); + } + result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST, + (dtr ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE) | + (rts ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE), + mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); + if (result != 0) { + throw new IOException("Init RTS,DTR failed: result=" + result); + } + + // mDevice.getVersion() would require API 23 + byte[] rawDescriptors = connection.getRawDescriptors(); + if(rawDescriptors == null || rawDescriptors.length < 14) { + throw new IOException("Could not get device descriptors"); + } + int deviceType = rawDescriptors[13]; + baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9; // ...H devices } @Override @@ -318,18 +150,69 @@ public class FtdiSerialDriver implements UsbSerialDriver { } catch(Exception ignored) {} } - private int setBaudRate(int baudRate) throws IOException { - long[] vals = convertBaudrate(baudRate); - long actualBaudrate = vals[0]; - long index = vals[1]; - long value = vals[2]; - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, - SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index, - null, 0, USB_WRITE_TIMEOUT_MILLIS); + @Override + protected int readFilter(byte[] buffer, int totalBytesRead) throws IOException { + final int maxPacketSize = mReadEndpoint.getMaxPacketSize(); + int destPos = 0; + for(int srcPos = 0; srcPos < totalBytesRead; srcPos += maxPacketSize) { + int length = Math.min(srcPos + maxPacketSize, totalBytesRead) - (srcPos + READ_HEADER_LENGTH); + if (length < 0) + throw new IOException("Expected at least " + READ_HEADER_LENGTH + " bytes"); + System.arraycopy(buffer, srcPos + READ_HEADER_LENGTH, buffer, destPos, length); + destPos += length; + } + return destPos; + } + + private void setBaudrate(int baudRate) throws IOException { + int divisor, subdivisor, effectiveBaudRate; + if (baudRate > 3500000) { + throw new IOException("Baud rate to high"); + } else if(baudRate >= 2500000) { + divisor = 0; + subdivisor = 0; + effectiveBaudRate = 3000000; + } else if(baudRate >= 1750000) { + divisor = 1; + subdivisor = 0; + effectiveBaudRate = 2000000; + } else { + divisor = (24000000 << 1) / baudRate; + divisor = (divisor + 1) >> 1; // round + subdivisor = divisor & 0x07; + divisor >>= 3; + if (divisor > 0x3fff) // exceeds bit 13 at 183 baud + throw new IOException("Baud rate to low"); + effectiveBaudRate = (24000000 << 1) / ((divisor << 3) + subdivisor); + effectiveBaudRate = (effectiveBaudRate +1) >> 1; + } + double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate)); + if(baudRateError >= 0.031) // can happen only > 1.5Mbaud + throw new IOException(String.format("baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100)); + int value = divisor; + int index = 0; + switch(subdivisor) { + case 0: break; // 16,15,14 = 000 - sub-integer divisor = 0 + case 4: value |= 0x4000; break; // 16,15,14 = 001 - sub-integer divisor = 0.5 + case 2: value |= 0x8000; break; // 16,15,14 = 010 - sub-integer divisor = 0.25 + case 1: value |= 0xc000; break; // 16,15,14 = 011 - sub-integer divisor = 0.125 + case 3: value |= 0x0000; index |= 1; break; // 16,15,14 = 100 - sub-integer divisor = 0.375 + case 5: value |= 0x4000; index |= 1; break; // 16,15,14 = 101 - sub-integer divisor = 0.625 + case 6: value |= 0x8000; index |= 1; break; // 16,15,14 = 110 - sub-integer divisor = 0.75 + case 7: value |= 0xc000; index |= 1; break; // 16,15,14 = 111 - sub-integer divisor = 0.875 + } + if(baudRateWithPort) { + index <<= 8; + index |= mPortNumber+1; + } + Log.d(TAG, String.format("baud rate=%d, effective=%d, error=%.1f%%, value=0x%04x, index=0x%04x, divisor=%d, subdivisor=%d", + baudRate, effectiveBaudRate, baudRateError*100, value, index, divisor, subdivisor)); + + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_BAUD_RATE_REQUEST, + value, index, null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("Setting baudrate failed: result=" + result); } - return (int) actualBaudrate; } @Override @@ -337,7 +220,7 @@ public class FtdiSerialDriver implements UsbSerialDriver { if(baudRate <= 0) { throw new IllegalArgumentException("Invalid baud rate: " + baudRate); } - setBaudRate(baudRate); + setBaudrate(baudRate); int config = 0; switch (dataBits) { @@ -354,19 +237,18 @@ public class FtdiSerialDriver implements UsbSerialDriver { switch (parity) { case PARITY_NONE: - config |= (0x00 << 8); break; case PARITY_ODD: - config |= (0x01 << 8); + config |= 0x100; break; case PARITY_EVEN: - config |= (0x02 << 8); + config |= 0x200; break; case PARITY_MARK: - config |= (0x03 << 8); + config |= 0x300; break; case PARITY_SPACE: - config |= (0x04 << 8); + config |= 0x400; break; default: throw new IllegalArgumentException("Invalid parity: " + parity); @@ -374,170 +256,93 @@ public class FtdiSerialDriver implements UsbSerialDriver { switch (stopBits) { case STOPBITS_1: - config |= (0x00 << 11); break; case STOPBITS_1_5: throw new UnsupportedOperationException("Unsupported stop bits: 1.5"); case STOPBITS_2: - config |= (0x02 << 11); + config |= 0x1000; break; default: throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, - SIO_SET_DATA_REQUEST, config, mIndex, - null, 0, USB_WRITE_TIMEOUT_MILLIS); + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_DATA_REQUEST, + config, mPortNumber+1,null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("Setting parameters failed: result=" + result); } } - private long[] convertBaudrate(int baudrate) { - // TODO(mikey): Braindead transcription of libfti method. Clean up, - // using more idiomatic Java where possible. - int divisor = 24000000 / baudrate; - int bestDivisor = 0; - int bestBaud = 0; - int bestBaudDiff = 0; - int fracCode[] = { - 0, 3, 2, 4, 1, 5, 6, 7 - }; - - for (int i = 0; i < 2; i++) { - int tryDivisor = divisor + i; - int baudEstimate; - int baudDiff; - - if (tryDivisor <= 8) { - // Round up to minimum supported divisor - tryDivisor = 8; - } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) { - // BM doesn't support divisors 9 through 11 inclusive - tryDivisor = 12; - } else if (divisor < 16) { - // AM doesn't support divisors 9 through 15 inclusive - tryDivisor = 16; - } else { - if (mType == DeviceType.TYPE_AM) { - // TODO - } else { - if (tryDivisor > 0x1FFFF) { - // Round down to maximum supported divisor value (for - // BM) - tryDivisor = 0x1FFFF; - } - } - } - - // Get estimated baud rate (to nearest integer) - baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor; - - // Get absolute difference from requested baud rate - if (baudEstimate < baudrate) { - baudDiff = baudrate - baudEstimate; - } else { - baudDiff = baudEstimate - baudrate; - } - - if (i == 0 || baudDiff < bestBaudDiff) { - // Closest to requested baud rate so far - bestDivisor = tryDivisor; - bestBaud = baudEstimate; - bestBaudDiff = baudDiff; - if (baudDiff == 0) { - // Spot on! No point trying - break; - } - } + private int getStatus() throws IOException { + byte[] data = new byte[2]; + int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST, + 0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS); + if (result != 2) { + throw new IOException("Get modem status failed: result=" + result); } - - // Encode the best divisor value - long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14); - // Deal with special cases for encoded value - if (encodedDivisor == 1) { - encodedDivisor = 0; // 3000000 baud - } else if (encodedDivisor == 0x4001) { - encodedDivisor = 1; // 2000000 baud (BM only) - } - - // Split into "value" and "index" values - long value = encodedDivisor & 0xFFFF; - long index; - if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H - || mType == DeviceType.TYPE_4232H) { - index = (encodedDivisor >> 8) & 0xff00; - index |= mIndex; - } else { - index = (encodedDivisor >> 16) & 0xffff; - } - - // Return the nearest baud rate - return new long[] { - bestBaud, index, value - }; + return data[0]; } @Override public boolean getCD() throws IOException { - return (getModemStatus() & SIO_MODEM_STATUS_RLSD) != 0; + return (getStatus() & MODEM_STATUS_CD) != 0; } @Override public boolean getCTS() throws IOException { - return (getModemStatus() & SIO_MODEM_STATUS_CTS) != 0; + return (getStatus() & MODEM_STATUS_CTS) != 0; } @Override public boolean getDSR() throws IOException { - return (getModemStatus() & SIO_MODEM_STATUS_DSR) != 0; + return (getStatus() & MODEM_STATUS_DSR) != 0; } @Override public boolean getDTR() throws IOException { - return mDtrState; + return dtr; } @Override public void setDTR(boolean value) throws IOException { - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_MODEM_CTRL_REQUEST, - value ? SIO_SET_DTR_HIGH : SIO_SET_DTR_LOW, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST, + value ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("Set DTR failed: result=" + result); } - mDtrState = value; + dtr = value; } @Override public boolean getRI() throws IOException { - return (getModemStatus() & SIO_MODEM_STATUS_RI) != 0; + return (getStatus() & MODEM_STATUS_RI) != 0; } @Override public boolean getRTS() throws IOException { - return mRtsState; + return rts; } @Override public void setRTS(boolean value) throws IOException { - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_MODEM_CTRL_REQUEST, - value ? SIO_SET_RTS_HIGH : SIO_SET_RTS_LOW, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST, + value ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("Set DTR failed: result=" + result); } - mRtsState = value; + rts = value; } @Override public EnumSet getControlLines() throws IOException { - int status = getModemStatus(); + int status = getStatus(); EnumSet set = EnumSet.noneOf(ControlLine.class); - if(mRtsState) set.add(ControlLine.RTS); - if((status & SIO_MODEM_STATUS_CTS) != 0) set.add(ControlLine.CTS); - if(mDtrState) set.add(ControlLine.DTR); - if((status & SIO_MODEM_STATUS_DSR) != 0) set.add(ControlLine.DSR); - if((status & SIO_MODEM_STATUS_RLSD) != 0) set.add(ControlLine.CD); - if((status & SIO_MODEM_STATUS_RI) != 0) set.add(ControlLine.RI); + if(rts) set.add(ControlLine.RTS); + if((status & MODEM_STATUS_CTS) != 0) set.add(ControlLine.CTS); + if(dtr) set.add(ControlLine.DTR); + if((status & MODEM_STATUS_DSR) != 0) set.add(ControlLine.DSR); + if((status & MODEM_STATUS_CD) != 0) set.add(ControlLine.CD); + if((status & MODEM_STATUS_RI) != 0) set.add(ControlLine.RI); return set; } @@ -549,22 +354,41 @@ public class FtdiSerialDriver implements UsbSerialDriver { @Override public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { if (purgeWriteBuffers) { - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, - SIO_RESET_PURGE_RX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST, + RESET_PURGE_RX, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("purge write buffer failed: result=" + result); } } if (purgeReadBuffers) { - int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, - SIO_RESET_PURGE_TX, mIndex, null, 0, USB_WRITE_TIMEOUT_MILLIS); + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST, + RESET_PURGE_TX, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); if (result != 0) { throw new IOException("purge read buffer failed: result=" + result); } } return true; } + + public void setLatencyTimer(int latencyTime) throws IOException { + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_LATENCY_TIMER_REQUEST, + latencyTime, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS); + if (result != 0) { + throw new IOException("Set latency timer failed: result=" + result); + } + } + + public int getLatencyTimer() throws IOException { + byte[] data = new byte[1]; + int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_LATENCY_TIMER_REQUEST, + 0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS); + if (result != 1) { + throw new IOException("Get latency timer failed: result=" + result); + } + return data[0]; + } + } public static Map getSupportedDevices() { @@ -575,7 +399,6 @@ public class FtdiSerialDriver implements UsbSerialDriver { UsbId.FTDI_FT232H, UsbId.FTDI_FT2232H, UsbId.FTDI_FT4232H, - UsbId.FTDI_FT231X, }); return supportedDevices; } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java index 35a501c..d34bbe8 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java @@ -36,7 +36,6 @@ public final class UsbId { public static final int FTDI_FT2232H = 0x6010; public static final int FTDI_FT4232H = 0x6011; public static final int FTDI_FT232H = 0x6014; - public static final int FTDI_FT231X = 0x6015; public static final int VENDOR_ATMEL = 0x03EB; public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;