Changes to allow hardware camera trigger

Dependencies:   mbed

Fork of GPS_Incremental by james kain

main.cpp

Committer:
jekain314
Date:
2013-03-29
Revision:
4:68268737ff89
Parent:
3:5913df46f94a
Child:
6:2a8486283198

File content as of revision 4:68268737ff89:

#include "mbed.h" 

//set up the message buffer to be filled by the GPS read process
#define MODSERIAL_DEFAULT_RX_BUFFER_SIZE 256 

#include "MODSERIAL.h"
#include "SDFileSystem.h"      //imported using the import utility    
//#include "rtos.h"
#include "OEM615.h"

#include "ADIS16488.h"
#include <string>

//these are defines for the messages that are sent from the PC across the USB
//these messages produce reactions on the mbed
#define STATUS_MSG 0
#define POSVEL_MSG 1
#define STARTDATA_MSG 2
#define STOPDATA_MSG 3
#define STARTSTREAM_MSG 4
#define STOPSTREAM_MSG 5
#define STARTLOGINFO_MSG 6
#define STOPLOGINFO_MSG 7

#define DEGREES_TO_RADIANS (3.14519/180.0)

//general digital I/O specifications for this application
//SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
SDFileSystem sd(p11,p12,p13,p14,"sd");
//Serial debug(USBTX, USBRX); // tx, rx  USB communication to the PC for debug purposes
DigitalOut ppsled(LED1);   //blink an LED at the 1PPS
DigitalOut trig1led(LED2);  //blink an LED at the camera trigger detection
DigitalOut recordDataled(LED4);  //set the led when the record is on
InterruptIn camera1Int(p30); // camera interrupt in
DigitalOut camera2Pin(p29);  // i dont believe we use the second camera interrupt
//USB serial data stream back to the PC
Serial toPC(USBTX, USBRX); //connect the GPS TX, RX to p9 and p10

bool detectedGPS1PPS = false;  //flag set in the ISR and reset after processing the 1PPS event
bool recordData = false;  //set to true when commanded from the PC
int PPSCounter = 0;  //counts the 1PPS occurrences
int byteCounter = 0; //byte counter -- where used??
unsigned short perSecMessageCounter=0; //counts the number of messages in a sec based on the header detection
bool lookingForMessages = true; //set in the PPS ISR and set false after the message processing in the main
bool messageDetected = false; //have detected a message header
int savedIMUClockCounter=0; 
unsigned long IMUbytesWritten = 0;
int savedByteCounter = 0;
int savedPerSecMessageCounter=0;
int IMUClockCounter = 0;
bool camera1EventDetected = false;
double camera1Time;
char serBuf[128];
int serBufChars=0;

//flags to control the PC command actions
bool sendPosVel=false;
bool sendStatus=false;
bool sendRecData=false;
bool streamPos=false;
bool sendStreamPos=false;
bool logMsgInfo=false;
bool sendLogMsgInfo=false;

//ISR for detection of the GPS 1PPS
void detect1PPSISR(void)
{
    timeFromPPS.reset();  //reset the 1PPS timer upon 1PPS detection
    savedIMUClockCounter = IMUClockCounter; //number of IMU clocks received since last 1PPS
    savedByteCounter = byteCounter;
    savedPerSecMessageCounter = perSecMessageCounter;
    IMUClockCounter = 0;  //counts number of IMU samples between 1PPS events
    GPS_COM1.rxBufferFlush();  //flush the GPS serial buffer -- likely not needed but OK
    byteCounter = 0;
    perSecMessageCounter = 0;
    
    detectedGPS1PPS = true;  //reset in the main when 1PPS actions are complete
    lookingForMessages = true; //means we should begin looking for new GPS messages
    PPSCounter++;  //count number of 1PPS epochs
    PPSTimeOffset++;   //counts the 1PPS events between occurrences when we have matching POS and VEL messages
    ppsled = !ppsled;  //blink an LED at the 1PPS
};

