 1Content-type: application/x-Unknown; charset=UTF8package nmc.sidekick;
import com.ajile.jem.rawJEM;
import com.ajile.drivers.irq.InterruptController;
import com.ajile.drivers.irq.InterruptEventListener;

// Let's Use AjileAddr instead of nested class...
/*
class Addr {
    public static final int IOCR = 0xffff00a0;

    public static final int GPTC_GMR    = 0x09001000;
    public static final int GPTC_IOMR   = 0x09001004;
    public static final int GPTC_IOPR   = 0x09001008;
    public static final int GPTC_ISR    = 0x09001010;  // Interrupt Status Reg
    public static final int GPTC_PRLR   = 0x09001014;

    public static final int GPTC0_MR    = 0x09001018;
    public static final int GPTC0_RLR   = 0x0900101c;
    public static final int GPTC0_STICR = 0x09001028;

    public static final int GPIOE_OER   = 0x09002400;
    public static final int GPIOE_OR    = 0x09002404;
    public static final int GPIOE_IR    = 0x09002408;
}

*/
public class PressureTempSensor implements InterruptEventListener {

   private static PressureTempSensor ThePTSensor=new PressureTempSensor();
    boolean debugOutput = false;

    int Word1;
    int Word2;
    int Word3;
    int Word4;

    int C1;
    int C2;
    int C3;
    int C4;
    int C5;
    int C6;

    int D1;
    int D2;
    private boolean constantsGotten = false;
    private int dataX;
    private int scanBitX;
    private int bitsReadX;
    private boolean validReading = true;
    private int bitsReadDummyVal = 0x1248;
    private int sclkX;
    private boolean running;
    private boolean dataReady;
    private int sendsDone = 0;
    private int printOnSend = 1;
    public int iTemp=0;
    public int iPressure=0;
    
    public static PressureTempSensor getInstance(){
        if(ThePTSensor !=null)
          return ThePTSensor;
        else{
          DebugMessage.println("PressureTempSensor.getInstance() no instance -- returning null");
          return null;
        }    
    }
    
    public void check4Timeout(String aLabel) {
        if (timer0TimeoutIntrOccurred())
            DebugMessage.println(aLabel + ": A TIMEOUT INTERRUPT HAS OCCURRED.");
        else
            DebugMessage.println(aLabel + ": no timeout interrupt has occurred.");
    }

    /**
     * Starts the application.
     * @param args an array of command-line arguments
     */

    public static void main(java.lang.String[] args) {

        DebugMessage.println("Setting up pressure/temperature chip");

        PressureTempSensor pts = new PressureTempSensor();

        pts.configureAjileForPressureTemperatureChip();

        if (! pts.takeReading()) {
            DebugMessage.println("pressure temperature reading failed!!!");
        }

        pts.calculatePresTemp();
        
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            DebugMessage.println("got exception: " + e);
        }

