【背景】
新买的USB的HART猫:
【记录】为USB接口的HART猫ExSaf ESH232U安装对应的USB转RS232驱动
【记录】使用USB口的HART猫ExSaf ESH232U去检测某HART设备
其内部是Silicon Labs的CP2102的USB转串口的芯片。
现在是,希望将其用到之前:
已经支持了FTDI的FT232R的usb-serial-for-android
中的CP2102,也去添加对应的RTS和DTR,使得也可以用此HART猫去和HART设备通讯。
【折腾过程】
1.之前整理的一些可参考的资料:
2.
http://124.16.139.131:24080/lxr/source/kernel/omap/drivers/usb/serial/cp210x.c?v=android-4.0.4
中有:
#define REQTYPE_HOST_TO_DEVICE 0x41
和
3.
http://www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx
中的源码:
4.
http://code.google.com/p/usb-serial-for-android/issues/detail?id=17
或许也有参考价值。
然后发现了,对于下载到的:
http://www.firmsys.com/down/UARTtoUSB.zip
其中包含了之前就知道的:
CP2102的
Linux_3.x.x_VCP_Driver_Source.zip
其中的驱动,就是我后来看到的:
http://lxr.free-electrons.com/source/drivers/usb/serial/cp210x.c#L286
5.参考源码后,就去折腾:
| D:\DevRoot\android\android_root\UsbSerialLibrary\src\com\hoho\android\usbserial\driver\Cp2102SerialDriver.java |
中的内容,尤其是:
@Override
public void setRTS(boolean value) throws IOException {
}
@Override
public void setDTR(boolean value) throws IOException {
}6.开始折腾了,去:
http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers.aspx
供参考。
7.开始是参考:
| D:\DevTool\USB-To-RS232\Linux_2.6.x_VCP_Driver_Source\Linux_2.6.x_VCP_Driver_Source\cp210x.c |
去写代码的。
8.但是期间发现,很多细节的定义,还是需要找对应的datasheet看,才更清楚。
所以去搜CP2102的datasheet,但是搜到:
https://www.sparkfun.com/datasheets/IC/cp2102.pdf
http://www.sinforcon.com/down/html/50.html
https://www.sparkfun.com/datasheets/PCB/CP2102%20Breakout-v01.pdf
却没有找到想要包含RTS DTR的位含义的定义的寄存器。。
9.另外,关于:
TIOCM_DTR
和
TIOCM_RTS
代码中找不到,也没有对应的.h头文件。
10.后来是在:
http://lxr.free-electrons.com/source/drivers/usb/serial/cp210x.c#L286
->
http://lxr.free-electrons.com/ident?i=TIOCM_DTR
->
http://lxr.free-electrons.com/source/include/uapi/asm-generic/termios.h#L33
找到的:
/* modem lines */ #define TIOCM_DTR 0x002 #define TIOCM_RTS 0x004 #define TIOCM_CTS 0x020 #define TIOCM_DSR 0x100
11.但是折腾代码期间,发现其原先有个问题:
setParameters
中,先去对于configDataBits,configParityBits,configStopBits
竟然是分别三次都单独设置一次,去调用setConfigSingle
而对应的
D:\DevTool\USB-To-RS232\Linux_2.6.x_VCP_Driver_Source\Linux_2.6.x_VCP_Driver_Source\cp210x.c
是:
分别计算对应的值,得到合并后的配置的值,然后最后只去调用一次:
cp210x_set_config
不过,后来又在:
D:\DevTool\USB-To-RS232\Silicon Labs\CP210x\UARTtoUSB\Ver.3.0\Driver\Linux_3.x.x_VCP_Driver_Source\Linux_3.x.x_VCP_Driver_Source\cp210x.c
中看到:
也是分别对于三种配置,分别去配置的。
但是很明显:
其三次调用
cp210x_set_config
去配置对应的值bits,都是分别获得最新的bits值,然后加上当前的配置,才去写入的。
而上面的代码中:
configDataBits,configParityBits,configStopBits
三个值,都只是自己独立的值:
搞得配置后面一个配置,就把之前的配置冲掉了。。。
所以,去改对应的代码为:
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
throws IOException {
setBaudRate(baudRate);
int configBits = 0;
//int configDataBits = 0;
switch (dataBits) {
case DATABITS_5:
configBits |= 0x0500;
break;
case DATABITS_6:
configBits |= 0x0600;
break;
case DATABITS_7:
configBits |= 0x0700;
break;
case DATABITS_8:
configBits |= 0x0800;
break;
default:
configBits |= 0x0800;
break;
}
//setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
//int configParityBits = 0; // PARITY_NONE
switch (parity) {
case PARITY_ODD:
configBits |= 0x0010;
break;
case PARITY_EVEN:
configBits |= 0x0020;
break;
}
//setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configParityBits);
//int configStopBits = 0;
switch (stopBits) {
case STOPBITS_1:
configBits |= 0;
break;
case STOPBITS_1_5:
configBits |= 1;
break;
case STOPBITS_2:
configBits |= 2;
break;
}
//setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configStopBits);
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configBits);
}12.后面继续去调试。
然后发现:
http://code.google.com/p/usb-serial-for-android/issues/detail?id=17
中的patch:
才是,根据cp210x.c修正后的,更加完整的驱动。
然后想办法去打上此patch:
还是参考之前的:
结果是:
CLi@PC-CLI-1 /cygdrive/d/DevTool/Android/libs/usb serial/usb-serial-for-android $ ls -lha total 61K drwx------+ 1 Administrators Domänen-Benutzer 0 Nov 27 12:48 ./ drwx------+ 1 Administrators Domänen-Benutzer 0 Nov 27 12:48 ../ -rwx------+ 1 Administrators Domänen-Benutzer 218 Nov 7 10:34 .gitignore* drwx------+ 1 Administrators Domänen-Benutzer 0 Nov 27 12:46 arduino/ -rwx------+ 1 Administrators Domänen-Benutzer 673 Nov 7 10:34 CHANGELOG.txt* -rwx------+ 1 Administrators Domänen-Benutzer 7.5K Nov 7 10:34 LICENSE.txt* -rwx------+ 1 Administrators Domänen-Benutzer 4.0K Nov 7 10:34 README.md* drwx------+ 1 Administrators Domänen-Benutzer 0 Nov 27 12:46 UsbSerialExamples/ -rwx------+ 1 Administrators Domänen-Benutzer 27K Nov 27 12:45 usb-serial-for-android-cp210x.patch* drwx------+ 1 Administrators Domänen-Benutzer 0 Nov 27 12:46 UsbSerialLibrary/ CLi@PC-CLI-1 /cygdrive/d/DevTool/Android/libs/usb serial/usb-serial-for-android $ patch -p1 < usb-serial-for-android-cp210x.patch patching file UsbSerialExamples/project.properties patching file UsbSerialExamples/res/xml/device_filter.xml Hunk #1 succeeded at 11 with fuzz 2 (offset 3 lines). patching file UsbSerialLibrary/project.properties patching file UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CP210xSerialDriver.java patching file UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java Hunk #1 FAILED at 51. 1 out of 1 hunk FAILED -- saving rejects to file UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java.rej patching file UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java Hunk #1 succeeded at 79 with fuzz 2 (offset 9 lines). patching file UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java Hunk #1 succeeded at 112 with fuzz 2 (offset 45 lines). patching file UsbSerialLibrary/src/com/hoho/android/usbserial/util/SerialInputOutputManager.java
很明显,部分内容没有完全打上。
估计是版本不匹配?
另外看到:
https://github.com/mik3y/usb-serial-for-android/issues/17
中说已经在2b3528b 合并了此补丁了。
所以,那就去:
https://github.com/mik3y/usb-serial-for-android
下载最新的代码,看看是否的确已经合并。
结果貌似最新的代码,和我之前就已经下载的,是一样的。
即:
最新的代码中,虽然像:
说的:
“A similar patch was merged in 2b3528b”
但是实际上,从master下载到最新的:
usb-serial-for-android-master.zip
中,对应的
CP210xSerialDriver.java
中的代码,却不是上面patch中的。
因为该patch中是:
CP210xSerialDriver.java
且包含对应的定义,都是和之前的Linux中的cp210x.c中都是一致的;
而新下载到的usb-serial-for-android-master.zip,中是:
Cp2102SerialDriver.java
且其中很多代码,就是我前面提到的,写法都是不正确的。
算了,单独从patch中,拷贝出对应的:
CP210xSerialDriver.java
然后保存后,和当前已有的
Cp2102SerialDriver.java
去比较看看。
算了,最后决定,还是手动去合并这个patch,使得不仅仅支持CP2102,而是支持CP210x。
13.后来写了代码:
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A {@link UsbSerialDriver} implementation for a variety of CP210x devices
* <p>
* This driver is based on the source codes from linux kernel 3.7.
*
* </p>
* <p>
* Not all devices are tested.
* <ul>
* <li>Read and write of serial data (see {@link #read(byte[], int)} and
* {@link #write(byte[], int)}.
* <li>Setting baud rate (see {@link #setBaudRate(int)}).
* </ul>
* </p>
* *
* @author Jongmoo Sohn ([email protected])
* @see <a href="http://code.google.com/p/usb-serial-for-android/">USB Serial
* for Android project page</a>
*/
public class Cp210xSerialDriver extends CommonUsbSerialDriver {
private final String TAG = Cp210xSerialDriver.class.getSimpleName();
/* Config request types */
private static final int REQTYPE_HOST_TO_INTERFACE = 0x41;
private static final int REQTYPE_INTERFACE_TO_HOST = 0xc1;
private static final int REQTYPE_HOST_TO_DEVICE = 0x40;
private static final int REQTYPE_DEVICE_TO_HOST = 0xc0;
/* Config request codes */
private static final int CP210X_IFC_ENABLE = 0x00;
private static final int CP210X_SET_BAUDDIV = 0x01;
private static final int CP210X_GET_BAUDDIV = 0x02;
private static final int CP210X_SET_LINE_CTL = 0x03;
private static final int CP210X_GET_LINE_CTL = 0x04;
private static final int CP210X_SET_BREAK = 0x05;
private static final int CP210X_IMM_CHAR = 0x06;
private static final int CP210X_SET_MHS = 0x07;
private static final int CP210X_GET_MDMSTS = 0x08;
private static final int CP210X_SET_XON = 0x09;
private static final int CP210X_SET_XOFF = 0x0A;
private static final int CP210X_SET_EVENTMASK = 0x0B;
private static final int CP210X_GET_EVENTMASK = 0x0C;
private static final int CP210X_SET_CHAR = 0x0D;
private static final int CP210X_GET_CHARS = 0x0E;
private static final int CP210X_GET_PROPS = 0x0F;
private static final int CP210X_GET_COMM_STATUS = 0x10;
private static final int CP210X_RESET = 0x11;
private static final int CP210X_PURGE = 0x12;
private static final int CP210X_SET_FLOW = 0x13;
private static final int CP210X_GET_FLOW = 0x14;
private static final int CP210X_EMBED_EVENTS = 0x15;
private static final int CP210X_GET_EVENTSTATE = 0x16;
private static final int CP210X_SET_CHARS = 0x19;
private static final int CP210X_GET_BAUDRATE = 0x1D;
private static final int CP210X_SET_BAUDRATE = 0x1E;
/* CP210X_IFC_ENABLE */
private static final int UART_ENABLE = 0x0001;
private static final int UART_DISABLE = 0x0000;
/* CP210X_(SET|GET)_BAUDDIV */
private static final int BAUD_RATE_GEN_FREQ = 0x384000;
/* CP210X_(SET|GET)_LINE_CTL */
private static final int BITS_DATA_MASK = 0X0f00;
private static final int BITS_DATA_5 = 0X0500;
private static final int BITS_DATA_6 = 0X0600;
private static final int BITS_DATA_7 = 0X0700;
private static final int BITS_DATA_8 = 0X0800;
private static final int BITS_DATA_9 = 0X0900;
private static final int BITS_PARITY_MASK = 0x00f0;
private static final int BITS_PARITY_NONE = 0x0000;
private static final int BITS_PARITY_ODD = 0x0010;
private static final int BITS_PARITY_EVEN = 0x0020;
private static final int BITS_PARITY_MARK = 0x0030;
private static final int BITS_PARITY_SPACE = 0x0040;
private static final int BITS_STOP_MASK = 0x000f;
private static final int BITS_STOP_1 = 0x0000;
private static final int BITS_STOP_1_5 = 0x0001;
private static final int BITS_STOP_2 = 0x0002;
/* CP210X_SET_BREAK */
private static final int BREAK_ON = 0x0001;
private static final int BREAK_OFF = 0x0000;
/* CP210X_(SET_MHS|GET_MDMSTS) */
private static final int CONTROL_DTR = 0x0001;
private static final int CONTROL_RTS = 0x0002;
private static final int CONTROL_CTS = 0x0010;
private static final int CONTROL_DSR = 0x0020;
private static final int CONTROL_RING = 0x0040;
private static final int CONTROL_DCD = 0x0080;
private static final int CONTROL_WRITE_DTR = 0x0100;
private static final int CONTROL_WRITE_RTS = 0x0200;
private int mBulkInSize = 256;
private int mBaudRate = 0;
private int mDataBits = 0;
private int mParity = 0;
private int mStopBits = 0;
private static final int DEFAULT_BAUD_RATE = 115200;
private static final int DEFAULT_DATA_BITS = DATABITS_8;
private static final int DEFAULT_PARITY = PARITY_NONE;
private static final int DEFAULT_STOP_BITS = STOPBITS_1;
/**
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
* since it gives no indication of number of bytes read. Set this to
* {@code true} on platforms where it is fixed.
* Safe to assume anything less than API level 17 is broken.
*/
private static final boolean ENABLE_ASYNC_READS = true;
private UsbEndpoint mEndpointOut = null;
private UsbEndpoint mEndpointIn = null;
public static final int USB_CTRL_GET_TIMEOUT_MILLIS = 5000;
public static final int USB_CTRL_SET_TIMEOUT_MILLIS = 5000;
private boolean mRts = false;
private boolean mDtr = false;
/**
* Constructor.
*
* @param usbDevice the {@link UsbDevice} to use
* @param usbConnection the {@link UsbDeviceConnection} to use
* @throws UsbSerialRuntimeException if the given device is incompatible
* with this driver
*/
public Cp210xSerialDriver(UsbDevice usbDevice, UsbDeviceConnection usbConnection) {
super(usbDevice, usbConnection);
UsbInterface intf = findInterface(usbDevice);
if (setInterface(usbDevice, intf)) {
UsbEndpoint epOut = null;
UsbEndpoint epIn = null;
// Look for bulk endpoints
for (int i = 0; i < intf.getEndpointCount(); i++) {
UsbEndpoint ep = intf.getEndpoint(i);
if (UsbConstants.USB_ENDPOINT_XFER_BULK == ep.getType()) {
if (UsbConstants.USB_DIR_OUT == ep.getDirection()) {
epOut = ep;
Log.d(TAG, "endpointOut: " + i);
} else {
epIn = ep;
Log.d(TAG, "endpointIn: " + i);
}
}
}
if (epOut == null || epIn == null) {
throw new IllegalArgumentException("Not all endpoints found");
}
mEndpointOut = epOut;
mEndpointIn = epIn;
}
}
private UsbInterface findInterface(UsbDevice device) {
Log.d(TAG, "findInterface " + device);
int count = device.getInterfaceCount();
for (int i =0 ; i < count ; i++) {
UsbInterface intf = device.getInterface(i);
Log.d(TAG, "Interface: " + count + " Class: " + intf.getInterfaceClass() +
" Subclass: " + intf.getInterfaceSubclass() +
" Protocol: " + intf.getInterfaceProtocol());
if (intf.getInterfaceClass() == 255
&& intf.getInterfaceSubclass() == 00
&& intf.getInterfaceProtocol() == 0) {
return intf;
}
}
return null;
}
private boolean setInterface(UsbDevice device, UsbInterface intf) {
if (mConnection != null) {
Log.d(TAG, "Open succeeded.");
if (mConnection.claimInterface(intf, false)) {
Log.d(TAG, "Claim interface succeeded.");
return true;
} else {
Log.d(TAG, "Claim interface failed.");
}
} else {
Log.d(TAG, "No connection to set interface.");
}
return false;
}
private int cp210x_set_config(int request, int value, byte[] buffer, int length) throws IOException {
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_INTERFACE, request,
value, 0x0 /* index */, buffer, length, USB_CTRL_SET_TIMEOUT_MILLIS);
if (result != length) {
throw new IOException("cp210x_set_config failed: result=" + result);
}
return result;
}
private int cp210x_set_config_single(int request, int value) throws IOException {
return cp210x_set_config(request, value, null, 0x0);
}
// From Sniffed Data
private static final byte[] CP210X_SET_CHARS_DATA = {
(byte)0x04, (byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x00 };
// From Sniffed Data
private static final byte[] CP210X_SET_FLOW_DATA = {
(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
@Override
public void open() throws IOException {
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
if (mConnection.claimInterface(mDevice.getInterface(i), true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
Log.d(TAG, "claimInterface " + i + " FAIL");
}
}
// Configure Single Port
// cp210x_set_config_single(CP210X_IFC_ENABLE, UART_ENABLE);
// From Sniffed Data
cp210x_set_config_single(CP210X_IFC_ENABLE, 0xFFFF); // UART_ENABLE = 0x0001? 0xFFFF?
cp210x_set_config(CP210X_SET_CHARS, 0x0000, CP210X_SET_CHARS_DATA, CP210X_SET_CHARS_DATA.length);
cp210x_set_config(CP210X_SET_FLOW, 0x0000, CP210X_SET_FLOW_DATA, CP210X_SET_FLOW_DATA.length);
// Configure the termios structure
// cp210x_get_termios() NOT IMPLEMENTED !
// Instead, following default values are set.
if (0 == mBaudRate) mBaudRate = DEFAULT_BAUD_RATE;
if (0 == mDataBits) mDataBits = DEFAULT_DATA_BITS;
if (0 == mParity) mParity = DEFAULT_PARITY;
if (0 == mStopBits) mStopBits = DEFAULT_STOP_BITS;
// The baud rate must be initialised on cp2104
// cp210x_change_speed(mBaudRate);
setParameters(mBaudRate, mDataBits, mStopBits, mParity);
// From Sniffed Data
cp210x_set_config_single(CP210X_SET_MHS, CONTROL_WRITE_RTS); // 0x0200
cp210x_set_config_single(CP210X_SET_MHS, CONTROL_WRITE_DTR + CONTROL_DTR); // 0x0101
cp210x_set_config_single(CP210X_SET_BREAK, BREAK_OFF);
opened = true;
} finally {
if (!opened) {
close();
}
}
}
@Override
public void close() {
try {
// From Sniffed Data
cp210x_set_config_single(CP210X_SET_BREAK, BREAK_OFF);
cp210x_set_config_single(CP210X_IFC_ENABLE, UART_DISABLE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mConnection.close();
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
if (ENABLE_ASYNC_READS) {
final int readAmt;
synchronized (mReadBufferLock) {
// mReadBuffer is only used for maximum read size.
readAmt = Math.min(dest.length, mReadBuffer.length);
}
final UsbRequest request = new UsbRequest();
request.initialize(mConnection, mEndpointIn);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, readAmt)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = mConnection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int BytesRead = buf.position();
if (BytesRead > 0) {
// Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return BytesRead;
} else {
return 0;
}
} else {
final int totalBytesRead;
synchronized (mReadBufferLock) {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
totalBytesRead = mConnection.bulkTransfer(mEndpointIn, mReadBuffer,
readAmt, timeoutMillis);
}
if (totalBytesRead > 0) {
System.arraycopy(mReadBuffer, 0, dest, 0, totalBytesRead);
}
return totalBytesRead;
}
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mEndpointOut, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
@Override
@Deprecated
public int setBaudRate(int baudRate) throws IOException {
mBaudRate = cp210x_quantise_baudrate(baudRate);
cp210x_change_speed(mBaudRate);
return mBaudRate;
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity)
throws IOException {
mBaudRate = cp210x_quantise_baudrate(baudRate);
cp210x_change_speed(mBaudRate);
int config = 0x0000;
switch (dataBits) {
case DATABITS_5:
config |= BITS_DATA_5;
break;
case DATABITS_6:
config |= BITS_DATA_6;
break;
case DATABITS_7:
config |= BITS_DATA_7;
break;
case DATABITS_8:
config |= BITS_DATA_8;
break;
default:
throw new IllegalArgumentException("Unknown dataBits value: " + dataBits);
}
switch (parity) {
case PARITY_NONE:
config |= BITS_PARITY_NONE;
break;
case PARITY_ODD:
config |= BITS_PARITY_ODD;
break;
case PARITY_EVEN:
config |= BITS_PARITY_EVEN;
break;
case PARITY_MARK:
config |= BITS_PARITY_MARK;
break;
case PARITY_SPACE:
config |= BITS_PARITY_SPACE;
break;
default:
throw new IllegalArgumentException("Unknown parity value: " + parity);
}
switch (stopBits) {
case STOPBITS_1:
config |= BITS_STOP_1;
break;
case STOPBITS_1_5:
config |= BITS_STOP_1_5;
break;
case STOPBITS_2:
config |= BITS_STOP_2;
break;
default:
throw new IllegalArgumentException("Unknown stopBits value: " + stopBits);
}
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_INTERFACE,
CP210X_SET_LINE_CTL, config, 0 /* index */,
null, 0, USB_CTRL_SET_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Setting parameters failed: result=" + result);
}
mParity = parity;
mStopBits = stopBits;
mDataBits = dataBits;
verifyConfig(baudRate, config);
}
//convert byte array to integer type value
//possible returned value: byte/short/int/long
//Note: max support long -> input byte array length should not exceed 8
public static long byteArrToInteger(byte[] byteArr){
long convertedInterger = 0;
//follow works:
//int readbackBaudrate= (baudrateByteArr[3]<<24)&0xff000000|(baudrateByteArr[2]<<16)&0xff0000|(baudrateByteArr[1]<<8)&0xff00|(baudrateByteArr[0]<<0)&0xff;
//115200 == [0, -62, 1, 0]
//1200==[-80, 4, 0, 0]
for(int i = 0; i < byteArr.length; i++){
//long curValue = byteArr[i];
//int curValue = byteArr[i];
byte curValue = byteArr[i];
long shiftedValue = curValue << (i * 8);
long mask = 0xFF << (i * 8);
long maskedShiftedValue = shiftedValue & mask;
//0x0, 0xC200, 0x10000, 0x0 -> 115200==0x1C200
//0xB0, 0x400, 0x0, 0x0-> 1200==0x4B0
convertedInterger |= maskedShiftedValue;
}
return convertedInterger;
}
//convert interger type value to byte array
//possible input value: byte/short/int/long
//Note: max return byte array is 8 -> max support long
public static byte[] integerToByteArr(long inputIntergerValue, int byteLen){
byte[] convertedByteArr = new byte[byteLen];
for (int i = 0; i < convertedByteArr.length; i++) {
convertedByteArr[i] = (byte) ((inputIntergerValue >> (8 * i)) & 0xFF);
//115200 == [0, -62, 1, 0, 0, 0, 0, 0]
//1200==[-80, 4, 0, 0]
//600==[88, 2]
//32==[32]
}
return convertedByteArr;
}
private void verifyConfig(int writtenBaudrate, int writtenLineControl){
//1. verify baudrate
byte[] baudrateByteArr = new byte[]{0,0,0,0};
mConnection.controlTransfer(REQTYPE_INTERFACE_TO_HOST, CP210X_GET_BAUDRATE,
0, 0/* index */, baudrateByteArr, 4, USB_CTRL_GET_TIMEOUT_MILLIS);
//int readbackBaudrate = (baudrateByteArr[0]) | (baudrateByteArr[1] << 8) | (baudrateByteArr[2] << 16) | (baudrateByteArr[3] << 24);
//int readbackBaudrate= (baudrateByteArr[3]<<24)&0xff000000|(baudrateByteArr[2]<<16)&0xff0000|(baudrateByteArr[1]<<8)&0xff00|(baudrateByteArr[0]<<0)&0xff;
int readbackBaudrate = (int)byteArrToInteger(baudrateByteArr);
if(writtenBaudrate == readbackBaudrate){
//ok
}
else{
//false
}
//2.verify other config
byte[] lineControlByteArr = new byte[]{0,0};
mConnection.controlTransfer(REQTYPE_INTERFACE_TO_HOST, CP210X_GET_LINE_CTL,
0, 0/* index */, lineControlByteArr, 2, USB_CTRL_GET_TIMEOUT_MILLIS);
//int readbackLineControl = (lineControlByteArr[0]) | (lineControlByteArr[1] << 8);
int readbackLineControl = (int)byteArrToInteger(lineControlByteArr);
if(writtenLineControl == readbackLineControl){
//ok
}
else{
//false
}
}
@Override
public boolean getCD() throws IOException {
return false;
}
@Override
public boolean getCTS() throws IOException {
return false;
}
@Override
public boolean getDSR() throws IOException {
return false;
}
@Override
public boolean getDTR() throws IOException {
return mDtr;
//return true;
}
@Override
public void setDTR(boolean value) throws IOException {
mDtr = value;
short control = 0;
if (mDtr) {
control |= CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
else{
control &= ~CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
try {
cp210x_set_config_single(CP210X_SET_MHS, control);
verifyRtsDtr(control);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public boolean getRI() throws IOException {
return false;
}
@Override
public boolean getRTS() throws IOException {
return mRts;
//return true;
}
@Override
public void setRTS(boolean value) throws IOException {
mRts = value;
short control = 0;
if (mRts) {
control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
else {
control &= ~CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
try {
cp210x_set_config_single(CP210X_SET_MHS, control);
verifyRtsDtr(control);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
// set/clear RTS/CTS and DTR/DSR
private void setDtrRts() {
short control = 0;
if (mRts) {
control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
else {
control &= ~CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
if (mDtr) {
control |= CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
else{
control &= ~CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
try {
cp210x_set_config_single(CP210X_SET_MHS, control);
verifyRtsDtr(control);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
*/
private void verifyRtsDtr(int writtenMhsControl){
//1. verify RTS DTR
int writtenControlValue = writtenMhsControl & 0xFF; // only lowest 8 bit used for indicate RTS, DTR, ...
// byte[] mhsControlByteArr = new byte[]{0};
byte[] mhsControlByteArr = new byte[]{0}; // so here only need to read 1 byte
mConnection.controlTransfer(REQTYPE_INTERFACE_TO_HOST, CP210X_GET_MDMSTS,
0, 0/* index */, mhsControlByteArr, mhsControlByteArr.length, USB_CTRL_GET_TIMEOUT_MILLIS);
int readbackMhsControl = (int)byteArrToInteger(mhsControlByteArr);
//seem here can not verify written ok or not
//for those bit not reflect whether happen RTS or DTR
if(writtenControlValue == readbackMhsControl){
//ok
//written 769==0x301 -> read back: 0x01 => OK
//higher bits auto become 0 after written
}
else{
//false
}
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILAB),
new int[] {
UsbId.SILAB_CP210X_DEFAULT_0,
UsbId.SILAB_CP210X_DEFAULT_1,
UsbId.SILAB_CP210X_DEFAULT_2,
UsbId.SILAB_CP210X_DEFAULT_3
});
return supportedDevices;
}
/*
* cp210x_quantise_baudrate
* Quantises the baud rate as per AN205 Table 1
*/
private int cp210x_quantise_baudrate(int baud) {
if (baud <= 300)
baud = 300;
else if (baud <= 600) baud = 600;
else if (baud <= 1200) baud = 1200;
else if (baud <= 1800) baud = 1800;
else if (baud <= 2400) baud = 2400;
else if (baud <= 4000) baud = 4000;
else if (baud <= 4803) baud = 4800;
else if (baud <= 7207) baud = 7200;
else if (baud <= 9612) baud = 9600;
else if (baud <= 14428) baud = 14400;
else if (baud <= 16062) baud = 16000;
else if (baud <= 19250) baud = 19200;
else if (baud <= 28912) baud = 28800;
else if (baud <= 38601) baud = 38400;
else if (baud <= 51558) baud = 51200;
else if (baud <= 56280) baud = 56000;
else if (baud <= 58053) baud = 57600;
else if (baud <= 64111) baud = 64000;
else if (baud <= 77608) baud = 76800;
else if (baud <= 117028) baud = 115200;
else if (baud <= 129347) baud = 128000;
else if (baud <= 156868) baud = 153600;
else if (baud <= 237832) baud = 230400;
else if (baud <= 254234) baud = 250000;
else if (baud <= 273066) baud = 256000;
else if (baud <= 491520) baud = 460800;
else if (baud <= 567138) baud = 500000;
else if (baud <= 670254) baud = 576000;
else if (baud < 1000000)
baud = 921600;
else if (baud > 2000000)
baud = 2000000;
return baud;
}
/*
* CP2101 supports the following baud rates:
*
* 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
* 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
*
* CP2102 and CP2103 support the following additional rates:
*
* 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
* 576000
*
* The device will map a requested rate to a supported one, but the result
* of requests for rates greater than 1053257 is undefined (see AN205).
*
* CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
* respectively, with an error less than 1%. The actual rates are determined
* by
*
* div = round(freq / (2 x prescale x request))
* actual = freq / (2 x prescale x div)
*
* For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
* or 1 otherwise.
* For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
* otherwise.
*/
private void cp210x_change_speed(int baudrate) throws IOException {
// byte[] rawData = new byte[4];
//
// for (int i = 0; i < rawData.length; i++) {
// rawData[i] = (byte) ((baudrate >> (8 * i)) & 0xFF);
// }
//
// cp210x_set_config(CP210X_SET_BAUDRATE, 0x0000, rawData, rawData.length);
byte[] baudrateByteArr = integerToByteArr(baudrate, 4);
cp210x_set_config(CP210X_SET_BAUDRATE, 0x0000, baudrateByteArr, baudrateByteArr.length);
}
}调试结果是:
verifyConfig和verifyRtsDtr
都验证通过了。
但是结果最后HART猫还是无法从HART设备上读取信息,
发送对应的command 0,还是没有对应的返回信息。
14.试试去改为:
//private static final boolean ENABLE_ASYNC_READS = true;
private static final boolean ENABLE_ASYNC_READS = false;看看效果,结果还是不行。
暂时就这样了。
等以后再说吧。
【总结】
目前结果是:
根据已有资料,基本确定了:
配置baudrate和其他config,以及设置RTS,DTR等动作,都是成功配置的。
但是目前还是不知道:
为何USB HART猫,此处最终没有成功的和HART设备通信。
可能的原因:
1.android的app中的代码有问题。
2.本身此处的USB HART猫,就是不能很好的支持此处通过代码配置RTS,DTR的形式去和物理上的HART设备通信,而无法获得对应的command 0的返回值的。
3.其他未知原因。
【后记】
1.后来看到:
提到了:
CP2102的write有问题。
所以,此处我这里HART不工作,估计就是和此write不工作有关,导致我的command 0的数据,实际没有真正写下去,没写到HART设备中。
注:
不过,对于ExSaf的ESH232U的TXD的指示灯,当我发送write时,是正常可以闪的,说明是:
代码的write真正执行到了,且也通过HART猫去发送数据了,但是实际上由于上面说的write底层有问题,导致无法反正正确的数据。
另外:
另外一个,正常工作的HART猫,是可以的。
其物理连接是:USB转串口:FTDI的FT232R + RS232接口的HART猫:Exsaf ESH232R
2.所以,目前基本确定:
应该是由于
UsbSerialDriver.write() or SerialInputOutputManager.writeAsync()
不工作,导致此处HART猫不工作的。
所以:
此处,没有足够的设备和方法去调试,暂时无法通过个人解决此问题。
希望作者有空帮忙解决。
【后记 2013-11-28】
1.忘了记录于此了:
之前调试android的apk期间,记录的,该usb hart猫的vid和pid,记录与此:
UsbDevice[mName=/dev/bus/usb/001/018,mVendorId=4292,mProductId=60000,mClass=0,mSubclass=0,mProtocol=0,mInterfaces=[Landroid.os.Parcelable;@414efa70] 4292=0x10c4 60000=0xEA60 |
供以后需要时参考。
转载请注明:在路上 » 【记录】给usb-serial-for-android中的Silicon Labs的CP2102中添加RTS和DTR的支持