From 5469087f2791244f25f065de9e1ed09aa3860293 Mon Sep 17 00:00:00 2001 From: Jeff Eberl Date: Sun, 3 Jun 2012 17:35:00 -0600 Subject: [PATCH 1/4] Periodic Digital Input. Firmware changes. --- firmware/app_layer_v1/digital.c | 131 +++++++++++++++++++++++++++++++ firmware/app_layer_v1/digital.h | 4 +- firmware/app_layer_v1/features.c | 2 + firmware/app_layer_v1/protocol.c | 9 ++- 4 files changed, 143 insertions(+), 3 deletions(-) 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); From a5093e3e1d2e0ea99a743f92db6dc581002edbfb Mon Sep 17 00:00:00 2001 From: Jeff Eberl Date: Sun, 3 Jun 2012 17:50:02 -0600 Subject: [PATCH 2/4] Periodic Digital Input. IOIOLib updates. It's working, some. --- .../ioio/lib/api/DigitalPeriodicInput.java | 52 +++++ software/IOIOLib/src/ioio/lib/api/IOIO.java | 9 + .../lib/impl/DigitalPeriodicInputImpl.java | 191 ++++++++++++++++++ .../IOIOLib/src/ioio/lib/impl/IOIOImpl.java | 41 ++++ .../src/ioio/lib/impl/IOIOProtocol.java | 21 +- .../src/ioio/lib/impl/IncomingState.java | 22 +- 6 files changed, 325 insertions(+), 11 deletions(-) create mode 100644 software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java create mode 100644 software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java diff --git a/software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java b/software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java new file mode 100644 index 000000000..eed5bf822 --- /dev/null +++ b/software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.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 DigitalPeriodicInput 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/api/IOIO.java b/software/IOIOLib/src/ioio/lib/api/IOIO.java index 2f2de6ce8..b08fe2925 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 DigitalPeriodicInput openDigitalPeriodicInput(DigitalInput.Spec[] pins, int freqScale) + throws ConnectionLostException; + + public DigitalPeriodicInput openDigitalPeriodicInput(int[] pins, int freqScale) + throws ConnectionLostException; + /** * Open a pin for digital output. *

