UsbSerial/usbserial/src/main/java/com/felhr/usbserial/CDCSerialDevice.java

396 wiersze
10 KiB
Java

package com.felhr.usbserial;
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 com.felhr.utils.SafeUsbRequest;
public class CDCSerialDevice extends UsbSerialDevice
{
private static final String CLASS_ID = CDCSerialDevice.class.getSimpleName();
private static final int CDC_REQTYPE_HOST2DEVICE = 0x21;
private static final int CDC_REQTYPE_DEVICE2HOST = 0xA1;
private static final int CDC_SET_LINE_CODING = 0x20;
private static final int CDC_GET_LINE_CODING = 0x21;
private static final int CDC_SET_CONTROL_LINE_STATE = 0x22;
private static final int CDC_SET_CONTROL_LINE_STATE_RTS = 0x2;
private static final int CDC_SET_CONTROL_LINE_STATE_DTR = 0x1;
/***
* Default Serial Configuration
* Baud rate: 115200
* Data bits: 8
* Stop bits: 1
* Parity: None
* Flow Control: Off
*/
private static final byte[] CDC_DEFAULT_LINE_CODING = new byte[] {
(byte) 0x00, // Offset 0:4 dwDTERate
(byte) 0xC2,
(byte) 0x01,
(byte) 0x00,
(byte) 0x00, // Offset 5 bCharFormat (1 Stop bit)
(byte) 0x00, // bParityType (None)
(byte) 0x08 // bDataBits (8)
};
private static final int CDC_CONTROL_LINE_ON = 0x0003;
private static final int CDC_CONTROL_LINE_OFF = 0x0000;
private UsbInterface mInterface;
private UsbEndpoint inEndpoint;
private UsbEndpoint outEndpoint;
private UsbRequest requestIN;
private int initialBaudRate = 0;
private int controlLineState = CDC_CONTROL_LINE_ON;
public CDCSerialDevice(UsbDevice device, UsbDeviceConnection connection)
{
this(device, connection, -1);
}
public CDCSerialDevice(UsbDevice device, UsbDeviceConnection connection, int iface)
{
super(device, connection);
mInterface = device.getInterface(iface >= 0 ? iface : findFirstCDC(device));
}
@Override
public void setInitialBaudRate(int initialBaudRate) {
this.initialBaudRate = initialBaudRate;
}
@Override
public int getInitialBaudRate() {
return initialBaudRate;
}
@Override
public boolean open()
{
boolean ret = openCDC();
if(ret)
{
// Initialize UsbRequest
requestIN = new SafeUsbRequest();
requestIN.initialize(connection, inEndpoint);
// Restart the working thread if it has been killed before and get and claim interface
restartWorkingThread();
restartWriteThread();
// Pass references to the threads
setThreadsParams(requestIN, outEndpoint);
asyncMode = true;
isOpen = true;
return true;
}else
{
isOpen = false;
return false;
}
}
@Override
public void close()
{
setControlCommand(CDC_SET_CONTROL_LINE_STATE, CDC_CONTROL_LINE_OFF, null);
killWorkingThread();
killWriteThread();
connection.releaseInterface(mInterface);
connection.close();
isOpen = false;
}
@Override
public boolean syncOpen()
{
boolean ret = openCDC();
if(ret)
{
setSyncParams(inEndpoint, outEndpoint);
asyncMode = false;
isOpen = true;
// Init Streams
inputStream = new SerialInputStream(this);
outputStream = new SerialOutputStream(this);
return true;
}else
{
isOpen = false;
return false;
}
}
@Override
public void syncClose()
{
setControlCommand(CDC_SET_CONTROL_LINE_STATE, CDC_CONTROL_LINE_OFF, null);
connection.releaseInterface(mInterface);
connection.close();
isOpen = false;
}
@Override
public void setBaudRate(int baudRate)
{
byte[] data = getLineCoding();
data[0] = (byte) (baudRate & 0xff);
data[1] = (byte) (baudRate >> 8 & 0xff);
data[2] = (byte) (baudRate >> 16 & 0xff);
data[3] = (byte) (baudRate >> 24 & 0xff);
setControlCommand(CDC_SET_LINE_CODING, 0, data);
}
@Override
public void setDataBits(int dataBits)
{
byte[] data = getLineCoding();
switch(dataBits)
{
case UsbSerialInterface.DATA_BITS_5:
data[6] = 0x05;
break;
case UsbSerialInterface.DATA_BITS_6:
data[6] = 0x06;
break;
case UsbSerialInterface.DATA_BITS_7:
data[6] = 0x07;
break;
case UsbSerialInterface.DATA_BITS_8:
data[6] = 0x08;
break;
default:
return;
}
setControlCommand(CDC_SET_LINE_CODING, 0, data);
}
@Override
public void setStopBits(int stopBits)
{
byte[] data = getLineCoding();
switch(stopBits)
{
case UsbSerialInterface.STOP_BITS_1:
data[4] = 0x00;
break;
case UsbSerialInterface.STOP_BITS_15:
data[4] = 0x01;
break;
case UsbSerialInterface.STOP_BITS_2:
data[4] = 0x02;
break;
default:
return;
}
setControlCommand(CDC_SET_LINE_CODING, 0, data);
}
@Override
public void setParity(int parity)
{
byte[] data = getLineCoding();
switch(parity)
{
case UsbSerialInterface.PARITY_NONE:
data[5] = 0x00;
break;
case UsbSerialInterface.PARITY_ODD:
data[5] = 0x01;
break;
case UsbSerialInterface.PARITY_EVEN:
data[5] = 0x02;
break;
case UsbSerialInterface.PARITY_MARK:
data[5] = 0x03;
break;
case UsbSerialInterface.PARITY_SPACE:
data[5] = 0x04;
break;
default:
return;
}
setControlCommand(CDC_SET_LINE_CODING, 0, data);
}
@Override
public void setFlowControl(int flowControl)
{
// TODO Auto-generated method stub
}
@Override
public void setRTS(boolean state)
{
if (state)
controlLineState |= CDC_SET_CONTROL_LINE_STATE_RTS;
else
controlLineState &= ~CDC_SET_CONTROL_LINE_STATE_RTS;
setControlCommand(CDC_SET_CONTROL_LINE_STATE, controlLineState, null);
}
@Override
public void setDTR(boolean state)
{
if (state)
controlLineState |= CDC_SET_CONTROL_LINE_STATE_DTR;
else
controlLineState &= ~CDC_SET_CONTROL_LINE_STATE_DTR;
setControlCommand(CDC_SET_CONTROL_LINE_STATE, controlLineState, null);
}
@Override
public void getCTS(UsbCTSCallback ctsCallback)
{
//TODO
}
@Override
public void getDSR(UsbDSRCallback dsrCallback)
{
//TODO
}
@Override
public void getBreak(UsbBreakCallback breakCallback)
{
//TODO
}
@Override
public void getFrame(UsbFrameCallback frameCallback)
{
//TODO
}
@Override
public void getOverrun(UsbOverrunCallback overrunCallback)
{
//TODO
}
@Override
public void getParity(UsbParityCallback parityCallback)
{
//TODO
}
private boolean openCDC()
{
if(connection.claimInterface(mInterface, true))
{
Log.i(CLASS_ID, "Interface succesfully claimed");
}else
{
Log.i(CLASS_ID, "Interface could not be claimed");
return false;
}
// Assign endpoints
int numberEndpoints = mInterface.getEndpointCount();
for(int i=0;i<=numberEndpoints-1;i++)
{
UsbEndpoint endpoint = mInterface.getEndpoint(i);
if(endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK
&& endpoint.getDirection() == UsbConstants.USB_DIR_IN)
{
inEndpoint = endpoint;
}else if(endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK
&& endpoint.getDirection() == UsbConstants.USB_DIR_OUT)
{
outEndpoint = endpoint;
}
}
if(outEndpoint == null || inEndpoint == null)
{
Log.i(CLASS_ID, "Interface does not have an IN or OUT interface");
return false;
}
return true;
}
protected byte[] getInitialLineCoding() {
byte[] lineCoding;
int initialBaudRate = getInitialBaudRate();
if(initialBaudRate > 0) {
lineCoding = CDC_DEFAULT_LINE_CODING.clone();
for (int i = 0; i < 4; i++) {
lineCoding[i] = (byte) (initialBaudRate >> i*8 & 0xFF);
}
} else {
lineCoding = CDC_DEFAULT_LINE_CODING;
}
return lineCoding;
}
private int setControlCommand(int request, int value, byte[] data)
{
int dataLength = 0;
if(data != null)
{
dataLength = data.length;
}
int response = connection.controlTransfer(CDC_REQTYPE_HOST2DEVICE, request, value, 0, data, dataLength, USB_TIMEOUT);
Log.i(CLASS_ID,"Control Transfer Response: " + String.valueOf(response));
return response;
}
private byte[] getLineCoding()
{
byte[] data = new byte[7];
int response = connection.controlTransfer(CDC_REQTYPE_DEVICE2HOST, CDC_GET_LINE_CODING, 0, 0, data, data.length, USB_TIMEOUT);
Log.i(CLASS_ID,"Control Transfer Response: " + String.valueOf(response));
return data;
}
private static int findFirstCDC(UsbDevice device)
{
int interfaceCount = device.getInterfaceCount();
for (int iIndex = 0; iIndex < interfaceCount; ++iIndex)
{
if (device.getInterface(iIndex).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
{
return iIndex;
}
}
Log.i(CLASS_ID, "There is no CDC class interface");
return -1;
}
}