//ISR for detection of the hotshoe trigger 1
void camera1ISR(void)
{
    //PPSTimeOffset keeps track of missed 
    camera1Time = GPSTime + (double)PPSTimeOffset + timeFromPPS.read();
    
    trig1led = !trig1led;  //blink an LEWD at the camera event detection
    camera1EventDetected = true;  //reset to false in main after processing the image detection
};

void readFromPC()
{

    //better solution
    //start a timer when we get a char from the PC and set a bool: detectingPCMessage = true
    //keep reading bytes until elapsed time from the first byte is : 0.01 secs of numByes > 16
    //the messages are from 10 to 16 bytes -- this will take from 10/921600 to 16/921600 secs at 921600 baud
    //8*115200 = 921600
    //this is about 2e-5  or 20usec.
    //so we could wait 50usec from the first char reeived and be certain we had all the chars for a message.
    //the steps are below .... 
    //(1) convert this procedures to a ISR per byte
    //(2) in the ISR, start the timer on the first byte received when !detectingPCMessage
    //(3) set detectingPCMessage = true
    //(4) in the main loop, test the timer for >50usec and parse the bytes to test fr a message
    //(5) reset the timer to zero in the main loop after parsing the message
    //(6) set detectingPCMessage = false;

    //The received commands obnly occur at the initialization stage -- time is not that critical there.
    //during the real-time action, we will never pass the followong if test ( no characters received)
    if (toPC.readable()) //read a PC serial byte and test it for a command
    {
        // Read in next character
        char inChar = toPC.getc();
        serBuf[serBufChars++] = inChar;
        
        // Append end of string character
        //why do this for every character we read?
        //answer: we always assume we have a complete message and test for this below
        serBuf[serBufChars] = '\0';
        
        // Need to parse message to determine behavior
        // Need to clean this up 
        //need to do this outside the read byte --- 
        char msgList[8][32];
        sprintf(msgList[STATUS_MSG], "WMsg STATUS");
        sprintf(msgList[POSVEL_MSG], "WMsg POSVEL");
        sprintf(msgList[STARTDATA_MSG], "WMsg RECORDDATA Y");
        sprintf(msgList[STOPDATA_MSG], "WMsg RECORDDATA N");
        sprintf(msgList[STARTSTREAM_MSG], "WMsg POSSTREAM Y");
        sprintf(msgList[STOPSTREAM_MSG], "WMsg POSSTREAM N");
        sprintf(msgList[STARTLOGINFO_MSG], "WMsg LOGINFO Y");
        sprintf(msgList[STOPLOGINFO_MSG], "WMsg LOGINFO N");
        //message length is from 10 to 16 chars
        
        // assume an invalid message which needs to be reset
        bool validMessage = false;
        bool resetMessage = true;
        
        // Check for valid message
        for (int m = 0; m < 8 && !validMessage; m++) //check for all messages ... 
        {
            if (strncmp(serBuf, msgList[m], serBufChars) == 0)
            {
                validMessage = true;
                //test that chars in the serial buffer is same as message length
                if (serBufChars == strlen(msgList[m]))
                {
                    switch(m)
                    {
                        case STATUS_MSG:
                            sendStatus = true;
                        break;
                        case POSVEL_MSG:
                            sendPosVel = true;
                        break;
                        case STARTDATA_MSG:
                        case STOPDATA_MSG:
                            recordData = (m == STARTDATA_MSG);
                            sendRecData = true;
                        break;
                        case STARTSTREAM_MSG:
                        case STOPSTREAM_MSG:
                            streamPos = (m == STARTSTREAM_MSG);
                            sendStreamPos = true;
                        break;
                        case STARTLOGINFO_MSG:
                        case STOPLOGINFO_MSG:
                            logMsgInfo = (m == STARTLOGINFO_MSG);
                            sendLogMsgInfo = true;
                        break;
                        
                    }
                }
                // message is still in progress, do not reset
                else
                {
                    resetMessage = false;
                }
            }
        }
        
        // if message should be reset
        if (resetMessage)
        {
            // reset serial buffer character count
            serBufChars = 0;
            // if invalid message and most recent character is 'W' (first message character),
            // possible message collision
            if ((!validMessage) && (inChar == 'W'))
            {
                // start a new message
                serBuf[serBufChars++] = inChar;
                serBuf[serBufChars] = '\0';
            }
            // Append end of string character
            serBuf[serBufChars] = '\0';
        }
    }
};

