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