/* * 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.SpiMaster; import ioio.lib.api.exception.ConnectionLostException; import ioio.lib.impl.FlowControlledPacketSender.Packet; import ioio.lib.impl.FlowControlledPacketSender.Sender; import ioio.lib.impl.IncomingState.DataModuleListener; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; class SpiMasterImpl extends AbstractResource implements SpiMaster, DataModuleListener, Sender { public class SpiResult implements Result { boolean ready_; final byte[] data_; SpiResult(byte[] data) { data_ = data; } @Override public synchronized void waitReady() throws ConnectionLostException, InterruptedException { while (!ready_ && state_ != State.DISCONNECTED) { wait(); } checkState(); } } class OutgoingPacket implements Packet { int writeSize_; byte[] writeData_; int ssPin_; int readSize_; int totalSize_; @Override public int getSize() { return writeSize_ + 4; } } private final Queue<SpiResult> pendingRequests_ = new ConcurrentLinkedQueue<SpiResult>(); private final FlowControlledPacketSender outgoing_ = new FlowControlledPacketSender( this); private final int spiNum_; private final Map<Integer, Integer> ssPinToIndex_; private final int[] indexToSsPin_; private final int mosiPinNum_; private final int misoPinNum_; private final int clkPinNum_; SpiMasterImpl(IOIOImpl ioio, int spiNum, int mosiPinNum, int misoPinNum, int clkPinNum, int[] ssPins) throws ConnectionLostException { super(ioio); spiNum_ = spiNum; mosiPinNum_ = mosiPinNum; misoPinNum_ = misoPinNum; clkPinNum_ = clkPinNum; indexToSsPin_ = ssPins.clone(); ssPinToIndex_ = new HashMap<Integer, Integer>(ssPins.length); for (int i = 0; i < ssPins.length; ++i) { ssPinToIndex_.put(ssPins[i], i); } } @Override synchronized public void disconnected() { super.disconnected(); outgoing_.kill(); for (SpiResult tr : pendingRequests_) { synchronized (tr) { tr.notify(); } } } @Override public void writeRead(int slave, byte[] writeData, int writeSize, int totalSize, byte[] readData, int readSize) throws ConnectionLostException, InterruptedException { Result result = writeReadAsync(slave, writeData, writeSize, totalSize, readData, readSize); result.waitReady(); } @Override public SpiResult writeReadAsync(int slave, byte[] writeData, int writeSize, int totalSize, byte[] readData, int readSize) throws ConnectionLostException { checkState(); SpiResult result = new SpiResult(readData); OutgoingPacket p = new OutgoingPacket(); p.writeSize_ = writeSize; p.writeData_ = writeData; p.readSize_ = readSize; p.ssPin_ = indexToSsPin_[slave]; p.totalSize_ = totalSize; if (p.readSize_ > 0) { synchronized (this) { pendingRequests_.add(result); } } else { result.ready_ = true; } try { outgoing_.write(p); } catch (IOException e) { Log.e("SpiMasterImpl", "Exception caught", e); } return result; } @Override public void writeRead(byte[] writeData, int writeSize, int totalSize, byte[] readData, int readSize) throws ConnectionLostException, InterruptedException { writeRead(0, writeData, writeSize, totalSize, readData, readSize); } @Override public void dataReceived(byte[] data, int size) { SpiResult result = pendingRequests_.remove(); synchronized (result) { result.ready_ = true; System.arraycopy(data, 0, result.data_, 0, size); result.notify(); } } @Override public void reportAdditionalBuffer(int bytesRemaining) { outgoing_.readyToSend(bytesRemaining); } @Override synchronized public void close() { super.close(); outgoing_.close(); ioio_.closeSpi(spiNum_); ioio_.closePin(mosiPinNum_); ioio_.closePin(misoPinNum_); ioio_.closePin(clkPinNum_); for (int pin : indexToSsPin_) { ioio_.closePin(pin); } } @Override public void send(Packet packet) { OutgoingPacket p = (OutgoingPacket) packet; try { ioio_.protocol_.spiMasterRequest(spiNum_, p.ssPin_, p.writeData_, p.writeSize_, p.totalSize_, p.readSize_); } catch (IOException e) { Log.e("SpiImpl", "Caught exception", e); } } }