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
Diff: PCMessaging.h
- Revision:
- 29:dead10cce6e9
- Parent:
- 26:c2208b0ff78b
- Child:
- 30:96d133f3008e
--- a/PCMessaging.h Wed Nov 13 22:12:04 2013 +0000 +++ b/PCMessaging.h Thu Jan 09 14:09:05 2014 +0000 @@ -1,382 +1,40 @@ //these are defines for the messages that are sent from the PC across the USB //these messages produce reactions on the mbed -const unsigned char POSVEL_MSG =0; -const unsigned char FIRE_TRIGGER_MSG =1; -const unsigned char STATUS_MSG =2; -const unsigned char STARTDATA_MSG =3; -const unsigned char STOPDATA_MSG =4; -const unsigned char STARTSTREAM_MSG =5; -const unsigned char STOPSTREAM_MSG =6; -const unsigned char STARTLOGINFO_MSG =7; -const unsigned char STOPLOGINFO_MSG =8; -const unsigned char GETFILE_MSG =9; // added to get a file from the SD card - -const double DEGREES_TO_RADIANS = acos(-1.0)/180.0; -const double eccen = 0.0818191908426; //WGS84 earth eccentricity -const double earthRadius = 6378137; //WGS84 earthRadius in meters +const unsigned char FIRE_TRIGGER_MSG = 1; const unsigned short serBuffMax = 18; char serBuf[serBuffMax]; 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; -bool recordData =false; bool fireTrigger =false; -bool get_file_msg =false; // added for GETFILE command - -const unsigned char numMessages = 10; //number of potential messages (updated to 10 sg-) -char msgList[numMessages][32]; //text array storing the command messages from the PC -char minMessageSize = 11; //minimum size of a text message unsigned char CR = 0x0d; //ASCII Carriage Return unsigned char LF = 0x0a; //ASCII Line Feed -char preamble[5] = "WMsg"; -char testPreamble[5]; bool validMessage = false; -void setUpMessages(void) -{ - //set up the ASCII text records that are candidates to be passed from the PC - 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"); - sprintf(msgList[FIRE_TRIGGER_MSG], "WMsg TRIGGER"); - sprintf(msgList[GETFILE_MSG], "WMsg GETFILE"); // added to get the file off of sd cards - //message length is from 10 to 16 chars - - // toPC.printf(" finished setting up messages \n"); -} - void readFromPC() { // should this be a while rather than if ??? -- may have multiple bytes in buffer if (toPC.readable()) //read a PC serial byte and test it for a command { - // Read in next character -- why not read all available?? + // Read in next character + // why not read all available bytes unsigned char inChar = 0; inChar = toPC.getc(); //read char from the USB serial link to the PC - //toPC.printf("%02x ",inChar); //incoming messages will end witb a CR / LF -- disregard these chars if (inChar == CR || inChar == LF) return; //CR is a 0x0a - //all received messages assumed to have a WMsg preamble - //if we have read 4 chars, test these for "WMsg", if they are not WMsg, reset the buffer counter - //if we receive an occasional bad byte that messes up a message, this will resynch fast to a next message - //this will let us miss a message --- but hopefully only one - - // serBuffMax = 18 -- largest serBuffMax is 16 -- but we add one below for the '\0' - // if the following occurs we have had a trash byte following a WMsg header - if (serBufChars >= (serBuffMax-2)) {toPC.printf("WMsg restart message search\n"); serBufChars = 0; } - - serBuf[serBufChars] = inChar; //set this char in a char array for testing complete message - - testPreamble[serBufChars] = inChar; //char array for testing the preamble - serBufChars++; - - if (serBufChars == 4) //four initial chars detected (0, 1, 2, 3) - { - testPreamble[4] = '\0'; //form null-terminated string for compare - if (strncmp(testPreamble, preamble, 5) != 0) //compare the chars to the WMsg preamble - { - toPC.printf("WMsg preamble mismatch \n"); - serBufChars = 0; //if they dont match -- restart the search for a preamble - return; - } - } - - //if we get here, we have found a preamble and we are looking for a complete message - //no need to continue if numChars are less than the shortest candidate message - if (serBufChars < minMessageSize) return; - - // Append end of string - // We always assume we have a complete message string and test for this below - serBuf[serBufChars] = '\0'; - - validMessage = false; - - // Check for valid message -- there are numMessages possible messages - //this assumes that the message buffer contains an exact message - for (int m = 0; m < numMessages && !validMessage; m++) //check for all messages ... - { - //toPC.printf(" \n\n found chars to test %3d %3d %s \n\n\n ", serBufChars, strlen(msgList[m]), serBuf ); - - //check the current partial message against ALL possible messages - //messages must match in both strength length and text - if (serBufChars == strlen(msgList[m]) && strncmp(serBuf, msgList[m], serBufChars) == 0 ) - { - - //toPC.printf( "\n found valid message %s \n\n", serBuf); - rxMsg = !rxMsg; - - validMessage = true; - serBufChars = 0; //reset the character count to reset for next message - - //set programmatic action flags based on the message - switch(m) - { - case STATUS_MSG: - sendStatus = true; //send a status message back to PC - break; - - case POSVEL_MSG: - sendPosVel = true; //send a posvel message back to PC - timeFromPosVelMessageReceipt.reset(); //start time and close SD card file if too long - break; - - case STARTDATA_MSG: //start the data recording to the SD card - recordData = true; - sendRecData = true; - break; - - case STOPDATA_MSG: //stop the data recording to the SD card - recordData = false; - 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; - - case FIRE_TRIGGER_MSG: - fireTrigger = true; - toPC.printf("WMsg MBED received trigger command \n"); - break; - - case GETFILE_MSG: - get_file_msg = true; // signal to main that we can unload the file that was written - toPC.printf("WMsg request to get SD card file \n"); - break; - - } //end Switch statement - break; - } //end test for a valid message - - } //end message text loop + //all incoming messages will start with "mbedMessage", "messageType", numberDataBytes, and will end with CR & LF + //1) look for the mbedMessage and then get the next byte as numberDataBytes; + //2) read the next numberDataBytes and then look for CR & LF + //if 1) & 2) are successful, declare a valid incoming message + //if message is valid, then send a response as a repeat of the original message + // } //end pc.readable }; -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 - //latRateFac & lonRateFac multiplied by Vnorth or VEast to get latRate and lonRate - //see this document (page 32) www.fas.org/spp/military/program/nav/basicnav.pdf - - 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; - - //divide Vnorth by latRateFac to get the latitude rate in deg per sec - latRateFac = (r_meridian + height)* DEGREES_TO_RADIANS; - - //divide VEast by lonRateFac to get the longitude rate in deg per sec - lonRateFac = (r_normal + height) * cos(latitudeRad)* DEGREES_TO_RADIANS; -} - -void sendPosVelMessageToPC(OEM615BESTPOS posMsg, OEM615BESTVEL velMsg) -{ - //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); - - double latRateFac; - double lonRateFac; - - earthCoefficients( posMsg.latitude*DEGREES_TO_RADIANS, - posMsg.longitude*DEGREES_TO_RADIANS, - posMsg.height, - latRateFac, lonRateFac); - - //commented calculations are for a spherical earth (Chris's original computation) - // 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 most recent 1PPS - double elTime = (double)PPSTimeOffset + timeFromPPS.read(); - - //this is the best estimate of the GPS time of the requested POSVEL data - double posTime = GPSTimemsecs/1000.0 + elTime; - - // Position time -- posMsgTime is the time of the last valid GPS position message - // this time may differ from GPSTimemsecs if the last position message (42) was missed due to CRC error - double posMsgTime = posMsg.msgHeader.GPSTime_msecs/1000.0; - - //toPC.printf(" elTime = %6.3f PPSimeOffset = %6.3f \n", elTime, PPSTimeOffset); - //toPC.printf(" latRateFac = %10.3f lonRateFac = %10.3f \n", latRateFac, lonRateFac); - //toPC.printf(" latRateFac = %10.3f lonRateFac = %10.3f \n", latMetersPerDeg, lonMetersPerDeg); - - // 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 latPos = posMsg.latitude + (nVel/latRateFac)*(posTime - posMsgTime); - double lonPos = posMsg.longitude + (eVel/lonRateFac)*(posTime - posMsgTime); - double htPos = posMsg.height + velMsg.verticalSpeed/(60*1852)*elTime; - - char solReady = 'N'; - //solStatus - if (posMsg.solStatus == 0) //see description of solution status in OEMV615.h - { - solReady = 'Y'; - } - - toPC.printf("WMsg POSVEL %5.3lf %1d %c %8.6lf %9.6lf %4.3lf %4.3lf %4.3lf %4.3lf\n", - posTime, - posMsg.numSolSV, - solReady, - latPos, - lonPos, - htPos, - nVel, - eVel, - velMsg.verticalSpeed - ); - txMsg = !txMsg; -} - -void processPCmessages(FILE* &fpNav, OEM615BESTPOS posMsg, OEM615BESTVEL velMsg) -{ - - - - //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 - { - //if we are receiving POSVEL requests -- always open the file for storage and store the data - //th file is closed(in main) if we dont receive POSVAL messages for 60 secs - if (fpNav == NULL) - { - toPC.printf("WMsg opening the SD card file at first PosVel message \n"); - fpNav = fopen("/sd/Data/NAV.bin", "wb"); - wait_ms(10); - recordData = true; - } - sendPosVel=false; //set to true if a POSVEL is requested from the PC - sendPosVelMessageToPC(posMsg, velMsg); - } - - //all this does is assess the GPS convergence -- really available in the above - if (sendStatus) //send the status message to the PC - { - txMsg = !txMsg; - sendStatus=false; - char solReady = 'N'; - //solStatus - if (posMsg.solStatus == 0) //see description of solution status in OEMV615.h - { - solReady = 'Y'; - } - toPC.printf("WMsg STATUS %5.3lf %c\n", - GPSTimemsecs, - solReady - ); - } - - //should just record ALL the data -- can pick over it in the post-processing - if (sendRecData) //begin to (or stop) record the serial data - { - sendRecData=false; //reset the flag so we dont continue to come through here - char recChar = 'N'; - //recordData set to true only if we receive a STARTDATA from the PC - if (recordData) //here we have received a message to record the data - { - if ((fpNav == NULL)) //if file not opened -- open it - { - toPC.printf(" opening the SD card file from RECORD message \n"); - fpNav = fopen("/sd/Data/NAV.bin", "wb"); - wait_ms(10); - } - if (fpNav != NULL) //if the file was already opened we will respond to the PC with a Y - { - recChar = 'Y'; - } - else //is the file was not opened we will write a message to the PC - { - toPC.printf(" Could not open the SD card \n\n"); - } - } - //recordData set to false only if we receive a STOPDATA from the PC - else //here we have received a message to stop the recording - { - if (fpNav != NULL) //if the file is open -- close it - { - toPC.printf(" closing the SD card file from RECORD message\n\n"); - fflush(fpNav); - fclose(fpNav); - wait_ms(100); - //toPC.printf("\n after closing the SD card file \n\n"); - fpNav = NULL; - } - //if stop recording received and the file is already closed -- just do nothing - recordData = false; - - } - toPC.printf("WMsg RECORDDATA %c\n", - recChar - ); - } - - 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 - ); - } - - -}