Resolved: Sending complete packets by serial

Hi All,

Using the Serial input basics guide

I have a dummy UNO sending a long string:

// Dummy Tx

String stringa = "7E00AA900013A200412723B4FFFEC1CC392C4335314D7025A2000100010030008ACC818730000005A7F67694D8874620ABD4237FF98BDBB0F1AF6B932FC8177382A0483773839D42C1059C3481FCFC6F1C1945D7D2C7372A676EDA361960A18376AD31129536DF0237FA627C04FD59A4DD42E4021A02598D59B633DBCF902B9F4759335B8EA63AA336B32A6D898739093D450495FCA603854B9D3EA53C4AB1369FCE08C61192A882158D33000146";

void setup() {
    Serial.begin(9600);
    Serial.println(stringa);
}

void loop() {
    delay(5000);
}

Then there is another UNO that receives and splits the packet to send onto a radio at a different baud rate. Note the radio is limited to 32 ASCII char per packet but splits into different packets if \r received:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(3, 2); // RX, TX
  
const byte numChars = 32;
char receivedChars[numChars];   // array to store received data

boolean newData = false;

int charCount = 0;

void setup() {
    Serial.begin(9600);
    mySerial.begin(115200);
    mySerial.println("...");
}

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

    while (Serial.available() > 0 && newData == false) {
      rc = Serial.read();
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
        
      else {
         receivedChars[ndx] = '\0'; // terminate the string
         ndx = 0;
         newData = true;
         if (charCount == 32){
           mySerial.print("\r\n");
           charCount = 0;
         }
         charCount ++;
        }
    }
}

void showNewData() {
  if (newData == true) {
      mySerial.print(receivedChars);
      newData = false;
  }
}

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

What I am finding is that the received string should be:
7E00AA900013A200412723B4FFFEC1CC392C4335314D7025A2000100010030008ACC818730000005A7F67694D8874620ABD4237FF98BDBB0F1AF6B932FC8177382A0483773839D42C1059C3481FCFC6F1C1945D7D2C7372A676EDA361960A18376AD31129536DF0237FA627C04FD59A4DD42E4021A02598D59B633DBCF902B9F4759335B8EA63AA336B32A6D898739093D450495FCA603854B9D3EA53C4AB1369FCE08C61192A882158D33000146

But I am getting some '?' in place of some characters (different each time):

?RX 14:25:18.694: ?E00AA900013A200412

RX 14:25:18.726: 723B4FFFEC1CC392C4335314D7025A20

RX 14:25:18.758: 00100010030008ACC818730000005A7F

RX 14:25:18.790: 67694D8874620ABD4237FF98BDBB0F1A

RX 14:25:18.822: F6B932FC8177382A0483773839D42C10

RX 14:25:18.869: 59C3481FCFC6F1C1945D7D2C7372A676

RX 14:25:18.901: ED?361960?18376AD3?129536DF0237F

RX 14:25:18.933: A627C?4FD59A4DD42E4021A02598D59B

RX 14:25:18.965: 633DBCF902B9F4759335B8EA63AA336B

RX 14:25:18.997: 32A6D898739093?450495FCA603854B9

RX 14:25:19.030: D3EA5?C4AB1369FCE08C61192A882?58

RX 14:25:19.050: D33000146

Can you see anything that I have missed or can try to get this more reliable?

Thanks,
Ben.

You should make your receivedChars buffer big enough to receive a full message plus a terminating nul character.

Note that your receive finction checks for '\n' and not for '\r''

You might have other options like reading 32 bytes and send that, read another 32 bytes and send etc. The reading if the blocks of 32 bytes stops once you find a '\r' in a block.

String stringa = "7E00AA900013A200412723B4FFFEC1CC392C4335314D7025A2000100010030008ACC818730000005A7F67694D8874620ABD4237FF98BDBB0F1AF6B932FC8177382A0483773839D42C1059C3481FCFC6F1C1945D7D2C7372A676EDA361960A18376AD31129536DF0237FA627C04FD59A4DD42E4021A02598D59B633DBCF902B9F4759335B8EA63AA336B32A6D898739093D450495FCA603854B9D3EA53C4AB1369FCE08C61192A882158D33000146";

Bad idea on an UNO. The string constant contains 348 bytes. It needs twice this in RAM as the literal is copied into RAM at startup and then copied into a String object. String objects should be avoided on AVR Arduinos anyway as the fragment the memory much to fast. It's not relevant in this basic sketch though.

   mySerial.begin(115200);

SoftwareSerial at baudrates above 38400 won't work in most situations. I never saw a device accepting a serial stream from an UNO using SoftwareSerial at 115200 reliably.

Thanks both for quick replies,

The received packet has no delimiter/end marker, simply a pause of more than 1 second. I should have removed the endMarker declaration from the original example as it isn't used. The received string is also of variable length but the example is the worst case length.

I have struggled with software serials in the past at high baud rates so this makes sense.

My difficulty is the connected device is 9600 and the radio is 115200. I like the mega328 as it is so easy to use and through-hole for quick prototypes. No space for a mega2560/ADK.

Is there anything smaller with hardware serials or is there a way to mitigate this issue with the software serial?

I will try to switch, using hardware serial for 115200 and software serial for the read at 9600. Didn't manage it the first time but it must be doable as it doesn't need to do anything else when the code stops to read.

Switched the software and hardware serials, down to one '?'

It appears to always be the first/first few characters so definitely progress. Annoying the radio ignores any string with char outside 0x20 to 0xFF. So progress..

RX 18:44:10.019: ?E00AA900013A2

RX 18:44:10.067: 00412723B4FFFEC1CC392C4335314D70

RX 18:44:10.101: 25A2000100010030008ACC8187300000

RX 18:44:10.129: 05A7F67694D8874620ABD4237FF98BDB

RX 18:44:10.159: B0F1AF6B932FC8177382A0483773839D

RX 18:44:10.189: 42C1059C3481FCFC6F1C1945D7D2C737

RX 18:44:10.219: 2A676EDA361960A18376AD31129536DF

RX 18:44:10.249: 0237FA627C04FD59A4DD42E4021A0259

RX 18:44:10.289: 8D59B633DBCF902B9F4759335B8EA63A

RX 18:44:10.319: A336B32A6D898739093D450495FCA603

RX 18:44:10.349: 854B9D3EA53C4AB1369FCE08C61192A8

RX 18:44:10.369: 82158D33000146

// Read from meter send to tag
#include <SoftwareSerial.h>

SoftwareSerial mySerial(3, 2); // RX, TX
  
const byte numChars = 32;
char receivedChars[numChars];   // array to store received data

boolean newData = false;

int charCount = 0;

void setup() {
    Serial.begin(115200);
    mySerial.begin(9600);
    Serial.println("...");
}

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

    while (mySerial.available() > 0 && newData == false) {
      rc = mySerial.read();
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
        
      else {
         receivedChars[ndx] = '\0'; // terminate the string
         ndx = 0;
         newData = true;
         if (charCount == 32){
           Serial.print("\r\n");
           charCount = 0;
         }
         charCount ++;
        }
    }
}

void showNewData() {
  if (newData == true) {
      Serial.print(receivedChars);
      newData = false;
  }
}

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

Change of resistor sorted the last '?'. Thanks!