diff --git a/firmware/app_layer_v1/digital.c b/firmware/app_layer_v1/digital.c index 5258d99ad..8b9966b61 100644 --- a/firmware/app_layer_v1/digital.c +++ b/firmware/app_layer_v1/digital.c @@ -34,6 +34,10 @@ #include "protocol.h" #include "sync.h" +static int num_digital_periodic_input_pins; +static int frame_num; +static BYTE freq_scale_by_pin[NUM_PINS]; + void SetDigitalOutLevel(int pin, int value) { log_printf("SetDigitalOutLevel(%d, %d)", pin, value); SAVE_PIN_FOR_LOG(pin); @@ -65,6 +69,133 @@ static void SendDigitalInStatusMessage(int pin, int value) { AppProtocolSendMessage(&msg); } +// timer 4 is clocked @250kHz +// we set its period to 25 so that a match occurs @10KHz +// used for PeriodicDigitalInput +static inline void Timer4Prepare() { + _T4IE = 0; // disable interrupt + _T4IF = 0; // clear interrupt + PR4 = 0x0019; // period is 25 clocks + //PR4 = 0x00F0; // period is 240 clocks + //PR4 = 0xC350; // period is 50000 clocks + _T4IP = 1; // interrupt priority 1 (this interrupt may write to outgoing channel) +} + +static inline void Timer4Start() { + log_printf("Starting Timer"); + TMR4 = 0x0000; // reset counter + _T4IE = 1; // enable interrupt +} + +static inline void Timer4Stop() { + log_printf("Stopping Timer"); + _T4IE = 0; // disable interrupt + _T4IF = 0; // clear interrupt +} + +static inline void DigitalInputStart() { + Timer4Start(); +} + +static inline void DigitalInputStop() { + Timer4Stop(); +} + +void DigitalInit() { + int i = 0; + num_digital_periodic_input_pins = 0; + frame_num = 0; + for (i = 0 ; i < NUM_PINS ; ++i) { + freq_scale_by_pin[i] = 0; + } + Timer4Prepare(); +} + +void SetDigitalPeriodicInput(int pin, int freq_scale) { + log_printf("SetDigitalPeriodicInput( %d, %d)", pin, freq_scale); + SAVE_PIN_FOR_LOG(pin); + + if (freq_scale) { + // Turn on a pin + if (0 == freq_scale_by_pin[pin]) { + num_digital_periodic_input_pins++; + if (num_digital_periodic_input_pins == 1) { // this is the first. + DigitalInputStart(); + } + } + } else { + // Turn off a pin + if (freq_scale_by_pin[pin]) { + num_digital_periodic_input_pins--; + } + } + freq_scale_by_pin[pin] = freq_scale; +} + +static inline void SetBit(int value, BYTE* byte_array, + int* p_byte_location, int* p_bit_location) { + if (*p_bit_location == 0) { + // initialize the byte + byte_array[*p_byte_location] = 0; + } + // set the value + BYTE mask = 1 << *p_bit_location; + if (value) { + byte_array[*p_byte_location] |= mask; + } else { + byte_array[*p_byte_location] &= ~mask; + } + (*p_bit_location)++; + if (*p_bit_location >= 8) { + *p_bit_location = 0; + (*p_byte_location)++; + byte_array[*p_byte_location] = 0; + } +} + +static inline void ReportPeriodicDigitalInStatus() { + + if (num_digital_periodic_input_pins) { + int pin = 0; + BYTE byte_message[16]; + int byte_location = 0; + byte_message[0] = frame_num; + byte_location = 1; + int bit_location = 0; + while (pin < NUM_PINS) { + if (freq_scale_by_pin[pin] && + frame_num % freq_scale_by_pin[pin] == 0) { + // capture the bit + SetBit(PinGetPort(pin), byte_message, &byte_location, &bit_location); + } + pin++; + } + + if (byte_location != 1 || bit_location != 0) { + OUTGOING_MESSAGE msg; + if (bit_location != 0) { + byte_location++; + } + + log_printf("ReportPeriodicDigitalInStatus(): #p:%d", num_digital_periodic_input_pins); + msg.type = REPORT_PERIODIC_DIGITAL_IN_STATUS; + msg.args.report_periodic_digital_in_status.size = byte_location; + AppProtocolSendMessageWithVarArg(&msg, byte_message, msg.args.report_periodic_digital_in_status.size); + } + } else { + DigitalInputStop(); + } + frame_num++; + if (frame_num >= 240) { + frame_num = 0; + } +} + +void __attribute__((__interrupt__, auto_psv)) _T4Interrupt() { + ReportPeriodicDigitalInStatus(); + _T4IF = 0; // clear +} + #define CHECK_PORT_CHANGE(name) \ do { \ unsigned int i = 0; \ diff --git a/firmware/app_layer_v1/digital.h b/firmware/app_layer_v1/digital.h index d32529eda..19f791918 100644 --- a/firmware/app_layer_v1/digital.h +++ b/firmware/app_layer_v1/digital.h @@ -30,9 +30,9 @@ #ifndef __DIGITAL_H__ #define __DIGITAL_H__ - +void DigitalInit(); void SetDigitalOutLevel(int pin, int value); void SetChangeNotify(int pin, int changeNotify); - +void SetDigitalPeriodicInput(int pin, int freqScale); #endif // __DIGITAL_H__ diff --git a/firmware/app_layer_v1/features.c b/firmware/app_layer_v1/features.c index 0e8b467c8..5372b7486 100644 --- a/firmware/app_layer_v1/features.c +++ b/firmware/app_layer_v1/features.c @@ -36,6 +36,7 @@ #include "logging.h" #include "protocol.h" #include "adc.h" +#include "digital.h" #include "pwm.h" #include "uart.h" #include "spi.h" @@ -223,6 +224,7 @@ void SoftReset() { PinsInit(); PWMInit(); ADCInit(); + DigitalInit(); UARTInit(); SPIInit(); I2CInit(); diff --git a/firmware/app_layer_v1/protocol.c b/firmware/app_layer_v1/protocol.c index e88840c57..25701ff01 100644 --- a/firmware/app_layer_v1/protocol.c +++ b/firmware/app_layer_v1/protocol.c @@ -90,7 +90,7 @@ const BYTE outgoing_arg_size[MESSAGE_TYPE_LIMIT] = { sizeof(CHECK_INTERFACE_RESPONSE_ARGS), sizeof(RESERVED_ARGS), sizeof(REPORT_DIGITAL_IN_STATUS_ARGS), - sizeof(RESERVED_ARGS), + sizeof(REPORT_PERIODIC_DIGITAL_IN_STATUS_ARGS), sizeof(SET_CHANGE_NOTIFY_ARGS), sizeof(REGISTER_PERIODIC_DIGITAL_SAMPLING_ARGS), sizeof(RESERVED_ARGS), @@ -294,6 +294,13 @@ static BOOL MessageDone() { } break; + case REGISTER_PERIODIC_DIGITAL_SAMPLING: + CHECK(rx_msg.args.register_periodic_digital_sampling.pin < NUM_PINS); + Echo(); + SetDigitalPeriodicInput(rx_msg.args.register_periodic_digital_sampling.pin, + rx_msg.args.register_periodic_digital_sampling.freq_scale); + break; + case SET_PIN_PWM: CHECK(rx_msg.args.set_pin_pwm.pin < NUM_PINS); CHECK(rx_msg.args.set_pin_pwm.pwm_num < NUM_PWM_MODULES); diff --git a/software/IOIOLib/src/ioio/lib/api/IOIO.java b/software/IOIOLib/src/ioio/lib/api/IOIO.java index 2f2de6ce8..d8addafaf 100644 --- a/software/IOIOLib/src/ioio/lib/api/IOIO.java +++ b/software/IOIOLib/src/ioio/lib/api/IOIO.java @@ -263,6 +263,15 @@ public DigitalInput openDigitalInput(int pin) public DigitalInput openDigitalInput(int pin, DigitalInput.Spec.Mode mode) throws ConnectionLostException; + /** + * TODO Write some documentation... + */ + public PeriodicDigitalInput openPeriodicDigitalInput(DigitalInput.Spec[] pins, int freqScale) + throws ConnectionLostException; + + public PeriodicDigitalInput openPeriodicDigitalInput(int[] pins, int freqScale) + throws ConnectionLostException; + /** * Open a pin for digital output. *