void sendASCII(char* ASCI_message, int numChars)
{
    /////////////////////////////////////////////////
    //send an ASCII command to the GPS receiver
    /////////////////////////////////////////////////

    //char ASCI_message[] = "unlogall COM1";
    int as = numChars - 1;
    unsigned char CR = 0x0d;  //ASCII Carriage Return
    unsigned char LF = 0x0a;  //ASCII Line Feed
    
    //printf("%s", ch);
    //printf("\n");

    for (int i=0; i<as; i++) GPS_COM1.putc(ASCI_message[i]); 
    GPS_COM1.putc(CR);   //carriage return at end
    GPS_COM1.putc(LF);   //line feed at end
};

//FILE* fp = NULL;
void setupCOM(void)
{
    //system starts with GPS in reset active
    //dis-engage the reset to get the GPS started
    GPS_Reset=1; wait_ms(1000); 
    
    //establish 1PPS ISR 
    PPSInt.rise(&detect1PPSISR);
    
    //set the USB serial data rate -- rate must be matched at the PC end
    //This the serial communication back to the the PC host
    //Launch the C++ serial port read program there to catch the ASCII characters
    //toPC.baud(9600); wait_ms(100);    
    toPC.baud(8*115200); wait_ms(100);
    //toPC.baud(1*115200); wait_ms(100);
    toPC.printf("\n\n released GPS from RESET and set to high baud rate \n\n");
    
    //just wait to launch the GPS receiver
    for (int i=0; i<5; i++) { toPC.printf(" to start: %3d \n", 4-i); wait(1); }

    
    mkdir("/sd/Data", 0777);
    
    /*
    fp = fopen("/sd/Data/IMUGPS.bin", "wb");
    if (fp == NULL)
    {
        toPC.printf(" cannot open the IMUGPS data file \n");
    }
    else
        toPC.printf(" opened the IMUGPS data file \n");
    */
     
    //NOTE:  we do not assume that the GPS receiver has been pre-set up for the WALDO_FCS functionality
    //we alwsys start with a reset and reprogram the receiver with our data out products
    // this prevents failure because of a blown NVRAM as occurred for the older camera systems
    
    //this is the COM1 port from th GPS receiuver to the mbed
    //it should be always started at 9600 baud because thats the default for the GPS receiver 
    GPS_COM1.baud(9600); wait_ms(100);
   
    // this ASCII command sets up the serial data from the GPS receiver on its COM1
    char ch7[] = "serialconfig COM1 9600 n 8 1 n off";
    // this is a software reset and has the same effect as a hardware reset (why do it?) 
    //char ch0[] = "RESET"; 
    //this command stops all communication from the GPS receiver on COM1
    //logs should still be presented on USB port so the Novatel CDU application can be used on the PC in parallel
    char ch1[] = "unlogall COM1";
    //set the final baud rate that we will use from here  
    //allowable baud rate values: 9600 115200 230400 460800 921600
    //char ch2[] = "serialconfig COM1 921600 n 8 1 n off";
    char ch2[] = "serialconfig COM1 460800 n 8 1 n off";
    
    //the below commands request the POS, VEL, RANGE, and TIME messages
    char ch3[] = "log COM1 BESTPOSB ONTIME 1";   //messageID = 42 
    char ch4[] = "log COM1 BESTVelB ONTIME 1";   //messageID = 99
    char ch5[] = "log COM1 RANGEB ONTIME 1";     //messageID = 43
    //char ch6[] = "log COM1 TIMEB ONTIME 1";      //messageID = 101
    
    //set up VARF to be 100Hz with 1X10^4 * 10^-8 = 10^-4 sec (10usec) pulse width
    //in fact, we do not use this output but it is available.
    //originally planned to use this to command the IMU data
    char ch8[] = "FREQUENCYOUT enable 10000 1000000";
    
    toPC.printf("set serial config \n");
    sendASCII(ch7, sizeof(ch7)); wait_ms(500);
    //sendASCII(ch0, sizeof(ch0));  
    toPC.printf("unlog all messages \n");
    sendASCII(ch1, sizeof(ch1)); wait_ms(500);
    toPC.printf("log BESTPOSB on COM1 \n");
    sendASCII(ch3, sizeof(ch3)); wait_ms(500);
    toPC.printf("log BESTVELB on COM1\n");
    sendASCII(ch4, sizeof(ch4)); wait_ms(500);
    toPC.printf("log RANGEB on COM1\n");
    sendASCII(ch5, sizeof(ch5)); wait_ms(500);
    
    //toPC.printf("log TIMEB om COM1 \n");
    //sendASCII(ch6, sizeof(ch6)); wait_ms(100);
    
    toPC.printf(" set up th VARF signal \n"); 
    sendASCII(ch8, sizeof(ch8)); wait_ms(500);
       
    //set GPS output COM1 to the final high rate
    toPC.printf("set the COM ports to high rate\n");
    sendASCII(ch2, sizeof(ch2)); wait_ms(500);
    
    //set the mbed COM port to match the GPS transmit rate
    //the below baud rate must match the COM1 rate coming from the GPS receiver 
    GPS_COM1.baud(460800); wait_ms(500);  //without this wait -- the baud rate is not detected when using MODSERIAL     
    //GPS_COM1.baud(921600); wait_ms(500);  //without this wait -- the baud rate is not detected when using MODSERIAL     
};

