package org.droidplanner.services.android.impl.communication.connection.usb;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import com.ftdi.j2xx.D2xxManager;
import com.ftdi.j2xx.FT_Device;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
class UsbFTDIConnection extends UsbConnection.UsbConnectionImpl {
private static final String TAG = UsbFTDIConnection.class.getSimpleName();
private static final byte LATENCY_TIMER = 32;
private final AtomicReference<FT_Device> ftDevRef = new AtomicReference<>();
protected UsbFTDIConnection(Context context, UsbConnection parentConn, int baudRate) {
super(context, parentConn, baudRate);
}
@Override
protected void openUsbConnection(Bundle extras) throws IOException {
D2xxManager ftD2xx = null;
try {
ftD2xx = D2xxManager.getInstance(mContext);
} catch (D2xxManager.D2xxException ex) {
mLogger.logErr(TAG, ex);
}
if (ftD2xx == null) {
throw new IOException("Unable to retrieve D2xxManager instance.");
}
int DevCount = ftD2xx.createDeviceInfoList(mContext);
Log.d(TAG, "Found " + DevCount + " ftdi devices.");
if (DevCount < 1) {
throw new IOException("No Devices found");
}
FT_Device ftDev = null;
try {
// FIXME: The NPE is coming from the library. Investigate if it's
// possible to fix there.
ftDev = ftD2xx.openByIndex(mContext, 0);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
if (ftDev == null) {
throw new IOException("No Devices found");
}
}
Log.d(TAG, "Opening using Baud rate " + mBaudRate);
ftDev.setBitMode((byte) 0, D2xxManager.FT_BITMODE_RESET);
ftDev.setBaudRate(mBaudRate);
ftDev.setDataCharacteristics(D2xxManager.FT_DATA_BITS_8, D2xxManager.FT_STOP_BITS_1,
D2xxManager.FT_PARITY_NONE);
ftDev.setFlowControl(D2xxManager.FT_FLOW_NONE, (byte) 0x00, (byte) 0x00);
ftDev.setLatencyTimer(LATENCY_TIMER);
ftDev.purge((byte) (D2xxManager.FT_PURGE_TX | D2xxManager.FT_PURGE_RX));
if (!ftDev.isOpen()) {
throw new IOException("Unable to open usb device connection.");
} else {
Log.d(TAG, "COM open");
}
ftDevRef.set(ftDev);
onUsbConnectionOpened(extras);
}
@Override
protected int readDataBlock(byte[] readData) throws IOException {
final FT_Device ftDev = ftDevRef.get();
if (ftDev == null || !ftDev.isOpen()) {
throw new IOException("Device is unavailable.");
}
int iavailable = ftDev.getQueueStatus();
if (iavailable > 0) {
if (iavailable > 4096)
iavailable = 4096;
try {
ftDev.read(readData, iavailable);
} catch (NullPointerException e) {
final String errorMsg = "Error Reading: " + e.getMessage()
+ "\nAssuming inaccessible USB device. Closing connection.";
Log.e(TAG, errorMsg, e);
throw new IOException(errorMsg, e);
}
}
if (iavailable == 0) {
iavailable = -1;
}
return iavailable;
}
@Override
protected void sendBuffer(byte[] buffer) {
final FT_Device ftDev = ftDevRef.get();
if (ftDev != null && ftDev.isOpen()) {
try {
ftDev.write(buffer);
} catch (Exception e) {
Log.e(TAG, "Error Sending: " + e.getMessage(), e);
}
}
}
@Override
protected void closeUsbConnection() throws IOException {
final FT_Device ftDev = ftDevRef.getAndSet(null);
if (ftDev != null) {
try {
ftDev.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
@Override
public String toString() {
return TAG;
}
}