package org.schmivits.airball.dataproxy.data;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import tw.com.prolific.driver.pl2303.PL2303Driver;
import tw.com.prolific.driver.pl2303.PL2303Driver.BaudRate;
import tw.com.prolific.driver.pl2303.PL2303Driver.DataBits;
import tw.com.prolific.driver.pl2303.PL2303Driver.FlowControl;
import tw.com.prolific.driver.pl2303.PL2303Driver.Parity;
import tw.com.prolific.driver.pl2303.PL2303Driver.StopBits;
import android.content.Context;
import android.hardware.usb.UsbManager;
public class ActualDataSourceStream extends ConcurrentProcess implements DataSourceStream {
private static final String USB_PERMISSION = "org.schmivits.airball.dataproxy.USB_PERMISSION";
private static final int READ_BUFFER_SIZE = 2048;
private static final long ENUMERATE_PAUSE = 1000L;
private static final long SETUP_PAUSE = 500L;
private static final long READ_PAUSE = 10L;
public static class SerialParameters {
public final BaudRate mBaudRate;
public final DataBits mDataBits;
public final StopBits mStopBits;
public final Parity mParity;
public final FlowControl mFlowControl;
public SerialParameters(
BaudRate baudRate,
DataBits dataBits,
StopBits stopBits,
Parity parity,
FlowControl flowControl) {
mBaudRate = baudRate;
mDataBits = dataBits;
mStopBits = stopBits;
mParity = parity;
mFlowControl = flowControl;
}
}
private final List<Listener> mListeners = new ArrayList<Listener>();
private SerialParameters mSerialParameters = new SerialParameters(
BaudRate.B115200,
DataBits.D8,
StopBits.S1,
Parity.NONE,
FlowControl.OFF);
private PL2303Driver mDriver;
private final byte[] mReadBuffer = new byte[READ_BUFFER_SIZE];
private final StringBuilder mLineBuilder = new StringBuilder();
private boolean mSerialChanged = false;
public ActualDataSourceStream(Context context, ProcessNode parent, String title) {
super(context, parent, title);
}
@Override protected void doRun() throws InterruptedException {
mDriver = new PL2303Driver(
(UsbManager) getContext().getSystemService(Context.USB_SERVICE),
getContext(),
USB_PERMISSION);
boolean doneSetup = false;
while (isRunning()) {
if (mSerialChanged) {
synchronized (this) {
if (mSerialChanged) {
doneSetup = false;
mSerialChanged = false;
}
}
}
if (!mDriver.isConnected()) {
doneSetup = false;
enumerateDriver();
} else if (mDriver.isConnected() && !doneSetup) {
doneSetup = setupDriver();
} else {
readFromDriver();
}
}
}
private void enumerateDriver() throws InterruptedException {
setStatus("Attempting enumerate ...");
if (mDriver.enumerate()) {
setStatus("Enumerate successful");
} else {
setStatus("Enumerate failed, sleeping ...");
Thread.sleep(ENUMERATE_PAUSE);
}
}
private boolean setupDriver() throws InterruptedException {
setStatus("Setting up driver ...");
boolean success;
try {
int setup = mDriver.setup(
mSerialParameters.mBaudRate,
mSerialParameters.mDataBits,
mSerialParameters.mStopBits,
mSerialParameters.mParity,
mSerialParameters.mFlowControl);
boolean initByBaudRate = mDriver.InitByBaudRate(
mSerialParameters.mBaudRate);
success = setup == 0 && initByBaudRate;
} catch (IOException e) {
success = false;
setStatus(e.toString());
}
if (success) {
setStatus("Setup succeeded");
return true;
} else {
setStatus("Setup failed, sleeping ...");
Thread.sleep(SETUP_PAUSE);
return false;
}
}
private void readFromDriver() throws InterruptedException {
for (int n; (n = mDriver.read(mReadBuffer)) > 0; ) {
receivedData(n);
}
Thread.sleep(READ_PAUSE);
}
private boolean isLineSeparator(char c) {
return c == '\r' || c == '\n';
}
private void receivedData(int n) {
for (int i = 0; i < n; i++) {
char c = (char) mReadBuffer[i];
if (isLineSeparator(c)) {
if (mLineBuilder.length() > 0) {
notifyListeners(mLineBuilder.toString());
setStatus(mLineBuilder.toString());
mLineBuilder.setLength(0);
}
} else {
mLineBuilder.append(c);
}
}
}
private void notifyListeners(String line) {
for (Listener l : mListeners) {
l.data(line);
}
}
@Override
public void addListener(Listener l) {
synchronized (mListeners) {
mListeners.add(l);
}
}
@Override
public void removeListener(Listener l) {
synchronized (mListeners) {
mListeners.remove(l);
}
}
public void setSerialParameters(SerialParameters p) {
synchronized (this) {
mSerialParameters = p;
mSerialChanged = true;
}
}
public SerialParameters getSerialParameters() {
return mSerialParameters;
}
}