Sorting NMEA Sentences, works great but adds an extra byte somehow.

I found this small program on this forum and it works rather well with very minimal overhead. KUDOS, to choose specific NMEA sentences, but it adds a extra mystery byte and I am not sure where it is coming from. At the end of the NMEA sentence the end should always be "0D 0A"

But this script is making the end come come out "0D 0D 0A" The other gps i am interfacing with does not like this and prompts "invalid gps". Any thoughts where the extra "0D" is magically appearing from.

I have been using IO Ninja to verify my outputs, The gps's I have neither produce this so it is coming from the Arduino somehow? Any thoughts? I have been learning C for 1 week so far BTW.

/*
Example 17.1 UART ONLY - MODIFIED
Display any data coming out of the GPS receiver in the serial monitor box
tronixstuff.com/tutorials > Chapter 17
*/
/*
  Modified by Robert M. Jaarsma
  sends only desired sentences as a string over the serial port.
  String can be inspected and/or manipulated before sending it to serial.
  Could be usefull for long range (low baudrate) RF modems or with power limited applications.
  Can extract different NMEA sentences by entering different sentence identifiers ar begin of the code
  at String sentence1 = "$GPRMC";

  MAKE SURE SHIELD SWITCH IS SET TO UART, code will not work when DLINE is selected.
  However, DLINE does need to be selected when code is uploaded to the board.
  After uploading the code to the board set shield to UART and reset de board (reset button on shield).
  Without resetting after code upload the UART serial communications to the PC will not work (unless
  you reconnect the USB cable).

  Revision: 12 jun 2011 13:08 GMT
*/

char gpsin;
String stringgps = "$";                          // as the code looks for the '

it needs
                                                 // to be added manually again in the string

// SET DESIRED SENTENCE IDENTIFIER HERE, set "$" only for all sentences
                                    String sentence1 = "$GPRMC";
                         
void setup()
  {
Serial.begin(4800);                     // the 406A GPS module puts out serial at 4800 bps
  }
void loop()
  {
    if (Serial.available()>0)                   // if there is data coming into the serial line
      {
        gpsin = Serial.read();                  // get a byte of data
      }
        if (gpsin == 36)                        // ascii code '



          {
            while (gpsin != 13)                 // ascii code 'return', end of sentence
              {
                if (Serial.available()>0)       // if there is data coming into the serial line
                  {
                    gpsin = Serial.read();      // get the next byte of data while gpsin != 13                 
                    stringgps += gpsin;         // add the latest byte to the string
                  }               
              }
            
            if (stringgps.startsWith(sentence1))// look if string starts with ex. '$GPRMC'
              {
                Serial.println (stringgps);     // when gpsin != 13 NOT true (gpsin == 13)
                                                // send string with complete sentence to serial
              }
            stringgps = "$";                    // empty string for next sentence,
                                                // '

is already added to the string manually here.
            //delay (100);
          }
  }

ASCII 0x0D (decimal 13) is indeed carriage return but it is not uniformly defined as a line ending. Some systems use 0x0A (decimal 10, line feed) or both in either order, as the line ending.

Since the code checks only for decimal 13, it ignores the 10, and Serial.println() adds another CR-LF (or LF-CR).

We strongly recommend to avoid use of Strings, as on AVR based Arduinos, the poor memory management associated with String objects leads to unexpected program crashes. Strings are completely unnecessary.

Use C-strings (zero terminated character arrays) instead. Look up "C/C++ string.h" for tutorials.

When you have your finished string, you use:

Serial.println(stringgps);

println() appends at CRLF.

Try using:

Serial.print(stringgps);

Here is an example that parses the speed from the RMC sentence using c_strings and c_string functions strstr() and strtok(). This avoids the use of the problematic String class. It uses a software serial port to read the GPS.

Perhaps this will be of use to you.

// Robin2's Example 2 - Receive with an end-marker modified to work with software serial
// retrieve speed from the $GPRMC sentance from GPS data string.
// by groundfungus aka c. goulding

#include <SoftwareSerial.h>

SoftwareSerial ssPort(5, -1);

const byte numChars = 64;
char receivedChars[numChars];   // an array to store the received data
char rmcLine[64];
boolean newData = false;

char *strings[16];
char *ptr = NULL;
float knots2MPH = 1.1507794;
float speed = 0;
boolean speedIsValid = false;

void setup()
{
   Serial.begin(115200);
   ssPort.begin(9600);
   Serial.println("<Arduino is ready>");
}

void loop()
{
   recvWithEndMarker();
   getRMCdata();
}

void recvWithEndMarker()
{
   static byte ndx = 0;
   char endMarker = '\n';
   char rc;

   while (ssPort.available() > 0 && newData == false)
   {
      rc = ssPort.read();

      if (rc != endMarker)
      {
         receivedChars[ndx] = rc;
         ndx++;
         if (ndx >= numChars)
         {
            ndx = numChars - 1;
         }
      }
      else
      {
         receivedChars[ndx] = '\0'; // terminate the string
         ndx = 0;
         newData = true;
      }
   }
}

void getRMCdata()
{
   if (newData == true)
   {

      if (strstr(receivedChars, "$GPRMC") )
      {
         strcpy(rmcLine, receivedChars);
         Serial.print("This just in ... ");
         Serial.println(rmcLine);
         byte index = 0;
         ptr = strtok(rmcLine, ",");
         while (ptr != NULL)
         {
            strings[index] = ptr;
            index++;
            ptr = strtok(NULL, ",");
         }
         if (*strings[2] == 'A')   // if the fix is valid print speed
         {
            speed = atof(strings[7]) * knots2MPH;
            speedIsValid = true;
            Serial.print("Speed = ");
            Serial.print(speed);
            Serial.println(" MPH");
         }
         else
         {
            Serial.println("Speed not valid");
            speedIsValid = false;
         }
      }
      newData = false;
   }
}

Thanks for the replies!

It was “ln” on print.ln but after i removed it i had to add the 0x0a back.

It works great for one sentence. I also figured out how to change the GN talker codes to GP. Works great at 5 or 10hz with only 1 sentence.

I am looking to filter out 2 GGA and VTG sentences out of a sea of 20 flying out the serial port of a drone GPS.

But as soon as i try to add the second sentence in halves the HZ of the output.

I am leaning quick but C is alot like banging rocks together. I am used to plc programming which is much more like lego.

Im not sure if parsing is what i am trying to do.

My flow would be to:

  1. Sort out only the needed strings GNGGA GNVTG
  2. Change talker codes from GN to GP
  3. Encapsulate the GPGGA and GPVTG separately in a custom wrapper to interface with my other GPS unit

Ambitious i know but its teaching me to code.

Any ideas how to optimize for a second sentence?