diff --git a/software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java b/software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java new file mode 100644 index 000000000..9781d7363 --- /dev/null +++ b/software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java @@ -0,0 +1,52 @@ +/* + * 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.api; + +import java.util.BitSet; + +import ioio.lib.api.exception.ConnectionLostException; + +/** + * TODO Documentation... + */ +public interface PeriodicDigitalInput extends Closeable { + + /** + * Read the value sensed on the pin. May block for a few milliseconds if + * called right after creation of the instance. If this is a problem, the + * calling thread may be interrupted. + * + * @return True for logical "HIGH", false for logical "LOW". + * @throws InterruptedException + * The calling thread has been interrupted. + * @throws ConnectionLostException + * The connection with the IOIO has been lost. + */ + public BitSet nextFrame() throws InterruptedException, ConnectionLostException; +} diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java index ea7aeb192..30f91f771 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java +++ b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java @@ -33,6 +33,7 @@ import ioio.lib.api.DigitalInput.Spec; import ioio.lib.api.DigitalInput.Spec.Mode; import ioio.lib.api.DigitalOutput; +import ioio.lib.api.PeriodicDigitalInput; import ioio.lib.api.IOIO; import ioio.lib.api.IOIOConnection; import ioio.lib.api.IcspMaster; @@ -347,6 +348,42 @@ synchronized public DigitalInput openDigitalInput(DigitalInput.Spec spec) } return result; } + + @Override + synchronized public PeriodicDigitalInput openPeriodicDigitalInput(DigitalInput.Spec[] pins, int freqScale) + throws ConnectionLostException { + checkState(); + int[] pinNumbers = new int[pins.length]; + for (int i = 0; i < pins.length ; ++i) { + PinFunctionMap.checkValidPin(pins[i].pin); + checkPinFree(pins[i].pin); + pinNumbers[i] = pins[i].pin; + } + + PeriodicDigitalInputImpl result = new PeriodicDigitalInputImpl(this, pinNumbers); + addDisconnectListener(result); + + for (int i = 0; i < pins.length ; ++i) { + openPins_[pins[i].pin] = true; + try { + Log.e(TAG, "Calling RPDI"); + incomingState_.addPeriodicDigitalInputListener(pins[i].pin, result); + protocol_.setPinDigitalIn(pins[i].pin, pins[i].mode); + protocol_.registerPeriodicDigitalSampling(pins[i].pin, freqScale); + } catch (IOException e) { + result.close(); + throw new ConnectionLostException(e); + } + } + return result; + } + + @Override + synchronized public PeriodicDigitalInput openPeriodicDigitalInput(int[] pins, int freqScale) + throws ConnectionLostException { + DigitalInput.Spec[] specs = new DigitalInput.Spec[pins.length]; + return openPeriodicDigitalInput(specs, freqScale); + } @Override public DigitalOutput openDigitalOutput(int pin, diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java b/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java index 8d8a40a80..ebcc70406 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java +++ b/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java @@ -324,7 +324,12 @@ synchronized public void setChangeNotify(int pin, boolean changeNotify) synchronized public void registerPeriodicDigitalSampling(int pin, int freqScale) throws IOException { - // TODO: implement + // TODO catch invalid values for pin and freqScale either in the lib, or here. + beginBatch(); + writeByte(REGISTER_PERIODIC_DIGITAL_SAMPLING); + writeByte(pin); + writeByte(freqScale); + endBatch(); } synchronized public void setPinAnalogIn(int pin) throws IOException { @@ -509,8 +514,7 @@ public void handleEstablishConnection(byte[] hardwareId, public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale); - public void handleReportPeriodicDigitalInStatus(int frameNum, - boolean values[]); + public void handleReportPeriodicDigitalInStatus(int size, byte[] data); public void handleAnalogPinStatus(int pin, boolean open); @@ -661,11 +665,18 @@ public void run() { break; case REGISTER_PERIODIC_DIGITAL_SAMPLING: - // TODO: implement + arg1 = readByte(); // pin + arg2 = readByte(); // freqScale + handler_.handleRegisterPeriodicDigitalSampling(arg1, arg2); break; case REPORT_PERIODIC_DIGITAL_IN_STATUS: - // TODO: implement + int msg_size = readByte(); + for (int i = 0; + i < msg_size ; i++) { + data[i] = (byte) readByte(); + } + handler_.handleReportPeriodicDigitalInStatus(msg_size, data); break; case REPORT_ANALOG_IN_FORMAT: diff --git a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java index 05cbccc4a..e57039f9e 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java +++ b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java @@ -37,6 +37,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import android.util.Log; +import android.widget.SlidingDrawer; class IncomingState implements IncomingHandler { enum ConnectionState { @@ -57,6 +58,10 @@ interface DataModuleListener { void reportAdditionalBuffer(int bytesToAdd); } + interface MultiPinDataModuleListener extends DataModuleListener { + int[] getPins(); + } + class InputPinState { private Queue listeners_ = new ConcurrentLinkedQueue(); private boolean currentOpen_ = false; @@ -86,8 +91,8 @@ void setValue(int v) { } class DataModuleState { - private Queue listeners_ = new ConcurrentLinkedQueue(); - private boolean currentOpen_ = false; + protected Queue listeners_ = new ConcurrentLinkedQueue(); + protected boolean currentOpen_ = false; void pushListener(DataModuleListener listener) { listeners_.add(listener); @@ -116,6 +121,19 @@ public void reportAdditionalBuffer(int bytesRemaining) { assert (currentOpen_); listeners_.peek().reportAdditionalBuffer(bytesRemaining); } + + boolean getCurrentOpen() { + return currentOpen_; + } + } + + class MultiPinDataModuleState extends DataModuleState { + protected Queue listeners_ = new ConcurrentLinkedQueue(); + + int[] getCurrentListenerPins() { + assert (currentOpen_); + return listeners_.peek().getPins(); + } } private final InputPinState[] intputPinStates_ = new InputPinState[Constants.NUM_PINS]; @@ -126,6 +144,8 @@ public void reportAdditionalBuffer(int bytesRemaining) { * Constants.INCAP_MODULES_DOUBLE.length + Constants.INCAP_MODULES_SINGLE.length]; private final DataModuleState icspState_ = new DataModuleState(); + private final MultiPinDataModuleState[] periodicDigitalInputStates_ = new MultiPinDataModuleState[Constants.NUM_PINS]; + private final int[] periodicDigitalInputFreqScale_ = new int[Constants.NUM_PINS]; private final Set disconnectListeners_ = new HashSet(); private ConnectionState connection_ = ConnectionState.INIT; public String hardwareId_; @@ -148,6 +168,12 @@ public IncomingState() { for (int i = 0; i < incapStates_.length; ++i) { incapStates_[i] = new DataModuleState(); } + for (int i = 0; i < periodicDigitalInputStates_.length; ++i) { + periodicDigitalInputStates_[i] = new MultiPinDataModuleState(); + } + for (int i = 0; i < periodicDigitalInputFreqScale_.length; ++i) { + periodicDigitalInputFreqScale_[i] = 0; + } } synchronized public void waitConnectionEstablished() @@ -201,6 +227,10 @@ public void addIcspListener(DataModuleListener listener) { icspState_.pushListener(listener); } + public void addPeriodicDigitalInputListener(int pin, DataModuleListener listener) { + periodicDigitalInputStates_[pin].pushListener(listener); + } + public void addSpiListener(int spiNum, DataModuleListener listener) { spiStates_[spiNum].pushListener(listener); } @@ -252,6 +282,9 @@ public void handleSoftReset() { incapState.closeCurrentListener(); } icspState_.closeCurrentListener(); + for (DataModuleState pdiState : periodicDigitalInputStates_) { + pdiState.closeCurrentListener(); + } } @Override @@ -274,10 +307,49 @@ public void handleSetChangeNotify(int pin, boolean changeNotify) { @Override public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale) { - // logMethod("handleRegisterPeriodicDigitalSampling", pin, freqScale); - assert (false); + Log.v("handleRegisterPeriodicDigitalSampling", "pin: " + Integer.toString(pin) + " freq: " + Integer.toString(freqScale)); + if (freqScale != 0) { + periodicDigitalInputStates_[pin].openNextListener(); + } else { + periodicDigitalInputStates_[pin].closeCurrentListener(); + } + periodicDigitalInputFreqScale_[pin] = freqScale; } + @Override + public void handleReportPeriodicDigitalInStatus(int size, byte[] data) { + // logMethod("handleReportPeriodicDigitalInStatus", size, data); + if (size <= 0) { return; } + byte frame_num = data[0]; + + int currentByte = 1; + byte mask = 1; + for (int pin = 0 ; + pin < Constants.NUM_PINS && + pin < periodicDigitalInputStates_.length && + pin < periodicDigitalInputFreqScale_.length ; + pin++) { + + final int freqScale = periodicDigitalInputFreqScale_[pin]; + if (freqScale == 0 || freqScale > 240) { continue; } + + if ( frame_num % freqScale == 0 ) { + // this bit is active. + if (0 == mask) { + mask = 1; + currentByte++; + } + // Set the next bit (size) to the bit in question. + byte[] bitData = new byte[2]; + bitData[0] = (byte) pin; + bitData[1] = (byte) ((0 != (data[currentByte] & mask)) ? 1 : 0); + periodicDigitalInputStates_[pin].dataReceived(bitData, bitData.length); + mask <<= 1; + + } + } + } + @Override public void handleAnalogPinStatus(int pin, boolean open) { // logMethod("handleAnalogPinStatus", pin, open); @@ -388,12 +460,6 @@ public void handleReportDigitalInStatus(int pin, boolean level) { intputPinStates_[pin].setValue(level ? 1 : 0); } - @Override - public void handleReportPeriodicDigitalInStatus(int frameNum, - boolean[] values) { - // logMethod("handleReportPeriodicDigitalInStatus", frameNum, values); - } - @Override public void handleReportAnalogInStatus(int pins[], int values[]) { // logMethod("handleReportAnalogInStatus", pins, values); diff --git a/software/IOIOLib/src/ioio/lib/impl/PeriodicDigitalInputImpl.java b/software/IOIOLib/src/ioio/lib/impl/PeriodicDigitalInputImpl.java new file mode 100644 index 000000000..8c54fda9f --- /dev/null +++ b/software/IOIOLib/src/ioio/lib/impl/PeriodicDigitalInputImpl.java @@ -0,0 +1,125 @@ +/* + * 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 ioio.lib.api.PeriodicDigitalInput; +import ioio.lib.api.exception.ConnectionLostException; +import ioio.lib.impl.IncomingState.DataModuleListener; + +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.BitSet; +import java.util.Deque; +import android.util.Log; + +class PeriodicDigitalInputImpl extends AbstractResource implements PeriodicDigitalInput, DataModuleListener { + private int[] pins_; + private BitSet currentValues_; + private BitSet validValues_; + private Deque values_ = new ArrayDeque(); + + PeriodicDigitalInputImpl(IOIOImpl ioio, int[] pins) throws ConnectionLostException { + super(ioio); + pins_ = pins; + currentValues_ = new BitSet(pins_.length); + validValues_ = new BitSet(pins_.length); + } + + @Override + synchronized public void close() { + super.close(); + try { + for (int i = 0 ; i < pins_.length ; i++) { + ioio_.protocol_.registerPeriodicDigitalSampling(pins_[i], 0); + } + } catch (IOException e) { + Log.e("ioio.lib.api.PeriodicDigitalInputImpl", "Exception occurred during close."); + } + } + + @Override + synchronized public BitSet nextFrame() throws InterruptedException, + ConnectionLostException { + checkState(); + while (0 == values_.size() && state_ != State.DISCONNECTED ) { + wait(); + } + checkState(); + Log.v("PeriodicDigitalInputImpl", "Internal Buffer Size: " + Integer.toString(values_.size() - 1)); + return values_.removeFirst(); + } + + @Override + public synchronized void disconnected() { + super.disconnected(); + notifyAll(); + } + + @Override + synchronized public void dataReceived(byte[] data, int size) { + assert(size == 2); + int pin = (int) data[0]; + byte value = data[1]; + int i = 0; + while (i < pins_.length) { + if (pins_[i] == pin) { + break; + } + i++; + } + assert (i < pins_.length); + + if (validValues_.get(i)) { + // We have an incomplete message. Clear it and start another one. + validValues_.clear(); + currentValues_.clear(); + } + + validValues_.set(i); + if (0 != value) { + currentValues_.set(i); + } + + if (validValues_.cardinality() == validValues_.length()) { + // Complete frame + BitSet currentValuesClone = (BitSet) currentValues_.clone(); + values_.addLast(currentValuesClone); + currentValues_.clear(); + validValues_.clear(); + // TODO Catch overflow here. We should just clear the buffer. + } + notifyAll(); + } + + @Override + public void reportAdditionalBuffer(int bytesToAdd) { + // Do Nothing + assert(false); + } +}