/*
* Copyright 2013 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 java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import ioio.lib.api.PulseInput;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.impl.IncomingState.DataModuleListener;
class IncapImpl extends AbstractPin implements DataModuleListener, PulseInput {
private static final int MAX_QUEUE_LEN = 32;
private final PulseMode mode_;
private final ResourceManager.Resource incap_;
private long lastDuration_;
private final float timeBase_;
private final boolean doublePrecision_;
private long sampleCount_ = 0;
// TODO: a fixed-size array would have been much better than a linked list.
private Queue<Long> pulseQueue_ = new LinkedList<Long>();
public IncapImpl(IOIOImpl ioio, PulseMode mode, ResourceManager.Resource incap,
ResourceManager.Resource pin, int clockRate, int scale, boolean doublePrecision)
throws ConnectionLostException {
super(ioio, pin);
mode_ = mode;
incap_ = incap;
timeBase_ = 1.0f / (scale * clockRate);
doublePrecision_ = doublePrecision;
}
@Override
public float getFrequency() throws InterruptedException, ConnectionLostException {
if (mode_ != PulseMode.FREQ && mode_ != PulseMode.FREQ_SCALE_4
&& mode_ != PulseMode.FREQ_SCALE_16) {
throw new IllegalStateException(
"Cannot query frequency when module was not opened in frequency mode.");
}
return 1.0f / getDuration();
}
@Override
public float getFrequencySync() throws InterruptedException, ConnectionLostException {
if (mode_ != PulseMode.FREQ && mode_ != PulseMode.FREQ_SCALE_4
&& mode_ != PulseMode.FREQ_SCALE_16) {
throw new IllegalStateException(
"Cannot query frequency when module was not opened in frequency mode.");
}
return 1.0f / getDurationSync();
}
@Override
public synchronized float getDuration() throws InterruptedException, ConnectionLostException {
checkState();
// Wait for sample count to be non-zero.
while (sampleCount_ == 0) {
safeWait();
}
return timeBase_ * lastDuration_;
}
@Override
public synchronized float getDurationSync() throws InterruptedException, ConnectionLostException {
checkState();
final long initialSampleCount = sampleCount_;
// Wait for sample count to increase.
while (sampleCount_ == initialSampleCount) {
safeWait();
}
return timeBase_ * lastDuration_;
}
@Override
public synchronized float waitPulseGetDuration() throws InterruptedException,
ConnectionLostException {
return getDurationBuffered();
}
@Override
public synchronized float getDurationBuffered() throws InterruptedException,
ConnectionLostException {
if (mode_ != PulseMode.POSITIVE && mode_ != PulseMode.NEGATIVE) {
throw new IllegalStateException(
"Cannot wait for pulse when module was not opened in pulse mode.");
}
checkState();
while (pulseQueue_.isEmpty()) {
safeWait();
}
return timeBase_ * pulseQueue_.remove();
}
@Override
public synchronized void dataReceived(byte[] data, int size) {
lastDuration_ = ByteArrayToLong(data, size);
if (pulseQueue_.size() == MAX_QUEUE_LEN) {
pulseQueue_.remove();
}
pulseQueue_.add(lastDuration_);
++sampleCount_;
notifyAll();
}
private static long ByteArrayToLong(byte[] data, int size) {
long result = 0;
int i = size;
while (i-- > 0) {
result <<= 8;
result |= ((int) data[i]) & 0xFF;
}
if (result == 0) {
result = 1 << (size * 8);
}
return result;
}
@Override
public synchronized void reportAdditionalBuffer(int bytesToAdd) {
}
@Override
public synchronized void close() {
checkClose();
try {
ioio_.protocol_.incapClose(incap_.id, doublePrecision_);
ioio_.resourceManager_.free(incap_);
} catch (IOException e) {
}
super.close();
}
}