Jump to content
43oh

[SOLVED] Bug involving serial and C style character string


Recommended Posts

Apologies in advance for a long post....

 

First, here is what I am trying to do:

post-45284-0-32007900-1452201040_thumb.jpg

I have a MSP430F5529 LP with a dAISy backpack sending serial data at 38400 Baud to a Tiva C LP with a CC3100 backpack.  The Tiva C can send debug information to a Windows 10 machine at 115200 Baud.  I am using Energia v17.  The Tiva C sends NMEA sentences received from dAISy through WiFi to the marinetraffic.com site where the information is posted along with other stations all over the world.  If you aren't familiar with dAISy and AIS, here is a screen shot from marinetraffic of ships being tracked by my station:

post-45284-0-62063500-1452201481_thumb.jpg

A quick diversion:  dAISy works great!  I was able to get it up and running easily in OpenCPN and for the most part on marinetraffic.  Thanks to @@chicken for his help on understanding NEMA sentences (how the ship information is communicated) and a great product.  The problem is occurring in my sketch which transmits the data to marinetraffic.

 

The screenshot above comes from my original sketch where I used the String class to store incoming data from dAISy and then send it to marinetraffic.  This works pretty good on the Tiva athough it seems to introduce rare errors.  It introduces lots of errors if I try to use a F5529 with a CC3100.  Thinking the problem was with String, I decided to use C style character arrays.  Unfortunately by doing this I have introduced even more errors.  An outline of the code I am using is shown below:

/*
    Code to set up WiFi goes here...
*/

char nmea[100];                                // holds incoming NMEA sentences from dAISy                

WiFiClient client;