void setupTriggers()
{
    camera1Int.mode(PullUp);
    camera2Pin = 1;
    //establish Trigger ISR 
    camera1Int.rise(&camera1ISR);
    
};

int test = 0;
unsigned short messageCounter = 0;
unsigned short savedMessageCounter = 0;
unsigned char msgBuffer[1536];  //array to contain one full second of GPS bytes
unsigned short messageLocation[6] = {0};  //stores the message location start within the message buffer

//see the mbed COOKBOOK for MODSERIAL
//MODSERIAL is an easy to use library that extends Serial to add fully buffered input and output.
void readSerialByte(MODSERIAL_IRQ_INFO *q)
{ 
    MODSERIAL *serial = q->serial;
    unsigned char synch0 = serial->getc();
    msgBuffer[byteCounter] = synch0;

    //we need to trap the GPS message header byte-string 0xAA44121C
    //generate a 4-byte sliding-window sequence from the input bytes
    //shift last 4-byte value left 8 bits & push recently read byte (synch0) into low-order byte
    test = (test<<8) | synch0;  //
   
    if (test == 0xAA44121C) //test for the Receiver message header signature
    {
        messageLocation[perSecMessageCounter] = byteCounter-3; //store the location of this message (with 4 synch words)
        perSecMessageCounter++;
        messageDetected = true;
     }   
     //byteCounter reset to zero in main after the 1PPS is detected -- its NOT reset in the 1PPS ISR
     byteCounter++;     //total per-sec byte counter (reset to zero in main when 1PPS detected) 

};

void earthCoefficients(double latitudeRad, double longitudeRad, double height, double &latRateFac, double &lonRateFac)
{
    //compute the lat and lon factors for use in the interpolation of the lat and lon between 1 sec epochs
    //see this document (page 32)    www.fas.org/spp/military/program/nav/basicnav.pdf
    double eccen = 0.0818191908426; //WGS84 earth eccentricity
    double earthRadius = 6378137;  //WGS84 earthRadius in meters
    double eccenSinLat = eccen * sin(latitudeRad); 
    double temp1 = 1.0 - eccenSinLat*eccenSinLat;
    double temp2 = sqrt(temp1);
    double r_meridian = earthRadius * ( 1.0 - eccen*eccen)/ (temp1 * temp2);
    double r_normal   = earthRadius / temp2;
    
    //multiply latRateFac times V-north to get the latitude rate in radians [er sec
    latRateFac = 1.0 / (r_meridian + height);
    
    //multiply lonRatFac by VEast to get the longitude rate in radians per sec
    lonRateFac = 1.0  / ( (r_normal + height) * cos(latitudeRad) );
}

