Update the usb serial stack and fix several serial issues.
This commit is contained in:
parent
cfbb0c16bc
commit
e7a7503151
27 changed files with 3026 additions and 2746 deletions
12
ReadMe.txt
12
ReadMe.txt
|
@ -58,9 +58,15 @@ CHANGES
|
||||||
Version 2.3 (2021-02-xx)
|
Version 2.3 (2021-02-xx)
|
||||||
|
|
||||||
- Add the serial port support (via USB OTG).
|
- Add the serial port support (via USB OTG).
|
||||||
TODO: When stop the app, Serial exception seems to delay the save of the calc state!!!!
|
FIX: When stop the app, Serial exception seems to delay the save of the calc state!!!!
|
||||||
TODO: Inform if the connection is not possible.
|
FIX: Inform if the connection is not possible.
|
||||||
TODO: What's happen if I hot unplug?
|
BUG: From Windows to Android with HP49G QINHENG CH340 -> all character at once bug
|
||||||
|
No issue with Prolific PL2303GT3
|
||||||
|
Not reproducible!
|
||||||
|
FIX: No 'No driver' on real device
|
||||||
|
BUG: When openIO on real device, 1st OPENIO failed, 2nd OPENIO succeeded
|
||||||
|
BUG: ID change -> replace id by vendor:device ids?
|
||||||
|
TEST: With real HP48SX
|
||||||
TODO: Check the self test about UART (http://regis.cosnier.free.fr/private/private.php?journal=HP48&index=-4637&nomenu)
|
TODO: Check the self test about UART (http://regis.cosnier.free.fr/private/private.php?journal=HP48&index=-4637&nomenu)
|
||||||
- Allows pressing a calculator button with the right button of the mouse and prevents its release to allow the On+A+F key combination (with Android version >= 5.0).
|
- Allows pressing a calculator button with the right button of the mouse and prevents its release to allow the On+A+F key combination (with Android version >= 5.0).
|
||||||
- Update the embedded help file "Emu48.html" to the latest version.
|
- Update the embedded help file "Emu48.html" to the latest version.
|
||||||
|
|
|
@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 3.4.1)
|
||||||
#add_compile_options(-DDEBUG_ANDROID_PAINT)
|
#add_compile_options(-DDEBUG_ANDROID_PAINT)
|
||||||
#add_compile_options(-DDEBUG_ANDROID_THREAD)
|
#add_compile_options(-DDEBUG_ANDROID_THREAD)
|
||||||
#add_compile_options(-DDEBUG_ANDROID_FILE)
|
#add_compile_options(-DDEBUG_ANDROID_FILE)
|
||||||
#add_compile_options(-DDEBUG_ANDROID_SERIAL)
|
add_compile_options(-DDEBUG_ANDROID_SERIAL)
|
||||||
|
|
||||||
#add_compile_options(-DNEW_WIN32_SOUND_ENGINE)
|
#add_compile_options(-DNEW_WIN32_SOUND_ENGINE)
|
||||||
|
|
||||||
|
|
|
@ -375,6 +375,20 @@ int writeSerialPort(int serialPortId, LPBYTE buffer, int bufferSize) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int serialPortPurgeComm(int serialPortId, int dwFlags) {
|
||||||
|
int result = 0;
|
||||||
|
JNIEnv *jniEnv = getJNIEnvironment();
|
||||||
|
if(jniEnv) {
|
||||||
|
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
|
||||||
|
if(mainActivityClass) {
|
||||||
|
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "serialPortPurgeComm", "(II)I");
|
||||||
|
result = (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, serialPortId);
|
||||||
|
(*jniEnv)->DeleteLocalRef(jniEnv, mainActivityClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int serialPortSetBreak(int serialPortId) {
|
int serialPortSetBreak(int serialPortId) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
JNIEnv *jniEnv = getJNIEnvironment();
|
JNIEnv *jniEnv = getJNIEnvironment();
|
||||||
|
@ -1283,9 +1297,21 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setConfiguration(J
|
||||||
SwitchToState(nOldState);
|
SwitchToState(nOldState);
|
||||||
}
|
}
|
||||||
} else if(_tcscmp(_T("settings_serial_ports_wire"), configKey) == 0) {
|
} else if(_tcscmp(_T("settings_serial_ports_wire"), configKey) == 0) {
|
||||||
_tcsncpy(szSerialWire, _tcscmp(_T("0,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue, sizeof(szSerialWire));
|
const char * newSerialWire = _tcscmp(_T("0,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||||
|
BOOL serialWireChanged = _tcscmp(szSerialWire, newSerialWire) != 0;
|
||||||
|
_tcsncpy(szSerialWire, newSerialWire, sizeof(szSerialWire));
|
||||||
|
if(bCommInit && serialWireChanged) {
|
||||||
|
// Not the right thread, but it seems to work.
|
||||||
|
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
||||||
|
}
|
||||||
} else if(_tcscmp(_T("settings_serial_ports_ir"), configKey) == 0) {
|
} else if(_tcscmp(_T("settings_serial_ports_ir"), configKey) == 0) {
|
||||||
_tcsncpy(szSerialIr, _tcscmp(_T("0,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue, sizeof(szSerialIr));
|
const char * newSerialIr = _tcscmp(_T("0,0"), configStringValue) == 0 ? NO_SERIAL : configStringValue;
|
||||||
|
BOOL serialIrChanged = _tcscmp(szSerialIr, newSerialIr) != 0;
|
||||||
|
_tcsncpy(szSerialIr, newSerialIr, sizeof(szSerialIr));
|
||||||
|
if(bCommInit && serialIrChanged) {
|
||||||
|
// Not the right thread, but it seems to work.
|
||||||
|
bCommInit = CommOpen(szSerialWire, szSerialIr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(configKey)
|
if(configKey)
|
||||||
|
|
|
@ -330,14 +330,13 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,LPDWO
|
||||||
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
||||||
return writenByteCount >= 0;
|
return writenByteCount >= 0;
|
||||||
} else if(hFile->handleType == HANDLE_TYPE_COM) {
|
} else if(hFile->handleType == HANDLE_TYPE_COM) {
|
||||||
Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
|
||||||
ssize_t writenByteCount = writeSerialPort(hFile->commId, lpBuffer, nNumberOfBytesToWrite);
|
ssize_t writenByteCount = writeSerialPort(hFile->commId, lpBuffer, nNumberOfBytesToWrite);
|
||||||
#if defined DEBUG_ANDROID_SERIAL
|
#if defined DEBUG_ANDROID_SERIAL
|
||||||
char * hexAsciiDump = dumpToHexAscii(lpBuffer, writenByteCount, 8);
|
char * hexAsciiDump = dumpToHexAscii(lpBuffer, writenByteCount, 8);
|
||||||
SERIAL_LOGD("WriteFile(hFile: %p, lpBuffer: 0x%08x, nNumberOfBytesToWrite: %d) -> %d bytes\n%s", hFile, lpBuffer, nNumberOfBytesToWrite, writenByteCount, hexAsciiDump);
|
SERIAL_LOGD("WriteFile(hFile: %p, lpBuffer: 0x%08x, nNumberOfBytesToWrite: %d) -> %d bytes\n%s", hFile, lpBuffer, nNumberOfBytesToWrite, writenByteCount, hexAsciiDump);
|
||||||
free(hexAsciiDump);
|
free(hexAsciiDump);
|
||||||
#endif
|
#endif
|
||||||
commEvent(hFile->commId, EV_TXEMPTY); // Not sure about that (not the same thread)!
|
//Sleep(4); // Seems to be needed else the kermit packet does not fully reach the genuine calculator.
|
||||||
if(lpNumberOfBytesWritten)
|
if(lpNumberOfBytesWritten)
|
||||||
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
*lpNumberOfBytesWritten = (DWORD) writenByteCount;
|
||||||
return writenByteCount >= 0;
|
return writenByteCount >= 0;
|
||||||
|
@ -748,7 +747,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
|
||||||
|
|
||||||
BOOL WINAPI CloseHandle(HANDLE hObject) {
|
BOOL WINAPI CloseHandle(HANDLE hObject) {
|
||||||
FILE_LOGD("CloseHandle(hObject: %p)", hObject);
|
FILE_LOGD("CloseHandle(hObject: %p)", hObject);
|
||||||
if(hObject)
|
if(!hObject)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
//https://msdn.microsoft.com/en-us/9b84891d-62ca-4ddc-97b7-c4c79482abd9
|
//https://msdn.microsoft.com/en-us/9b84891d-62ca-4ddc-97b7-c4c79482abd9
|
||||||
// Can be a thread/event/file handle!
|
// Can be a thread/event/file handle!
|
||||||
|
@ -3107,6 +3106,7 @@ BOOL WaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||||
hFile->commEventMask = 0;
|
hFile->commEventMask = 0;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&commsLock);
|
pthread_mutex_unlock(&commsLock);
|
||||||
|
SERIAL_LOGD("WaitCommEvent(hFile: %p, lpEvtMask: %p) -> *lpEvtMask=%d", hFile, lpEvtMask, *lpEvtMask);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -3149,8 +3149,9 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) {
|
BOOL PurgeComm(HANDLE hFile, DWORD dwFlags) {
|
||||||
SERIAL_LOGD("SetCommState(hFile: %p, dwFlags: 0x%08X) TODO", hFile, dwFlags);
|
SERIAL_LOGD("PurgeComm(hFile: %p, dwFlags: 0x%08X) TODO", hFile, dwFlags);
|
||||||
//TODO
|
if(hFile && hFile->handleType == HANDLE_TYPE_COM)
|
||||||
|
return serialPortPurgeComm(hFile->commId, dwFlags);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
BOOL SetCommBreak(HANDLE hFile) {
|
BOOL SetCommBreak(HANDLE hFile) {
|
||||||
|
|
|
@ -1277,6 +1277,7 @@ extern int closeSerialPort(int serialPortId);
|
||||||
extern int setSerialPortParameters(int serialPortId, int baudRate);
|
extern int setSerialPortParameters(int serialPortId, int baudRate);
|
||||||
extern int readSerialPort(int serialPortId, LPBYTE buffer, int nNumberOfBytesToRead);
|
extern int readSerialPort(int serialPortId, LPBYTE buffer, int nNumberOfBytesToRead);
|
||||||
extern int writeSerialPort(int serialPortId, LPBYTE buffer, int bufferSize);
|
extern int writeSerialPort(int serialPortId, LPBYTE buffer, int bufferSize);
|
||||||
|
extern int serialPortPurgeComm(int serialPortId, int dwFlags);
|
||||||
extern int serialPortSetBreak(int serialPortId);
|
extern int serialPortSetBreak(int serialPortId);
|
||||||
extern int serialPortClearBreak(int serialPortId);
|
extern int serialPortClearBreak(int serialPortId);
|
||||||
extern int showAlert(const TCHAR * messageText, int flags);
|
extern int showAlert(const TCHAR * messageText, int flags);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.graphics.Paint;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
|
@ -615,7 +616,7 @@ public class PanAndScaleView extends View {
|
||||||
|
|
||||||
|
|
||||||
boolean osdAllowed = false;
|
boolean osdAllowed = false;
|
||||||
Handler osdTimerHandler = new Handler();
|
Handler osdTimerHandler = new Handler(Looper.getMainLooper());
|
||||||
Runnable osdTimerRunnable = () -> {
|
Runnable osdTimerRunnable = () -> {
|
||||||
// OSD should stop now!
|
// OSD should stop now!
|
||||||
osdAllowed = false;
|
osdAllowed = false;
|
||||||
|
|
|
@ -9,9 +9,11 @@ import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.emulator.calculator.usbserial.CustomProber;
|
import org.emulator.calculator.usbserial.CustomProber;
|
||||||
|
import org.emulator.calculator.usbserial.driver.SerialTimeoutException;
|
||||||
import org.emulator.calculator.usbserial.driver.UsbSerialDriver;
|
import org.emulator.calculator.usbserial.driver.UsbSerialDriver;
|
||||||
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
||||||
import org.emulator.calculator.usbserial.driver.UsbSerialProber;
|
import org.emulator.calculator.usbserial.driver.UsbSerialProber;
|
||||||
|
@ -26,13 +28,19 @@ import java.util.regex.Pattern;
|
||||||
public class Serial {
|
public class Serial {
|
||||||
|
|
||||||
private static final String TAG = "Serial";
|
private static final String TAG = "Serial";
|
||||||
private final boolean debug = false;
|
private final boolean debug = true;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final int serialPortId;
|
private final int serialPortId;
|
||||||
private static final String INTENT_ACTION_GRANT_USB = "EMU48.GRANT_USB";
|
private static final String INTENT_ACTION_GRANT_USB = "EMU48.GRANT_USB";
|
||||||
private static final int WRITE_WAIT_MILLIS = 2000;
|
private static final int WRITE_WAIT_MILLIS = 2000;
|
||||||
|
|
||||||
|
private static final int PURGE_TXABORT = 0x0001;
|
||||||
|
private static final int PURGE_RXABORT = 0x0002;
|
||||||
|
private static final int PURGE_TXCLEAR = 0x0004;
|
||||||
|
private static final int PURGE_RXCLEAR = 0x0008;
|
||||||
|
|
||||||
|
|
||||||
private final Handler mainLooper;
|
private final Handler mainLooper;
|
||||||
private SerialInputOutputManager usbIoManager;
|
private SerialInputOutputManager usbIoManager;
|
||||||
private UsbSerialPort usbSerialPort;
|
private UsbSerialPort usbSerialPort;
|
||||||
|
@ -41,7 +49,7 @@ public class Serial {
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
private String connectionStatus = "";
|
private String connectionStatus = "";
|
||||||
|
|
||||||
private final ArrayDeque<Byte> reveivedByteQueue = new ArrayDeque<>();
|
private final ArrayDeque<Byte> readByteQueue = new ArrayDeque<>();
|
||||||
|
|
||||||
|
|
||||||
public Serial(Context context, int serialPortId) {
|
public Serial(Context context, int serialPortId) {
|
||||||
|
@ -62,7 +70,7 @@ public class Serial {
|
||||||
mainLooper = new Handler(Looper.getMainLooper());
|
mainLooper = new Handler(Looper.getMainLooper());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean connect(String serialPort) {
|
public synchronized boolean connect(String serialPort) {
|
||||||
if(debug) Log.d(TAG, "connect( " + serialPort + ")");
|
if(debug) Log.d(TAG, "connect( " + serialPort + ")");
|
||||||
|
|
||||||
Pattern patternSerialPort = Pattern.compile("\\\\.\\\\(\\d+),(\\d+)");
|
Pattern patternSerialPort = Pattern.compile("\\\\.\\\\(\\d+),(\\d+)");
|
||||||
|
@ -87,11 +95,11 @@ public class Serial {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getConnectionStatus() {
|
public synchronized String getConnectionStatus() {
|
||||||
return connectionStatus;
|
return connectionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean connect(int deviceId, int portNum) {
|
public synchronized boolean connect(int deviceId, int portNum) {
|
||||||
if(debug) Log.d(TAG, "connect(deviceId: " + deviceId + ", portNum" + portNum + ")");
|
if(debug) Log.d(TAG, "connect(deviceId: " + deviceId + ", portNum" + portNum + ")");
|
||||||
|
|
||||||
UsbDevice device = null;
|
UsbDevice device = null;
|
||||||
|
@ -154,10 +162,10 @@ public class Serial {
|
||||||
@Override
|
@Override
|
||||||
public void onNewData(byte[] data) {
|
public void onNewData(byte[] data) {
|
||||||
if(debug) Log.d(TAG, "onNewData: " + Utils.bytesToHex(data));
|
if(debug) Log.d(TAG, "onNewData: " + Utils.bytesToHex(data));
|
||||||
boolean wasEmpty = reveivedByteQueue.isEmpty();
|
boolean wasEmpty = readByteQueue.isEmpty();
|
||||||
synchronized (reveivedByteQueue) {
|
synchronized (readByteQueue) {
|
||||||
for (byte datum : data)
|
for (byte datum : data)
|
||||||
reveivedByteQueue.add(datum);
|
readByteQueue.add(datum);
|
||||||
}
|
}
|
||||||
if (wasEmpty)
|
if (wasEmpty)
|
||||||
onReceivedByteQueueNotEmpty();
|
onReceivedByteQueueNotEmpty();
|
||||||
|
@ -172,14 +180,15 @@ public class Serial {
|
||||||
usbIo.setDaemon(true);
|
usbIo.setDaemon(true);
|
||||||
usbIo.start();
|
usbIo.start();
|
||||||
connected = true;
|
connected = true;
|
||||||
|
connectionStatus = "";
|
||||||
|
if(debug) Log.d(TAG, "connected!");
|
||||||
|
purgeComm(PURGE_TXCLEAR | PURGE_RXCLEAR);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
connectionStatus = "serial_connection_failed_open_failed";
|
connectionStatus = "serial_connection_failed_open_failed";
|
||||||
if(debug) Log.d(TAG, "connectionStatus = " + connectionStatus + ", " + e.getMessage());
|
if(debug) Log.d(TAG, "connectionStatus = " + connectionStatus + ", " + e.getMessage());
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
if(debug) Log.d(TAG, "connected!");
|
|
||||||
connectionStatus = "";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,15 +203,16 @@ public class Serial {
|
||||||
Log.d(TAG, "onRunError: " + e.getMessage());
|
Log.d(TAG, "onRunError: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
disconnect();
|
//disconnect();
|
||||||
});
|
});
|
||||||
|
//disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setParameters(int baudRate) {
|
public synchronized boolean setParameters(int baudRate) {
|
||||||
return setParameters(baudRate, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
return setParameters(baudRate, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setParameters(int baudRate, int dataBits, int stopBits, int parity) {
|
public synchronized boolean setParameters(int baudRate, int dataBits, int stopBits, int parity) {
|
||||||
if(debug) Log.d(TAG, "setParameters(baudRate: " + baudRate + ", dataBits: " + dataBits + ", stopBits: " + stopBits + ", parity: " + parity +")");
|
if(debug) Log.d(TAG, "setParameters(baudRate: " + baudRate + ", dataBits: " + dataBits + ", stopBits: " + stopBits + ", parity: " + parity +")");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -214,38 +224,84 @@ public class Serial {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] receive(int nNumberOfBytesToRead) {
|
public synchronized byte[] read(int nNumberOfBytesToRead) {
|
||||||
|
if(debug) Log.d(TAG, "read(nNumberOfBytesToRead: " + nNumberOfBytesToRead + ")");
|
||||||
|
|
||||||
|
if(!connected)
|
||||||
|
return new byte[0];
|
||||||
|
|
||||||
byte[] result;
|
byte[] result;
|
||||||
synchronized (reveivedByteQueue) {
|
synchronized (readByteQueue) {
|
||||||
int nNumberOfReadBytes = Math.min(nNumberOfBytesToRead, reveivedByteQueue.size());
|
int nNumberOfReadBytes = Math.min(nNumberOfBytesToRead, readByteQueue.size());
|
||||||
result = new byte[nNumberOfReadBytes];
|
result = new byte[nNumberOfReadBytes];
|
||||||
for (int i = 0; i < nNumberOfReadBytes; i++) {
|
for (int i = 0; i < nNumberOfReadBytes; i++) {
|
||||||
Byte byteRead = reveivedByteQueue.poll();
|
Byte byteRead = readByteQueue.poll();
|
||||||
if(byteRead != null)
|
if(byteRead != null)
|
||||||
result[i] = byteRead;
|
result[i] = byteRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(result == null) {
|
if(readByteQueue.size() > 0)
|
||||||
result = new byte[0];
|
|
||||||
} else if(reveivedByteQueue.size() > 0) {
|
|
||||||
mainLooper.post(() -> NativeLib.commEvent(serialPortId, NativeLib.EV_RXCHAR));
|
mainLooper.post(() -> NativeLib.commEvent(serialPortId, NativeLib.EV_RXCHAR));
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int send(byte[] data) {
|
long maxWritePeriod = 4; //ms
|
||||||
|
long lastTime = 0;
|
||||||
|
public synchronized int write(byte[] data) {
|
||||||
if(!connected)
|
if(!connected)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
long currentTime = SystemClock.elapsedRealtime();
|
||||||
|
long writePeriod = currentTime - lastTime;
|
||||||
|
|
||||||
|
if(debug) Log.d(TAG, "write(data: [" + data.length + "]: " + Utils.bytesToHex(data) + ") writePeriod: " + writePeriod + "ms");
|
||||||
|
|
||||||
|
if(lastTime > 0 && writePeriod < maxWritePeriod) {
|
||||||
|
// Wait 1ms - (currentTime - lastTime)ms
|
||||||
|
android.os.SystemClock.sleep(maxWritePeriod - writePeriod);
|
||||||
|
}
|
||||||
|
lastTime = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return usbSerialPort.write(data, WRITE_WAIT_MILLIS);
|
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
|
||||||
|
if(debug) Log.d(TAG, "write() return: " + data.length);
|
||||||
|
// No exception, so, all the data has been sent!
|
||||||
|
|
||||||
|
// Consider that the write buffer is empty?
|
||||||
|
NativeLib.commEvent(serialPortId, NativeLib.EV_TXEMPTY);
|
||||||
|
|
||||||
|
return data.length;
|
||||||
|
} catch (SerialTimeoutException e) {
|
||||||
|
if(debug) Log.d(TAG, "write() Exception: " + e.toString());
|
||||||
|
return data.length - e.bytesTransferred;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
if(debug) Log.d(TAG, "write() Exception: " + e.toString());
|
||||||
onReceivedError(e);
|
onReceivedError(e);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int setBreak() {
|
|
||||||
|
public synchronized int purgeComm(int dwFlags) {
|
||||||
|
if(!connected)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(debug) Log.d(TAG, "purgeComm(" + dwFlags + ")");
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean purgeWriteBuffers = (dwFlags & PURGE_TXABORT) == PURGE_TXABORT || (dwFlags & PURGE_TXCLEAR) == PURGE_TXCLEAR;
|
||||||
|
boolean purgeReadBuffers = (dwFlags & PURGE_RXABORT) == PURGE_RXABORT || (dwFlags & PURGE_RXCLEAR) == PURGE_RXCLEAR;
|
||||||
|
if(purgeReadBuffers)
|
||||||
|
readByteQueue.clear();
|
||||||
|
usbSerialPort.purgeHwBuffers(purgeWriteBuffers, purgeReadBuffers);
|
||||||
|
return 1;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Exception mean return 0
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int setBreak() {
|
||||||
if(!connected)
|
if(!connected)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -258,7 +314,7 @@ public class Serial {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int clearBreak() {
|
public synchronized int clearBreak() {
|
||||||
if(!connected)
|
if(!connected)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -271,7 +327,7 @@ public class Serial {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public synchronized void disconnect() {
|
||||||
if(debug) Log.d(TAG, "disconnect()");
|
if(debug) Log.d(TAG, "disconnect()");
|
||||||
|
|
||||||
connected = false;
|
connected = false;
|
||||||
|
@ -280,7 +336,9 @@ public class Serial {
|
||||||
usbIoManager = null;
|
usbIoManager = null;
|
||||||
try {
|
try {
|
||||||
usbSerialPort.close();
|
usbSerialPort.close();
|
||||||
} catch (IOException ignored) {}
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
usbSerialPort = null;
|
usbSerialPort = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,12 +216,15 @@ public class Utils {
|
||||||
|
|
||||||
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
||||||
public static String bytesToHex(byte[] bytes) {
|
public static String bytesToHex(byte[] bytes) {
|
||||||
char[] hexChars = new char[bytes.length * 2];
|
char[] hexChars = new char[bytes.length * 4];
|
||||||
for (int j = 0; j < bytes.length; j++) {
|
for (int j = 0; j < bytes.length; j++) {
|
||||||
int v = bytes[j] & 0xFF;
|
int v = bytes[j] & 0xFF;
|
||||||
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
hexChars[j * 3] = HEX_ARRAY[v >>> 4];
|
||||||
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
hexChars[j * 3 + 1] = HEX_ARRAY[v & 0x0F];
|
||||||
|
hexChars[j * 3 + 2] = ' ';
|
||||||
}
|
}
|
||||||
|
for (int j = 0; j < bytes.length; j++)
|
||||||
|
hexChars[bytes.length * 3 + j] = Character.isISOControl(bytes[j]) ? '.' : (char) bytes[j];
|
||||||
return new String(hexChars);
|
return new String(hexChars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ public class DevicesFragment extends ListFragment {
|
||||||
else
|
else
|
||||||
text1.setText(String.format(Locale.US, getString(Utils.resId(DevicesFragment.this, "string", "serial_ports_device_item_title")), deviceName, item.port));
|
text1.setText(String.format(Locale.US, getString(Utils.resId(DevicesFragment.this, "string", "serial_ports_device_item_title")), deviceName, item.port));
|
||||||
}
|
}
|
||||||
text2.setText(String.format(Locale.US, getString(Utils.resId(DevicesFragment.this, "string", "serial_ports_device_item_description")), item.device.getVendorId(), item.device.getProductId()));
|
if(item.device != null)
|
||||||
|
text2.setText(String.format(Locale.US, getString(Utils.resId(DevicesFragment.this, "string", "serial_ports_device_item_description")), item.device.getVendorId(), item.device.getProductId()));
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -90,6 +91,7 @@ public class DevicesFragment extends ListFragment {
|
||||||
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
|
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
|
||||||
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
|
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
|
||||||
listItems.clear();
|
listItems.clear();
|
||||||
|
listItems.add(new ListItem(null, 0, null));
|
||||||
for(UsbDevice device : usbManager.getDeviceList().values()) {
|
for(UsbDevice device : usbManager.getDeviceList().values()) {
|
||||||
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
|
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
|
||||||
if(driver == null) {
|
if(driver == null) {
|
||||||
|
@ -98,8 +100,6 @@ public class DevicesFragment extends ListFragment {
|
||||||
if(driver != null) {
|
if(driver != null) {
|
||||||
for(int port = 0; port < driver.getPorts().size(); port++)
|
for(int port = 0; port < driver.getPorts().size(); port++)
|
||||||
listItems.add(new ListItem(device, port, driver));
|
listItems.add(new ListItem(device, port, driver));
|
||||||
} else {
|
|
||||||
listItems.add(new ListItem(device, 0, null));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listAdapter.notifyDataSetChanged();
|
listAdapter.notifyDataSetChanged();
|
||||||
|
|
|
@ -204,7 +204,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||||
if(baudRate <= 0) {
|
if(baudRate <= 0) {
|
||||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_ARDUINO,
|
supportedDevices.put(UsbId.VENDOR_ARDUINO,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.ARDUINO_UNO,
|
UsbId.ARDUINO_UNO,
|
||||||
|
@ -317,6 +317,10 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.ARM_MBED,
|
UsbId.ARM_MBED,
|
||||||
});
|
});
|
||||||
|
supportedDevices.put(UsbId.VENDOR_ST,
|
||||||
|
new int[] {
|
||||||
|
UsbId.ST_CDC,
|
||||||
|
});
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,374 +1,374 @@
|
||||||
/* Copyright 2014 Andreas Butti
|
/* Copyright 2014 Andreas Butti
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbConstants;
|
import android.hardware.usb.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Ch34xSerialDriver implements UsbSerialDriver {
|
public class Ch34xSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
private static final String TAG = Ch34xSerialDriver.class.getSimpleName();
|
private static final String TAG = Ch34xSerialDriver.class.getSimpleName();
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final UsbSerialPort mPort;
|
||||||
|
|
||||||
private static final int LCR_ENABLE_RX = 0x80;
|
private static final int LCR_ENABLE_RX = 0x80;
|
||||||
private static final int LCR_ENABLE_TX = 0x40;
|
private static final int LCR_ENABLE_TX = 0x40;
|
||||||
private static final int LCR_MARK_SPACE = 0x20;
|
private static final int LCR_MARK_SPACE = 0x20;
|
||||||
private static final int LCR_PAR_EVEN = 0x10;
|
private static final int LCR_PAR_EVEN = 0x10;
|
||||||
private static final int LCR_ENABLE_PAR = 0x08;
|
private static final int LCR_ENABLE_PAR = 0x08;
|
||||||
private static final int LCR_STOP_BITS_2 = 0x04;
|
private static final int LCR_STOP_BITS_2 = 0x04;
|
||||||
private static final int LCR_CS8 = 0x03;
|
private static final int LCR_CS8 = 0x03;
|
||||||
private static final int LCR_CS7 = 0x02;
|
private static final int LCR_CS7 = 0x02;
|
||||||
private static final int LCR_CS6 = 0x01;
|
private static final int LCR_CS6 = 0x01;
|
||||||
private static final int LCR_CS5 = 0x00;
|
private static final int LCR_CS5 = 0x00;
|
||||||
|
|
||||||
private static final int GCL_CTS = 0x01;
|
private static final int GCL_CTS = 0x01;
|
||||||
private static final int GCL_DSR = 0x02;
|
private static final int GCL_DSR = 0x02;
|
||||||
private static final int GCL_RI = 0x04;
|
private static final int GCL_RI = 0x04;
|
||||||
private static final int GCL_CD = 0x08;
|
private static final int GCL_CD = 0x08;
|
||||||
private static final int SCL_DTR = 0x20;
|
private static final int SCL_DTR = 0x20;
|
||||||
private static final int SCL_RTS = 0x40;
|
private static final int SCL_RTS = 0x40;
|
||||||
|
|
||||||
public Ch34xSerialDriver(UsbDevice device) {
|
public Ch34xSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPort = new Ch340SerialPort(mDevice, 0);
|
mPort = new Ch340SerialPort(mDevice, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbDevice getDevice() {
|
public UsbDevice getDevice() {
|
||||||
return mDevice;
|
return mDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UsbSerialPort> getPorts() {
|
public List<UsbSerialPort> getPorts() {
|
||||||
return Collections.singletonList(mPort);
|
return Collections.singletonList(mPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Ch340SerialPort extends CommonUsbSerialPort {
|
public class Ch340SerialPort extends CommonUsbSerialPort {
|
||||||
|
|
||||||
private static final int USB_TIMEOUT_MILLIS = 5000;
|
private static final int USB_TIMEOUT_MILLIS = 5000;
|
||||||
|
|
||||||
private final int DEFAULT_BAUD_RATE = 9600;
|
private final int DEFAULT_BAUD_RATE = 9600;
|
||||||
|
|
||||||
private boolean dtr = false;
|
private boolean dtr = false;
|
||||||
private boolean rts = false;
|
private boolean rts = false;
|
||||||
|
|
||||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbSerialDriver getDriver() {
|
public UsbSerialDriver getDriver() {
|
||||||
return Ch34xSerialDriver.this;
|
return Ch34xSerialDriver.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
UsbInterface usbIface = mDevice.getInterface(i);
|
UsbInterface usbIface = mDevice.getInterface(i);
|
||||||
if (!mConnection.claimInterface(usbIface, true)) {
|
if (!mConnection.claimInterface(usbIface, true)) {
|
||||||
throw new IOException("Could not claim data interface");
|
throw new IOException("Could not claim data interface");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
||||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
||||||
mReadEndpoint = ep;
|
mReadEndpoint = ep;
|
||||||
} else {
|
} else {
|
||||||
mWriteEndpoint = ep;
|
mWriteEndpoint = ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
setBaudRate(DEFAULT_BAUD_RATE);
|
setBaudRate(DEFAULT_BAUD_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeInt() {
|
protected void closeInt() {
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
||||||
mConnection.releaseInterface(mDevice.getInterface(i));
|
mConnection.releaseInterface(mDevice.getInterface(i));
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int controlOut(int request, int value, int index) {
|
private int controlOut(int request, int value, int index) {
|
||||||
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
||||||
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
||||||
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private int controlIn(int request, int value, int index, byte[] buffer) {
|
private int controlIn(int request, int value, int index, byte[] buffer) {
|
||||||
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
||||||
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
||||||
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
||||||
byte[] buffer = new byte[expected.length];
|
byte[] buffer = new byte[expected.length];
|
||||||
int ret = controlIn(request, value, 0, buffer);
|
int ret = controlIn(request, value, 0, buffer);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Failed send cmd [" + msg + "]");
|
throw new IOException("Failed send cmd [" + msg + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != expected.length) {
|
if (ret != expected.length) {
|
||||||
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
for (int i = 0; i < expected.length; i++) {
|
||||||
if (expected[i] == -1) {
|
if (expected[i] == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int current = buffer[i] & 0xff;
|
int current = buffer[i] & 0xff;
|
||||||
if (expected[i] != current) {
|
if (expected[i] != current) {
|
||||||
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setControlLines() throws IOException {
|
private void setControlLines() throws IOException {
|
||||||
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
||||||
throw new IOException("Failed to set control lines");
|
throw new IOException("Failed to set control lines");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getStatus() throws IOException {
|
private byte getStatus() throws IOException {
|
||||||
byte[] buffer = new byte[2];
|
byte[] buffer = new byte[2];
|
||||||
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
throw new IOException("Error getting control lines");
|
throw new IOException("Error getting control lines");
|
||||||
return buffer[0];
|
return buffer[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() throws IOException {
|
private void initialize() throws IOException {
|
||||||
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
||||||
|
|
||||||
if (controlOut(0xa1, 0, 0) < 0) {
|
if (controlOut(0xa1, 0, 0) < 0) {
|
||||||
throw new IOException("Init failed: #2");
|
throw new IOException("Init failed: #2");
|
||||||
}
|
}
|
||||||
|
|
||||||
setBaudRate(DEFAULT_BAUD_RATE);
|
setBaudRate(DEFAULT_BAUD_RATE);
|
||||||
|
|
||||||
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
|
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
|
||||||
|
|
||||||
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
|
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
|
||||||
throw new IOException("Init failed: #5");
|
throw new IOException("Init failed: #5");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkState("init #6", 0x95, 0x0706, new int[]{-1/*0xf?*/, -1/*0xec,0xee*/});
|
checkState("init #6", 0x95, 0x0706, new int[]{-1/*0xf?*/, -1/*0xec,0xee*/});
|
||||||
|
|
||||||
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
|
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
|
||||||
throw new IOException("Init failed: #7");
|
throw new IOException("Init failed: #7");
|
||||||
}
|
}
|
||||||
|
|
||||||
setBaudRate(DEFAULT_BAUD_RATE);
|
setBaudRate(DEFAULT_BAUD_RATE);
|
||||||
|
|
||||||
setControlLines();
|
setControlLines();
|
||||||
|
|
||||||
checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, -1/*0xec,0xee*/});
|
checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, -1/*0xec,0xee*/});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setBaudRate(int baudRate) throws IOException {
|
private void setBaudRate(int baudRate) throws IOException {
|
||||||
final long CH341_BAUDBASE_FACTOR = 1532620800;
|
final long CH341_BAUDBASE_FACTOR = 1532620800;
|
||||||
final int CH341_BAUDBASE_DIVMAX = 3;
|
final int CH341_BAUDBASE_DIVMAX = 3;
|
||||||
|
|
||||||
long factor = CH341_BAUDBASE_FACTOR / baudRate;
|
long factor = CH341_BAUDBASE_FACTOR / baudRate;
|
||||||
int divisor = CH341_BAUDBASE_DIVMAX;
|
int divisor = CH341_BAUDBASE_DIVMAX;
|
||||||
|
|
||||||
while ((factor > 0xfff0) && divisor > 0) {
|
while ((factor > 0xfff0) && divisor > 0) {
|
||||||
factor >>= 3;
|
factor >>= 3;
|
||||||
divisor--;
|
divisor--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (factor > 0xfff0) {
|
if (factor > 0xfff0) {
|
||||||
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
factor = 0x10000 - factor;
|
factor = 0x10000 - factor;
|
||||||
divisor |= 0x0080; // else ch341a waits until buffer full
|
divisor |= 0x0080; // else ch341a waits until buffer full
|
||||||
int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor));
|
int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Error setting baud rate: #1)");
|
throw new IOException("Error setting baud rate: #1)");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff));
|
ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Error setting baud rate: #2");
|
throw new IOException("Error setting baud rate: #2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||||
if(baudRate <= 0) {
|
if(baudRate <= 0) {
|
||||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||||
}
|
}
|
||||||
setBaudRate(baudRate);
|
setBaudRate(baudRate);
|
||||||
|
|
||||||
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
|
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
|
||||||
|
|
||||||
switch (dataBits) {
|
switch (dataBits) {
|
||||||
case DATABITS_5:
|
case DATABITS_5:
|
||||||
lcr |= LCR_CS5;
|
lcr |= LCR_CS5;
|
||||||
break;
|
break;
|
||||||
case DATABITS_6:
|
case DATABITS_6:
|
||||||
lcr |= LCR_CS6;
|
lcr |= LCR_CS6;
|
||||||
break;
|
break;
|
||||||
case DATABITS_7:
|
case DATABITS_7:
|
||||||
lcr |= LCR_CS7;
|
lcr |= LCR_CS7;
|
||||||
break;
|
break;
|
||||||
case DATABITS_8:
|
case DATABITS_8:
|
||||||
lcr |= LCR_CS8;
|
lcr |= LCR_CS8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parity) {
|
switch (parity) {
|
||||||
case PARITY_NONE:
|
case PARITY_NONE:
|
||||||
break;
|
break;
|
||||||
case PARITY_ODD:
|
case PARITY_ODD:
|
||||||
lcr |= LCR_ENABLE_PAR;
|
lcr |= LCR_ENABLE_PAR;
|
||||||
break;
|
break;
|
||||||
case PARITY_EVEN:
|
case PARITY_EVEN:
|
||||||
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
|
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
|
||||||
break;
|
break;
|
||||||
case PARITY_MARK:
|
case PARITY_MARK:
|
||||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
|
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
|
||||||
break;
|
break;
|
||||||
case PARITY_SPACE:
|
case PARITY_SPACE:
|
||||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
|
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid parity: " + parity);
|
throw new IllegalArgumentException("Invalid parity: " + parity);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (stopBits) {
|
switch (stopBits) {
|
||||||
case STOPBITS_1:
|
case STOPBITS_1:
|
||||||
break;
|
break;
|
||||||
case STOPBITS_1_5:
|
case STOPBITS_1_5:
|
||||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
||||||
case STOPBITS_2:
|
case STOPBITS_2:
|
||||||
lcr |= LCR_STOP_BITS_2;
|
lcr |= LCR_STOP_BITS_2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = controlOut(0x9a, 0x2518, lcr);
|
int ret = controlOut(0x9a, 0x2518, lcr);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Error setting control byte");
|
throw new IOException("Error setting control byte");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCD() throws IOException {
|
public boolean getCD() throws IOException {
|
||||||
return (getStatus() & GCL_CD) == 0;
|
return (getStatus() & GCL_CD) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCTS() throws IOException {
|
public boolean getCTS() throws IOException {
|
||||||
return (getStatus() & GCL_CTS) == 0;
|
return (getStatus() & GCL_CTS) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDSR() throws IOException {
|
public boolean getDSR() throws IOException {
|
||||||
return (getStatus() & GCL_DSR) == 0;
|
return (getStatus() & GCL_DSR) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDTR() throws IOException {
|
public boolean getDTR() throws IOException {
|
||||||
return dtr;
|
return dtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDTR(boolean value) throws IOException {
|
public void setDTR(boolean value) throws IOException {
|
||||||
dtr = value;
|
dtr = value;
|
||||||
setControlLines();
|
setControlLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRI() throws IOException {
|
public boolean getRI() throws IOException {
|
||||||
return (getStatus() & GCL_RI) == 0;
|
return (getStatus() & GCL_RI) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRTS() throws IOException {
|
public boolean getRTS() throws IOException {
|
||||||
return rts;
|
return rts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRTS(boolean value) throws IOException {
|
public void setRTS(boolean value) throws IOException {
|
||||||
rts = value;
|
rts = value;
|
||||||
setControlLines();
|
setControlLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||||
int status = getStatus();
|
int status = getStatus();
|
||||||
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||||
if(rts) set.add(ControlLine.RTS);
|
if(rts) set.add(ControlLine.RTS);
|
||||||
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
|
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
|
||||||
if(dtr) set.add(ControlLine.DTR);
|
if(dtr) set.add(ControlLine.DTR);
|
||||||
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
|
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
|
||||||
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
|
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
|
||||||
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
|
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||||
return EnumSet.allOf(ControlLine.class);
|
return EnumSet.allOf(ControlLine.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBreak(boolean value) throws IOException {
|
public void setBreak(boolean value) throws IOException {
|
||||||
byte[] req = new byte[2];
|
byte[] req = new byte[2];
|
||||||
if(controlIn(0x95, 0x1805, 0, req) < 0) {
|
if(controlIn(0x95, 0x1805, 0, req) < 0) {
|
||||||
throw new IOException("Error getting BREAK condition");
|
throw new IOException("Error getting BREAK condition");
|
||||||
}
|
}
|
||||||
if(value) {
|
if(value) {
|
||||||
req[0] &= ~1;
|
req[0] &= ~1;
|
||||||
req[1] &= ~0x40;
|
req[1] &= ~0x40;
|
||||||
} else {
|
} else {
|
||||||
req[0] |= 1;
|
req[0] |= 1;
|
||||||
req[1] |= 0x40;
|
req[1] |= 0x40;
|
||||||
}
|
}
|
||||||
int val = (req[1] & 0xff) << 8 | (req[0] & 0xff);
|
int val = (req[1] & 0xff) << 8 | (req[0] & 0xff);
|
||||||
if(controlOut(0x9a, 0x1805, val) < 0) {
|
if(controlOut(0x9a, 0x1805, val) < 0) {
|
||||||
throw new IOException("Error setting BREAK condition");
|
throw new IOException("Error setting BREAK condition");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
|
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
|
||||||
UsbId.QINHENG_CH340,
|
UsbId.QINHENG_CH340,
|
||||||
UsbId.QINHENG_CH341A,
|
UsbId.QINHENG_CH341A,
|
||||||
});
|
});
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,270 +1,301 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbRequest;
|
import android.hardware.usb.UsbRequest;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import org.emulator.calculator.usbserial.util.MonotonicClock;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.EnumSet;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
/**
|
import java.util.EnumSet;
|
||||||
* A base class shared by several driver implementations.
|
|
||||||
*
|
/**
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* A base class shared by several driver implementations.
|
||||||
*/
|
*
|
||||||
public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
|
*/
|
||||||
private static final String TAG = CommonUsbSerialPort.class.getSimpleName();
|
public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
private static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
|
|
||||||
private static final int MAX_READ_SIZE = 16 * 1024; // = old bulkTransfer limit
|
private static final String TAG = CommonUsbSerialPort.class.getSimpleName();
|
||||||
|
private static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
|
||||||
protected final UsbDevice mDevice;
|
private static final int MAX_READ_SIZE = 16 * 1024; // = old bulkTransfer limit
|
||||||
protected final int mPortNumber;
|
|
||||||
|
protected final UsbDevice mDevice;
|
||||||
// non-null when open()
|
protected final int mPortNumber;
|
||||||
protected UsbDeviceConnection mConnection = null;
|
|
||||||
protected UsbEndpoint mReadEndpoint;
|
// non-null when open()
|
||||||
protected UsbEndpoint mWriteEndpoint;
|
protected UsbDeviceConnection mConnection = null;
|
||||||
protected UsbRequest mUsbRequest;
|
protected UsbEndpoint mReadEndpoint;
|
||||||
|
protected UsbEndpoint mWriteEndpoint;
|
||||||
protected final Object mWriteBufferLock = new Object();
|
protected UsbRequest mUsbRequest;
|
||||||
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
|
|
||||||
protected byte[] mWriteBuffer;
|
protected final Object mWriteBufferLock = new Object();
|
||||||
|
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
|
||||||
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
|
protected byte[] mWriteBuffer;
|
||||||
mDevice = device;
|
|
||||||
mPortNumber = portNumber;
|
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
|
||||||
|
mDevice = device;
|
||||||
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
|
mPortNumber = portNumber;
|
||||||
}
|
|
||||||
|
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
|
||||||
@Override
|
}
|
||||||
public String toString() {
|
|
||||||
return String.format("<%s device_name=%s device_id=%s port_number=%s>",
|
@Override
|
||||||
getClass().getSimpleName(), mDevice.getDeviceName(),
|
public String toString() {
|
||||||
mDevice.getDeviceId(), mPortNumber);
|
return String.format("<%s device_name=%s device_id=%s port_number=%s>",
|
||||||
}
|
getClass().getSimpleName(), mDevice.getDeviceName(),
|
||||||
|
mDevice.getDeviceId(), mPortNumber);
|
||||||
@Override
|
}
|
||||||
public UsbDevice getDevice() {
|
|
||||||
return mDevice;
|
@Override
|
||||||
}
|
public UsbDevice getDevice() {
|
||||||
|
return mDevice;
|
||||||
@Override
|
}
|
||||||
public int getPortNumber() {
|
|
||||||
return mPortNumber;
|
@Override
|
||||||
}
|
public int getPortNumber() {
|
||||||
|
return mPortNumber;
|
||||||
/**
|
}
|
||||||
* Returns the device serial number
|
|
||||||
* @return serial number
|
@Override
|
||||||
*/
|
public UsbEndpoint getWriteEndpoint() { return mWriteEndpoint; }
|
||||||
@Override
|
|
||||||
public String getSerial() {
|
@Override
|
||||||
return mConnection.getSerial();
|
public UsbEndpoint getReadEndpoint() { return mReadEndpoint; }
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Returns the device serial number
|
||||||
* Sets the size of the internal buffer used to exchange data with the USB
|
* @return serial number
|
||||||
* stack for write operations. Most users should not need to change this.
|
*/
|
||||||
*
|
@Override
|
||||||
* @param bufferSize the size in bytes
|
public String getSerial() {
|
||||||
*/
|
return mConnection.getSerial();
|
||||||
public final void setWriteBufferSize(int bufferSize) {
|
}
|
||||||
synchronized (mWriteBufferLock) {
|
|
||||||
if (bufferSize == mWriteBuffer.length) {
|
/**
|
||||||
return;
|
* Sets the size of the internal buffer used to exchange data with the USB
|
||||||
}
|
* stack for write operations. Most users should not need to change this.
|
||||||
mWriteBuffer = new byte[bufferSize];
|
*
|
||||||
}
|
* @param bufferSize the size in bytes
|
||||||
}
|
*/
|
||||||
|
public final void setWriteBufferSize(int bufferSize) {
|
||||||
@Override
|
synchronized (mWriteBufferLock) {
|
||||||
public void open(UsbDeviceConnection connection) throws IOException {
|
if (bufferSize == mWriteBuffer.length) {
|
||||||
if (mConnection != null) {
|
return;
|
||||||
throw new IOException("Already open");
|
}
|
||||||
}
|
mWriteBuffer = new byte[bufferSize];
|
||||||
mConnection = connection;
|
}
|
||||||
try {
|
}
|
||||||
openInt(connection);
|
|
||||||
if (mReadEndpoint == null || mWriteEndpoint == null) {
|
@Override
|
||||||
throw new IOException("Could not get read & write endpoints");
|
public void open(UsbDeviceConnection connection) throws IOException {
|
||||||
}
|
if (mConnection != null) {
|
||||||
mUsbRequest = new UsbRequest();
|
throw new IOException("Already open");
|
||||||
mUsbRequest.initialize(mConnection, mReadEndpoint);
|
}
|
||||||
} catch(Exception e) {
|
if(connection == null) {
|
||||||
close();
|
throw new IllegalArgumentException("Connection is null");
|
||||||
throw e;
|
}
|
||||||
}
|
mConnection = connection;
|
||||||
}
|
try {
|
||||||
|
openInt(connection);
|
||||||
protected abstract void openInt(UsbDeviceConnection connection) throws IOException;
|
if (mReadEndpoint == null || mWriteEndpoint == null) {
|
||||||
|
throw new IOException("Could not get read & write endpoints");
|
||||||
@Override
|
}
|
||||||
public void close() throws IOException {
|
mUsbRequest = new UsbRequest();
|
||||||
if (mConnection == null) {
|
mUsbRequest.initialize(mConnection, mReadEndpoint);
|
||||||
throw new IOException("Already closed");
|
} catch(Exception e) {
|
||||||
}
|
try {
|
||||||
try {
|
close();
|
||||||
mUsbRequest.cancel();
|
} catch(Exception ignored) {}
|
||||||
} catch(Exception ignored) {}
|
throw e;
|
||||||
mUsbRequest = null;
|
}
|
||||||
try {
|
}
|
||||||
closeInt();
|
|
||||||
} catch(Exception ignored) {}
|
protected abstract void openInt(UsbDeviceConnection connection) throws IOException;
|
||||||
try {
|
|
||||||
mConnection.close();
|
@Override
|
||||||
} catch(Exception ignored) {}
|
public void close() throws IOException {
|
||||||
mConnection = null;
|
if (mConnection == null) {
|
||||||
}
|
throw new IOException("Already closed");
|
||||||
|
}
|
||||||
protected abstract void closeInt();
|
try {
|
||||||
|
mUsbRequest.cancel();
|
||||||
/**
|
} catch(Exception ignored) {}
|
||||||
* use simple USB request supported by all devices to test if connection is still valid
|
mUsbRequest = null;
|
||||||
*/
|
try {
|
||||||
protected void testConnection() throws IOException {
|
closeInt();
|
||||||
byte[] buf = new byte[2];
|
} catch(Exception ignored) {}
|
||||||
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
try {
|
||||||
if(len < 0)
|
mConnection.close();
|
||||||
throw new IOException("USB get_status request failed");
|
} catch(Exception ignored) {}
|
||||||
}
|
mConnection = null;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public int read(final byte[] dest, final int timeout) throws IOException {
|
protected abstract void closeInt();
|
||||||
return read(dest, timeout, true);
|
|
||||||
}
|
/**
|
||||||
|
* use simple USB request supported by all devices to test if connection is still valid
|
||||||
protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException {
|
*/
|
||||||
if(mConnection == null) {
|
protected void testConnection() throws IOException {
|
||||||
throw new IOException("Connection closed");
|
byte[] buf = new byte[2];
|
||||||
}
|
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
||||||
if(dest.length <= 0) {
|
if(len < 0)
|
||||||
throw new IllegalArgumentException("Read buffer to small");
|
throw new IOException("USB get_status request failed");
|
||||||
}
|
}
|
||||||
final int nread;
|
|
||||||
if (timeout != 0) {
|
@Override
|
||||||
// bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer
|
public int read(final byte[] dest, final int timeout) throws IOException {
|
||||||
// https://stackoverflow.com/questions/9108548/android-usb-host-bulktransfer-is-losing-data
|
return read(dest, timeout, true);
|
||||||
// but mConnection.requestWait(timeout) available since Android 8.0 es even worse,
|
}
|
||||||
// as it crashes with short timeout, e.g.
|
|
||||||
// A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x276a in tid 29846 (pool-2-thread-1), pid 29618 (.usbserial.test)
|
protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException {
|
||||||
// /system/lib64/libusbhost.so (usb_request_wait+192)
|
if(mConnection == null) {
|
||||||
// /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84)
|
throw new IOException("Connection closed");
|
||||||
// data loss / crashes were observed with timeout up to 200 msec
|
}
|
||||||
long endTime = testConnection ? System.currentTimeMillis() + timeout : 0;
|
if(dest.length <= 0) {
|
||||||
int readMax = Math.min(dest.length, MAX_READ_SIZE);
|
throw new IllegalArgumentException("Read buffer to small");
|
||||||
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
}
|
||||||
// Android error propagation is improvable, nread == -1 can be: timeout, connection lost, buffer undersized, ...
|
final int nread;
|
||||||
if(nread == -1 && testConnection && System.currentTimeMillis() < endTime)
|
if (timeout != 0) {
|
||||||
testConnection();
|
// bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer
|
||||||
|
// https://stackoverflow.com/questions/9108548/android-usb-host-bulktransfer-is-losing-data
|
||||||
} else {
|
// but mConnection.requestWait(timeout) available since Android 8.0 es even worse,
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
// as it crashes with short timeout, e.g.
|
||||||
if (!mUsbRequest.queue(buf, dest.length)) {
|
// A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x276a in tid 29846 (pool-2-thread-1), pid 29618 (.usbserial.test)
|
||||||
throw new IOException("Queueing USB request failed");
|
// /system/lib64/libusbhost.so (usb_request_wait+192)
|
||||||
}
|
// /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84)
|
||||||
final UsbRequest response = mConnection.requestWait();
|
// data loss / crashes were observed with timeout up to 200 msec
|
||||||
if (response == null) {
|
long endTime = testConnection ? MonotonicClock.millis() + timeout : 0;
|
||||||
throw new IOException("Waiting for USB request failed");
|
int readMax = Math.min(dest.length, MAX_READ_SIZE);
|
||||||
}
|
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
||||||
nread = buf.position();
|
// Android error propagation is improvable:
|
||||||
}
|
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
||||||
if (nread > 0)
|
if(nread == -1 && testConnection && MonotonicClock.millis() < endTime)
|
||||||
return nread;
|
testConnection();
|
||||||
else
|
|
||||||
return 0;
|
} else {
|
||||||
}
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
|
if (!mUsbRequest.queue(buf, dest.length)) {
|
||||||
@Override
|
throw new IOException("Queueing USB request failed");
|
||||||
public int write(final byte[] src, final int timeout) throws IOException {
|
}
|
||||||
int offset = 0;
|
final UsbRequest response = mConnection.requestWait();
|
||||||
|
if (response == null) {
|
||||||
if(mConnection == null) {
|
throw new IOException("Waiting for USB request failed");
|
||||||
throw new IOException("Connection closed");
|
}
|
||||||
}
|
nread = buf.position();
|
||||||
while (offset < src.length) {
|
// Android error propagation is improvable:
|
||||||
final int writeLength;
|
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
||||||
final int amtWritten;
|
if(nread == 0) {
|
||||||
|
testConnection();
|
||||||
synchronized (mWriteBufferLock) {
|
}
|
||||||
final byte[] writeBuffer;
|
}
|
||||||
|
return Math.max(nread, 0);
|
||||||
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
|
}
|
||||||
if (offset == 0) {
|
|
||||||
writeBuffer = src;
|
@Override
|
||||||
} else {
|
public void write(final byte[] src, final int timeout) throws IOException {
|
||||||
// bulkTransfer does not support offsets, make a copy.
|
int offset = 0;
|
||||||
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
|
final long endTime = (timeout == 0) ? 0 : (MonotonicClock.millis() + timeout);
|
||||||
writeBuffer = mWriteBuffer;
|
|
||||||
}
|
if(mConnection == null) {
|
||||||
|
throw new IOException("Connection closed");
|
||||||
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, timeout);
|
}
|
||||||
}
|
while (offset < src.length) {
|
||||||
if (amtWritten <= 0) {
|
int requestTimeout;
|
||||||
throw new IOException("Error writing " + writeLength
|
final int requestLength;
|
||||||
+ " bytes at offset " + offset + " length=" + src.length);
|
final int actualLength;
|
||||||
}
|
|
||||||
|
synchronized (mWriteBufferLock) {
|
||||||
Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
|
final byte[] writeBuffer;
|
||||||
offset += amtWritten;
|
|
||||||
}
|
requestLength = Math.min(src.length - offset, mWriteBuffer.length);
|
||||||
return offset;
|
if (offset == 0) {
|
||||||
}
|
writeBuffer = src;
|
||||||
|
} else {
|
||||||
@Override
|
// bulkTransfer does not support offsets, make a copy.
|
||||||
public boolean isOpen() {
|
System.arraycopy(src, offset, mWriteBuffer, 0, requestLength);
|
||||||
return mConnection != null;
|
writeBuffer = mWriteBuffer;
|
||||||
}
|
}
|
||||||
|
if (timeout == 0 || offset == 0) {
|
||||||
@Override
|
requestTimeout = timeout;
|
||||||
public abstract void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException;
|
} else {
|
||||||
|
requestTimeout = (int)(endTime - MonotonicClock.millis());
|
||||||
@Override
|
if(requestTimeout == 0)
|
||||||
public boolean getCD() throws IOException { throw new UnsupportedOperationException(); }
|
requestTimeout = -1;
|
||||||
|
}
|
||||||
@Override
|
if (requestTimeout < 0) {
|
||||||
public boolean getCTS() throws IOException { throw new UnsupportedOperationException(); }
|
actualLength = -2;
|
||||||
|
} else {
|
||||||
@Override
|
actualLength = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, requestLength, requestTimeout);
|
||||||
public boolean getDSR() throws IOException { throw new UnsupportedOperationException(); }
|
}
|
||||||
|
}
|
||||||
@Override
|
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout);
|
||||||
public boolean getDTR() throws IOException { throw new UnsupportedOperationException(); }
|
if (actualLength <= 0) {
|
||||||
|
if (timeout != 0 && MonotonicClock.millis() >= endTime) {
|
||||||
@Override
|
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + ", rc=" + actualLength);
|
||||||
public void setDTR(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
ex.bytesTransferred = offset;
|
||||||
|
throw ex;
|
||||||
@Override
|
} else {
|
||||||
public boolean getRI() throws IOException { throw new UnsupportedOperationException(); }
|
throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public boolean getRTS() throws IOException { throw new UnsupportedOperationException(); }
|
offset += actualLength;
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public void setRTS(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
|
||||||
|
@Override
|
||||||
@Override
|
public boolean isOpen() {
|
||||||
public abstract EnumSet<ControlLine> getControlLines() throws IOException;
|
return mConnection != null;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public abstract EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
@Override
|
||||||
|
public abstract void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException;
|
||||||
@Override
|
|
||||||
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
@Override
|
||||||
throw new UnsupportedOperationException();
|
public boolean getCD() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public boolean getCTS() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
public void setBreak(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
|
||||||
|
@Override
|
||||||
}
|
public boolean getDSR() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDTR() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDTR(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getRI() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getRTS() throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRTS(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract EnumSet<ControlLine> getControlLines() throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBreak(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,335 +1,335 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbConstants;
|
import android.hardware.usb.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Cp21xxSerialDriver implements UsbSerialDriver {
|
public class Cp21xxSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
|
private static final String TAG = Cp21xxSerialDriver.class.getSimpleName();
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
private final List<UsbSerialPort> mPorts;
|
private final List<UsbSerialPort> mPorts;
|
||||||
|
|
||||||
public Cp21xxSerialDriver(UsbDevice device) {
|
public Cp21xxSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPorts = new ArrayList<>();
|
mPorts = new ArrayList<>();
|
||||||
for( int port = 0; port < device.getInterfaceCount(); port++) {
|
for( int port = 0; port < device.getInterfaceCount(); port++) {
|
||||||
mPorts.add(new Cp21xxSerialPort(mDevice, port));
|
mPorts.add(new Cp21xxSerialPort(mDevice, port));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbDevice getDevice() {
|
public UsbDevice getDevice() {
|
||||||
return mDevice;
|
return mDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UsbSerialPort> getPorts() {
|
public List<UsbSerialPort> getPorts() {
|
||||||
return mPorts;
|
return mPorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cp21xxSerialPort extends CommonUsbSerialPort {
|
public class Cp21xxSerialPort extends CommonUsbSerialPort {
|
||||||
|
|
||||||
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
|
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration Request Types
|
* Configuration Request Types
|
||||||
*/
|
*/
|
||||||
private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
|
private static final int REQTYPE_HOST_TO_DEVICE = 0x41;
|
||||||
private static final int REQTYPE_DEVICE_TO_HOST = 0xc1;
|
private static final int REQTYPE_DEVICE_TO_HOST = 0xc1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration Request Codes
|
* Configuration Request Codes
|
||||||
*/
|
*/
|
||||||
private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;
|
private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00;
|
||||||
private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;
|
private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03;
|
||||||
private static final int SILABSER_SET_BREAK_REQUEST_CODE = 0x05;
|
private static final int SILABSER_SET_BREAK_REQUEST_CODE = 0x05;
|
||||||
private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;
|
private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07;
|
||||||
private static final int SILABSER_SET_BAUDRATE = 0x1E;
|
private static final int SILABSER_SET_BAUDRATE = 0x1E;
|
||||||
private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;
|
private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12;
|
||||||
private static final int SILABSER_GET_MDMSTS_REQUEST_CODE = 0x08;
|
private static final int SILABSER_GET_MDMSTS_REQUEST_CODE = 0x08;
|
||||||
|
|
||||||
private static final int FLUSH_READ_CODE = 0x0a;
|
private static final int FLUSH_READ_CODE = 0x0a;
|
||||||
private static final int FLUSH_WRITE_CODE = 0x05;
|
private static final int FLUSH_WRITE_CODE = 0x05;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SILABSER_IFC_ENABLE_REQUEST_CODE
|
* SILABSER_IFC_ENABLE_REQUEST_CODE
|
||||||
*/
|
*/
|
||||||
private static final int UART_ENABLE = 0x0001;
|
private static final int UART_ENABLE = 0x0001;
|
||||||
private static final int UART_DISABLE = 0x0000;
|
private static final int UART_DISABLE = 0x0000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SILABSER_SET_MHS_REQUEST_CODE
|
* SILABSER_SET_MHS_REQUEST_CODE
|
||||||
*/
|
*/
|
||||||
private static final int DTR_ENABLE = 0x101;
|
private static final int DTR_ENABLE = 0x101;
|
||||||
private static final int DTR_DISABLE = 0x100;
|
private static final int DTR_DISABLE = 0x100;
|
||||||
private static final int RTS_ENABLE = 0x202;
|
private static final int RTS_ENABLE = 0x202;
|
||||||
private static final int RTS_DISABLE = 0x200;
|
private static final int RTS_DISABLE = 0x200;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SILABSER_GET_MDMSTS_REQUEST_CODE
|
* SILABSER_GET_MDMSTS_REQUEST_CODE
|
||||||
*/
|
*/
|
||||||
private static final int STATUS_CTS = 0x10;
|
private static final int STATUS_CTS = 0x10;
|
||||||
private static final int STATUS_DSR = 0x20;
|
private static final int STATUS_DSR = 0x20;
|
||||||
private static final int STATUS_RI = 0x40;
|
private static final int STATUS_RI = 0x40;
|
||||||
private static final int STATUS_CD = 0x80;
|
private static final int STATUS_CD = 0x80;
|
||||||
|
|
||||||
|
|
||||||
private boolean dtr = false;
|
private boolean dtr = false;
|
||||||
private boolean rts = false;
|
private boolean rts = false;
|
||||||
|
|
||||||
// second port of Cp2105 has limited baudRate, dataBits, stopBits, parity
|
// second port of Cp2105 has limited baudRate, dataBits, stopBits, parity
|
||||||
// unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored
|
// unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored
|
||||||
private boolean mIsRestrictedPort;
|
private boolean mIsRestrictedPort;
|
||||||
|
|
||||||
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
|
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbSerialDriver getDriver() {
|
public UsbSerialDriver getDriver() {
|
||||||
return Cp21xxSerialDriver.this;
|
return Cp21xxSerialDriver.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConfigSingle(int request, int value) throws IOException {
|
private void setConfigSingle(int request, int value) throws IOException {
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value,
|
||||||
mPortNumber, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
mPortNumber, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
throw new IOException("Control transfer failed: " + request + " / " + value + " -> " + result);
|
throw new IOException("Control transfer failed: " + request + " / " + value + " -> " + result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getStatus() throws IOException {
|
private byte getStatus() throws IOException {
|
||||||
byte[] buffer = new byte[1];
|
byte[] buffer = new byte[1];
|
||||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0,
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0,
|
||||||
mPortNumber, buffer, buffer.length, USB_WRITE_TIMEOUT_MILLIS);
|
mPortNumber, buffer, buffer.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
throw new IOException("Control transfer failed: " + SILABSER_GET_MDMSTS_REQUEST_CODE + " / " + 0 + " -> " + result);
|
throw new IOException("Control transfer failed: " + SILABSER_GET_MDMSTS_REQUEST_CODE + " / " + 0 + " -> " + result);
|
||||||
}
|
}
|
||||||
return buffer[0];
|
return buffer[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
||||||
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
||||||
throw new IOException("Unknown port number");
|
throw new IOException("Unknown port number");
|
||||||
}
|
}
|
||||||
UsbInterface dataIface = mDevice.getInterface(mPortNumber);
|
UsbInterface dataIface = mDevice.getInterface(mPortNumber);
|
||||||
if (!mConnection.claimInterface(dataIface, true)) {
|
if (!mConnection.claimInterface(dataIface, true)) {
|
||||||
throw new IOException("Could not claim interface " + mPortNumber);
|
throw new IOException("Could not claim interface " + mPortNumber);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
||||||
mReadEndpoint = ep;
|
mReadEndpoint = ep;
|
||||||
} else {
|
} else {
|
||||||
mWriteEndpoint = ep;
|
mWriteEndpoint = ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);
|
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE);
|
||||||
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, (dtr ? DTR_ENABLE : DTR_DISABLE) | (rts ? RTS_ENABLE : RTS_DISABLE));
|
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, (dtr ? DTR_ENABLE : DTR_DISABLE) | (rts ? RTS_ENABLE : RTS_DISABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeInt() {
|
protected void closeInt() {
|
||||||
try {
|
try {
|
||||||
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
|
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
try {
|
try {
|
||||||
mConnection.releaseInterface(mDevice.getInterface(mPortNumber));
|
mConnection.releaseInterface(mDevice.getInterface(mPortNumber));
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBaudRate(int baudRate) throws IOException {
|
private void setBaudRate(int baudRate) throws IOException {
|
||||||
byte[] data = new byte[] {
|
byte[] data = new byte[] {
|
||||||
(byte) ( baudRate & 0xff),
|
(byte) ( baudRate & 0xff),
|
||||||
(byte) ((baudRate >> 8 ) & 0xff),
|
(byte) ((baudRate >> 8 ) & 0xff),
|
||||||
(byte) ((baudRate >> 16) & 0xff),
|
(byte) ((baudRate >> 16) & 0xff),
|
||||||
(byte) ((baudRate >> 24) & 0xff)
|
(byte) ((baudRate >> 24) & 0xff)
|
||||||
};
|
};
|
||||||
int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
|
int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE,
|
||||||
0, mPortNumber, data, 4, USB_WRITE_TIMEOUT_MILLIS);
|
0, mPortNumber, data, 4, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Error setting baud rate");
|
throw new IOException("Error setting baud rate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||||
if(baudRate <= 0) {
|
if(baudRate <= 0) {
|
||||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||||
}
|
}
|
||||||
setBaudRate(baudRate);
|
setBaudRate(baudRate);
|
||||||
|
|
||||||
int configDataBits = 0;
|
int configDataBits = 0;
|
||||||
switch (dataBits) {
|
switch (dataBits) {
|
||||||
case DATABITS_5:
|
case DATABITS_5:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
||||||
configDataBits |= 0x0500;
|
configDataBits |= 0x0500;
|
||||||
break;
|
break;
|
||||||
case DATABITS_6:
|
case DATABITS_6:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
||||||
configDataBits |= 0x0600;
|
configDataBits |= 0x0600;
|
||||||
break;
|
break;
|
||||||
case DATABITS_7:
|
case DATABITS_7:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
||||||
configDataBits |= 0x0700;
|
configDataBits |= 0x0700;
|
||||||
break;
|
break;
|
||||||
case DATABITS_8:
|
case DATABITS_8:
|
||||||
configDataBits |= 0x0800;
|
configDataBits |= 0x0800;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parity) {
|
switch (parity) {
|
||||||
case PARITY_NONE:
|
case PARITY_NONE:
|
||||||
break;
|
break;
|
||||||
case PARITY_ODD:
|
case PARITY_ODD:
|
||||||
configDataBits |= 0x0010;
|
configDataBits |= 0x0010;
|
||||||
break;
|
break;
|
||||||
case PARITY_EVEN:
|
case PARITY_EVEN:
|
||||||
configDataBits |= 0x0020;
|
configDataBits |= 0x0020;
|
||||||
break;
|
break;
|
||||||
case PARITY_MARK:
|
case PARITY_MARK:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported parity: mark");
|
throw new UnsupportedOperationException("Unsupported parity: mark");
|
||||||
configDataBits |= 0x0030;
|
configDataBits |= 0x0030;
|
||||||
break;
|
break;
|
||||||
case PARITY_SPACE:
|
case PARITY_SPACE:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported parity: space");
|
throw new UnsupportedOperationException("Unsupported parity: space");
|
||||||
configDataBits |= 0x0040;
|
configDataBits |= 0x0040;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid parity: " + parity);
|
throw new IllegalArgumentException("Invalid parity: " + parity);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (stopBits) {
|
switch (stopBits) {
|
||||||
case STOPBITS_1:
|
case STOPBITS_1:
|
||||||
break;
|
break;
|
||||||
case STOPBITS_1_5:
|
case STOPBITS_1_5:
|
||||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
||||||
case STOPBITS_2:
|
case STOPBITS_2:
|
||||||
if(mIsRestrictedPort)
|
if(mIsRestrictedPort)
|
||||||
throw new UnsupportedOperationException("Unsupported stop bits: 2");
|
throw new UnsupportedOperationException("Unsupported stop bits: 2");
|
||||||
configDataBits |= 2;
|
configDataBits |= 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
||||||
}
|
}
|
||||||
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
|
setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCD() throws IOException {
|
public boolean getCD() throws IOException {
|
||||||
return (getStatus() & STATUS_CD) != 0;
|
return (getStatus() & STATUS_CD) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getCTS() throws IOException {
|
public boolean getCTS() throws IOException {
|
||||||
return (getStatus() & STATUS_CTS) != 0;
|
return (getStatus() & STATUS_CTS) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDSR() throws IOException {
|
public boolean getDSR() throws IOException {
|
||||||
return (getStatus() & STATUS_DSR) != 0;
|
return (getStatus() & STATUS_DSR) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDTR() throws IOException {
|
public boolean getDTR() throws IOException {
|
||||||
return dtr;
|
return dtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDTR(boolean value) throws IOException {
|
public void setDTR(boolean value) throws IOException {
|
||||||
dtr = value;
|
dtr = value;
|
||||||
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, dtr ? DTR_ENABLE : DTR_DISABLE);
|
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, dtr ? DTR_ENABLE : DTR_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRI() throws IOException {
|
public boolean getRI() throws IOException {
|
||||||
return (getStatus() & STATUS_RI) != 0;
|
return (getStatus() & STATUS_RI) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRTS() throws IOException {
|
public boolean getRTS() throws IOException {
|
||||||
return rts;
|
return rts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRTS(boolean value) throws IOException {
|
public void setRTS(boolean value) throws IOException {
|
||||||
rts = value;
|
rts = value;
|
||||||
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, rts ? RTS_ENABLE : RTS_DISABLE);
|
setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, rts ? RTS_ENABLE : RTS_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||||
byte status = getStatus();
|
byte status = getStatus();
|
||||||
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||||
if(rts) set.add(ControlLine.RTS);
|
if(rts) set.add(ControlLine.RTS);
|
||||||
if((status & STATUS_CTS) != 0) set.add(ControlLine.CTS);
|
if((status & STATUS_CTS) != 0) set.add(ControlLine.CTS);
|
||||||
if(dtr) set.add(ControlLine.DTR);
|
if(dtr) set.add(ControlLine.DTR);
|
||||||
if((status & STATUS_DSR) != 0) set.add(ControlLine.DSR);
|
if((status & STATUS_DSR) != 0) set.add(ControlLine.DSR);
|
||||||
if((status & STATUS_CD) != 0) set.add(ControlLine.CD);
|
if((status & STATUS_CD) != 0) set.add(ControlLine.CD);
|
||||||
if((status & STATUS_RI) != 0) set.add(ControlLine.RI);
|
if((status & STATUS_RI) != 0) set.add(ControlLine.RI);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||||
return EnumSet.allOf(ControlLine.class);
|
return EnumSet.allOf(ControlLine.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// note: only working on some devices, on other devices ignored w/o error
|
// note: only working on some devices, on other devices ignored w/o error
|
||||||
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
|
int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0)
|
||||||
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
|
| (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);
|
||||||
|
|
||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
|
setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBreak(boolean value) throws IOException {
|
public void setBreak(boolean value) throws IOException {
|
||||||
setConfigSingle(SILABSER_SET_BREAK_REQUEST_CODE, value ? 1 : 0);
|
setConfigSingle(SILABSER_SET_BREAK_REQUEST_CODE, value ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_SILABS,
|
supportedDevices.put(UsbId.VENDOR_SILABS,
|
||||||
new int[] {
|
new int[] {
|
||||||
UsbId.SILABS_CP2102, // same ID for CP2101, CP2103, CP2104, CP2109
|
UsbId.SILABS_CP2102, // same ID for CP2101, CP2103, CP2104, CP2109
|
||||||
UsbId.SILABS_CP2105,
|
UsbId.SILABS_CP2105,
|
||||||
UsbId.SILABS_CP2108,
|
UsbId.SILABS_CP2108,
|
||||||
});
|
});
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,428 +1,430 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
* Copyright 2020 kai morich <mail@kai-morich.de>
|
* Copyright 2020 kai morich <mail@kai-morich.de>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbConstants;
|
import android.hardware.usb.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
import org.emulator.calculator.usbserial.util.MonotonicClock;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.EnumSet;
|
import java.io.IOException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.EnumSet;
|
||||||
import java.util.Map;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
/*
|
import java.util.Map;
|
||||||
* driver is implemented from various information scattered over FTDI documentation
|
|
||||||
*
|
/*
|
||||||
* baud rate calculation https://www.ftdichip.com/Support/Documents/AppNotes/AN232B-05_BaudRates.pdf
|
* driver is implemented from various information scattered over FTDI documentation
|
||||||
* 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
|
* 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
|
||||||
|
*
|
||||||
public class FtdiSerialDriver implements UsbSerialDriver {
|
*/
|
||||||
|
|
||||||
private static final String TAG = FtdiSerialPort.class.getSimpleName();
|
public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private static final String TAG = FtdiSerialPort.class.getSimpleName();
|
||||||
private final List<UsbSerialPort> mPorts;
|
|
||||||
|
private final UsbDevice mDevice;
|
||||||
public FtdiSerialDriver(UsbDevice device) {
|
private final List<UsbSerialPort> mPorts;
|
||||||
mDevice = device;
|
|
||||||
mPorts = new ArrayList<>();
|
public FtdiSerialDriver(UsbDevice device) {
|
||||||
for( int port = 0; port < device.getInterfaceCount(); port++) {
|
mDevice = device;
|
||||||
mPorts.add(new FtdiSerialPort(mDevice, port));
|
mPorts = new ArrayList<>();
|
||||||
}
|
for( int port = 0; port < device.getInterfaceCount(); port++) {
|
||||||
}
|
mPorts.add(new FtdiSerialPort(mDevice, port));
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public UsbDevice getDevice() {
|
|
||||||
return mDevice;
|
@Override
|
||||||
}
|
public UsbDevice getDevice() {
|
||||||
|
return mDevice;
|
||||||
@Override
|
}
|
||||||
public List<UsbSerialPort> getPorts() {
|
|
||||||
return mPorts;
|
@Override
|
||||||
}
|
public List<UsbSerialPort> getPorts() {
|
||||||
|
return mPorts;
|
||||||
public class FtdiSerialPort extends CommonUsbSerialPort {
|
}
|
||||||
|
|
||||||
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
|
public class FtdiSerialPort extends CommonUsbSerialPort {
|
||||||
private static final int READ_HEADER_LENGTH = 2; // contains MODEM_STATUS
|
|
||||||
|
private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
|
||||||
private static final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
private static final int READ_HEADER_LENGTH = 2; // contains MODEM_STATUS
|
||||||
private static final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
|
||||||
|
private static final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
||||||
private static final int RESET_REQUEST = 0;
|
private static final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
||||||
private static final int MODEM_CONTROL_REQUEST = 1;
|
|
||||||
private static final int SET_BAUD_RATE_REQUEST = 3;
|
private static final int RESET_REQUEST = 0;
|
||||||
private static final int SET_DATA_REQUEST = 4;
|
private static final int MODEM_CONTROL_REQUEST = 1;
|
||||||
private static final int GET_MODEM_STATUS_REQUEST = 5;
|
private static final int SET_BAUD_RATE_REQUEST = 3;
|
||||||
private static final int SET_LATENCY_TIMER_REQUEST = 9;
|
private static final int SET_DATA_REQUEST = 4;
|
||||||
private static final int GET_LATENCY_TIMER_REQUEST = 10;
|
private static final int GET_MODEM_STATUS_REQUEST = 5;
|
||||||
|
private static final int SET_LATENCY_TIMER_REQUEST = 9;
|
||||||
private static final int MODEM_CONTROL_DTR_ENABLE = 0x0101;
|
private static final int GET_LATENCY_TIMER_REQUEST = 10;
|
||||||
private static final int MODEM_CONTROL_DTR_DISABLE = 0x0100;
|
|
||||||
private static final int MODEM_CONTROL_RTS_ENABLE = 0x0202;
|
private static final int MODEM_CONTROL_DTR_ENABLE = 0x0101;
|
||||||
private static final int MODEM_CONTROL_RTS_DISABLE = 0x0200;
|
private static final int MODEM_CONTROL_DTR_DISABLE = 0x0100;
|
||||||
private static final int MODEM_STATUS_CTS = 0x10;
|
private static final int MODEM_CONTROL_RTS_ENABLE = 0x0202;
|
||||||
private static final int MODEM_STATUS_DSR = 0x20;
|
private static final int MODEM_CONTROL_RTS_DISABLE = 0x0200;
|
||||||
private static final int MODEM_STATUS_RI = 0x40;
|
private static final int MODEM_STATUS_CTS = 0x10;
|
||||||
private static final int MODEM_STATUS_CD = 0x80;
|
private static final int MODEM_STATUS_DSR = 0x20;
|
||||||
private static final int RESET_ALL = 0;
|
private static final int MODEM_STATUS_RI = 0x40;
|
||||||
private static final int RESET_PURGE_RX = 1;
|
private static final int MODEM_STATUS_CD = 0x80;
|
||||||
private static final int RESET_PURGE_TX = 2;
|
private static final int RESET_ALL = 0;
|
||||||
|
private static final int RESET_PURGE_RX = 1;
|
||||||
private boolean baudRateWithPort = false;
|
private static final int RESET_PURGE_TX = 2;
|
||||||
private boolean dtr = false;
|
|
||||||
private boolean rts = false;
|
private boolean baudRateWithPort = false;
|
||||||
private int breakConfig = 0;
|
private boolean dtr = false;
|
||||||
|
private boolean rts = false;
|
||||||
public FtdiSerialPort(UsbDevice device, int portNumber) {
|
private int breakConfig = 0;
|
||||||
super(device, portNumber);
|
|
||||||
}
|
public FtdiSerialPort(UsbDevice device, int portNumber) {
|
||||||
|
super(device, portNumber);
|
||||||
@Override
|
}
|
||||||
public UsbSerialDriver getDriver() {
|
|
||||||
return FtdiSerialDriver.this;
|
@Override
|
||||||
}
|
public UsbSerialDriver getDriver() {
|
||||||
|
return FtdiSerialDriver.this;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
|
||||||
if (!connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
@Override
|
||||||
throw new IOException("Could not claim interface " + mPortNumber);
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
}
|
if (!connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
||||||
if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) {
|
throw new IOException("Could not claim interface " + mPortNumber);
|
||||||
throw new IOException("Not enough endpoints");
|
}
|
||||||
}
|
if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) {
|
||||||
mReadEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(0);
|
throw new IOException("Not enough endpoints");
|
||||||
mWriteEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(1);
|
}
|
||||||
|
mReadEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(0);
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
mWriteEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(1);
|
||||||
RESET_ALL, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
||||||
throw new IOException("Reset failed: result=" + result);
|
RESET_ALL, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
throw new IOException("Reset failed: result=" + result);
|
||||||
(dtr ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE) |
|
}
|
||||||
(rts ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE),
|
result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
||||||
mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
(dtr ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE) |
|
||||||
if (result != 0) {
|
(rts ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE),
|
||||||
throw new IOException("Init RTS,DTR failed: result=" + result);
|
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) {
|
// mDevice.getVersion() would require API 23
|
||||||
throw new IOException("Could not get device descriptors");
|
byte[] rawDescriptors = connection.getRawDescriptors();
|
||||||
}
|
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
||||||
int deviceType = rawDescriptors[13];
|
throw new IOException("Could not get device descriptors");
|
||||||
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9; // ...H devices
|
}
|
||||||
}
|
int deviceType = rawDescriptors[13];
|
||||||
|
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9; // ...H devices
|
||||||
@Override
|
}
|
||||||
protected void closeInt() {
|
|
||||||
try {
|
@Override
|
||||||
mConnection.releaseInterface(mDevice.getInterface(mPortNumber));
|
protected void closeInt() {
|
||||||
} catch(Exception ignored) {}
|
try {
|
||||||
}
|
mConnection.releaseInterface(mDevice.getInterface(mPortNumber));
|
||||||
|
} catch(Exception ignored) {}
|
||||||
@Override
|
}
|
||||||
public int read(final byte[] dest, final int timeout) throws IOException {
|
|
||||||
if(dest.length <= READ_HEADER_LENGTH) {
|
@Override
|
||||||
throw new IllegalArgumentException("Read buffer to small");
|
public int read(final byte[] dest, final int timeout) throws IOException {
|
||||||
// could allocate larger buffer, including space for 2 header bytes, but this would
|
if(dest.length <= READ_HEADER_LENGTH) {
|
||||||
// result in buffers not being 64 byte aligned any more, causing data loss at continuous
|
throw new IllegalArgumentException("Read buffer to small");
|
||||||
// data transfer at high baud rates when buffers are fully filled.
|
// could allocate larger buffer, including space for 2 header bytes, but this would
|
||||||
}
|
// result in buffers not being 64 byte aligned any more, causing data loss at continuous
|
||||||
int nread;
|
// data transfer at high baud rates when buffers are fully filled.
|
||||||
if (timeout != 0) {
|
}
|
||||||
long endTime = System.currentTimeMillis() + timeout;
|
int nread;
|
||||||
do {
|
if (timeout != 0) {
|
||||||
nread = super.read(dest, Math.max(1, (int)(endTime - System.currentTimeMillis())), false);
|
long endTime = MonotonicClock.millis() + timeout;
|
||||||
} while (nread == READ_HEADER_LENGTH && System.currentTimeMillis() < endTime);
|
do {
|
||||||
if(nread <= 0 && System.currentTimeMillis() < endTime)
|
nread = super.read(dest, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
|
||||||
testConnection();
|
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
|
||||||
} else {
|
if(nread <= 0 && MonotonicClock.millis() < endTime)
|
||||||
do {
|
testConnection();
|
||||||
nread = super.read(dest, timeout, false);
|
} else {
|
||||||
} while (nread == READ_HEADER_LENGTH);
|
do {
|
||||||
}
|
nread = super.read(dest, timeout, false);
|
||||||
return readFilter(dest, nread);
|
} while (nread == READ_HEADER_LENGTH);
|
||||||
}
|
}
|
||||||
|
return readFilter(dest, nread);
|
||||||
private int readFilter(byte[] buffer, int totalBytesRead) throws IOException {
|
}
|
||||||
final int maxPacketSize = mReadEndpoint.getMaxPacketSize();
|
|
||||||
int destPos = 0;
|
protected int readFilter(byte[] buffer, int totalBytesRead) throws IOException {
|
||||||
for(int srcPos = 0; srcPos < totalBytesRead; srcPos += maxPacketSize) {
|
final int maxPacketSize = mReadEndpoint.getMaxPacketSize();
|
||||||
int length = Math.min(srcPos + maxPacketSize, totalBytesRead) - (srcPos + READ_HEADER_LENGTH);
|
int destPos = 0;
|
||||||
if (length < 0)
|
for(int srcPos = 0; srcPos < totalBytesRead; srcPos += maxPacketSize) {
|
||||||
throw new IOException("Expected at least " + READ_HEADER_LENGTH + " bytes");
|
int length = Math.min(srcPos + maxPacketSize, totalBytesRead) - (srcPos + READ_HEADER_LENGTH);
|
||||||
System.arraycopy(buffer, srcPos + READ_HEADER_LENGTH, buffer, destPos, length);
|
if (length < 0)
|
||||||
destPos += length;
|
throw new IOException("Expected at least " + READ_HEADER_LENGTH + " bytes");
|
||||||
}
|
System.arraycopy(buffer, srcPos + READ_HEADER_LENGTH, buffer, destPos, length);
|
||||||
//Log.d(TAG, "read filter " + totalBytesRead + " -> " + destPos);
|
destPos += length;
|
||||||
return destPos;
|
}
|
||||||
}
|
//Log.d(TAG, "read filter " + totalBytesRead + " -> " + destPos);
|
||||||
|
return destPos;
|
||||||
private void setBaudrate(int baudRate) throws IOException {
|
}
|
||||||
int divisor, subdivisor, effectiveBaudRate;
|
|
||||||
if (baudRate > 3500000) {
|
private void setBaudrate(int baudRate) throws IOException {
|
||||||
throw new UnsupportedOperationException("Baud rate to high");
|
int divisor, subdivisor, effectiveBaudRate;
|
||||||
} else if(baudRate >= 2500000) {
|
if (baudRate > 3500000) {
|
||||||
divisor = 0;
|
throw new UnsupportedOperationException("Baud rate to high");
|
||||||
subdivisor = 0;
|
} else if(baudRate >= 2500000) {
|
||||||
effectiveBaudRate = 3000000;
|
divisor = 0;
|
||||||
} else if(baudRate >= 1750000) {
|
subdivisor = 0;
|
||||||
divisor = 1;
|
effectiveBaudRate = 3000000;
|
||||||
subdivisor = 0;
|
} else if(baudRate >= 1750000) {
|
||||||
effectiveBaudRate = 2000000;
|
divisor = 1;
|
||||||
} else {
|
subdivisor = 0;
|
||||||
divisor = (24000000 << 1) / baudRate;
|
effectiveBaudRate = 2000000;
|
||||||
divisor = (divisor + 1) >> 1; // round
|
} else {
|
||||||
subdivisor = divisor & 0x07;
|
divisor = (24000000 << 1) / baudRate;
|
||||||
divisor >>= 3;
|
divisor = (divisor + 1) >> 1; // round
|
||||||
if (divisor > 0x3fff) // exceeds bit 13 at 183 baud
|
subdivisor = divisor & 0x07;
|
||||||
throw new UnsupportedOperationException("Baud rate to low");
|
divisor >>= 3;
|
||||||
effectiveBaudRate = (24000000 << 1) / ((divisor << 3) + subdivisor);
|
if (divisor > 0x3fff) // exceeds bit 13 at 183 baud
|
||||||
effectiveBaudRate = (effectiveBaudRate +1) >> 1;
|
throw new UnsupportedOperationException("Baud rate to low");
|
||||||
}
|
effectiveBaudRate = (24000000 << 1) / ((divisor << 3) + subdivisor);
|
||||||
double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate));
|
effectiveBaudRate = (effectiveBaudRate +1) >> 1;
|
||||||
if(baudRateError >= 0.031) // can happen only > 1.5Mbaud
|
}
|
||||||
throw new UnsupportedOperationException(String.format("Baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100));
|
double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate));
|
||||||
int value = divisor;
|
if(baudRateError >= 0.031) // can happen only > 1.5Mbaud
|
||||||
int index = 0;
|
throw new UnsupportedOperationException(String.format("Baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100));
|
||||||
switch(subdivisor) {
|
int value = divisor;
|
||||||
case 0: break; // 16,15,14 = 000 - sub-integer divisor = 0
|
int index = 0;
|
||||||
case 4: value |= 0x4000; break; // 16,15,14 = 001 - sub-integer divisor = 0.5
|
switch(subdivisor) {
|
||||||
case 2: value |= 0x8000; break; // 16,15,14 = 010 - sub-integer divisor = 0.25
|
case 0: break; // 16,15,14 = 000 - sub-integer divisor = 0
|
||||||
case 1: value |= 0xc000; break; // 16,15,14 = 011 - sub-integer divisor = 0.125
|
case 4: value |= 0x4000; break; // 16,15,14 = 001 - sub-integer divisor = 0.5
|
||||||
case 3: value |= 0x0000; index |= 1; break; // 16,15,14 = 100 - sub-integer divisor = 0.375
|
case 2: value |= 0x8000; break; // 16,15,14 = 010 - sub-integer divisor = 0.25
|
||||||
case 5: value |= 0x4000; index |= 1; break; // 16,15,14 = 101 - sub-integer divisor = 0.625
|
case 1: value |= 0xc000; break; // 16,15,14 = 011 - sub-integer divisor = 0.125
|
||||||
case 6: value |= 0x8000; index |= 1; break; // 16,15,14 = 110 - sub-integer divisor = 0.75
|
case 3: value |= 0x0000; index |= 1; break; // 16,15,14 = 100 - sub-integer divisor = 0.375
|
||||||
case 7: value |= 0xc000; index |= 1; break; // 16,15,14 = 111 - sub-integer divisor = 0.875
|
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
|
||||||
if(baudRateWithPort) {
|
case 7: value |= 0xc000; index |= 1; break; // 16,15,14 = 111 - sub-integer divisor = 0.875
|
||||||
index <<= 8;
|
}
|
||||||
index |= mPortNumber+1;
|
if(baudRateWithPort) {
|
||||||
}
|
index <<= 8;
|
||||||
Log.d(TAG, String.format("baud rate=%d, effective=%d, error=%.1f%%, value=0x%04x, index=0x%04x, divisor=%d, subdivisor=%d",
|
index |= mPortNumber+1;
|
||||||
baudRate, effectiveBaudRate, baudRateError*100, value, index, divisor, subdivisor));
|
}
|
||||||
|
Log.d(TAG, String.format("baud rate=%d, effective=%d, error=%.1f%%, value=0x%04x, index=0x%04x, divisor=%d, subdivisor=%d",
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_BAUD_RATE_REQUEST,
|
baudRate, effectiveBaudRate, baudRateError*100, value, index, divisor, subdivisor));
|
||||||
value, index, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_BAUD_RATE_REQUEST,
|
||||||
throw new IOException("Setting baudrate failed: result=" + result);
|
value, index, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
}
|
throw new IOException("Setting baudrate failed: result=" + result);
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
|
||||||
if(baudRate <= 0) {
|
@Override
|
||||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||||
}
|
if(baudRate <= 0) {
|
||||||
setBaudrate(baudRate);
|
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||||
|
}
|
||||||
int config = 0;
|
setBaudrate(baudRate);
|
||||||
switch (dataBits) {
|
|
||||||
case DATABITS_5:
|
int config = 0;
|
||||||
case DATABITS_6:
|
switch (dataBits) {
|
||||||
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
case DATABITS_5:
|
||||||
case DATABITS_7:
|
case DATABITS_6:
|
||||||
case DATABITS_8:
|
throw new UnsupportedOperationException("Unsupported data bits: " + dataBits);
|
||||||
config |= dataBits;
|
case DATABITS_7:
|
||||||
break;
|
case DATABITS_8:
|
||||||
default:
|
config |= dataBits;
|
||||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
break;
|
||||||
}
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||||
switch (parity) {
|
}
|
||||||
case PARITY_NONE:
|
|
||||||
break;
|
switch (parity) {
|
||||||
case PARITY_ODD:
|
case PARITY_NONE:
|
||||||
config |= 0x100;
|
break;
|
||||||
break;
|
case PARITY_ODD:
|
||||||
case PARITY_EVEN:
|
config |= 0x100;
|
||||||
config |= 0x200;
|
break;
|
||||||
break;
|
case PARITY_EVEN:
|
||||||
case PARITY_MARK:
|
config |= 0x200;
|
||||||
config |= 0x300;
|
break;
|
||||||
break;
|
case PARITY_MARK:
|
||||||
case PARITY_SPACE:
|
config |= 0x300;
|
||||||
config |= 0x400;
|
break;
|
||||||
break;
|
case PARITY_SPACE:
|
||||||
default:
|
config |= 0x400;
|
||||||
throw new IllegalArgumentException("Invalid parity: " + parity);
|
break;
|
||||||
}
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid parity: " + parity);
|
||||||
switch (stopBits) {
|
}
|
||||||
case STOPBITS_1:
|
|
||||||
break;
|
switch (stopBits) {
|
||||||
case STOPBITS_1_5:
|
case STOPBITS_1:
|
||||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
break;
|
||||||
case STOPBITS_2:
|
case STOPBITS_1_5:
|
||||||
config |= 0x1000;
|
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
||||||
break;
|
case STOPBITS_2:
|
||||||
default:
|
config |= 0x1000;
|
||||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
break;
|
||||||
}
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_DATA_REQUEST,
|
}
|
||||||
config, mPortNumber+1,null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_DATA_REQUEST,
|
||||||
throw new IOException("Setting parameters failed: result=" + result);
|
config, mPortNumber+1,null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
breakConfig = config;
|
throw new IOException("Setting parameters failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
breakConfig = config;
|
||||||
private int getStatus() throws IOException {
|
}
|
||||||
byte[] data = new byte[2];
|
|
||||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST,
|
private int getStatus() throws IOException {
|
||||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
byte[] data = new byte[2];
|
||||||
if (result != 2) {
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST,
|
||||||
throw new IOException("Get modem status failed: result=" + result);
|
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 2) {
|
||||||
return data[0];
|
throw new IOException("Get modem status failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
return data[0];
|
||||||
@Override
|
}
|
||||||
public boolean getCD() throws IOException {
|
|
||||||
return (getStatus() & MODEM_STATUS_CD) != 0;
|
@Override
|
||||||
}
|
public boolean getCD() throws IOException {
|
||||||
|
return (getStatus() & MODEM_STATUS_CD) != 0;
|
||||||
@Override
|
}
|
||||||
public boolean getCTS() throws IOException {
|
|
||||||
return (getStatus() & MODEM_STATUS_CTS) != 0;
|
@Override
|
||||||
}
|
public boolean getCTS() throws IOException {
|
||||||
|
return (getStatus() & MODEM_STATUS_CTS) != 0;
|
||||||
@Override
|
}
|
||||||
public boolean getDSR() throws IOException {
|
|
||||||
return (getStatus() & MODEM_STATUS_DSR) != 0;
|
@Override
|
||||||
}
|
public boolean getDSR() throws IOException {
|
||||||
|
return (getStatus() & MODEM_STATUS_DSR) != 0;
|
||||||
@Override
|
}
|
||||||
public boolean getDTR() throws IOException {
|
|
||||||
return dtr;
|
@Override
|
||||||
}
|
public boolean getDTR() throws IOException {
|
||||||
|
return dtr;
|
||||||
@Override
|
}
|
||||||
public void setDTR(boolean value) throws IOException {
|
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
@Override
|
||||||
value ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
public void setDTR(boolean value) throws IOException {
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
||||||
throw new IOException("Set DTR failed: result=" + result);
|
value ? MODEM_CONTROL_DTR_ENABLE : MODEM_CONTROL_DTR_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
dtr = value;
|
throw new IOException("Set DTR failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
dtr = value;
|
||||||
@Override
|
}
|
||||||
public boolean getRI() throws IOException {
|
|
||||||
return (getStatus() & MODEM_STATUS_RI) != 0;
|
@Override
|
||||||
}
|
public boolean getRI() throws IOException {
|
||||||
|
return (getStatus() & MODEM_STATUS_RI) != 0;
|
||||||
@Override
|
}
|
||||||
public boolean getRTS() throws IOException {
|
|
||||||
return rts;
|
@Override
|
||||||
}
|
public boolean getRTS() throws IOException {
|
||||||
|
return rts;
|
||||||
@Override
|
}
|
||||||
public void setRTS(boolean value) throws IOException {
|
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
@Override
|
||||||
value ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
public void setRTS(boolean value) throws IOException {
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, MODEM_CONTROL_REQUEST,
|
||||||
throw new IOException("Set DTR failed: result=" + result);
|
value ? MODEM_CONTROL_RTS_ENABLE : MODEM_CONTROL_RTS_DISABLE, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
rts = value;
|
throw new IOException("Set DTR failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
rts = value;
|
||||||
@Override
|
}
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
|
||||||
int status = getStatus();
|
@Override
|
||||||
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||||
if(rts) set.add(ControlLine.RTS);
|
int status = getStatus();
|
||||||
if((status & MODEM_STATUS_CTS) != 0) set.add(ControlLine.CTS);
|
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||||
if(dtr) set.add(ControlLine.DTR);
|
if(rts) set.add(ControlLine.RTS);
|
||||||
if((status & MODEM_STATUS_DSR) != 0) set.add(ControlLine.DSR);
|
if((status & MODEM_STATUS_CTS) != 0) set.add(ControlLine.CTS);
|
||||||
if((status & MODEM_STATUS_CD) != 0) set.add(ControlLine.CD);
|
if(dtr) set.add(ControlLine.DTR);
|
||||||
if((status & MODEM_STATUS_RI) != 0) set.add(ControlLine.RI);
|
if((status & MODEM_STATUS_DSR) != 0) set.add(ControlLine.DSR);
|
||||||
return set;
|
if((status & MODEM_STATUS_CD) != 0) set.add(ControlLine.CD);
|
||||||
}
|
if((status & MODEM_STATUS_RI) != 0) set.add(ControlLine.RI);
|
||||||
|
return set;
|
||||||
@Override
|
}
|
||||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
|
||||||
return EnumSet.allOf(ControlLine.class);
|
@Override
|
||||||
}
|
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||||
|
return EnumSet.allOf(ControlLine.class);
|
||||||
@Override
|
}
|
||||||
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
|
||||||
if (purgeWriteBuffers) {
|
@Override
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
|
||||||
RESET_PURGE_RX, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
if (purgeWriteBuffers) {
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
||||||
throw new IOException("Purge write buffer failed: result=" + result);
|
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(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
|
||||||
RESET_PURGE_TX, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
if (purgeReadBuffers) {
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, RESET_REQUEST,
|
||||||
throw new IOException("Purge read buffer failed: result=" + result);
|
RESET_PURGE_TX, mPortNumber+1, null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
}
|
throw new IOException("Purge read buffer failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public void setBreak(boolean value) throws IOException {
|
|
||||||
int config = breakConfig;
|
@Override
|
||||||
if(value) config |= 0x4000;
|
public void setBreak(boolean value) throws IOException {
|
||||||
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_DATA_REQUEST,
|
int config = breakConfig;
|
||||||
config, mPortNumber+1,null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
if(value) config |= 0x4000;
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_DATA_REQUEST,
|
||||||
throw new IOException("Setting BREAK failed: result=" + result);
|
config, mPortNumber+1,null, 0, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 0) {
|
||||||
}
|
throw new IOException("Setting BREAK failed: result=" + result);
|
||||||
|
}
|
||||||
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);
|
public void setLatencyTimer(int latencyTime) throws IOException {
|
||||||
if (result != 0) {
|
int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SET_LATENCY_TIMER_REQUEST,
|
||||||
throw new IOException("Set latency timer failed: result=" + result);
|
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,
|
public int getLatencyTimer() throws IOException {
|
||||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
byte[] data = new byte[1];
|
||||||
if (result != 1) {
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_LATENCY_TIMER_REQUEST,
|
||||||
throw new IOException("Get latency timer failed: result=" + result);
|
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
}
|
if (result != 1) {
|
||||||
return data[0];
|
throw new IOException("Get latency timer failed: result=" + result);
|
||||||
}
|
}
|
||||||
|
return data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
}
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
|
|
||||||
supportedDevices.put(UsbId.VENDOR_FTDI,
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
new int[] {
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
UsbId.FTDI_FT232R,
|
supportedDevices.put(UsbId.VENDOR_FTDI,
|
||||||
UsbId.FTDI_FT232H,
|
new int[] {
|
||||||
UsbId.FTDI_FT2232H,
|
UsbId.FTDI_FT232R,
|
||||||
UsbId.FTDI_FT4232H,
|
UsbId.FTDI_FT232H,
|
||||||
UsbId.FTDI_FT231X, // same ID for FT230X, FT231X, FT234XD
|
UsbId.FTDI_FT2232H,
|
||||||
});
|
UsbId.FTDI_FT4232H,
|
||||||
return supportedDevices;
|
UsbId.FTDI_FT231X, // same ID for FT230X, FT231X, FT234XD
|
||||||
}
|
});
|
||||||
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,87 +1,87 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps (vendor id, product id) pairs to the corresponding serial driver.
|
* Maps (vendor id, product id) pairs to the corresponding serial driver.
|
||||||
*
|
*
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public class ProbeTable {
|
public class ProbeTable {
|
||||||
|
|
||||||
private final Map<Pair<Integer, Integer>, Class<? extends UsbSerialDriver>> mProbeTable =
|
private final Map<Pair<Integer, Integer>, Class<? extends UsbSerialDriver>> mProbeTable =
|
||||||
new LinkedHashMap<Pair<Integer,Integer>, Class<? extends UsbSerialDriver>>();
|
new LinkedHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates a (vendor, product) pair in the table.
|
* Adds or updates a (vendor, product) pair in the table.
|
||||||
*
|
*
|
||||||
* @param vendorId the USB vendor id
|
* @param vendorId the USB vendor id
|
||||||
* @param productId the USB product id
|
* @param productId the USB product id
|
||||||
* @param driverClass the driver class responsible for this pair
|
* @param driverClass the driver class responsible for this pair
|
||||||
* @return {@code this}, for chaining
|
* @return {@code this}, for chaining
|
||||||
*/
|
*/
|
||||||
public ProbeTable addProduct(int vendorId, int productId,
|
public ProbeTable addProduct(int vendorId, int productId,
|
||||||
Class<? extends UsbSerialDriver> driverClass) {
|
Class<? extends UsbSerialDriver> driverClass) {
|
||||||
mProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
mProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method to add all supported products from
|
* Internal method to add all supported products from
|
||||||
* {@code getSupportedProducts} static method.
|
* {@code getSupportedProducts} static method.
|
||||||
*
|
*
|
||||||
* @param driverClass
|
* @param driverClass
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ProbeTable addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
ProbeTable addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
||||||
final Method method;
|
final Method method;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
method = driverClass.getMethod("getSupportedDevices");
|
method = driverClass.getMethod("getSupportedDevices");
|
||||||
} catch (SecurityException | NoSuchMethodException e) {
|
} catch (SecurityException | NoSuchMethodException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<Integer, int[]> devices;
|
final Map<Integer, int[]> devices;
|
||||||
try {
|
try {
|
||||||
devices = (Map<Integer, int[]>) method.invoke(null);
|
devices = (Map<Integer, int[]>) method.invoke(null);
|
||||||
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
|
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<Integer, int[]> entry : devices.entrySet()) {
|
for (Map.Entry<Integer, int[]> entry : devices.entrySet()) {
|
||||||
final int vendorId = entry.getKey();
|
final int vendorId = entry.getKey();
|
||||||
for (int productId : entry.getValue()) {
|
for (int productId : entry.getValue()) {
|
||||||
addProduct(vendorId, productId, driverClass);
|
addProduct(vendorId, productId, driverClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the driver for the given (vendor, product) pair, or {@code null}
|
* Returns the driver for the given (vendor, product) pair, or {@code null}
|
||||||
* if no match.
|
* if no match.
|
||||||
*
|
*
|
||||||
* @param vendorId the USB vendor id
|
* @param vendorId the USB vendor id
|
||||||
* @param productId the USB product id
|
* @param productId the USB product id
|
||||||
* @return the driver class matching this pair, or {@code null}
|
* @return the driver class matching this pair, or {@code null}
|
||||||
*/
|
*/
|
||||||
public Class<? extends UsbSerialDriver> findDriver(int vendorId, int productId) {
|
public Class<? extends UsbSerialDriver> findDriver(int vendorId, int productId) {
|
||||||
final Pair<Integer, Integer> pair = Pair.create(vendorId, productId);
|
final Pair<Integer, Integer> pair = Pair.create(vendorId, productId);
|
||||||
return mProbeTable.get(pair);
|
return mProbeTable.get(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,15 @@
|
||||||
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that a timeout has occurred on serial write.
|
||||||
|
* Similar to SocketTimeoutException.
|
||||||
|
*
|
||||||
|
* {@see InterruptedIOException#bytesTransferred} may contain bytes transferred
|
||||||
|
*/
|
||||||
|
public class SerialTimeoutException extends InterruptedIOException {
|
||||||
|
public SerialTimeoutException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +1,77 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry of USB vendor/product ID constants.
|
* Registry of USB vendor/product ID constants.
|
||||||
*
|
*
|
||||||
* Culled from various sources; see
|
* Culled from various sources; see
|
||||||
* <a href="http://www.linux-usb.org/usb.ids">usb.ids</a> for one listing.
|
* <a href="http://www.linux-usb.org/usb.ids">usb.ids</a> for one listing.
|
||||||
*
|
*
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public final class UsbId {
|
public final class UsbId {
|
||||||
|
|
||||||
public static final int VENDOR_FTDI = 0x0403;
|
public static final int VENDOR_FTDI = 0x0403;
|
||||||
public static final int FTDI_FT232R = 0x6001;
|
public static final int FTDI_FT232R = 0x6001;
|
||||||
public static final int FTDI_FT2232H = 0x6010;
|
public static final int FTDI_FT2232H = 0x6010;
|
||||||
public static final int FTDI_FT4232H = 0x6011;
|
public static final int FTDI_FT4232H = 0x6011;
|
||||||
public static final int FTDI_FT232H = 0x6014;
|
public static final int FTDI_FT232H = 0x6014;
|
||||||
public static final int FTDI_FT231X = 0x6015; // same ID for FT230X, FT231X, FT234XD
|
public static final int FTDI_FT231X = 0x6015; // same ID for FT230X, FT231X, FT234XD
|
||||||
|
|
||||||
public static final int VENDOR_ATMEL = 0x03EB;
|
public static final int VENDOR_ATMEL = 0x03EB;
|
||||||
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
|
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
|
||||||
|
|
||||||
public static final int VENDOR_ARDUINO = 0x2341;
|
public static final int VENDOR_ARDUINO = 0x2341;
|
||||||
public static final int ARDUINO_UNO = 0x0001;
|
public static final int ARDUINO_UNO = 0x0001;
|
||||||
public static final int ARDUINO_MEGA_2560 = 0x0010;
|
public static final int ARDUINO_MEGA_2560 = 0x0010;
|
||||||
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
|
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
|
||||||
public static final int ARDUINO_MEGA_ADK = 0x003f;
|
public static final int ARDUINO_MEGA_ADK = 0x003f;
|
||||||
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
|
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
|
||||||
public static final int ARDUINO_UNO_R3 = 0x0043;
|
public static final int ARDUINO_UNO_R3 = 0x0043;
|
||||||
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
|
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
|
||||||
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
|
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
|
||||||
public static final int ARDUINO_LEONARDO = 0x8036;
|
public static final int ARDUINO_LEONARDO = 0x8036;
|
||||||
public static final int ARDUINO_MICRO = 0x8037;
|
public static final int ARDUINO_MICRO = 0x8037;
|
||||||
|
|
||||||
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
|
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
|
||||||
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
|
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
|
||||||
|
|
||||||
public static final int VENDOR_LEAFLABS = 0x1eaf;
|
public static final int VENDOR_LEAFLABS = 0x1eaf;
|
||||||
public static final int LEAFLABS_MAPLE = 0x0004;
|
public static final int LEAFLABS_MAPLE = 0x0004;
|
||||||
|
|
||||||
public static final int VENDOR_SILABS = 0x10c4;
|
public static final int VENDOR_SILABS = 0x10c4;
|
||||||
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
|
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
|
||||||
public static final int SILABS_CP2105 = 0xea70;
|
public static final int SILABS_CP2105 = 0xea70;
|
||||||
public static final int SILABS_CP2108 = 0xea71;
|
public static final int SILABS_CP2108 = 0xea71;
|
||||||
|
|
||||||
public static final int VENDOR_PROLIFIC = 0x067b;
|
public static final int VENDOR_PROLIFIC = 0x067b;
|
||||||
public static final int PROLIFIC_PL2303 = 0x2303;
|
public static final int PROLIFIC_PL2303 = 0x2303; // device type 01, T, HX
|
||||||
|
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
|
||||||
public static final int VENDOR_QINHENG = 0x1a86;
|
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
|
||||||
public static final int QINHENG_CH340 = 0x7523;
|
public static final int PROLIFIC_PL2303GT = 0x23cd; // "
|
||||||
public static final int QINHENG_CH341A = 0x5523;
|
public static final int PROLIFIC_PL2303GT3 = 0x23c3; // "
|
||||||
|
public static final int PROLIFIC_PL2303GL = 0x23e3; // "
|
||||||
// at www.linux-usb.org/usb.ids listed for NXP/LPC1768, but all processors supported by ARM mbed DAPLink firmware report these ids
|
public static final int PROLIFIC_PL2303GE = 0x23e3; // "
|
||||||
public static final int VENDOR_ARM = 0x0d28;
|
public static final int PROLIFIC_PL2303GS = 0x23f3; // "
|
||||||
public static final int ARM_MBED = 0x0204;
|
|
||||||
|
public static final int VENDOR_QINHENG = 0x1a86;
|
||||||
private UsbId() {
|
public static final int QINHENG_CH340 = 0x7523;
|
||||||
throw new IllegalAccessError("Non-instantiable class");
|
public static final int QINHENG_CH341A = 0x5523;
|
||||||
}
|
|
||||||
|
// at www.linux-usb.org/usb.ids listed for NXP/LPC1768, but all processors supported by ARM mbed DAPLink firmware report these ids
|
||||||
}
|
public static final int VENDOR_ARM = 0x0d28;
|
||||||
|
public static final int ARM_MBED = 0x0204;
|
||||||
|
|
||||||
|
public static final int VENDOR_ST = 0x0483;
|
||||||
|
public static final int ST_CDC = 0x5740;
|
||||||
|
|
||||||
|
private UsbId() {
|
||||||
|
throw new IllegalAccessError("Non-instantiable class");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public interface UsbSerialDriver {
|
public interface UsbSerialDriver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the raw {@link UsbDevice} backing this port.
|
* Returns the raw {@link UsbDevice} backing this port.
|
||||||
*
|
*
|
||||||
* @return the device
|
* @return the device
|
||||||
*/
|
*/
|
||||||
public UsbDevice getDevice();
|
UsbDevice getDevice();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all available ports for this device. This list must have at least
|
* Returns all available ports for this device. This list must have at least
|
||||||
* one entry.
|
* one entry.
|
||||||
*
|
*
|
||||||
* @return the ports
|
* @return the ports
|
||||||
*/
|
*/
|
||||||
public List<UsbSerialPort> getPorts();
|
List<UsbSerialPort> getPorts();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,263 +1,261 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
|
import android.hardware.usb.UsbManager;
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import androidx.annotation.IntDef;
|
||||||
import java.util.EnumSet;
|
|
||||||
|
import java.io.Closeable;
|
||||||
/**
|
import java.io.IOException;
|
||||||
* Interface for a single serial port.
|
import java.lang.annotation.Retention;
|
||||||
*
|
import java.lang.annotation.RetentionPolicy;
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
import java.util.EnumSet;
|
||||||
*/
|
|
||||||
public interface UsbSerialPort extends Closeable {
|
/**
|
||||||
|
* Interface for a single serial port.
|
||||||
/** 5 data bits. */
|
*
|
||||||
public static final int DATABITS_5 = 5;
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
|
*/
|
||||||
/** 6 data bits. */
|
public interface UsbSerialPort extends Closeable {
|
||||||
public static final int DATABITS_6 = 6;
|
|
||||||
|
/** 5 data bits. */
|
||||||
/** 7 data bits. */
|
int DATABITS_5 = 5;
|
||||||
public static final int DATABITS_7 = 7;
|
/** 6 data bits. */
|
||||||
|
int DATABITS_6 = 6;
|
||||||
/** 8 data bits. */
|
/** 7 data bits. */
|
||||||
public static final int DATABITS_8 = 8;
|
int DATABITS_7 = 7;
|
||||||
|
/** 8 data bits. */
|
||||||
/** No flow control. */
|
int DATABITS_8 = 8;
|
||||||
public static final int FLOWCONTROL_NONE = 0;
|
|
||||||
|
/** Values for setParameters(..., parity) */
|
||||||
/** RTS/CTS input flow control. */
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public static final int FLOWCONTROL_RTSCTS_IN = 1;
|
@IntDef({PARITY_NONE, PARITY_ODD, PARITY_EVEN, PARITY_MARK, PARITY_SPACE})
|
||||||
|
@interface Parity {}
|
||||||
/** RTS/CTS output flow control. */
|
/** No parity. */
|
||||||
public static final int FLOWCONTROL_RTSCTS_OUT = 2;
|
int PARITY_NONE = 0;
|
||||||
|
/** Odd parity. */
|
||||||
/** XON/XOFF input flow control. */
|
int PARITY_ODD = 1;
|
||||||
public static final int FLOWCONTROL_XONXOFF_IN = 4;
|
/** Even parity. */
|
||||||
|
int PARITY_EVEN = 2;
|
||||||
/** XON/XOFF output flow control. */
|
/** Mark parity. */
|
||||||
public static final int FLOWCONTROL_XONXOFF_OUT = 8;
|
int PARITY_MARK = 3;
|
||||||
|
/** Space parity. */
|
||||||
/** No parity. */
|
int PARITY_SPACE = 4;
|
||||||
public static final int PARITY_NONE = 0;
|
|
||||||
|
/** 1 stop bit. */
|
||||||
/** Odd parity. */
|
int STOPBITS_1 = 1;
|
||||||
public static final int PARITY_ODD = 1;
|
/** 1.5 stop bits. */
|
||||||
|
int STOPBITS_1_5 = 3;
|
||||||
/** Even parity. */
|
/** 2 stop bits. */
|
||||||
public static final int PARITY_EVEN = 2;
|
int STOPBITS_2 = 2;
|
||||||
|
|
||||||
/** Mark parity. */
|
/** Values for get[Supported]ControlLines() */
|
||||||
public static final int PARITY_MARK = 3;
|
enum ControlLine { RTS, CTS, DTR, DSR, CD, RI }
|
||||||
|
|
||||||
/** Space parity. */
|
/**
|
||||||
public static final int PARITY_SPACE = 4;
|
* Returns the driver used by this port.
|
||||||
|
*/
|
||||||
/** 1 stop bit. */
|
UsbSerialDriver getDriver();
|
||||||
public static final int STOPBITS_1 = 1;
|
|
||||||
|
/**
|
||||||
/** 1.5 stop bits. */
|
* Returns the currently-bound USB device.
|
||||||
public static final int STOPBITS_1_5 = 3;
|
*/
|
||||||
|
UsbDevice getDevice();
|
||||||
/** 2 stop bits. */
|
|
||||||
public static final int STOPBITS_2 = 2;
|
/**
|
||||||
|
* Port number within driver.
|
||||||
/** values for get[Supported]ControlLines() */
|
*/
|
||||||
public enum ControlLine { RTS, CTS, DTR, DSR, CD, RI };
|
int getPortNumber();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the driver used by this port.
|
* Returns the write endpoint.
|
||||||
*/
|
* @return write endpoint
|
||||||
public UsbSerialDriver getDriver();
|
*/
|
||||||
|
UsbEndpoint getWriteEndpoint();
|
||||||
/**
|
|
||||||
* Returns the currently-bound USB device.
|
/**
|
||||||
*/
|
* Returns the read endpoint.
|
||||||
public UsbDevice getDevice();
|
* @return read endpoint
|
||||||
|
*/
|
||||||
/**
|
UsbEndpoint getReadEndpoint();
|
||||||
* Port number within driver.
|
|
||||||
*/
|
/**
|
||||||
public int getPortNumber();
|
* The serial number of the underlying UsbDeviceConnection, or {@code null}.
|
||||||
|
*
|
||||||
/**
|
* @return value from {@link UsbDeviceConnection#getSerial()}
|
||||||
* The serial number of the underlying UsbDeviceConnection, or {@code null}.
|
* @throws SecurityException starting with target SDK 29 (Android 10) if permission for USB device is not granted
|
||||||
*
|
*/
|
||||||
* @return value from {@link UsbDeviceConnection#getSerial()}
|
String getSerial();
|
||||||
* @throws SecurityException starting with target SDK 29 (Android 10) if permission for USB device is not granted
|
|
||||||
*/
|
/**
|
||||||
public String getSerial();
|
* Opens and initializes the port. Upon success, caller must ensure that
|
||||||
|
* {@link #close()} is eventually called.
|
||||||
/**
|
*
|
||||||
* Opens and initializes the port. Upon success, caller must ensure that
|
* @param connection an open device connection, acquired with
|
||||||
* {@link #close()} is eventually called.
|
* {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)}
|
||||||
*
|
* @throws IOException on error opening or initializing the port.
|
||||||
* @param connection an open device connection, acquired with
|
*/
|
||||||
* {@link UsbManager#openDevice(UsbDevice)}
|
void open(UsbDeviceConnection connection) throws IOException;
|
||||||
* @throws IOException on error opening or initializing the port.
|
|
||||||
*/
|
/**
|
||||||
public void open(UsbDeviceConnection connection) throws IOException;
|
* Closes the port and {@link UsbDeviceConnection}
|
||||||
|
*
|
||||||
/**
|
* @throws IOException on error closing the port.
|
||||||
* Closes the port and {@link UsbDeviceConnection}
|
*/
|
||||||
*
|
void close() throws IOException;
|
||||||
* @throws IOException on error closing the port.
|
|
||||||
*/
|
/**
|
||||||
public void close() throws IOException;
|
* Reads as many bytes as possible into the destination buffer.
|
||||||
|
*
|
||||||
/**
|
* @param dest the destination byte buffer
|
||||||
* Reads as many bytes as possible into the destination buffer.
|
* @param timeout the timeout for reading in milliseconds, 0 is infinite
|
||||||
*
|
* @return the actual number of bytes read
|
||||||
* @param dest the destination byte buffer
|
* @throws IOException if an error occurred during reading
|
||||||
* @param timeout the timeout for reading in milliseconds, 0 is infinite
|
*/
|
||||||
* @return the actual number of bytes read
|
int read(final byte[] dest, final int timeout) throws IOException;
|
||||||
* @throws IOException if an error occurred during reading
|
|
||||||
*/
|
/**
|
||||||
public int read(final byte[] dest, final int timeout) throws IOException;
|
* Writes as many bytes as possible from the source buffer.
|
||||||
|
*
|
||||||
/**
|
* @param src the source byte buffer
|
||||||
* Writes as many bytes as possible from the source buffer.
|
* @param timeout the timeout for writing in milliseconds, 0 is infinite
|
||||||
*
|
* @throws SerialTimeoutException if timeout reached before sending all data.
|
||||||
* @param src the source byte buffer
|
* ex.bytesTransferred may contain bytes transferred
|
||||||
* @param timeout the timeout for writing in milliseconds, 0 is infinite
|
* @throws IOException if an error occurred during writing
|
||||||
* @return the actual number of bytes written
|
*/
|
||||||
* @throws IOException if an error occurred during writing
|
void write(final byte[] src, final int timeout) throws IOException;
|
||||||
*/
|
|
||||||
public int write(final byte[] src, final int timeout) throws IOException;
|
/**
|
||||||
|
* Sets various serial port parameters.
|
||||||
/**
|
*
|
||||||
* Sets various serial port parameters.
|
* @param baudRate baud rate as an integer, for example {@code 115200}.
|
||||||
*
|
* @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},
|
||||||
* @param baudRate baud rate as an integer, for example {@code 115200}.
|
* {@link #DATABITS_7}, or {@link #DATABITS_8}.
|
||||||
* @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6},
|
* @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or {@link #STOPBITS_2}.
|
||||||
* {@link #DATABITS_7}, or {@link #DATABITS_8}.
|
* @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},
|
||||||
* @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or {@link #STOPBITS_2}.
|
* {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or {@link #PARITY_SPACE}.
|
||||||
* @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD},
|
* @throws IOException on error setting the port parameters
|
||||||
* {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or {@link #PARITY_SPACE}.
|
* @throws UnsupportedOperationException if values are not supported by a specific device
|
||||||
* @throws IOException on error setting the port parameters
|
*/
|
||||||
* @throws UnsupportedOperationException if values are not supported by a specific device
|
void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException;
|
||||||
*/
|
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException;
|
/**
|
||||||
|
* Gets the CD (Carrier Detect) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the CD (Carrier Detect) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getCD() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getCD() throws IOException;
|
/**
|
||||||
|
* Gets the CTS (Clear To Send) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the CTS (Clear To Send) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getCTS() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getCTS() throws IOException;
|
/**
|
||||||
|
* Gets the DSR (Data Set Ready) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the DSR (Data Set Ready) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getDSR() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getDSR() throws IOException;
|
/**
|
||||||
|
* Gets the DTR (Data Terminal Ready) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the DTR (Data Terminal Ready) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getDTR() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getDTR() throws IOException;
|
/**
|
||||||
|
* Sets the DTR (Data Terminal Ready) bit on the underlying UART, if supported.
|
||||||
/**
|
*
|
||||||
* Sets the DTR (Data Terminal Ready) bit on the underlying UART, if supported.
|
* @param value the value to set
|
||||||
*
|
* @throws IOException if an error occurred during writing
|
||||||
* @param value the value to set
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during writing
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
void setDTR(boolean value) throws IOException;
|
||||||
*/
|
|
||||||
public void setDTR(boolean value) throws IOException;
|
/**
|
||||||
|
* Gets the RI (Ring Indicator) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the RI (Ring Indicator) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getRI() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getRI() throws IOException;
|
/**
|
||||||
|
* Gets the RTS (Request To Send) bit from the underlying UART.
|
||||||
/**
|
*
|
||||||
* Gets the RTS (Request To Send) bit from the underlying UART.
|
* @return the current state
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return the current state
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during reading
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
boolean getRTS() throws IOException;
|
||||||
*/
|
|
||||||
public boolean getRTS() throws IOException;
|
/**
|
||||||
|
* Sets the RTS (Request To Send) bit on the underlying UART, if supported.
|
||||||
/**
|
*
|
||||||
* Sets the RTS (Request To Send) bit on the underlying UART, if supported.
|
* @param value the value to set
|
||||||
*
|
* @throws IOException if an error occurred during writing
|
||||||
* @param value the value to set
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during writing
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
void setRTS(boolean value) throws IOException;
|
||||||
*/
|
|
||||||
public void setRTS(boolean value) throws IOException;
|
/**
|
||||||
|
* Gets all control line values from the underlying UART, if supported.
|
||||||
/**
|
* Requires less USB calls than calling getRTS() + ... + getRI() individually.
|
||||||
* Gets all control line values from the underlying UART, if supported.
|
*
|
||||||
* Requires less USB calls than calling getRTS() + ... + getRI() individually.
|
* @return EnumSet.contains(...) is {@code true} if set, else {@code false}
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return EnumSet.contains(...) is {@code true} if set, else {@code false}
|
*/
|
||||||
* @throws IOException if an error occurred during reading
|
EnumSet<ControlLine> getControlLines() throws IOException;
|
||||||
*/
|
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException;
|
/**
|
||||||
|
* Gets all control line supported flags.
|
||||||
/**
|
*
|
||||||
* Gets all control line supported flags.
|
* @return EnumSet.contains(...) is {@code true} if supported, else {@code false}
|
||||||
*
|
* @throws IOException if an error occurred during reading
|
||||||
* @return EnumSet.contains(...) is {@code true} if supported, else {@code false}
|
*/
|
||||||
* @throws IOException if an error occurred during reading
|
EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
||||||
*/
|
|
||||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
/**
|
||||||
|
* Purge non-transmitted output data and / or non-read input data.
|
||||||
/**
|
*
|
||||||
* Purge non-transmitted output data and / or non-read input data.
|
* @param purgeWriteBuffers {@code true} to discard non-transmitted output data
|
||||||
*
|
* @param purgeReadBuffers {@code true} to discard non-read input data
|
||||||
* @param purgeWriteBuffers {@code true} to discard non-transmitted output data
|
* @throws IOException if an error occurred during flush
|
||||||
* @param purgeReadBuffers {@code true} to discard non-read input data
|
* @throws UnsupportedOperationException if not supported
|
||||||
* @throws IOException if an error occurred during flush
|
*/
|
||||||
* @throws UnsupportedOperationException if not supported
|
void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException;
|
||||||
*/
|
|
||||||
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException;
|
/**
|
||||||
|
* send BREAK condition.
|
||||||
/**
|
*
|
||||||
* send BREAK condition.
|
* @param value set/reset
|
||||||
*
|
*/
|
||||||
* @param value set/reset
|
void setBreak(boolean value) throws IOException;
|
||||||
*/
|
|
||||||
public void setBreak(boolean value) throws IOException;
|
/**
|
||||||
|
* Returns the current state of the connection.
|
||||||
/**
|
*/
|
||||||
* Returns the current state of the connection.
|
boolean isOpen();
|
||||||
*/
|
|
||||||
public boolean isOpen();
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,92 +1,92 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.driver;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public class UsbSerialProber {
|
public class UsbSerialProber {
|
||||||
|
|
||||||
private final ProbeTable mProbeTable;
|
private final ProbeTable mProbeTable;
|
||||||
|
|
||||||
public UsbSerialProber(ProbeTable probeTable) {
|
public UsbSerialProber(ProbeTable probeTable) {
|
||||||
mProbeTable = probeTable;
|
mProbeTable = probeTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UsbSerialProber getDefaultProber() {
|
public static UsbSerialProber getDefaultProber() {
|
||||||
return new UsbSerialProber(getDefaultProbeTable());
|
return new UsbSerialProber(getDefaultProbeTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProbeTable getDefaultProbeTable() {
|
public static ProbeTable getDefaultProbeTable() {
|
||||||
final ProbeTable probeTable = new ProbeTable();
|
final ProbeTable probeTable = new ProbeTable();
|
||||||
probeTable.addDriver(CdcAcmSerialDriver.class);
|
probeTable.addDriver(CdcAcmSerialDriver.class);
|
||||||
probeTable.addDriver(Cp21xxSerialDriver.class);
|
probeTable.addDriver(Cp21xxSerialDriver.class);
|
||||||
probeTable.addDriver(FtdiSerialDriver.class);
|
probeTable.addDriver(FtdiSerialDriver.class);
|
||||||
probeTable.addDriver(ProlificSerialDriver.class);
|
probeTable.addDriver(ProlificSerialDriver.class);
|
||||||
probeTable.addDriver(Ch34xSerialDriver.class);
|
probeTable.addDriver(Ch34xSerialDriver.class);
|
||||||
return probeTable;
|
return probeTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}
|
* Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers}
|
||||||
* from the currently-attached {@link UsbDevice} hierarchy. This method does
|
* from the currently-attached {@link UsbDevice} hierarchy. This method does
|
||||||
* not require permission from the Android USB system, since it does not
|
* not require permission from the Android USB system, since it does not
|
||||||
* open any of the devices.
|
* open any of the devices.
|
||||||
*
|
*
|
||||||
* @param usbManager
|
* @param usbManager usb manager
|
||||||
* @return a list, possibly empty, of all compatible drivers
|
* @return a list, possibly empty, of all compatible drivers
|
||||||
*/
|
*/
|
||||||
public List<UsbSerialDriver> findAllDrivers(final UsbManager usbManager) {
|
public List<UsbSerialDriver> findAllDrivers(final UsbManager usbManager) {
|
||||||
final List<UsbSerialDriver> result = new ArrayList<UsbSerialDriver>();
|
final List<UsbSerialDriver> result = new ArrayList<>();
|
||||||
|
|
||||||
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
|
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
|
||||||
final UsbSerialDriver driver = probeDevice(usbDevice);
|
final UsbSerialDriver driver = probeDevice(usbDevice);
|
||||||
if (driver != null) {
|
if (driver != null) {
|
||||||
result.add(driver);
|
result.add(driver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probes a single device for a compatible driver.
|
* Probes a single device for a compatible driver.
|
||||||
*
|
*
|
||||||
* @param usbDevice the usb device to probe
|
* @param usbDevice the usb device to probe
|
||||||
* @return a new {@link UsbSerialDriver} compatible with this device, or
|
* @return a new {@link UsbSerialDriver} compatible with this device, or
|
||||||
* {@code null} if none available.
|
* {@code null} if none available.
|
||||||
*/
|
*/
|
||||||
public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
|
public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
|
||||||
final int vendorId = usbDevice.getVendorId();
|
final int vendorId = usbDevice.getVendorId();
|
||||||
final int productId = usbDevice.getProductId();
|
final int productId = usbDevice.getProductId();
|
||||||
|
|
||||||
final Class<? extends UsbSerialDriver> driverClass =
|
final Class<? extends UsbSerialDriver> driverClass =
|
||||||
mProbeTable.findDriver(vendorId, productId);
|
mProbeTable.findDriver(vendorId, productId);
|
||||||
if (driverClass != null) {
|
if (driverClass != null) {
|
||||||
final UsbSerialDriver driver;
|
final UsbSerialDriver driver;
|
||||||
try {
|
try {
|
||||||
final Constructor<? extends UsbSerialDriver> ctor =
|
final Constructor<? extends UsbSerialDriver> ctor =
|
||||||
driverClass.getConstructor(UsbDevice.class);
|
driverClass.getConstructor(UsbDevice.class);
|
||||||
driver = ctor.newInstance(usbDevice);
|
driver = ctor.newInstance(usbDevice);
|
||||||
} catch (NoSuchMethodException | IllegalArgumentException | InstantiationException |
|
} catch (NoSuchMethodException | IllegalArgumentException | InstantiationException |
|
||||||
IllegalAccessException | InvocationTargetException e) {
|
IllegalAccessException | InvocationTargetException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.emulator.calculator.usbserial.util;
|
||||||
|
|
||||||
|
public final class MonotonicClock {
|
||||||
|
|
||||||
|
private static final long NS_PER_MS = 1_000_000;
|
||||||
|
|
||||||
|
private MonotonicClock() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long millis() {
|
||||||
|
return System.nanoTime() / NS_PER_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,239 +1,254 @@
|
||||||
/* Copyright 2011-2013 Google Inc.
|
/* Copyright 2011-2013 Google Inc.
|
||||||
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
* Copyright 2013 mike wakerly <opensource@hoho.com>
|
||||||
*
|
*
|
||||||
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
* Project home page: https://github.com/mik3y/usb-serial-for-android
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.emulator.calculator.usbserial.util;
|
package org.emulator.calculator.usbserial.util;
|
||||||
|
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class which services a {@link UsbSerialPort} in its {@link #run()} method.
|
* Utility class which services a {@link UsbSerialPort} in its {@link #run()} method.
|
||||||
*
|
*
|
||||||
* @author mike wakerly (opensource@hoho.com)
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public class SerialInputOutputManager implements Runnable {
|
public class SerialInputOutputManager implements Runnable {
|
||||||
|
|
||||||
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
|
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
|
||||||
private static final boolean DEBUG = false;
|
public static boolean DEBUG = false;
|
||||||
private static final int BUFSIZ = 4096;
|
private static final int BUFSIZ = 4096;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* default read timeout is infinite, to avoid data loss with bulkTransfer API
|
* default read timeout is infinite, to avoid data loss with bulkTransfer API
|
||||||
*/
|
*/
|
||||||
private int mReadTimeout = 0;
|
private int mReadTimeout = 0;
|
||||||
private int mWriteTimeout = 0;
|
private int mWriteTimeout = 0;
|
||||||
|
|
||||||
private final Object mReadBufferLock = new Object();
|
private final Object mReadBufferLock = new Object();
|
||||||
private final Object mWriteBufferLock = new Object();
|
private final Object mWriteBufferLock = new Object();
|
||||||
|
|
||||||
private ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
|
private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
|
||||||
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
STOPPED,
|
STOPPED,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
STOPPING
|
STOPPING
|
||||||
}
|
}
|
||||||
|
|
||||||
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
|
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
|
||||||
private State mState = State.STOPPED; // Synchronized by 'this'
|
private State mState = State.STOPPED; // Synchronized by 'this'
|
||||||
private Listener mListener; // Synchronized by 'this'
|
private Listener mListener; // Synchronized by 'this'
|
||||||
private final UsbSerialPort mSerialPort;
|
private final UsbSerialPort mSerialPort;
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
/**
|
/**
|
||||||
* Called when new incoming data is available.
|
* Called when new incoming data is available.
|
||||||
*/
|
*/
|
||||||
public void onNewData(byte[] data);
|
void onNewData(byte[] data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when {@link SerialInputOutputManager#run()} aborts due to an error.
|
* Called when {@link SerialInputOutputManager#run()} aborts due to an error.
|
||||||
*/
|
*/
|
||||||
public void onRunError(Exception e);
|
void onRunError(Exception e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerialInputOutputManager(UsbSerialPort serialPort) {
|
public SerialInputOutputManager(UsbSerialPort serialPort) {
|
||||||
mSerialPort = serialPort;
|
mSerialPort = serialPort;
|
||||||
}
|
mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
|
||||||
|
}
|
||||||
public SerialInputOutputManager(UsbSerialPort serialPort, Listener listener) {
|
|
||||||
mSerialPort = serialPort;
|
public SerialInputOutputManager(UsbSerialPort serialPort, Listener listener) {
|
||||||
mListener = listener;
|
mSerialPort = serialPort;
|
||||||
}
|
mListener = listener;
|
||||||
|
mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
|
||||||
public synchronized void setListener(Listener listener) {
|
}
|
||||||
mListener = listener;
|
|
||||||
}
|
public synchronized void setListener(Listener listener) {
|
||||||
|
mListener = listener;
|
||||||
public synchronized Listener getListener() {
|
}
|
||||||
return mListener;
|
|
||||||
}
|
public synchronized Listener getListener() {
|
||||||
|
return mListener;
|
||||||
/**
|
}
|
||||||
* setThreadPriority. By default use higher priority than UI thread to prevent data loss
|
|
||||||
*
|
/**
|
||||||
* @param threadPriority see {@link Process#setThreadPriority(int)}
|
* setThreadPriority. By default a higher priority than UI thread is used to prevent data loss
|
||||||
* */
|
*
|
||||||
public void setThreadPriority(int threadPriority) {
|
* @param threadPriority see {@link Process#setThreadPriority(int)}
|
||||||
if (mState != State.STOPPED)
|
* */
|
||||||
throw new IllegalStateException("threadPriority only configurable before SerialInputOutputManager is started");
|
public void setThreadPriority(int threadPriority) {
|
||||||
mThreadPriority = threadPriority;
|
if (mState != State.STOPPED)
|
||||||
}
|
throw new IllegalStateException("threadPriority only configurable before SerialInputOutputManager is started");
|
||||||
|
mThreadPriority = threadPriority;
|
||||||
/**
|
}
|
||||||
* read/write timeout
|
|
||||||
*/
|
/**
|
||||||
public void setReadTimeout(int timeout) {
|
* read/write timeout
|
||||||
// when set if already running, read already blocks and the new value will not become effective now
|
*/
|
||||||
if(mReadTimeout == 0 && timeout != 0 && mState != State.STOPPED)
|
public void setReadTimeout(int timeout) {
|
||||||
throw new IllegalStateException("readTimeout only configurable before SerialInputOutputManager is started");
|
// when set if already running, read already blocks and the new value will not become effective now
|
||||||
mReadTimeout = timeout;
|
if(mReadTimeout == 0 && timeout != 0 && mState != State.STOPPED)
|
||||||
}
|
throw new IllegalStateException("readTimeout only configurable before SerialInputOutputManager is started");
|
||||||
|
mReadTimeout = timeout;
|
||||||
public int getReadTimeout() {
|
}
|
||||||
return mReadTimeout;
|
|
||||||
}
|
public int getReadTimeout() {
|
||||||
|
return mReadTimeout;
|
||||||
public void setWriteTimeout(int timeout) {
|
}
|
||||||
mWriteTimeout = timeout;
|
|
||||||
}
|
public void setWriteTimeout(int timeout) {
|
||||||
|
mWriteTimeout = timeout;
|
||||||
public int getWriteTimeout() {
|
}
|
||||||
return mWriteTimeout;
|
|
||||||
}
|
public int getWriteTimeout() {
|
||||||
|
return mWriteTimeout;
|
||||||
/**
|
}
|
||||||
* read/write buffer size
|
|
||||||
*/
|
/**
|
||||||
public void setReadBufferSize(int bufferSize) {
|
* read/write buffer size
|
||||||
if (getReadBufferSize() == bufferSize)
|
*/
|
||||||
return;
|
public void setReadBufferSize(int bufferSize) {
|
||||||
synchronized (mReadBufferLock) {
|
if (getReadBufferSize() == bufferSize)
|
||||||
mReadBuffer = ByteBuffer.allocate(bufferSize);
|
return;
|
||||||
}
|
synchronized (mReadBufferLock) {
|
||||||
}
|
mReadBuffer = ByteBuffer.allocate(bufferSize);
|
||||||
|
}
|
||||||
public int getReadBufferSize() {
|
}
|
||||||
return mReadBuffer.capacity();
|
|
||||||
}
|
public int getReadBufferSize() {
|
||||||
|
return mReadBuffer.capacity();
|
||||||
public void setWriteBufferSize(int bufferSize) {
|
}
|
||||||
if(getWriteBufferSize() == bufferSize)
|
|
||||||
return;
|
public void setWriteBufferSize(int bufferSize) {
|
||||||
synchronized (mWriteBufferLock) {
|
if(getWriteBufferSize() == bufferSize)
|
||||||
ByteBuffer newWriteBuffer = ByteBuffer.allocate(bufferSize);
|
return;
|
||||||
if(mWriteBuffer.position() > 0)
|
synchronized (mWriteBufferLock) {
|
||||||
newWriteBuffer.put(mWriteBuffer.array(), 0, mWriteBuffer.position());
|
ByteBuffer newWriteBuffer = ByteBuffer.allocate(bufferSize);
|
||||||
mWriteBuffer = newWriteBuffer;
|
if(mWriteBuffer.position() > 0)
|
||||||
}
|
newWriteBuffer.put(mWriteBuffer.array(), 0, mWriteBuffer.position());
|
||||||
}
|
mWriteBuffer = newWriteBuffer;
|
||||||
|
}
|
||||||
public int getWriteBufferSize() {
|
}
|
||||||
return mWriteBuffer.capacity();
|
|
||||||
}
|
public int getWriteBufferSize() {
|
||||||
|
return mWriteBuffer.capacity();
|
||||||
/*
|
}
|
||||||
* when writeAsync is used, it is recommended to use readTimeout != 0,
|
|
||||||
* else the write will be delayed until read data is available
|
/**
|
||||||
*/
|
* when using writeAsync, it is recommended to use readTimeout != 0,
|
||||||
public void writeAsync(byte[] data) {
|
* else the write will be delayed until read data is available
|
||||||
synchronized (mWriteBufferLock) {
|
*/
|
||||||
mWriteBuffer.put(data);
|
public void writeAsync(byte[] data) {
|
||||||
}
|
synchronized (mWriteBufferLock) {
|
||||||
}
|
mWriteBuffer.put(data);
|
||||||
|
}
|
||||||
public synchronized void stop() {
|
}
|
||||||
if (getState() == State.RUNNING) {
|
|
||||||
Log.i(TAG, "Stop requested");
|
/**
|
||||||
mState = State.STOPPING;
|
* start SerialInputOutputManager in separate thread
|
||||||
}
|
*/
|
||||||
}
|
public void start() {
|
||||||
|
if(mState != State.STOPPED)
|
||||||
public synchronized State getState() {
|
throw new IllegalStateException("already started");
|
||||||
return mState;
|
new Thread(this, this.getClass().getSimpleName()).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continuously services the read and write buffers until {@link #stop()} is
|
* stop SerialInputOutputManager thread
|
||||||
* called, or until a driver exception is raised.
|
*
|
||||||
*/
|
* when using readTimeout == 0 (default), additionally use usbSerialPort.close() to
|
||||||
@Override
|
* interrupt blocking read
|
||||||
public void run() {
|
*/
|
||||||
if(mThreadPriority != Process.THREAD_PRIORITY_DEFAULT)
|
public synchronized void stop() {
|
||||||
setThreadPriority(mThreadPriority);
|
if (getState() == State.RUNNING) {
|
||||||
|
Log.i(TAG, "Stop requested");
|
||||||
synchronized (this) {
|
mState = State.STOPPING;
|
||||||
if (getState() != State.STOPPED) {
|
}
|
||||||
throw new IllegalStateException("Already running");
|
}
|
||||||
}
|
|
||||||
mState = State.RUNNING;
|
public synchronized State getState() {
|
||||||
}
|
return mState;
|
||||||
|
}
|
||||||
Log.i(TAG, "Running ...");
|
|
||||||
try {
|
/**
|
||||||
while (true) {
|
* Continuously services the read and write buffers until {@link #stop()} is
|
||||||
if (getState() != State.RUNNING) {
|
* called, or until a driver exception is raised.
|
||||||
Log.i(TAG, "Stopping mState=" + getState());
|
*/
|
||||||
break;
|
@Override
|
||||||
}
|
public void run() {
|
||||||
step();
|
synchronized (this) {
|
||||||
}
|
if (getState() != State.STOPPED) {
|
||||||
} catch (Exception e) {
|
throw new IllegalStateException("Already running");
|
||||||
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
}
|
||||||
final Listener listener = getListener();
|
mState = State.RUNNING;
|
||||||
if (listener != null) {
|
}
|
||||||
listener.onRunError(e);
|
Log.i(TAG, "Running ...");
|
||||||
}
|
try {
|
||||||
} finally {
|
if(mThreadPriority != Process.THREAD_PRIORITY_DEFAULT)
|
||||||
synchronized (this) {
|
Process.setThreadPriority(mThreadPriority);
|
||||||
mState = State.STOPPED;
|
while (true) {
|
||||||
Log.i(TAG, "Stopped");
|
if (getState() != State.RUNNING) {
|
||||||
}
|
Log.i(TAG, "Stopping mState=" + getState());
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
step();
|
||||||
private void step() throws IOException {
|
}
|
||||||
// Handle incoming data.
|
} catch (Exception e) {
|
||||||
byte[] buffer = null;
|
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
||||||
synchronized (mReadBufferLock) {
|
final Listener listener = getListener();
|
||||||
buffer = mReadBuffer.array();
|
if (listener != null) {
|
||||||
}
|
listener.onRunError(e);
|
||||||
int len = mSerialPort.read(buffer, mReadTimeout);
|
}
|
||||||
if (len > 0) {
|
} finally {
|
||||||
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
synchronized (this) {
|
||||||
final Listener listener = getListener();
|
mState = State.STOPPED;
|
||||||
if (listener != null) {
|
Log.i(TAG, "Stopped");
|
||||||
final byte[] data = new byte[len];
|
}
|
||||||
System.arraycopy(buffer, 0, data, 0, len);
|
}
|
||||||
listener.onNewData(data);
|
}
|
||||||
}
|
|
||||||
}
|
private void step() throws IOException {
|
||||||
|
// Handle incoming data.
|
||||||
// Handle outgoing data.
|
byte[] buffer;
|
||||||
buffer = null;
|
synchronized (mReadBufferLock) {
|
||||||
synchronized (mWriteBufferLock) {
|
buffer = mReadBuffer.array();
|
||||||
len = mWriteBuffer.position();
|
}
|
||||||
if (len > 0) {
|
int len = mSerialPort.read(buffer, mReadTimeout);
|
||||||
buffer = new byte[len];
|
if (len > 0) {
|
||||||
mWriteBuffer.rewind();
|
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
||||||
mWriteBuffer.get(buffer, 0, len);
|
final Listener listener = getListener();
|
||||||
mWriteBuffer.clear();
|
if (listener != null) {
|
||||||
}
|
final byte[] data = new byte[len];
|
||||||
}
|
System.arraycopy(buffer, 0, data, 0, len);
|
||||||
if (buffer != null) {
|
listener.onNewData(data);
|
||||||
if (DEBUG) {
|
}
|
||||||
Log.d(TAG, "Writing data len=" + len);
|
}
|
||||||
}
|
|
||||||
mSerialPort.write(buffer, mWriteTimeout);
|
// Handle outgoing data.
|
||||||
}
|
buffer = null;
|
||||||
}
|
synchronized (mWriteBufferLock) {
|
||||||
|
len = mWriteBuffer.position();
|
||||||
}
|
if (len > 0) {
|
||||||
|
buffer = new byte[len];
|
||||||
|
mWriteBuffer.rewind();
|
||||||
|
mWriteBuffer.get(buffer, 0, len);
|
||||||
|
mWriteBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "Writing data len=" + len);
|
||||||
|
}
|
||||||
|
mSerialPort.write(buffer, mWriteTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -53,7 +53,6 @@ import androidx.core.content.FileProvider;
|
||||||
import androidx.core.view.GravityCompat;
|
import androidx.core.view.GravityCompat;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
|
@ -2041,11 +2040,18 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
int openSerialPort(String serialPort) {
|
int openSerialPort(String serialPort) {
|
||||||
|
// Search if this same serial port is not already opened
|
||||||
|
|
||||||
|
|
||||||
Integer serialPortId = serialIndex;
|
Integer serialPortId = serialIndex;
|
||||||
Serial serial = new Serial(this, serialPortId);
|
Serial serial = new Serial(this, serialPortId);
|
||||||
if(serial.connect(serialPort)) {
|
if(serial.connect(serialPort)) {
|
||||||
serialsById.put(serialPortId, serial);
|
serialsById.put(serialPortId, serial);
|
||||||
serialIndex++;
|
serialIndex++;
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
int resId = Utils.resId(MainActivity.this, "string", "serial_connection_succeeded");
|
||||||
|
Toast.makeText(MainActivity.this, resId, Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
return serialPortId;
|
return serialPortId;
|
||||||
} else {
|
} else {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
|
@ -2069,6 +2075,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
if(serial != null) {
|
if(serial != null) {
|
||||||
serialsById.remove(serialPortIdInt);
|
serialsById.remove(serialPortIdInt);
|
||||||
serial.disconnect();
|
serial.disconnect();
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
int resId = Utils.resId(MainActivity.this, "string", "serial_disconnection_succeeded");
|
||||||
|
Toast.makeText(MainActivity.this, resId, Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2088,7 +2098,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
Integer serialPortIdInt = serialPortId;
|
Integer serialPortIdInt = serialPortId;
|
||||||
Serial serial = serialsById.get(serialPortIdInt);
|
Serial serial = serialsById.get(serialPortIdInt);
|
||||||
if(serial != null)
|
if(serial != null)
|
||||||
return serial.receive(nNumberOfBytesToRead);
|
return serial.read(nNumberOfBytesToRead);
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2097,7 +2107,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
Integer serialPortIdInt = serialPortId;
|
Integer serialPortIdInt = serialPortId;
|
||||||
Serial serial = serialsById.get(serialPortIdInt);
|
Serial serial = serialsById.get(serialPortIdInt);
|
||||||
if(serial != null)
|
if(serial != null)
|
||||||
return serial.send(buffer);
|
return serial.write(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
int serialPortPurgeComm(int serialPortId, int dwFlags) {
|
||||||
|
Integer serialPortIdInt = serialPortId;
|
||||||
|
Serial serial = serialsById.get(serialPortIdInt);
|
||||||
|
if(serial != null)
|
||||||
|
return serial.purgeComm(dwFlags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,8 @@
|
||||||
<string name="serial_ports_device_no_driver">No driver</string>
|
<string name="serial_ports_device_no_driver">No driver</string>
|
||||||
<string name="serial_ports_device_item_title">%s, Port %d</string>
|
<string name="serial_ports_device_item_title">%s, Port %d</string>
|
||||||
<string name="serial_ports_device_item_description">Vendor %04X, Product %04X</string>
|
<string name="serial_ports_device_item_description">Vendor %04X, Product %04X</string>
|
||||||
|
<string name="serial_connection_succeeded">USB serial device connected.</string>
|
||||||
|
<string name="serial_disconnection_succeeded">USB serial device disconnected.</string>
|
||||||
<string name="serial_connection_failed_device_not_found">Failed to connect the USB serial device: device not found (check the settings).</string>
|
<string name="serial_connection_failed_device_not_found">Failed to connect the USB serial device: device not found (check the settings).</string>
|
||||||
<string name="serial_connection_failed_no_driver_for_device">Failed to connect the USB serial device: no driver for device (check the settings).</string>
|
<string name="serial_connection_failed_no_driver_for_device">Failed to connect the USB serial device: no driver for device (check the settings).</string>
|
||||||
<string name="serial_connection_failed_not_enough_ports_at_device">Failed to connect the USB serial device: not enough ports at device (check the settings).</string>
|
<string name="serial_connection_failed_not_enough_ports_at_device">Failed to connect the USB serial device: not enough ports at device (check the settings).</string>
|
||||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
classpath 'com.android.tools.build:gradle:7.0.0'
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||||
|
|
Loading…
Reference in a new issue