diff --git a/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java b/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java new file mode 100644 index 000000000..9269273e2 --- /dev/null +++ b/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java @@ -0,0 +1,191 @@ +/* + * 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.DigitalPeriodicInput; +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 java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +import android.util.Log; +import android.util.Pair; + +class DigitalPeriodicInputImpl extends AbstractResource implements DigitalPeriodicInput { + static public DigitalPeriodicInputMasterImpl master_ = null; + private int freq_scale_ = 0; + private List pins_; + private Deque values_ = new ArrayDeque(); + + DigitalPeriodicInputImpl(IOIOImpl ioio, List pins, int freq_scale) throws ConnectionLostException { + super(ioio); + if ( null == master_) { + master_ = new DigitalPeriodicInputMasterImpl(ioio); + } + master_.addInput(this); + pins_ = pins; + freq_scale_ = freq_scale; + } + + synchronized public int getFreqScale() { + return freq_scale_; + } + + synchronized public List getPins() { + return pins_; + } + + synchronized public void addValues(BitSet values) { + // Log.v("DigitalInputImpl", "Pin " + pinNum_ + " value is " + value); + assert (values.size() == pins_.size()); + values_.addLast(values); + // TODO Catch overflow here. We should just clear the buffer. + notifyAll(); + } + + @Override + synchronized public void close() { + super.close(); + try { + master_.removeInput(this); + Iterator pin_it = pins_.iterator(); + while (pin_it.hasNext()) { + int pin = (Integer) pin_it.next(); + ioio_.protocol_.registerPeriodicDigitalSampling(pin, 0); + } + freq_scale_ = 0; + } catch (IOException e) { + Log.e("ioio.lib.api.DigitalPeriodicInputImpl", "Exception occurred during close."); + } + } + + @Override + synchronized public BitSet nextFrame() throws InterruptedException, + ConnectionLostException { + checkState(); + while (0 == values_.size() && state_ != State.DISCONNECTED ) { + wait(); + } + checkState(); + Log.v("DigitalPeriodicInputImpl", "Internal Buffer Size: " + Integer.toString(values_.size() - 1)); + return values_.removeFirst(); + } + + @Override + public synchronized void disconnected() { + super.disconnected(); + notifyAll(); + } +} + +class DigitalPeriodicInputMasterImpl extends AbstractResource implements DataModuleListener { + private Queue openDPIs_ = new ConcurrentLinkedQueue(); + + public DigitalPeriodicInputMasterImpl(IOIOImpl ioio) + throws ConnectionLostException { + super(ioio); + // TODO Auto-generated constructor stub + } + + public void addInput(DigitalPeriodicInputImpl input) { + openDPIs_.add(input); + } + + public void removeInput(DigitalPeriodicInputImpl input) { + // TODO Important... How do I remove just this one? Maybe I need a map + } + + @Override + public void dataReceived(byte[] data, int size) { + if (size <= 0) { return; } + byte frame_num = data[0]; + + DigitalPeriodicInputImpl[] reportingInputs = new DigitalPeriodicInputImpl[openDPIs_.size()]; + Map > pinCorrespondences = new TreeMap >(); + BitSet[] values = new BitSet[openDPIs_.size()]; + int numReportingInputs = 0; + for (DigitalPeriodicInputImpl input : openDPIs_) { + + if (input.getFreqScale() == 0 || input.getFreqScale() > 240) { continue; } + + if ( frame_num % input.getFreqScale() == 0 && input.getPins().size() > 0) { + // There are bits that belong to this input. + + reportingInputs[numReportingInputs] = input; + values[numReportingInputs] = new BitSet(input.getPins().size()); + + for (int i = 0 ; i < input.getPins().size() ; ++i) { + pinCorrespondences.put(input.getPins().get(i), new Pair(numReportingInputs, i)); + } + numReportingInputs++; + } + } + + Log.v("DPIMaster", "NextByte: " + Integer.toString((int)data[1])); + int currentByte = 1; + byte mask = 1; + for (Integer pin : pinCorrespondences.keySet()) { + BitSet bitSet = values[pinCorrespondences.get(pin).first]; + if (0 == mask) { + mask = 1; + currentByte++; + } + // Set the next bit (size) to the bit in question. + Log.v("DPIMaster", "pin: " + + Integer.toString(pin) + + " location: " + + Integer.toString(pinCorrespondences.get(pin).second) + + " value: " + + Boolean.toString(0 != (data[currentByte] & mask))); + + bitSet.set(pinCorrespondences.get(pin).second, 0 != (data[currentByte] & mask)); + mask <<= 1; + } + + for (int i = 0 ; i < numReportingInputs ; i++) { + reportingInputs[i].addValues(values[i]); + } + } + + @Override + public void reportAdditionalBuffer(int bytesToAdd) { + // Never gets called. + } + +} + diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java index ea7aeb192..b7bc0cd57 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.DigitalPeriodicInput; import ioio.lib.api.IOIO; import ioio.lib.api.IOIOConnection; import ioio.lib.api.IcspMaster; @@ -50,6 +51,8 @@ import ioio.lib.impl.IncomingState.DisconnectListener; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import android.util.Log; @@ -347,6 +350,44 @@ synchronized public DigitalInput openDigitalInput(DigitalInput.Spec spec) } return result; } + + @Override + synchronized public DigitalPeriodicInput openDigitalPeriodicInput(DigitalInput.Spec[] pins, int freqScale) + throws ConnectionLostException { + checkState(); + List pinNumbers = new ArrayList(); + for (int i = 0; i < pins.length ; ++i) { + PinFunctionMap.checkValidPin(pins[i].pin); + checkPinFree(pins[i].pin); + pinNumbers.add(pins[i].pin); + } + + DigitalPeriodicInputImpl result = new DigitalPeriodicInputImpl(this, pinNumbers, freqScale); + addDisconnectListener(result); + + // TODO We can only do this once. + incomingState_.addDigitalPeriodicInputListener(DigitalPeriodicInputImpl.master_); + + for (int i = 0; i < pins.length ; ++i) { + openPins_[pins[i].pin] = true; + try { + Log.e(TAG, "Calling RPDI"); + 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 DigitalPeriodicInput openDigitalPeriodicInput(int[] pins, int freqScale) + throws ConnectionLostException { + DigitalInput.Spec[] specs = new DigitalInput.Spec[pins.length]; + return openDigitalPeriodicInput(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..5cc981a35 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java +++ b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java @@ -126,6 +126,7 @@ public void reportAdditionalBuffer(int bytesRemaining) { * Constants.INCAP_MODULES_DOUBLE.length + Constants.INCAP_MODULES_SINGLE.length]; private final DataModuleState icspState_ = new DataModuleState(); + private final DataModuleState digitalPeriodicInputState_ = new DataModuleState(); private final Set disconnectListeners_ = new HashSet(); private ConnectionState connection_ = ConnectionState.INIT; public String hardwareId_; @@ -201,6 +202,10 @@ public void addIcspListener(DataModuleListener listener) { icspState_.pushListener(listener); } + public void addDigitalPeriodicInputListener(DataModuleListener listener) { + digitalPeriodicInputState_.pushListener(listener); + } + public void addSpiListener(int spiNum, DataModuleListener listener) { spiStates_[spiNum].pushListener(listener); } @@ -252,6 +257,7 @@ public void handleSoftReset() { incapState.closeCurrentListener(); } icspState_.closeCurrentListener(); + digitalPeriodicInputState_.closeCurrentListener(); } @Override @@ -275,9 +281,19 @@ public void handleSetChangeNotify(int pin, boolean changeNotify) { @Override public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale) { // logMethod("handleRegisterPeriodicDigitalSampling", pin, freqScale); + if (freqScale != 0) { + intputPinStates_[pin].openNextListener(); + } else { + intputPinStates_[pin].closeCurrentListener(); + } assert (false); } + @Override + public void handleReportPeriodicDigitalInStatus(int size, byte[] data) { + digitalPeriodicInputState_.dataReceived(data, size); + } + @Override public void handleAnalogPinStatus(int pin, boolean open) { // logMethod("handleAnalogPinStatus", pin, open); @@ -388,12 +404,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); From 0108fd434e837090fd4bba3323c72d8c73062bc3 Mon Sep 17 00:00:00 2001 From: Jeff Eberl Date: Sun, 3 Jun 2012 18:00:59 -0600 Subject: [PATCH 3/4] Periodic Digital Input. Fewer Log messages. --- .../src/ioio/lib/impl/DigitalPeriodicInputImpl.java | 8 -------- software/IOIOLib/src/ioio/lib/impl/IncomingState.java | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java b/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java index 9269273e2..641e3b106 100644 --- a/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java +++ b/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java @@ -156,7 +156,6 @@ public void dataReceived(byte[] data, int size) { } } - Log.v("DPIMaster", "NextByte: " + Integer.toString((int)data[1])); int currentByte = 1; byte mask = 1; for (Integer pin : pinCorrespondences.keySet()) { @@ -166,13 +165,6 @@ public void dataReceived(byte[] data, int size) { currentByte++; } // Set the next bit (size) to the bit in question. - Log.v("DPIMaster", "pin: " + - Integer.toString(pin) + - " location: " + - Integer.toString(pinCorrespondences.get(pin).second) + - " value: " + - Boolean.toString(0 != (data[currentByte] & mask))); - bitSet.set(pinCorrespondences.get(pin).second, 0 != (data[currentByte] & mask)); mask <<= 1; } diff --git a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java index 5cc981a35..e6e9f52d3 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java +++ b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java @@ -291,6 +291,7 @@ public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale) { @Override public void handleReportPeriodicDigitalInStatus(int size, byte[] data) { + // logMethod("handleReportPeriodicDigitalInStatus", size, data); digitalPeriodicInputState_.dataReceived(data, size); } From 03c1046c757f468f4bc0b5493803e43e4dae1f89 Mon Sep 17 00:00:00 2001 From: Jeff Eberl Date: Wed, 6 Jun 2012 20:16:47 -0600 Subject: [PATCH 4/4] Renamed to PeriodicDigitalInput and removed PeriodicDigitalInputMasterImpl class. --- software/IOIOLib/src/ioio/lib/api/IOIO.java | 4 +- ...icInput.java => PeriodicDigitalInput.java} | 2 +- .../lib/impl/DigitalPeriodicInputImpl.java | 183 ------------------ .../IOIOLib/src/ioio/lib/impl/IOIOImpl.java | 20 +- .../src/ioio/lib/impl/IncomingState.java | 77 ++++++-- .../lib/impl/PeriodicDigitalInputImpl.java | 125 ++++++++++++ 6 files changed, 202 insertions(+), 209 deletions(-) rename software/IOIOLib/src/ioio/lib/api/{DigitalPeriodicInput.java => PeriodicDigitalInput.java} (97%) delete mode 100644 software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java create mode 100644 software/IOIOLib/src/ioio/lib/impl/PeriodicDigitalInputImpl.java diff --git a/software/IOIOLib/src/ioio/lib/api/IOIO.java b/software/IOIOLib/src/ioio/lib/api/IOIO.java index b08fe2925..d8addafaf 100644 --- a/software/IOIOLib/src/ioio/lib/api/IOIO.java +++ b/software/IOIOLib/src/ioio/lib/api/IOIO.java @@ -266,10 +266,10 @@ public DigitalInput openDigitalInput(int pin, DigitalInput.Spec.Mode mode) /** * TODO Write some documentation... */ - public DigitalPeriodicInput openDigitalPeriodicInput(DigitalInput.Spec[] pins, int freqScale) + public PeriodicDigitalInput openPeriodicDigitalInput(DigitalInput.Spec[] pins, int freqScale) throws ConnectionLostException; - public DigitalPeriodicInput openDigitalPeriodicInput(int[] pins, int freqScale) + public PeriodicDigitalInput openPeriodicDigitalInput(int[] pins, int freqScale) throws ConnectionLostException; /** diff --git a/software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java b/software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java similarity index 97% rename from software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java rename to software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java index eed5bf822..9781d7363 100644 --- a/software/IOIOLib/src/ioio/lib/api/DigitalPeriodicInput.java +++ b/software/IOIOLib/src/ioio/lib/api/PeriodicDigitalInput.java @@ -35,7 +35,7 @@ /** * TODO Documentation... */ -public interface DigitalPeriodicInput extends Closeable { +public interface PeriodicDigitalInput extends Closeable { /** * Read the value sensed on the pin. May block for a few milliseconds if diff --git a/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java b/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java deleted file mode 100644 index 641e3b106..000000000 --- a/software/IOIOLib/src/ioio/lib/impl/DigitalPeriodicInputImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.DigitalPeriodicInput; -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 java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentLinkedQueue; - -import android.util.Log; -import android.util.Pair; - -class DigitalPeriodicInputImpl extends AbstractResource implements DigitalPeriodicInput { - static public DigitalPeriodicInputMasterImpl master_ = null; - private int freq_scale_ = 0; - private List pins_; - private Deque values_ = new ArrayDeque(); - - DigitalPeriodicInputImpl(IOIOImpl ioio, List pins, int freq_scale) throws ConnectionLostException { - super(ioio); - if ( null == master_) { - master_ = new DigitalPeriodicInputMasterImpl(ioio); - } - master_.addInput(this); - pins_ = pins; - freq_scale_ = freq_scale; - } - - synchronized public int getFreqScale() { - return freq_scale_; - } - - synchronized public List getPins() { - return pins_; - } - - synchronized public void addValues(BitSet values) { - // Log.v("DigitalInputImpl", "Pin " + pinNum_ + " value is " + value); - assert (values.size() == pins_.size()); - values_.addLast(values); - // TODO Catch overflow here. We should just clear the buffer. - notifyAll(); - } - - @Override - synchronized public void close() { - super.close(); - try { - master_.removeInput(this); - Iterator pin_it = pins_.iterator(); - while (pin_it.hasNext()) { - int pin = (Integer) pin_it.next(); - ioio_.protocol_.registerPeriodicDigitalSampling(pin, 0); - } - freq_scale_ = 0; - } catch (IOException e) { - Log.e("ioio.lib.api.DigitalPeriodicInputImpl", "Exception occurred during close."); - } - } - - @Override - synchronized public BitSet nextFrame() throws InterruptedException, - ConnectionLostException { - checkState(); - while (0 == values_.size() && state_ != State.DISCONNECTED ) { - wait(); - } - checkState(); - Log.v("DigitalPeriodicInputImpl", "Internal Buffer Size: " + Integer.toString(values_.size() - 1)); - return values_.removeFirst(); - } - - @Override - public synchronized void disconnected() { - super.disconnected(); - notifyAll(); - } -} - -class DigitalPeriodicInputMasterImpl extends AbstractResource implements DataModuleListener { - private Queue openDPIs_ = new ConcurrentLinkedQueue(); - - public DigitalPeriodicInputMasterImpl(IOIOImpl ioio) - throws ConnectionLostException { - super(ioio); - // TODO Auto-generated constructor stub - } - - public void addInput(DigitalPeriodicInputImpl input) { - openDPIs_.add(input); - } - - public void removeInput(DigitalPeriodicInputImpl input) { - // TODO Important... How do I remove just this one? Maybe I need a map - } - - @Override - public void dataReceived(byte[] data, int size) { - if (size <= 0) { return; } - byte frame_num = data[0]; - - DigitalPeriodicInputImpl[] reportingInputs = new DigitalPeriodicInputImpl[openDPIs_.size()]; - Map > pinCorrespondences = new TreeMap >(); - BitSet[] values = new BitSet[openDPIs_.size()]; - int numReportingInputs = 0; - for (DigitalPeriodicInputImpl input : openDPIs_) { - - if (input.getFreqScale() == 0 || input.getFreqScale() > 240) { continue; } - - if ( frame_num % input.getFreqScale() == 0 && input.getPins().size() > 0) { - // There are bits that belong to this input. - - reportingInputs[numReportingInputs] = input; - values[numReportingInputs] = new BitSet(input.getPins().size()); - - for (int i = 0 ; i < input.getPins().size() ; ++i) { - pinCorrespondences.put(input.getPins().get(i), new Pair(numReportingInputs, i)); - } - numReportingInputs++; - } - } - - int currentByte = 1; - byte mask = 1; - for (Integer pin : pinCorrespondences.keySet()) { - BitSet bitSet = values[pinCorrespondences.get(pin).first]; - if (0 == mask) { - mask = 1; - currentByte++; - } - // Set the next bit (size) to the bit in question. - bitSet.set(pinCorrespondences.get(pin).second, 0 != (data[currentByte] & mask)); - mask <<= 1; - } - - for (int i = 0 ; i < numReportingInputs ; i++) { - reportingInputs[i].addValues(values[i]); - } - } - - @Override - public void reportAdditionalBuffer(int bytesToAdd) { - // Never gets called. - } - -} - diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java index b7bc0cd57..30f91f771 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java +++ b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java @@ -33,7 +33,7 @@ import ioio.lib.api.DigitalInput.Spec; import ioio.lib.api.DigitalInput.Spec.Mode; import ioio.lib.api.DigitalOutput; -import ioio.lib.api.DigitalPeriodicInput; +import ioio.lib.api.PeriodicDigitalInput; import ioio.lib.api.IOIO; import ioio.lib.api.IOIOConnection; import ioio.lib.api.IcspMaster; @@ -51,8 +51,6 @@ import ioio.lib.impl.IncomingState.DisconnectListener; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import android.util.Log; @@ -352,26 +350,24 @@ synchronized public DigitalInput openDigitalInput(DigitalInput.Spec spec) } @Override - synchronized public DigitalPeriodicInput openDigitalPeriodicInput(DigitalInput.Spec[] pins, int freqScale) + synchronized public PeriodicDigitalInput openPeriodicDigitalInput(DigitalInput.Spec[] pins, int freqScale) throws ConnectionLostException { checkState(); - List pinNumbers = new ArrayList(); + int[] pinNumbers = new int[pins.length]; for (int i = 0; i < pins.length ; ++i) { PinFunctionMap.checkValidPin(pins[i].pin); checkPinFree(pins[i].pin); - pinNumbers.add(pins[i].pin); + pinNumbers[i] = pins[i].pin; } - DigitalPeriodicInputImpl result = new DigitalPeriodicInputImpl(this, pinNumbers, freqScale); + PeriodicDigitalInputImpl result = new PeriodicDigitalInputImpl(this, pinNumbers); addDisconnectListener(result); - // TODO We can only do this once. - incomingState_.addDigitalPeriodicInputListener(DigitalPeriodicInputImpl.master_); - 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) { @@ -383,10 +379,10 @@ synchronized public DigitalPeriodicInput openDigitalPeriodicInput(DigitalInput.S } @Override - synchronized public DigitalPeriodicInput openDigitalPeriodicInput(int[] pins, int freqScale) + synchronized public PeriodicDigitalInput openPeriodicDigitalInput(int[] pins, int freqScale) throws ConnectionLostException { DigitalInput.Spec[] specs = new DigitalInput.Spec[pins.length]; - return openDigitalPeriodicInput(specs, freqScale); + return openPeriodicDigitalInput(specs, freqScale); } @Override diff --git a/software/IOIOLib/src/ioio/lib/impl/IncomingState.java b/software/IOIOLib/src/ioio/lib/impl/IncomingState.java index e6e9f52d3..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,7 +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 DataModuleState digitalPeriodicInputState_ = 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_; @@ -149,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() @@ -202,8 +227,8 @@ public void addIcspListener(DataModuleListener listener) { icspState_.pushListener(listener); } - public void addDigitalPeriodicInputListener(DataModuleListener listener) { - digitalPeriodicInputState_.pushListener(listener); + public void addPeriodicDigitalInputListener(int pin, DataModuleListener listener) { + periodicDigitalInputStates_[pin].pushListener(listener); } public void addSpiListener(int spiNum, DataModuleListener listener) { @@ -257,7 +282,9 @@ public void handleSoftReset() { incapState.closeCurrentListener(); } icspState_.closeCurrentListener(); - digitalPeriodicInputState_.closeCurrentListener(); + for (DataModuleState pdiState : periodicDigitalInputStates_) { + pdiState.closeCurrentListener(); + } } @Override @@ -280,19 +307,47 @@ public void handleSetChangeNotify(int pin, boolean changeNotify) { @Override public void handleRegisterPeriodicDigitalSampling(int pin, int freqScale) { - // logMethod("handleRegisterPeriodicDigitalSampling", pin, freqScale); + Log.v("handleRegisterPeriodicDigitalSampling", "pin: " + Integer.toString(pin) + " freq: " + Integer.toString(freqScale)); if (freqScale != 0) { - intputPinStates_[pin].openNextListener(); + periodicDigitalInputStates_[pin].openNextListener(); } else { - intputPinStates_[pin].closeCurrentListener(); + periodicDigitalInputStates_[pin].closeCurrentListener(); } - assert (false); + periodicDigitalInputFreqScale_[pin] = freqScale; } @Override public void handleReportPeriodicDigitalInStatus(int size, byte[] data) { // logMethod("handleReportPeriodicDigitalInStatus", size, data); - digitalPeriodicInputState_.dataReceived(data, size); + 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 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); + } +}