int main() {

    //FILE *fpIMU = NULL;
    //FILE *fpGPS = NULL;
    FILE *fpNav = NULL;
    
    OEM615BESTPOS posMsg;   //BESTPOS structure in OEMV615.h
    OEM615BESTPOS curPos;   //BESTPOS structure in OEMV615.h
    OEM615BESTVEL velMsg;   //BESTVEL structure in OEMV615.h
    OEM615BESTVEL curVel;   //BESTVEL structure in OEMV615.h
    
    int msgLen;
    int msgEnd;

    //set up the GPS and mbed COM ports
    setupCOM(); 
    
    //set up the ADIS16488 
    setupADIS();
    
    //setup Hotshoe
    setupTriggers();
    
    //attempt to use the mbed RTOS library
    //Thread thread(writeThread);
    
    //this doesnt show up on the PC Rich Text Box because we dont start the init til after this occurs
    toPC.printf("completed setting up COM ports \n");
    
    //set up the interrupt to catch the GPS receiver serial bytes as they are presented
    GPS_COM1.attach(&readSerialByte, MODSERIAL::RxIrq);
    
    timeFromPPS.start();  //start the time for measuring time from 1PPS events

    while(PPSCounter < 100)
    ///////////////////////////////////////////////////////////////////////////
    // top of the while loop
    ///////////////////////////////////////////////////////////////////////////
    //while(1)
    {        
        //read the USB serial data from the PC to check for commands
        //in the primary real-time portion, there are no bytes from the PC so this has no impact
        readFromPC();

        //we should put the below stuff into the readPC() procedure.
        //only do these actions in response to a command so no need for the tests w/o an inoput byte from the PC
        //perform the activities as a response to the commands
        if (sendPosVel)  //true if we want to return a position solution
        {
            sendPosVel=false; //set to true if a POSVEL is requested from the PC
            char solReady = 'N';
            if (posMsg.solStatus == 0)  //how is this set??
            {
                solReady = 'Y';
            }
            
            //north and east velocity from the horizontal speed and heading
            //velMsg may not be the "current" message --- but is the one also associated with a position message
            double nVel = velMsg.horizontalSpeed*cos(velMsg.heading*DEGREES_TO_RADIANS);
            double eVel = velMsg.horizontalSpeed*sin(velMsg.heading*DEGREES_TO_RADIANS);
            
            // For the 1 second deltas with which we are dealing
            // This calculation should be close enough for now
            // Approximately 1 nautical mile / minute latitude, 60 minutes/degree, 1852 meters/nautical mile
            double latMetersPerDeg = 60.0*1852.0;
            // longitude separation is approximately equal to latitude separation * cosine of latitude
            double lonMetersPerDeg = latMetersPerDeg*cos(posMsg.latitude*DEGREES_TO_RADIANS);

            // Elapsed time since last known GPS position
            //PPSTimeOffset is a result of possibly missing a prior GPS position message
            // timeFromPPS.read() is always the time from the moset recent 1PPS
            double elTime = (double)PPSTimeOffset + timeFromPPS.read();
            
            // Position time -- GPSTime is the time of the last valid GPS position message
            double posTime = GPSTime + elTime;

            // Estimated position based on previous position and velocity
            // posMsg is the last time when the BESTVEL and BESTPOS messages had identical times
            double latPos = posMsg.latitude + (nVel/latMetersPerDeg)*elTime;
            double lonPos = posMsg.longitude + (eVel/lonMetersPerDeg)*elTime;
            double htPos = posMsg.height + velMsg.verticalSpeed/(60*1852)*elTime;
            toPC.printf("WMsg POSVEL %5.3lf %d %c %8.5lf %9.5lf %4.3lf %4.3lf %4.3lf %4.3lf\n", 
                         posTime, 
                         posMsg.numSolSV,
                         solReady,
                         latPos,
                         lonPos,
                         htPos,
                         nVel,
                         eVel,
                         velMsg.verticalSpeed
                         );
        }
        
        //all this does is assess the GPS convergence -- really available in the above
        if (sendStatus)  //send the status message to the PC
        {
            sendStatus=false;
            char solReady = 'N';
            if (posMsg.solStatus == 0)
            {
                solReady = 'Y';
            }
            toPC.printf("WMsg STATUS %5.3lf %c\n", 
                         GPSTime, 
                         solReady
                         );
        }
        
        //should just record ALL the data -- can pck over it in the post-processing
        if (sendRecData)  //begin to (or stop) record the serial data
        {
            sendRecData=false;
            char recChar = 'N';
            if (recordData)
            {
                if ((fpNav == NULL))
                {
                    fpNav = fopen("/sd/Data/NAV.bin", "wb");
                }
                if (fpNav != NULL)
                {
                    recChar = 'Y';
                }
                //recChar = 'Y';
            }
            else
            {
                if (fpNav != NULL)
                {
                    fclose(fpNav);
                    fpNav = NULL;
                }
                /*
                if (fpIMU != NULL)
                {
                    fclose(fpIMU);
                    fpIMU = NULL;
                }
                if (fpGPS != NULL)
                {
                    fclose(fpGPS);
                    fpGPS = NULL;
                }
                */
            }
            toPC.printf("WMsg RECORDDATA %c\n", 
                         recChar
                         );
        }
        
        //this is called everytime through the loop -- wasteful
        //recordDataled = recordData;
        
        if (sendStreamPos)  //stream the position data to the PC
        {
            sendStreamPos=false;
            char streamChar = 'N';
            if (streamPos)
            {
                streamChar = 'Y';
            }
            toPC.printf("WMsg POSSTREAM %c\n", 
                         streamChar
                         );
        }
        
        //not sure this is ever used ..
        if (sendLogMsgInfo)  //send log info to the PC
        {
            sendLogMsgInfo=false;
            char logChar = 'N';
            if (logMsgInfo)
            {
                logChar = 'Y';
            }
            toPC.printf("WMsg LOGINFO %c\n", 
                         logChar
                         );
        }
        

        ////////////////////////////////////////////////////////////////////////////
        //below is where we process the complete stored GPS message for the second
        //The !IMUDataReady test prevents the IMU and GPS data from being written 
        //to disk on the same pass through thi loop  
        /////////////////////////////////////////////////////////////////////////////
        if (!IMUDataReady && lookingForMessages && (timeFromPPS.read_us() > 20000))  //it takes less than 20msec to receive all messages
        {    
            toPC.printf(" num messages = %3d time = %5d \n", perSecMessageCounter, timeFromPPS.read_us());
            
            //cycle through all the bytes stored this sec (after the 1PPS as set)
            // perSecMessageCounter is incremented whenever we detect a new message headet 0xAA44121C sequence
            for (int i=0; i<perSecMessageCounter; i++)  
            {
               msgHeader[i] = (MESSAGEHEADER*)&msgBuffer[messageLocation[i]];
               toPC.printf("WMsg MESSAGEINFO %5d %5d \n", 
                                                    msgHeader[i]->messageID, 
                                                    messageLocation[i]);
                //test for a message 42 (BESTPOS)
                if (msgHeader[i]->messageID == 42)
                {
                    curPos = *((OEM615BESTPOS*)&msgBuffer[messageLocation[i]]);
                    
                    if (streamPos)
                    {
                            toPC.printf("WMsg BESTPOS %d %d %d %8.5lf %9.5lf %5.3lf %5.3f %5.3f %5.3f %5.3f %5.3f %5.3f %d %d %d %d %d\n",
                                              curPos.msgHeader.GPSTime_msecs,
                                              curPos.solStatus,
                                              curPos.posType,
                                              curPos.latitude,
                                              curPos.longitude,
                                              curPos.height,
                                              curPos.undulation,
                                              curPos.latitudeSTD,
                                              curPos.longitudeSTD,
                                              curPos.heightSTD,
                                              curPos.diffAge,
                                              curPos.solutionAge,
                                              curPos.numSV,
                                              curPos.numSolSV,
                                              curPos.numGGL1,
                                              curPos.extSolStatus,
                                              curPos.sigMask);
                    }
                }
                    
                //check for a message 99 (BESTVEL)  -- and cast it into its message structure
                else if (msgHeader[i]->messageID == 99)
                {
                    curVel = *((OEM615BESTVEL*)&msgBuffer[messageLocation[i]]);
                }
                
                //the below test ensures that the positin and veocity are matched in time
                //not sure the reason for the "250" below    
                if ((curVel.msgHeader.GPSTime_msecs+250)/1000 == 
                    (curPos.msgHeader.GPSTime_msecs+250)/1000)
                {
                    // update position and velocity used for calculation
                    GPSTimemsecs = curPos.msgHeader.GPSTime_msecs;
                    GPSTime = (double)GPSTimemsecs/1000.0;
                    velMsg = curVel;  //
                    posMsg = curPos;
                        
                    /////////////////////////////////////////////////////////////////////////////////////////
                    //IMPORTANT:   we reset the PPSTimeOffset when we have a matching position and velocity 
                    PPSTimeOffset = 0;
                    /////////////////////////////////////////////////////////////////////////////////////////
                }
            }
            lookingForMessages = false;
            
        }  //end of the GPS message processing
        
        //the IMU data record is read from the SPI in the ISR and the IMUDataReady is set true
        //we write the IMU data here
        if (IMUDataReady)  //IMUDataReady is true if we have a recent IMU data record
        {
            imuRec.GPSTime = GPSTimemsecs + timeFromPPS.read_us()/1000000.0;
            spi.write((int) HIGH_REGISTER[0]); // next read will return results from HIGH_REGITER[0]
            for (int i=0; i<6; i++)  //read the 6 rate and accel variables
            {
                wd.pt[1] = (unsigned short)spi.write((int) LOW_REGISTER[i]) ; 
                if (i<5)  // dont this on the last because this was pre-called
                {   wd.pt[0] = (unsigned short)spi.write((int) HIGH_REGISTER[i+1]); }
                imuRec.dataWord[i] = wd.dataWord; //data word is a signed long
                
            }
            IMURecordCounter++;
            //write the IMU data
            //if (recordData && (fpIMU != NULL))
            if (recordData && (fpNav != NULL))
            {
                IMUbytesWritten += fwrite(imuRec.dataWord, sizeof(IMUREC), 1, fpNav);
            }
            IMUClockCounter++;
            IMUDataReady = false;
        }
        
        if (messageDetected)  //some GPS message header has been detected
        {
            toPC.printf(" msgTime = %4d \n", timeFromPPS.read_us());
            messageDetected = false;
        }
        
        if (camera1EventDetected)  //we have detected a camera trigger event
        {
            toPC.printf("WMsg TRIGGERTIME %5.3lf\n", camera1Time);
            camera1EventDetected = false;
        }
        
        if (detectedGPS1PPS)  //true if we are exactly at a 1PPS event detection
        {   
            toPC.printf(" PPSCounter=%4d byteCounter=%10d Msgs Received=%3d IMUClock=%4d bytesWritten=%8d\n", 
                            PPSCounter, savedByteCounter, savedPerSecMessageCounter, savedIMUClockCounter, IMUbytesWritten);
            if (recordData && (fpNav != NULL) && (byteCounter > 0))
            {
                // we know that we are not reading a GPS message at exactly the 1PPS occurrence
                fwrite(msgBuffer, byteCounter, 1, fpNav);  // this writes out a complete set of messages for ths sec
            }
            detectedGPS1PPS = false;
        }
    }
    
    fclose(fpNav);
    toPC.printf(" normal termination \n");
}