diff --git a/src/com/felhr/usbserial/CH34xSerialDevice.java b/src/com/felhr/usbserial/CH34xSerialDevice.java new file mode 100644 index 0000000..e20590a --- /dev/null +++ b/src/com/felhr/usbserial/CH34xSerialDevice.java @@ -0,0 +1,345 @@ +/* + * 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 + * + * I do not own one of these, so I can assure this works + */ + +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; + +/* + * TODO: CLOSE, IDS, UsbSerial factory method update (felhr) + */ +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); + // TODO Auto-generated constructor stub + } + + public CH34xSerialDevice(UsbDevice device, UsbDeviceConnection connection, int iface) + { + super(device, connection); + mInterface = device.getInterface(iface >= 0 ? iface : 0); + } + + @Override + public boolean open() + { + // Restart the working thread and writeThread if it has been killed before and claim interface + restartWorkingThread(); + restartWriteThread(); + + 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 + { + outEndpoint = endpoint; + } + } + + // Default Setup + if(init() == 0) + { + setBaudRate(DEFAULT_BAUDRATE); + // Initialize UsbRequest + requestIN = new UsbRequest(); + requestIN.initialize(connection, inEndpoint); + + // Pass references to the threads + setThreadsParams(requestIN, outEndpoint); + + return true; + }else + { + return false; + } + } + + @Override + public void close() + { + // TODO felhr CLOSE + + } + + @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) == -1) + return -1; + + setBaudRate(DEFAULT_BAUDRATE); + + if(checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00}) == -1) + return -1; + + setControlCommandOut(0x9a, 0x2518, 0x0050, null); + + + if(checkState("init #6", 0x95, 0x0706, new int[]{0xff, 0xee}) == -1) + return -1; + + setControlCommandOut(0xa1, 0x501f, 0xd90a, null); + + 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; + } + +}