kopia lustrzana https://github.com/felHR85/UsbSerial
358 wiersze
9.3 KiB
Java
358 wiersze
9.3 KiB
Java
/*
|
|
* Heavily based on a pull-request made by Andreas Butti to https://github.com/mik3y/usb-serial-for-android
|
|
* https://github.com/mik3y/usb-serial-for-android/pull/92
|
|
*
|
|
* Update May 9 2015: First tests appear to be working. No error messages are received when config the chip
|
|
* Thanks to Paul Alcock for provide me with one of those Arduino nano clones!!!
|
|
* */
|
|
|
|
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;
|
|
|
|
public class CH34xSerialDevice extends UsbSerialDevice
|
|
{
|
|
private static final String CLASS_ID = CH34xSerialDevice.class.getSimpleName();
|
|
|
|
private static final int DEFAULT_BAUDRATE = 9600;
|
|
|
|
private static final int REQTYPE_HOST_FROM_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
|
private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
|
|
|
|
private static final int CH341_REQ_WRITE_REG = 0x9A;
|
|
private static final int CH341_REQ_READ_REG = 0x95;
|
|
private static final int CH341_REG_BREAK1 = 0x05;
|
|
private static final int CH341_REG_BREAK2 = 0x18;
|
|
private static final int CH341_NBREAK_BITS_REG1 = 0x01;
|
|
private static final int CH341_NBREAK_BITS_REG2 = 0x40;
|
|
|
|
private static final int CH34X_2400_1 = 0xd901;
|
|
private static final int CH34X_2400_2 = 0x0038;
|
|
private static final int CH34X_4800_1 = 0x6402;
|
|
private static final int CH34X_4800_2 = 0x001f;
|
|
private static final int CH34X_9600_1 = 0xb202;
|
|
private static final int CH34X_9600_2 = 0x0013;
|
|
private static final int CH34X_19200_1 = 0xd902;
|
|
private static final int CH34X_19200_2 = 0x000d;
|
|
private static final int CH34X_38400_1 = 0x6403;
|
|
private static final int CH34X_38400_2 = 0x000a;
|
|
private static final int CH34X_115200_1 = 0xcc03;
|
|
private static final int CH34X_115200_2 = 0x0008;
|
|
|
|
|
|
private UsbInterface mInterface;
|
|
private UsbEndpoint inEndpoint;
|
|
private UsbEndpoint outEndpoint;
|
|
private UsbRequest requestIN;
|
|
|
|
private boolean dtr = false;
|
|
private boolean rts = false;
|
|
|
|
|
|
public CH34xSerialDevice(UsbDevice device, UsbDeviceConnection connection)
|
|
{
|
|
super(device, connection);
|
|
}
|
|
|
|
public CH34xSerialDevice(UsbDevice device, UsbDeviceConnection connection, int iface)
|
|
{
|
|
super(device, connection);
|
|
mInterface = device.getInterface(iface >= 0 ? iface : 0);
|
|
}
|
|
|
|
@Override
|
|
public boolean open()
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Default Setup
|
|
if(init() == 0)
|
|
{
|
|
setBaudRate(DEFAULT_BAUDRATE);
|
|
// Initialize UsbRequest
|
|
requestIN = new UsbRequest();
|
|
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);
|
|
|
|
return true;
|
|
}else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void close()
|
|
{
|
|
killWorkingThread();
|
|
killWriteThread();
|
|
connection.releaseInterface(mInterface);
|
|
}
|
|
|
|
@Override
|
|
public void setBaudRate(int baudRate)
|
|
{
|
|
if(baudRate <= 2400)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_2400_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_2400_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
|
|
}else if(baudRate > 2400 && baudRate <= 4800)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_4800_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_4800_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
}else if(baudRate > 4800 && baudRate <= 9600)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_9600_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_9600_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
}else if(baudRate > 9600 && baudRate <= 19200)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_19200_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_19200_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
}else if(baudRate > 19200 && baudRate <= 38400)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_38400_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_38400_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
}else if(baudRate > 38400)
|
|
{
|
|
int ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x1312, CH34X_115200_1, null);
|
|
if(ret < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
}else
|
|
{
|
|
ret = setControlCommandOut(CH341_REQ_WRITE_REG, 0x0f2c, CH34X_115200_2, null);
|
|
if(ret < 0)
|
|
Log.i(CLASS_ID, "Error setting baudRate");
|
|
else
|
|
Log.i(CLASS_ID, "BaudRate set correctly");
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDataBits(int dataBits)
|
|
{
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void setStopBits(int stopBits)
|
|
{
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void setParity(int parity)
|
|
{
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void setFlowControl(int flowControl)
|
|
{
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
private int init()
|
|
{
|
|
if(checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00}) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if(setControlCommandOut(0xa1, 0, 0, null) < 0)
|
|
{
|
|
Log.i(CLASS_ID, "init failed! #2");
|
|
return -1;
|
|
}
|
|
|
|
setBaudRate(DEFAULT_BAUDRATE);
|
|
|
|
if(checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00}) == -1)
|
|
return -1;
|
|
|
|
if(setControlCommandOut(0x9a, 0x2518, 0x0050, null) < 0)
|
|
{
|
|
Log.i(CLASS_ID, "init failed! #5");
|
|
return -1;
|
|
}
|
|
|
|
|
|
if(checkState("init #6", 0x95, 0x0706, new int[]{0xff, 0xee}) == -1)
|
|
return -1;
|
|
|
|
if(setControlCommandOut(0xa1, 0x501f, 0xd90a, null) < 0)
|
|
{
|
|
Log.i(CLASS_ID, "init failed! #7");
|
|
return -1;
|
|
}
|
|
|
|
setBaudRate(DEFAULT_BAUDRATE);
|
|
|
|
if(writeHandshakeByte() == -1)
|
|
return -1;
|
|
|
|
if(checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, 0xee}) == -1)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private int checkState(String msg, int request, int value, int[] expected)
|
|
{
|
|
byte[] buffer = new byte[expected.length];
|
|
int ret = setControlCommandIn(request, value, 0, buffer);
|
|
|
|
if (ret != expected.length)
|
|
{
|
|
Log.i(CLASS_ID, ("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]"));
|
|
return -1;
|
|
}else
|
|
{
|
|
for (int i = 0; i < expected.length; i++)
|
|
{
|
|
if (expected[i] == -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int current = buffer[i] & 0xff;
|
|
if (expected[i] != current)
|
|
{
|
|
Log.i(CLASS_ID, "Expected 0x" + Integer.toHexString(expected[i]) + " bytes, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private int writeHandshakeByte()
|
|
{
|
|
if(setControlCommandOut(0xa4, ~((dtr ? 1 << 5 : 0) | (rts ? 1 << 6 : 0)), 0, null) < 0)
|
|
{
|
|
Log.i(CLASS_ID, "Faild to set handshake byte");
|
|
return -1;
|
|
}else if(setControlCommandOut(0xa4, ~((dtr ? 1 << 5 : 0) | (rts ? 1 << 6 : 0)), 0, null) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private int setControlCommandOut(int request, int value, int index, byte[] data)
|
|
{
|
|
int dataLength = 0;
|
|
if(data != null)
|
|
{
|
|
dataLength = data.length;
|
|
}
|
|
int response = connection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value, index, data, dataLength, USB_TIMEOUT);
|
|
Log.i(CLASS_ID,"Control Transfer Response: " + String.valueOf(response));
|
|
return response;
|
|
}
|
|
|
|
private int setControlCommandIn(int request, int value, int index, byte[] data)
|
|
{
|
|
int dataLength = 0;
|
|
if(data != null)
|
|
{
|
|
dataLength = data.length;
|
|
}
|
|
int response = connection.controlTransfer(REQTYPE_HOST_FROM_DEVICE, request, value, index, data, dataLength, USB_TIMEOUT);
|
|
Log.i(CLASS_ID,"Control Transfer Response: " + String.valueOf(response));
|
|
return response;
|
|
}
|
|
|
|
}
|