this version has all of Jim's fixes for reading the GPS and IMU data synchronously

Dependencies:   MODSERIAL SDFileSystem mbed SDShell CRC CommHandler FP LinkedList LogUtil

Revision:
0:432b860b6ff7
Child:
1:8e24e633f8d8
diff -r 000000000000 -r 432b860b6ff7 OEM615.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OEM615.h	Mon Apr 22 21:26:04 2013 +0000
@@ -0,0 +1,278 @@
+    
+#pragma pack(1)  //this forces the structure to be packed on byte boundaries (with no byte filler)
+//set up the GPS message header in a structure to enable easy reading -- see the OEM615 manual (Table 4, page 24)
+struct MESSAGEHEADER   
+{
+    char synchAA;                   //1st synch word
+    char synch44;                   //2nd synch word
+    char synch12;                   //3rd synch word
+    unsigned char headerLength;     //always 28
+    unsigned short messageID;       //42  (0x2A  BESTPOS) , 43 (2B  RANGE) , or 99 (x63 BESTVEL), 
+    char messageType;               //always = 0 for binary
+    unsigned char portAddress;      //0x20 for COM1
+    // from spec:  The length in bytes of the body of the message, not including the header nor the CRC
+    unsigned short messageLength;   //not including header or CRC
+    unsigned short sequence;        //typically 0
+    unsigned char idleTime;         //Time the processor is idle, in the last second
+    unsigned char timeStatus;       //Enum Indicating quality of the GPS reference time
+    unsigned short GPSweek;         //GPS reference week
+    unsigned long GPSTime_msecs;    //from beginning of week
+    unsigned long receiverStatus;   //32-bits representing the status of hardware and software
+    unsigned short reserved;
+    unsigned short receiverSWversion;  //receiver software build number
+    //total length in bytes of this header is 28
+};
+MESSAGEHEADER *msgHeader[6];
+
+#pragma pack(1)
+//structure for OEM615 BESTVEL log message  (page 314)
+struct OEM615BESTVEL
+{
+    MESSAGEHEADER msgHeader;
+    int solStatus;                      //solution status
+    //solutionStatusOEMStar solStatus;  //solution status
+    int velType;                        //position or velocity type
+    //velTypeOEMStar posType;           //position or velocity type   
+    float latency;
+    float age;
+    double horizontalSpeed;         //horizontal velocity vector magnitude (m/s)
+    double heading;                 //deg from North called TRK GND in specification
+    double verticalSpeed;           //vertical velocity magnitude (m/s)
+    float reserved;
+    unsigned long CRC;
+};
+
+/*  Solution Status descritpion from OEMV manual
+0   SOL_COMPUTED        Solution computed
+1   INSUFFICIENT_OBS    Insufficient observations
+2   NO_CONVERGENCE      No convergence
+3   SINGULARITY         Singularity at parameters matrix
+4   COV_TRACE           Covariance trace exceeds maximum (trace > 1000 m)
+5   TEST_DIST           Test distance exceeded (maximum of 3 rejections if distance >10 km)
+6   COLD_START          Not yet converged from cold start
+7   V_H_LIMIT           Height or velocity limits exceeded
+8   VARIANCE            Variance exceeds limits
+9   RESIDUALS           Residuals are too large
+10  DELTA_POS           Delta position is too large
+11  NEGATIVE_VAR        Negative variance
+12  Reserved
+13  INTEGRITY_WARNING   Large residuals make position unreliable
+18  PENDING             
+19  INVALID_FIX         The fixed position, entered using the FIX POSITION command, is not valid
+20  UNAUTHORIZED        Position type is unauthorized - HP or XP 
+*/
+
+#pragma pack(1)
+//structure for BESTPOS message 
+struct OEM615BESTPOS
+{
+    MESSAGEHEADER msgHeader;
+    int solStatus;                      //solution status
+    //solutionStatusOEMStar solStatus;  //solution status
+    int posType;                        //position or velocity type
+    //posTypeOEMStar posType;           //position or velocity type
+    double latitude;                    //latitude
+    double longitude;                   //longitude
+    double height;                      //height above mean sea level
+    float undulation;                   //the realtionship between the geoid and the
+                                        //ellipsoid of the chosen datum (m)
+    char datumID[4];                    //datum ID is actually an enum that is not implemented
+    float latitudeSTD;                  //latitude standard deviation
+    float longitudeSTD;                 //longitude standard deviation
+    float heightSTD;                    //height standard deviation
+    char baseStationID[4];              //base station ID
+    float diffAge;                      //differential age (s)
+    float solutionAge;                  //solution age (s)
+    unsigned char numSV;                //number of satellite vehicles tracked
+    unsigned char numSolSV;             //number of satellite vehicles used in solution
+    unsigned char numGGL1;              //number of GPS plus Glonass L1
+    unsigned char res1;
+    unsigned char res2;
+    unsigned char extSolStatus;         //extended solution status
+    unsigned char res3;
+    unsigned char sigMask;              //signals used mask
+    unsigned long CRC;
+};
+
+//GPS-specific pins
+DigitalOut GPS_Reset(p18);      //GPS RESET line
+InterruptIn PPSInt(p15);        // GPS 1PPS (timemark) from the OEM615
+InterruptIn IMUClock(p17);
+
+Timer timeFromPPS;
+unsigned long GPSTimemsecs = 0;
+double GPSTime = 0;
+
+//mbed tx/rx interface to the GPS COM1 port
+MODSERIAL GPS_COM1(p9,p10);  //this serial port communicates with the GPS receiver serial port (COM1)
+
+int test = 0;
+unsigned short messageCounter = 0;
+unsigned short savedMessageCounter = 0;
+const unsigned short maxGPSbytesPerSec = 1536;
+unsigned char msgBuffer[maxGPSbytesPerSec];  //array to contain one full second of GPS bytes
+const unsigned char maxGPSMessagesPerSec = 12;
+unsigned short messageLocation[maxGPSMessagesPerSec] = {0};  //stores the message location start within the message buffer
+
+unsigned short bytesFromMessageHdrDetect = 0;
+union SWAPBYTES { unsigned char b[2]; unsigned short w; };
+volatile SWAPBYTES messageLength;  //used to swap the bytes
+unsigned long computedCRC = 0;  //final resulting computed CRC for this message
+unsigned long incrementalCRC = 0;  //incrementally-formed CRC over message sequence
+unsigned short endByteForCRCcomputation[maxGPSMessagesPerSec];
+bool completeMessageAvailable = false;
+
+//this code was taken from the Novatel Firmware document page 35
+//#define CRC32_POLYNOMIAL 0xEDB88320L
+/* --------------------------------------------------------------------------
+Calculate a CRC value to be used by CRC calculation functions.
+-------------------------------------------------------------------------- */
+/*
+////////////////////////////////////////////
+//original code from the OEM615 manual
+////////////////////////////////////////////
+unsigned long CRC32Value(int i)
+{
+    int j;
+    unsigned long ulCRC;
+    ulCRC = i;
+    for ( j = 8 ; j > 0; j-- )
+    {
+        if ( ulCRC & 1 )
+        ulCRC = ( ulCRC >> 1 ) ^ CRC32_POLYNOMIAL;
+        else
+        ulCRC >>= 1;
+    }
+    return ulCRC;
+} 
+*/
+
+#define CRC32_POLYNOMIAL 0xEDB88320L
+void CRC32Value(unsigned long &CRC, unsigned char c)
+{
+    /////////////////////////////////////////////////////////////////////////////////////
+    //CRC must be initialized as zero 
+    //c is a character from the sequence that is used to form the CRC
+    //this code is a modification of the code from the Novatel OEM615 specification
+    /////////////////////////////////////////////////////////////////////////////////////
+    unsigned long ulTemp1 = ( CRC >> 8 ) & 0x00FFFFFFL;
+    unsigned long ulCRC = ((int) CRC ^ c ) & 0xff ;
+    for (int  j = 8 ; j > 0; j-- )
+    {
+        if ( ulCRC & 1 )
+            ulCRC = ( ulCRC >> 1 ) ^ CRC32_POLYNOMIAL;
+        else
+            ulCRC >>= 1;
+    }
+    CRC = ulTemp1 ^ ulCRC;
+} 
+
+/* --------------------------------------------------------------------------
+Calculates the CRC-32 of a block of data all at once
+//the CRC is from the complete message (header plus data) 
+//but excluding (of course) the CRC at the end
+-------------------------------------------------------------------------- */
+unsigned long CalculateBlockCRC32(
+        unsigned long ulCount,    /* Number of bytes in the data block */
+        unsigned char *ucBuffer ) /* Data block */
+{
+    //////////////////////////////////////////////////////////////////////
+    //the below code tests the CRC32Value procedure used in a markov form
+    //////////////////////////////////////////////////////////////////////
+    unsigned long CRC = 0;
+    for (int i = 0; i<ulCount; i++)  CRC32Value( CRC, *ucBuffer++ );
+    return  CRC;
+}
+
+/*
+unsigned long CalculateBlockCRC32(
+        unsigned long ulCount, 
+        unsigned char *ucBuffer )
+{
+////////////////////////////////////////////
+//original code from the OEM615 manual
+////////////////////////////////////////////
+    unsigned long ulTemp1;
+    unsigned long ulTemp2;
+    unsigned long ulCRC = 0;
+    while ( ulCount-- != 0 )
+    {
+        ulTemp1 = ( ulCRC >> 8 ) & 0x00FFFFFFL;
+        ulTemp2 = CRC32Value( ((int) ulCRC ^ *ucBuffer++ ) & 0xff );
+        ulCRC = ulTemp1 ^ ulTemp2;
+    }
+    return( ulCRC );
+}
+*/
+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
+};
+
+
+//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;      //see example of MODSERIAL usage in cookbook
+    unsigned char synch0 = serial->getc();  //get the next byte
+    
+    //byteCounter is zeroed only at a 1PPA event in the 1PPS ISR
+    //all message bytes stored for a single GPS second 
+    msgBuffer[byteCounter % maxGPSbytesPerSec] = synch0;
+    
+     //accumulate the CRC for this message
+     //incrementalCRC re-initialized after message header is is detected
+     CRC32Value( incrementalCRC, synch0); 
+
+    //Trap the GPS message header byte-string per Novatel OEM615 spec: 0xAA44121C
+    //generate a 4-byte sliding-window sequence from the input bytes
+    //shift last 4-byte value left 8 bits & push current-read byte (synch0) into low-order byte
+    test = (test<<8) | synch0; 
+   
+    if (test == 0xAA44121C) //test for the Receiver message header signature
+    {
+        messageLocation[perSecMessageCounter % maxGPSMessagesPerSec] = byteCounter-3; //store the location of this message (1st of 4 synch word)
+        perSecMessageCounter++;  //counts messages this second
+        bytesFromMessageHdrDetect = 0;  //start byte counter for this message
+        incrementalCRC = 0x39b0f0e1;    //initializes the recursive CRC after the AA44121C header byte sequence 
+     }
+     else if (bytesFromMessageHdrDetect == 5) messageLength.b[0] = synch0;  //first byte of msg length
+     else if (bytesFromMessageHdrDetect == 6)   //second byte of message length
+     {
+        messageLength.b[1] = synch0; 
+        endByteForCRCcomputation[perSecMessageCounter] = 24 + messageLength.w;  //use union to perform byte-swap from stored bytes
+     }
+     else if (bytesFromMessageHdrDetect == endByteForCRCcomputation[perSecMessageCounter])  //stop the CRC recursive computation
+        computedCRC = incrementalCRC;  //store the computed CRC for this message for use in main  
+     else if (bytesFromMessageHdrDetect == (endByteForCRCcomputation[perSecMessageCounter] + 4) )  //detect the end of the message (end of its CRC)
+     {
+        savedMessageCounter = perSecMessageCounter;  //message counter can be corrupted before use in main
+        completeMessageAvailable = true;  //set flg for the main message processing
+     }
+         
+     //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) 
+     bytesFromMessageHdrDetect++;  //counts the byes received after a message header
+};
+
+
+
+
+
+
+