        DebugMessage.println("about to get another reading and calc values");
        if (! pts.takeReading()) {
            DebugMessage.println("pressure temperature reading failed!!!");
        }
        pts.calculatePresTemp();
        while (true) {
            // do nothing but don't exit
        }
    }

 

    public void configureAjileForPressureTemperatureChip() {
        int sti = rawJEM.getInt(AjileAddr.GPTC0_STICR);

        timer0ClearTimeoutIntr();
      
        InterruptController.addInterruptListener(this,
                                         InterruptController.GPTC_INTERRUPT);
        configure();

        InterruptController.enableInterrupt(InterruptController.GPTC_INTERRUPT);

        timer0InterruptEnable();
    }        

    private void getConstants() {

        send(0xaaaa<<5, 21); // reset

        send(0xea8, 12); // Get Word 1 command
        send(0, 18);     // read Word 1       
        Word1 =  0xffff & (bitsReadX >> 1);

        send(0xeb0, 12); // Get Word 2 command
        send(0, 18);     // read Word 2       
        Word2 =  0xffff & (bitsReadX >> 1);

        send(0xec8, 12); // Get Word 3 command
        send(0, 18);     // read Word 3       
        Word3 =  0xffff & (bitsReadX >> 1);

        send(0xed0, 12); // Get Word 4 command
        send(0, 18);     // read Word 4       
        Word4 =  0xffff & (bitsReadX >> 1);

        calculateCalibrationConstants();
        constantsGotten = true;
    }

    public boolean takeReading() {

        if (! constantsGotten)
            getConstants();
        else
            send(0xaaaa<<5, 21); // reset


        send(0xf40, 12); // D1 acquire command

        try {
            Thread.sleep(2*34);
        } catch (java.lang.InterruptedException e) {
            DebugMessage.println("main(): caught InterruptedException: " + e);
        }

        int D1stat = rawJEM.getInt(AjileAddr.GPIOE_IR);
        if ((D1stat & DOUT) != 0) {
            validReading = false;
            DebugMessage.println("BADBADBAD... conversion1 not finished");
            return false;
        }
        
        send(0, 17); // read value of D1
        D1 = 0xffff & (bitsReadX >> 1);

        send(0xf20, 12); // D2 acquire command

        try {
            Thread.sleep(2*34);
        } catch (java.lang.InterruptedException e) {
            DebugMessage.println("takeReading(): caught InterruptedException: " + e);
        }

        int D2stat = rawJEM.getInt(AjileAddr.GPIOE_IR);
        if ((D2stat & DOUT) != 0) {
            validReading = false;
            DebugMessage.println("BADBADBAD... conversion2 not finished");
            return false;
        }

        send(0, 17);
        D2 = 0xffff & (bitsReadX >> 1);

        return true;
    }


    // A previous version had this -- I don't believe it has any use whatsoever now.
    // But if things start going strange, make sure that all the lines are zero
    // in between reads.
    //        pts.clrBits(AjileAddr.GPIOE_OR, (SCLK | DIN | DOUT));


    
    

    public void interruptEvent() {
        work();
        // clear the interrupt
        rawJEM.set(AjileAddr.GPTC0_STICR, (int)TOICLR);
    }

    public void work() {

        if (! running && ! dataReady)
            return;

        int regE = rawJEM.getInt(AjileAddr.GPIOE_OR);
        if (! running) {
            running = true;
            bitsReadX = 0;
            // do the phantom falling edge
            if ((scanBitX & dataX) != 0)
                regE |= DIN;
            else
                regE &= ~DIN;
            regE &= ~SCLK; // let's just make sure the clocking line is low
            running = true;
            sclkX = 0;
        } else if (sclkX == 0) {
            // SCLK rising edge
            regE |= SCLK;
            sclkX = 1;
        } else {
            // SCLK falling edge
            regE &= ~SCLK;
            sclkX = 0;

            // read data coming from the part
            bitsReadX <<= 1;
            int inputval = rawJEM.getInt(AjileAddr.GPIOE_IR);
            if ((inputval & DOUT) != 0)
                bitsReadX |= 1;

            // And clock out the next bit...
                                // There is not an OBOB here;
                                // the last bit of data goes with
                                // the next-to-last falling edge,
                                // and the last falling edge always
                                // drives a zero out on DIN.
            scanBitX >>= 1;
            if ((scanBitX & dataX) != 0)
                regE |= DIN;
            else
                regE &= ~DIN;
        }

        if (scanBitX == 0) {
            running = false;
            dataReady = false;
            sendsDone++;
        }
        rawJEM.set(AjileAddr.GPIOE_OR, regE);
    }


    public void calculatePresTemp() {
        calculatePresTemp(D1, D2);
    }
    
    private void calculatePresTemp(int D1, int D2) {
        int dT = D2 - (8*C5 + 10000);
        int OFF = C2 + (((C4-250)*dT)>>12) + 10000;
        int SENS = C1/2 + (((C3+200)*dT)>>13) + 3000;
        int P = ((SENS*(D1-OFF))>>12) + 1000;
        int TEMP = (200 + (dT*(C6+100)>>11))/10;
        DebugMessage.println("Pressure = " + P);
        DebugMessage.println("Temp = " + TEMP);
        iTemp=TEMP;
        iPressure=P;
    }

    private void calculateCalibrationConstants() {
        C1 = Word1 >> 3;
        C2 = ((Word1 & 0x7) << 10) | (Word2 >> 6);
        C3 = Word3 >> 6;

        C4 = Word4 >> 7;
        C5 = ((Word2 & 0x3f) << 6) | (Word3 & 0x3f);
        C6 = Word4 & 0x7f;

        DebugMessage.println("C1 is " + C1);
        DebugMessage.println("C2 is " + C2);
        DebugMessage.println("C3 is " + C3);
        DebugMessage.println("C4 is " + C4);
        DebugMessage.println("C5 is " + C5);
        DebugMessage.println("C6 is " + C6);
    }

    private final static void orBits(int addr, int val) {
        int i = rawJEM.getInt(addr);
        rawJEM.set(addr, (i | val));
    }

    private final static void clrBits(int addr, int val) {
        int i = rawJEM.getInt(addr);
        rawJEM.set(addr, (int)(0xf & (i & ~val)));
    }

    // NOTE:
    //    In aJile's online documentation (in their FAQ, I believe),
    //    they note that there is a bug in their implementation of the
    //    TC_IE (Timer-Counter Interrupt Enable) field in the GPTC_GMR
    //    register.  The manual says that in the GPTC_GMR register,
    //    TC_IE is a three-bit field covering bits 7 downto 5.  Bit 5
    //    enables interrupts on timer 0, bit 6 does IE for timer 1,
    //    and bit 7 for timer 2.  HOWEVER, they've got an off-by-one
    //    bug in their hardware, so that bit 5 is a don't-care, bit 6
    //    is IE for timer 0, bit 7 is IE for timer 1, and you better
    //    not need to generate an interrupt from timer 2 (because you
    //    can't enable it).  I need an interrupt from timer 0,
    //    therefore I set bit 6.

    // GPIOE bits
    private static final int SCLK  = (1<<1);
    private static final int DIN   = (1<<2);
    private static final int DOUT  = (1<<3);

    // GPTC_GMR fields/bits
    private static final int TC_IE0   = (1<<6); // BUG: bit 6 is TC0 (see above)
    private static final int PSCEN    = (1<<3);
    private static final int MTEN0    = (1<<0);


    // GPTC_IOMR fields/bits
    private static final int PSMODE   = (2<<0); // use TCK0 as the prescaler source

    // GPTCx_MR fields/bits
    private static final int TOIE = (1<<15);

    // GPTCx_STICR fields/bits
    private static final int TOIINT = (1<<0); // clears timeout intr
    private static final int TOICLR = (1<<0); // clears timeout intr


    private void send(int data, int bitCount) {
        while (running || dataReady) {
            if (debugOutput)
                DebugMessage.println("prestemp is already running or has data waiting, going to sleep");
            try {
                Thread.sleep(200);
            } catch(InterruptedException e) {}
        }
        dataX = data;
        scanBitX = (1 << (bitCount - 1));
        if (debugOutput) {
            DebugMessage.println("dataX=0x"
                               + Integer.toHexString(dataX)
                               +"\nscanBitX=0x"
                               + Integer.toHexString(scanBitX)
                               + "\nbitsReadX=0x"
                               + Integer.toHexString(bitsReadX)

                               + "\nsclkX=0x"
                               + Integer.toHexString(sclkX)
                               + "\nrunning="
                               + running);
        }
        dataReady = true; // the interrupt handler only clears this, send only sets it
        try {
            Thread.sleep(7*bitCount);
        } catch(InterruptedException e) {}
        while (dataReady) {
            try {
                if (debugOutput) {
                    DebugMessage.println("system was not cleared (set to false),"
                                       + " sleeping more");
                }
                Thread.sleep(10);
            } catch(InterruptedException e) {}
        }
    }




    // note:  if I were to put 2 into the GPTC1_MR it would count only
    // when timer0 was high; by changing the polarity I can make it count
    // only when T0 is low.  However, if T0 is output on a 50% duty cycle,
    // then this doesn't have the desired chaining effect.  That requires
    // that T0 be asserted for exactly one clock count (i.e., of the
    // prescaler output).  

    private void configure() {

        rawJEM.set(AjileAddr.GPTC_IOMR, (int) (PSMODE));
        rawJEM.set(AjileAddr.GPTC_PRLR, (int)  1      );

        // At RLR=50, the SCLK cycle time is about 6.2ms.
        // This implies that if we want 1ms, we should set RLR=8
        // 1ms is 32 cycles of a 32kHz clock.  The PT sensor does
        // not say exactly how many cycles of their microprocessor
        // are required for each SCLK cycle, but it seems to work
        // at RLR=50, giving observed cycle tim of 6.2ms, which is
        // about 198 clocks of a 32kHz clock.
        // Bottom line is:  we can dial down 50.  How far down is unknown.
        rawJEM.set(AjileAddr.GPTC0_RLR, (int)   50           );
        rawJEM.set(AjileAddr.GPTC0_MR , (int)   1           );

        rawJEM.set(AjileAddr.GPTC_GMR , (int) (PSCEN | MTEN0 ));
        DebugMessage.println("PressureTempSensor.configure() (REG_E_OER | "+(SCLK | DIN)+")");
        orBits(AjileAddr.GPIOE_OER, SCLK | DIN );

    }

    static void timer0InterruptEnable() {
        orBits(AjileAddr.GPTC0_MR, TOIE);
        orBits(AjileAddr.GPTC_GMR, TC_IE0); // enable timer/counter 0 to gen intr
    }

    static void timer0InterruptDisable() {
        clrBits(AjileAddr.GPTC_GMR, TC_IE0);
        //        clrBits(AjileAddr.GPTC0_MR, TOIE); // global masking is sufficient
    }

    static boolean timer0TimeoutIntrOccurred() {
        int i = rawJEM.getInt(AjileAddr.GPTC0_STICR);
        DebugMessage.println("t0tio:  i = 0x" + Integer.toHexString(i));
        int j = i & TOIINT;
        DebugMessage.println("t0tio:  j = 0x" + Integer.toHexString(j));
        boolean retval = (j != 0);
        DebugMessage.println("t0toi:  retval = " + retval);
        return retval;
        //        return ((rawJEM.getInt(AjileAddr.GPTC0_STICR) & TOIINT) != 0);
    }

    static void timer0ClearTimeoutIntr() {
        rawJEM.set(AjileAddr.GPTC0_STICR, TOICLR);
    }

}
