/*
* Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied.
*/
package ioio.lib.impl;
import android.util.Log;
import ioio.lib.api.DigitalInput;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.SpiMaster;
import ioio.lib.api.TwiMaster.Rate;
import ioio.lib.api.Uart;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class IOIOProtocol
{
static final int HARD_RESET = 0x00;
static final int ESTABLISH_CONNECTION = 0x00;
static final int SOFT_RESET = 0x01;
static final int CHECK_INTERFACE = 0x02;
static final int CHECK_INTERFACE_RESPONSE = 0x02;
static final int SET_PIN_DIGITAL_OUT = 0x03;
static final int SET_DIGITAL_OUT_LEVEL = 0x04;
static final int REPORT_DIGITAL_IN_STATUS = 0x04;
static final int SET_PIN_DIGITAL_IN = 0x05;
static final int REPORT_PERIODIC_DIGITAL_IN_STATUS = 0x05;
static final int SET_CHANGE_NOTIFY = 0x06;
static final int REGISTER_PERIODIC_DIGITAL_SAMPLING = 0x07;
static final int SET_PIN_PWM = 0x08;
static final int SET_PWM_DUTY_CYCLE = 0x09;
static final int SET_PWM_PERIOD = 0x0A;
static final int SET_PIN_ANALOG_IN = 0x0B;
static final int REPORT_ANALOG_IN_STATUS = 0x0B;
static final int SET_ANALOG_IN_SAMPLING = 0x0C;
static final int REPORT_ANALOG_IN_FORMAT = 0x0C;
static final int UART_CONFIG = 0x0D;
static final int UART_STATUS = 0x0D;
static final int UART_DATA = 0x0E;
static final int SET_PIN_UART = 0x0F;
static final int UART_REPORT_TX_STATUS = 0x0F;
static final int SPI_CONFIGURE_MASTER = 0x10;
static final int SPI_STATUS = 0x10;
static final int SPI_MASTER_REQUEST = 0x11;
static final int SPI_DATA = 0x11;
static final int SET_PIN_SPI = 0x12;
static final int SPI_REPORT_TX_STATUS = 0x12;
static final int I2C_CONFIGURE_MASTER = 0x13;
static final int I2C_STATUS = 0x13;
static final int I2C_WRITE_READ = 0x14;
static final int I2C_RESULT = 0x14;
static final int I2C_REPORT_TX_STATUS = 0x15;
static final int ICSP_SIX = 0x16;
static final int ICSP_REPORT_RX_STATUS = 0x16;
static final int ICSP_REGOUT = 0x17;
static final int ICSP_RESULT = 0x17;
static final int ICSP_PROG_ENTER = 0x18;
static final int ICSP_PROG_EXIT = 0x19;
static final int ICSP_CONFIG = 0x1A;
static final int INCAP_CONFIGURE = 0x1B;
static final int INCAP_STATUS = 0x1B;
static final int SET_PIN_INCAP = 0x1C;
static final int INCAP_REPORT = 0x1C;
static final int SOFT_CLOSE = 0x1D;
static final int[] SCALE_DIV = new int[] {
0x1F, // 31.25
0x1E, // 35.714
0x1D, // 41.667
0x1C, // 50
0x1B, // 62.5
0x1A, // 83.333
0x17, // 125
0x16, // 142.857
0x15, // 166.667
0x14, // 200
0x13, // 250
0x12, // 333.333
0x0F, // 500
0x0E, // 571.429
0x0D, // 666.667
0x0C, // 800
0x0B, // 1000
0x0A, // 1333.333
0x07, // 2000
0x06, // 2285.714
0x05, // 2666.667
0x04, // 3200
0x03, // 4000
0x02, // 5333.333
0x01 // 8000
};
private static final String TAG = "IOIOProtocol";
enum PwmScale {
SCALE_1X(1, 0), SCALE_8X(8, 3), SCALE_64X(64, 2), SCALE_256X(256, 1);
public final int scale;
private final int encoding;
PwmScale(int scale, int encoding) {
this.scale = scale;
this.encoding = encoding;
}
}
private byte[] outbuf_ = new byte[256];
private int pos_ = 0;
private int batchCounter_ = 0;
private void writeByte(int b) throws IOException {
assert (b >= 0 && b < 256);
if (pos_ == outbuf_.length) {
// buffer is full
flush();
}
//Log.v(TAG, "sending: 0x" + Integer.toHexString(b));
outbuf_[pos_++] = (byte) b;
}
public synchronized void beginBatch() {
++batchCounter_;
}
public synchronized void endBatch() throws IOException {
if (--batchCounter_ == 0) {
flush();
}
}
private void flush() throws IOException {
try {
out_.write(outbuf_, 0, pos_);
} finally {
pos_ = 0;
}
}
private void writeTwoBytes(int i) throws IOException {
writeByte(i & 0xFF);
writeByte(i >> 8);
}
private void writeThreeBytes(int i) throws IOException {
writeByte(i & 0xFF);
writeByte((i >> 8) & 0xFF);
writeByte((i >> 16) & 0xFF);
}
synchronized public void hardReset() throws IOException {
beginBatch();
writeByte(HARD_RESET);
writeByte('I');
writeByte('O');
writeByte('I');
writeByte('O');
endBatch();
}
synchronized public void softReset() throws IOException {
beginBatch();
writeByte(SOFT_RESET);
endBatch();
}
synchronized public void softClose() throws IOException {
beginBatch();
writeByte(SOFT_CLOSE);
endBatch();
}
synchronized public void checkInterface(byte[] interfaceId)
throws IOException {
if (interfaceId.length != 8) {
throw new IllegalArgumentException(
"interface ID must be exactly 8 bytes long");
}
beginBatch();
writeByte(CHECK_INTERFACE);
for (int i = 0; i < 8; ++i) {
writeByte(interfaceId[i]);
}
endBatch();
}
synchronized public void setDigitalOutLevel(int pin, boolean level)
throws IOException {
beginBatch();
writeByte(SET_DIGITAL_OUT_LEVEL);
writeByte(pin << 2 | (level ? 1 : 0));
endBatch();
}
synchronized public void setPinPwm(int pin, int pwmNum, boolean enable)
throws IOException {
beginBatch();
writeByte(SET_PIN_PWM);
writeByte(pin & 0x3F);
writeByte((enable ? 0x80 : 0x00) | (pwmNum & 0x0F));
endBatch();
}
synchronized public void setPwmDutyCycle(int pwmNum, int dutyCycle,
int fraction) throws IOException {
beginBatch();
writeByte(SET_PWM_DUTY_CYCLE);
writeByte(pwmNum << 2 | fraction);
writeTwoBytes(dutyCycle);
endBatch();
}
synchronized public void setPwmPeriod(int pwmNum, int period, PwmScale scale)
throws IOException {
beginBatch();
writeByte(SET_PWM_PERIOD);
writeByte(((scale.encoding & 0x02) << 6) | (pwmNum << 1)
| (scale.encoding & 0x01));
writeTwoBytes(period);
endBatch();
}
synchronized public void setPinIncap(int pin, int incapNum, boolean enable)
throws IOException {
beginBatch();
writeByte(SET_PIN_INCAP);
writeByte(pin);
writeByte(incapNum | (enable ? 0x80 : 0x00));
endBatch();
}
synchronized public void incapClose(int incapNum) throws IOException {
beginBatch();
writeByte(INCAP_CONFIGURE);
writeByte(incapNum);
writeByte(0x00);
endBatch();
}
synchronized public void incapConfigure(int incapNum, boolean double_prec,
int mode, int clock) throws IOException {
beginBatch();
writeByte(INCAP_CONFIGURE);
writeByte(incapNum);
writeByte((double_prec ? 0x80 : 0x00) | (mode << 3) | clock);
endBatch();
}
synchronized public void i2cWriteRead(int i2cNum, boolean tenBitAddr,
int address, int writeSize, int readSize, byte[] writeData)
throws IOException {
beginBatch();
writeByte(I2C_WRITE_READ);
writeByte(((address >> 8) << 6) | (tenBitAddr ? 0x20 : 0x00) | i2cNum);
writeByte(address & 0xFF);
writeByte(writeSize);
writeByte(readSize);
for (int i = 0; i < writeSize; ++i) {
writeByte(((int) writeData[i]) & 0xFF);
}
endBatch();
}
synchronized public void setPinDigitalOut(int pin, boolean value,
DigitalOutput.Spec.Mode mode) throws IOException {
beginBatch();
writeByte(SET_PIN_DIGITAL_OUT);
writeByte((pin << 2)
| (mode == DigitalOutput.Spec.Mode.OPEN_DRAIN ? 0x01 : 0x00)
| (value ? 0x02 : 0x00));
endBatch();
}
synchronized public void setPinDigitalIn(int pin,
DigitalInput.Spec.Mode mode) throws IOException {
int pull = 0;
if (mode == DigitalInput.Spec.Mode.PULL_UP) {
pull = 1;
} else if (mode == DigitalInput.Spec.Mode.PULL_DOWN) {
pull = 2;
}
beginBatch();
writeByte(SET_PIN_DIGITAL_IN);
writeByte((pin << 2) | pull);
endBatch();
}
synchronized public void setChangeNotify(int pin, boolean changeNotify)
throws IOException {
beginBatch();
writeByte(SET_CHANGE_NOTIFY);
writeByte((pin << 2) | (changeNotify ? 0x01 : 0x00));
endBatch();
}
synchronized public void registerPeriodicDigitalSampling(int pin,
int freqScale) throws IOException {
// TODO: implement
}
synchronized public void setPinAnalogIn(int pin) throws IOException {
beginBatch();
writeByte(SET_PIN_ANALOG_IN);
writeByte(pin);
endBatch();
}
synchronized public void setAnalogInSampling(int pin, boolean enable)
throws IOException {
beginBatch();
writeByte(SET_ANALOG_IN_SAMPLING);
writeByte((enable ? 0x80 : 0x00) | (pin & 0x3F));
endBatch();
}
synchronized public void uartData(int uartNum, int numBytes, byte data[])
throws IOException {
if (numBytes > 64) {
throw new IllegalArgumentException(
"A maximum of 64 bytes can be sent in one uartData message. Got: "
+ numBytes);
}
beginBatch();
writeByte(UART_DATA);
writeByte((numBytes - 1) | uartNum << 6);
for (int i = 0; i < numBytes; ++i) {
writeByte(((int) data[i]) & 0xFF);
}
endBatch();
}
synchronized public void uartConfigure(int uartNum, int rate,
boolean speed4x, Uart.StopBits stopbits, Uart.Parity parity)
throws IOException {
int parbits = parity == Uart.Parity.EVEN ? 1
: (parity == Uart.Parity.ODD ? 2 : 0);
beginBatch();
writeByte(UART_CONFIG);
writeByte((uartNum << 6) | (speed4x ? 0x08 : 0x00)
| (stopbits == Uart.StopBits.TWO ? 0x04 : 0x00) | parbits);
writeTwoBytes(rate);
endBatch();
}
synchronized public void uartClose(int uartNum) throws IOException {
beginBatch();
writeByte(UART_CONFIG);
writeByte(uartNum << 6);
writeTwoBytes(0);
endBatch();
}
synchronized public void setPinUart(int pin, int uartNum, boolean tx,
boolean enable) throws IOException {
beginBatch();
writeByte(SET_PIN_UART);
writeByte(pin);
writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | uartNum);
endBatch();
}
synchronized public void spiConfigureMaster(int spiNum,
SpiMaster.Config config) throws IOException {
beginBatch();
writeByte(SPI_CONFIGURE_MASTER);
writeByte((spiNum << 5) | SCALE_DIV[config.rate.ordinal()]);
writeByte((config.sampleOnTrailing ? 0x00 : 0x02)
| (config.invertClk ? 0x01 : 0x00));
endBatch();
}
synchronized public void spiClose(int spiNum) throws IOException {
beginBatch();
writeByte(SPI_CONFIGURE_MASTER);
writeByte(spiNum << 5);
writeByte(0x00);
endBatch();
}
synchronized public void setPinSpi(int pin, int mode, boolean enable,
int spiNum) throws IOException {
beginBatch();
writeByte(SET_PIN_SPI);
writeByte(pin);
writeByte((1 << 4) | (mode << 2) | spiNum);
endBatch();
}
synchronized public void spiMasterRequest(int spiNum, int ssPin,
byte data[], int dataBytes, int totalBytes, int responseBytes)
throws IOException {
final boolean dataNeqTotal = (dataBytes != totalBytes);
final boolean resNeqTotal = (responseBytes != totalBytes);
beginBatch();
writeByte(SPI_MASTER_REQUEST);
writeByte((spiNum << 6) | ssPin);
writeByte((dataNeqTotal ? 0x80 : 0x00) | (resNeqTotal ? 0x40 : 0x00)
| totalBytes - 1);
if (dataNeqTotal) {
writeByte(dataBytes);
}
if (resNeqTotal) {
writeByte(responseBytes);
}
for (int i = 0; i < dataBytes; ++i) {
writeByte(((int) data[i]) & 0xFF);
}
endBatch();
}
synchronized public void i2cConfigureMaster(int i2cNum, Rate rate,
boolean smbusLevels) throws IOException {
int rateBits = (rate == Rate.RATE_1MHz ? 3
: (rate == Rate.RATE_400KHz ? 2 : 1));
beginBatch();
writeByte(I2C_CONFIGURE_MASTER);
writeByte((smbusLevels ? 0x80 : 0) | (rateBits << 5) | i2cNum);
endBatch();
}
synchronized public void i2cClose(int i2cNum) throws IOException {
beginBatch();
writeByte(I2C_CONFIGURE_MASTER);
writeByte(i2cNum);
endBatch();
}
public void icspOpen() throws IOException {
beginBatch();
writeByte(ICSP_CONFIG);
writeByte(0x01);
endBatch();
}
public void icspClose() throws IOException {
beginBatch();
writeByte(ICSP_CONFIG);
writeByte(0x00);
endBatch();
}
public void icspEnter() throws IOException {
beginBatch();
writeByte(ICSP_PROG_ENTER);
endBatch();
}
public void icspExit() throws IOException {
beginBatch();
writeByte(ICSP_PROG_EXIT);
endBatch();
}
public void icspSix(int instruction) throws IOException {
beginBatch();
writeByte(ICSP_SIX);
writeThreeBytes(instruction);
endBatch();
}
public void icspRegout() throws IOException {
beginBatch();
writeByte(ICSP_REGOUT);
endBatch();
}
public interface IncomingHandler {
public void handleEstablishConnection(byte[] hardwareId,
byte[] bootloaderId, byte[] firmwareId);
public void handleConnectionLost();
public void handleSoftReset();
public void handleCheckInterfaceResponse(boolean supported);
public void handleSetChangeNotify(int pin, boolean changeNotify);
public void handleReportDigitalInStatus(int pin, boolean level);
public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale);
public void handleReportPeriodicDigitalInStatus(int frameNum,
boolean values[]);
public void handleAnalogPinStatus(int pin, boolean open);
public void handleReportAnalogInStatus(int pins[], int values[]);
public void handleUartOpen(int uartNum);
public void handleUartClose(int uartNum);
public void handleUartData(int uartNum, int numBytes, byte data[]);
public void handleUartReportTxStatus(int uartNum, int bytesRemaining);
public void handleSpiOpen(int spiNum);
public void handleSpiClose(int spiNum);
public void handleSpiData(int spiNum, int ssPin, byte data[],
int dataBytes);
public void handleSpiReportTxStatus(int spiNum, int bytesRemaining);
public void handleI2cOpen(int i2cNum);
public void handleI2cClose(int i2cNum);
public void handleI2cResult(int i2cNum, int size, byte[] data);
public void handleI2cReportTxStatus(int spiNum, int bytesRemaining);
void handleIcspOpen();
void handleIcspClose();
void handleIcspReportRxStatus(int bytesRemaining);
void handleIcspResult(int size, byte[] data);
public void handleIncapReport(int incapNum, int size, byte[] data);
public void handleIncapClose(int incapNum);
public void handleIncapOpen(int incapNum);
}
class IncomingThread extends Thread {
private int readOffset_ = 0;
private int validBytes_ = 0;
private byte[] inbuf_ = new byte[64];
private int[] analogFramePins_ = new int[0];
private Set<Integer> removedPins_ = new HashSet<Integer>(
Constants.NUM_ANALOG_PINS);
private Set<Integer> addedPins_ = new HashSet<Integer>(
Constants.NUM_ANALOG_PINS);
private void findDelta(int[] newPins) {
removedPins_.clear();
addedPins_.clear();
for (int i : analogFramePins_) {
removedPins_.add(i);
}
for (int i : newPins) {
addedPins_.add(i);
}
for (Iterator<Integer> it = removedPins_.iterator(); it.hasNext();) {
Integer current = it.next();
if (addedPins_.contains(current)) {
it.remove();
addedPins_.remove(current);
}
}
}
private void fillBuf() throws IOException {
try {
validBytes_ = in_.read(inbuf_, 0, inbuf_.length);
if (validBytes_ <= 0) {
throw new IOException("Unexpected stream closure");
}
//Log.v(TAG, "received " + validBytes_ + " bytes");
readOffset_ = 0;
} catch (IOException e) {
Log.i(TAG, "IOIO disconnected");
throw e;
}
}
private int readByte() throws IOException {
if (readOffset_ == validBytes_) {
fillBuf();
}
int b = inbuf_[readOffset_++];
b &= 0xFF; // make unsigned
//Log.v(TAG, "received: 0x" + Integer.toHexString(b));
return b;
}
private void readBytes(int size, byte[] buffer) throws IOException {
for (int i = 0; i < size; ++i) {
buffer[i] = (byte) readByte();
}
}
@Override
public void run() {
super.run();
setPriority(MAX_PRIORITY);
int arg1;
int arg2;
int numPins;
int size;
byte[] data = new byte[256];
try {
while (true) {
switch (arg1 = readByte()) {
case ESTABLISH_CONNECTION:
if (readByte() != 'I' || readByte() != 'O'
|| readByte() != 'I' || readByte() != 'O') {
throw new IOException(
"Bad establish connection magic");
}
byte[] hardwareId = new byte[8];
byte[] bootloaderId = new byte[8];
byte[] firmwareId = new byte[8];
readBytes(8, hardwareId);
readBytes(8, bootloaderId);
readBytes(8, firmwareId);
handler_.handleEstablishConnection(hardwareId,
bootloaderId, firmwareId);
break;
case SOFT_RESET:
handler_.handleSoftReset();
break;
case REPORT_DIGITAL_IN_STATUS:
arg1 = readByte();
handler_.handleReportDigitalInStatus(arg1 >> 2,
(arg1 & 0x01) == 1);
break;
case SET_CHANGE_NOTIFY:
arg1 = readByte();
handler_.handleSetChangeNotify(arg1 >> 2,
(arg1 & 0x01) == 1);
break;
case REGISTER_PERIODIC_DIGITAL_SAMPLING:
// TODO: implement
break;
case REPORT_PERIODIC_DIGITAL_IN_STATUS:
// TODO: implement
break;
case REPORT_ANALOG_IN_FORMAT:
numPins = readByte();
int[] newFormat = new int[numPins];
for (int i = 0; i < numPins; ++i) {
newFormat[i] = readByte();
}
findDelta(newFormat);
for (Integer i : removedPins_) {
handler_.handleAnalogPinStatus(i, false);
}
for (Integer i : addedPins_) {
handler_.handleAnalogPinStatus(i, true);
}
analogFramePins_ = newFormat;
break;
case REPORT_ANALOG_IN_STATUS:
numPins = analogFramePins_.length;
int header = 0;
int[] values = new int[numPins];
for (int i = 0; i < numPins; ++i) {
if (i % 4 == 0) {
header = readByte();
}
values[i] = (readByte() << 2) | (header & 0x03);
header >>= 2;
}
handler_.handleReportAnalogInStatus(analogFramePins_,
values);
break;
case UART_REPORT_TX_STATUS:
arg1 = readByte();
arg2 = readByte();
handler_.handleUartReportTxStatus(arg1 & 0x03,
(arg1 >> 2) | (arg2 << 6));
break;
case UART_DATA:
arg1 = readByte();
for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) {
data[i] = (byte) readByte();
}
handler_.handleUartData(arg1 >> 6, (arg1 & 0x3F) + 1,
data);
break;
case UART_STATUS:
arg1 = readByte();
if ((arg1 & 0x80) != 0) {
handler_.handleUartOpen(arg1 & 0x03);
} else {
handler_.handleUartClose(arg1 & 0x03);
}
break;
case SPI_DATA:
arg1 = readByte();
arg2 = readByte();
for (int i = 0; i < (arg1 & 0x3F) + 1; ++i) {
data[i] = (byte) readByte();
}
handler_.handleSpiData(arg1 >> 6, arg2 & 0x3F, data,
(arg1 & 0x3F) + 1);
break;
case SPI_REPORT_TX_STATUS:
arg1 = readByte();
arg2 = readByte();
handler_.handleSpiReportTxStatus(arg1 & 0x03,
(arg1 >> 2) | (arg2 << 6));
break;
case SPI_STATUS:
arg1 = readByte();
if ((arg1 & 0x80) != 0) {
handler_.handleSpiOpen(arg1 & 0x03);
} else {
handler_.handleSpiClose(arg1 & 0x03);
}
break;
case I2C_STATUS:
arg1 = readByte();
if ((arg1 & 0x80) != 0) {
handler_.handleI2cOpen(arg1 & 0x03);
} else {
handler_.handleI2cClose(arg1 & 0x03);
}
break;
case I2C_RESULT:
arg1 = readByte();
arg2 = readByte();
if (arg2 != 0xFF) {
for (int i = 0; i < arg2; ++i) {
data[i] = (byte) readByte();
}
}
handler_.handleI2cResult(arg1 & 0x03, arg2, data);
break;
case I2C_REPORT_TX_STATUS:
arg1 = readByte();
arg2 = readByte();
handler_.handleI2cReportTxStatus(arg1 & 0x03,
(arg1 >> 2) | (arg2 << 6));
break;
case CHECK_INTERFACE_RESPONSE:
arg1 = readByte();
handler_.handleCheckInterfaceResponse((arg1 & 0x01) == 1);
break;
case ICSP_REPORT_RX_STATUS:
arg1 = readByte();
arg2 = readByte();
handler_.handleIcspReportRxStatus(arg1 | (arg2 << 8));
break;
case ICSP_RESULT:
data[0] = (byte) readByte();
data[1] = (byte) readByte();
handler_.handleIcspResult(2, data);
break;
case ICSP_CONFIG:
arg1 = readByte();
if ((arg1 & 0x01) == 1) {
handler_.handleIcspOpen();
} else {
handler_.handleIcspClose();
}
break;
case INCAP_STATUS:
arg1 = readByte();
if ((arg1 & 0x80) != 0) {
handler_.handleIncapOpen(arg1 & 0x0F);
} else {
handler_.handleIncapClose(arg1 & 0x0F);
}
break;
case INCAP_REPORT:
arg1 = readByte();
size = arg1 >> 6;
if (size == 0) {
size = 4;
}
readBytes(size, data);
handler_.handleIncapReport(arg1 & 0x0F, size, data);
break;
case SOFT_CLOSE:
Log.d(TAG, "Received soft close.");
throw new IOException("Soft close");
default:
in_.close();
IOException e = new IOException(
"Received unexpected command: 0x"
+ Integer.toHexString(arg1));
Log.e("IOIOProtocol", "Protocol error", e);
throw e;
}
}
} catch (IOException e) {
handler_.handleConnectionLost();
}
}
}
private final InputStream in_;
private final OutputStream out_;
private final IncomingHandler handler_;
private final IncomingThread thread_ = new IncomingThread();
public IOIOProtocol(InputStream in, OutputStream out,
IncomingHandler handler) {
in_ = in;
out_ = out;
handler_ = handler;
thread_.start();
}
}