void setup()
{
  Serial1.begin(38400);                        // dAISy transmits to CC3200 at 38400 baud
                                               // on Serial1  
  Serial.begin(115200);                        // Output from CC3200 to serial monitor is
                                               // at 115200 baud on Serial
/*
    Code to get WiFi and Serial started goes here...
    Includes connections to network and to marinetraffic
*/
void loop() {
/*
    If marinetraffic gets disconnected there is code to reconnect herre...
*/
  
  int i = 0;                                   // counter set to 0 each time through the loop                                                           
  while (Serial1.available()) {                // look for incoming NMEA sentences from dAISy
    nmea[i] = (char)Serial1.read();            // place char into the array nmea[]
    Serial.print(nmea[i]);                     // debug print char by char as it is placed into nmea[]
    nmea[++i] = 0;                             // increment the counter and store a end of string marker                                                     

    if (nmea[i-1] == '\n') {                   // newline indicates the end of the NMEA sentence
      Serial.print(nmea);                      // print the entire sentence                                
      //client.print(nmea);                    // send the string to MarineTraffic 
                                               // (error occurs even when commented out)                                                          
    }                                           
  }
}


All the stuff where I have taken out code and replaced it with block comments seems to work.  But you can see the complete code here.

 

What this does is declare a char array named nmea and read data coming in byte by byte from dAISy.  I print out for debugging each nmea element as it comes in on the serial monitor.  A NMEA sentence uses a newline to indicate the end of the sentence.  So when a sentence ends I debug print it out to the serial monitor also.  Normally this is where the sentence would be sent to marinetraffic also.

 

What is expected is that each sentence would then show on the serial monitor twice.  Once when a char is read in, and once when the sentence is complete.  That is what happens with String.  But when I use a character array as shown above I get this kind of thing:

post-45284-0-12812500-1452202883_thumb.jpg

 

A valid NMEA sentence starts with !AIVDM and you can see that every other sentence looks good.  Those are coming from the print statement that does element by element of nmea as the data comes in from dAISy.  So data from dAISy looks good and the character array seems to be loading correctly.

 

The next line should look exactly the same.  Sometimes it does, usually it does not.  Notice that it will either be blank or have some portion of the end of the good sentence.

 

I have ruled out something to do with the CC3100 I think by commenting that print line out.  dAISy looks good.  What am I doing wrong (I am just starting to use char arrays instead of String)?  Or is it something to do with trying to read and write from Serial and Serial1 at the same time in Energia?  BTW, I think the same thing may be happening with String although it really shows up bad only on the F5529.

Link to post
Share on other sites

Hmmm. The Serial output implementation uses a ring buffer and on MSP430 it's 16 bytes. But on Tiva you have a setBufferSize() method you can run before .begin() to change the ring buffer sizes. Try that e.g. .setBufferSize(256, 256) on Serial and Serial1? I can't remember what the default is atm...

Link to post
Share on other sites

Anyway an easy glitch would be your loop waiting for >16 bytes from Serial1, then dumping it all at once - the first 16 bytes will go fast since you're just filling a ring buffer but after that print/println (calling .write() underneath) will block byte by byte, and if Serial1 keeps receiving data it'll overrun its 16 byte RX ring buffer fast before you're ready to loop again.

Link to post
Share on other sites

Oh, geez, ok now that I'm reading on a laptop I see the problem...

 

You have a 100-char array nmea, but your index into that array (i) never gets "reset" back to 0!  It eventually goes well beyond its buffer and starts corrupting and/or printing info from places it doesn't belong ;-)

 

Try this:

    if (nmea[i-1] == '\n') {                   // newline indicates the end of the NMEA sentence
      Serial.print(nmea);                      // print the entire sentence                                
      //client.print(nmea);                    // send the string to MarineTraffic 
                                               // (error occurs even when commented out) 
      i = 0;
      nmea[i] = '\0';  // Reset nmea array for next string!                                                         
    }                           

On second analysis, you are probably betting that after your Serial.print of nmea after the '\n' is complete, you'll find Serial1.available() to return false and loop() where i gets reset to 0... bad logic.  Declare i as static btw.  What happens if your while (Serial1.available()) returns false when there is still some of the "line" left but it hasn't arrived yet?  loop() will loop around and result in i getting reset to 0.

Link to post
Share on other sites

Reworking the code to indicate what I'm saying:

void loop() {
/*
    If marinetraffic gets disconnected there is code to reconnect herre...
*/
  
  static int i = 0;  // At the very start of the sketch, first time loop() runs, i gets initialized to 0.  It retains its last known value for every subsequent run of loop() though.
                                                  
  while (Serial1.available()) {                // look for incoming NMEA sentences from dAISy
    nmea[i] = (char)Serial1.read();            // place char into the array nmea[]
    Serial.print(nmea[i]);                     // debug print char by char as it is placed into nmea[]
    nmea[++i] = 0;                             // increment the counter and store a end of string marker                                                     

    if (nmea[i-1] == '\n') {                   // newline indicates the end of the NMEA sentence
      Serial.print(nmea);                      // print the entire sentence
      i = 0;
      nmea[i] = '\0';                 
    }                                           
  }
}
Link to post
Share on other sites

Thanks a million @@spirilis

 

On second analysis, you are probably betting that after your Serial.print of nmea after the '\n' is complete, you'll find Serial1.available() to return false and loop() where i gets reset to 0... bad logic.  Declare i as static btw.  What happens if your while (Serial1.available()) returns false when there is still some of the "line" left but it hasn't arrived yet?  loop() will loop around and result in i getting reset to 0.

That was it.

 

And thinking about it, when I used String I didn't need a counter.  I just let String fill up and then set it back back to empty after it printed.  Explains everything....

Link to post
Share on other sites

Thanks a million @@spirilis

That was it.

 

And thinking about it, when I used String I didn't need a counter.  I just let String fill up and then set it back back to empty after it printed.  Explains everything....

woot!  Good to hear, and now you should be ready to roll with using the WiFi boosterpack.  Do you have to mangle or process the NMEA string to produce what you need for marinetraffic.com, or encapsulate the data somehow?

Link to post
Share on other sites

What dAISy sends is ready to go to marinetraffic so no additional processing needed. The firmware that @@chicken wrote for dAISy weeds out bad sentences. There are some other interesting things you might do though if you wanted to track things within a specified radius or certain marine vessels within the microcontroller. I can see the ships out my window so it is pretty entertaining.

Link to post
Share on other sites

What dAISy sends is ready to go to marinetraffic so no additional processing needed. The firmware that @@chicken wrote for dAISy weeds out bad sentences. There are some other interesting things you might do though if you wanted to track things within a specified radius or certain marine vessels within the microcontroller. I can see the ships out my window so it is pretty entertaining.

That is awesome.  Totally a perk I wouldn't have imagined any use of because I'm comparatively landlocked, but Seattle sounds like an exciting area for that stuff!  Maybe Boston and NYC too.

Link to post
Share on other sites

Yep, that was a good catch by Spirillis.  I burned enough brain cells trying to figure it out that it is etched into my cranium now and doubt I will make that mistake again.  I have thought enough about char strings that I probably understand those now too  :) 

 

Anyway, the Tiva seems good but it did not fix the F5529.  I removed the Serial debug print entirely so as to remove as much overhead as possible in Energia and tested it with marinetraffic but still got some errors.  I looked up the ring buffer size and it is indeed 16 bytes as Spirillis said.  The NMEA sentences can be as much as 80 bytes or so long although usually shorter.  If that is the problem I could try changing  the buffer size but since I have no idea what the ramifications might be I will stick with the Tiva.  May try the MSP432 since I picked up a couple of those at $4.32.

Link to post
Share on other sites

With 10KB of total RAM in the F5529 it shouldn't be an issue to allocate a healthy ring buffer (e.g. 1KB). Serial was implemented in a defensive way so that it also works with the much smaller MSP430s.

 

OK, you talked me into it.  I thought that was the case but it is good to have verification.  I upped the MSP430 hardware ring buffer in Energia up to 256 and swapped over to the F5529 about a half hour ago. And it looks like it worked :D. No errors yet but I'll leave it running on MarineTraffic and see if it catches any.

 

CORRECTION:  I have the ring buffer set to 512.  My thinking was it might need to be a bit larger than the Tiva due to the slower clock speed of the F5529.  I've not tested to see what the threshold is.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...