/*---------------------------------------------------------------------------
 * Copyright (C) 1999-2001 Dallas Semiconductor Corporation,
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dallas Semiconductor
 * shall not be used except as stated in the Dallas Semiconductor
 * Branding Policy.
 *---------------------------------------------------------------------------
 */

/**
 * This class is a thin wrapper over a SPI native library for the DS400em's
 * SPI device
 * This is a master only implementation.
 *
 * Data rate is either 1 or 2 MHz, depending on whether "divide" is set to one
 * or not respectively
 */
public class SPI400EM {

    public static final int DEFAULT_CLOCK_DELAY = 1;
    public static final int MAX_CLOCK_DELAY = 63;

    // SPI config state
    private boolean divide;
    private int ss_channel;
    private boolean CPOL;
    private boolean CPHA;
    private int delay;
    private boolean noskew;
    private boolean use_ss;
    private boolean bitOrder;


    /* Load native library in static intializer */
    static {
        try {
            System.loadLibrary("spi400em.tlib");
        } catch (UnsatisfiedLinkError ule) {
            System.out.println("Unable to load/initialize library:" +
                               ule.getMessage());
            throw ule;
        }
    }

    /**
     * Construct an SPI object with default configuration state which
     * includes:
     *  DEFAULT_CLOCK_DELAY
     *  Allow clock skew (i.e. don't disable interrupts during byte transfers)
     *  Use the SS line
     *  Use SCLK idle low
     *  Use SCLK phase normal
     *  Use most significant bit first transmission
     */
    public SPI400EM() {
        this(false, 0, false, false);
    }

    /**
     * Construct an SPI object with all configuration state specified.
     *
     * @param delay # of microseconds of delay between clock edges
     * @param noskew set to true to disable interrupts for strict clock rates
     * @param use_ss set to true to enable use of the SS line
     * @param CPOL set to <code>true</code> forces SCLK to idle high
     * @param CPHA set to <code>true</code> forces SCLK to transition at start of bit timing
     * @param bitOrder set to <code>true</code> to use Least Significant Bit first transmission
     */
    public SPI400EM(boolean divide, int ss_channel, boolean CPOL, boolean CPHA ) {
        this.divide = divide;
        this.ss_channel = ss_channel;
        this.CPOL = CPOL;
        this.CPHA = CPHA;
        SPI_Open(divide,ss_channel,CPOL,CPHA);
    }


    /**
     * Write <code>len</code> bytes of data to MOSI. Return data
     * simultaneously read from MISO. Source data is contained
     * in <code>ba</code> starting at <code>off</code>. Read data is returned
     * in the same positions within the array.
     *
     * @param ba source byte array, contains data to be written to the SPI slave
     * @param off starting offset into <code>ba</code>
     * @param len number of bytes to write
     */
    public synchronized int xmit(byte[] ba, int off, int len) {
        // Bounds check array access (easier here than in native)
    if ((len < 0) || (off < 0) || ((len + off) > ba.length))
       throw new ArrayIndexOutOfBoundsException();

        return xmitSPI(ba, off, len, ss_channel, noskew, use_ss, CPOL, CPHA, bitOrder);
    }





    /**
     * Enable the use of the SS (slave select) line during communication. If
     * set to <code>true</code>, the SS line is asserted before each
     * read or write operation and deasserted immediately following the
     * operation. Otherwise this pin is ignored.
     *
     * @param use_ss set to <code>true</code> to force use of SS pin
     */
    public void SlaveSelectChannel(int ss_channel) {
        this.ss_channel = ss_channel;
        //SS_Change(ss_channel);
        SPI_Open(divide, ss_channel, CPOL, CPHA);
    }

    /**
     * Select the Polarity of the SCLK line.  If set to <code>true</code>,
     * the SCLK will idle high, otherwise the SCLK will idle low
     *
     * @param CPOL set to <code>true</code> forces SCLK to idle high
     */
    public void setPolarity(boolean CPOL) {
        this.CPOL = CPOL;
        SPI_Open(divide, ss_channel, CPOL, CPHA);
    }

    /**
     * Select the Phase of the SCLK line.  If set to <code>true</code>,
     * the SCLK will transition at the start of bit timing
     *
     * @param CPHA set to <code>true</code> forces SCLK to transition at start of bit timing
     */
    public void setPhase(boolean CPHA) {
        this.CPHA = CPHA;
        SPI_Open(divide, ss_channel, CPOL, CPHA);

    }



    // *** Native SPI read and write methods.

    private static native int xmitSPI(byte[] ba, int off, int len,
                                      int ss_channel, boolean noskew, boolean use_ss,
                                      boolean CPOL, boolean CPHA, boolean bitOrder);


    private static native int SPI_Open(boolean divide, int ss_channel,
                                       boolean CPOL, boolean CPHA);


}


