Serial add char to bytes

I want to add a step to check integrity of some bytes over serial. I dont know how i can combine the char and the bytes to send as a singe message to the receiver.

This is how i tried and it failed.

send,

struct a {
  int a= 25;
};
a b;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
delay(1000);
  Serial.print("ABCDEF");
  Serial.write((byte*)&b, sizeof(b)); //cast to bytes
}

recv,

struct a {
  int a;
};
a b;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  while (Serial.available()) {
    char verifyStart[7]; 
    char buffer[300];
    Serial.readBytes((char*)buffer, sizeof(6));
    strncpy (verifyStart, (char*)buffer, 6);//6 bytes
    verifyStart[6] = 0; //null terminate
    Serial.println(verifyStart);
    if (strcmp(verifyStart, "ABCDEF") == 0) {
      memcpy(&b, buffer + 6 , sizeof(b)); 
    }
  }

id like to extract the char string from the first 6 bytes. then use string compare to know what to do.

How do i send the message how id like, how can i receive it?

I know im only reading 6 bytes into buffer. i was initially just trying to receive the char. But why does it print in my serial console like this,

01:22:16.185 -> AB3⸮⸮~
01:22:16.185 -> CD3⸮⸮~
01:22:16.185 -> EF3⸮⸮~

I added this to my receiving code to get an idea how many bytes im getting. but it showing im only read 2 at a time? what is this behavior?

    int len = Serial.readBytes(buffer,sizeof(6));
    Serial.println(len);
01:34:29.583 -> AB⸮j
01:34:29.583 -> 2
01:34:29.583 -> CD⸮j
01:34:29.583 -> 2
01:34:29.583 -> EF⸮j
01:34:30.581 -> 2

= 2 (size of an integer).

Serial.readBytes(buffer,6);
1 Like

OOPS.. that was indeed the issue, but now how shall i send the message with the preceding char string. "ABCDEFstructbytes" Can it be done in 1 serial print/write?

There is no harm to try the following codes:

  Serial.println("ABCDEFstructbytes");
  Serial.write("ABCDEFstructbytes");

readbytes will wait until it receives the amount of bytes i specify. so i guess its okay to make multiple write with serial? i wonder how to do it with 1 print. i didn't find a way to concatenate the char string with the structbytes in a single write. '

This seems to work for sending,

struct a {
  int a = 25;
};
a b;
unsigned long now = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - now >= 1000) {
    Serial.print("ABCDEF");
    Serial.write((byte*)&b, sizeof(b));
    Serial.print("ABCDE>");
    now = millis();
  }
}

recv,

struct a {
  int a;
};
a b;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Boot");
}

void loop() {
  if (Serial.available()) {
    char verifyStart[7];
    char buffer[300];
    int len = Serial.readBytesUntil( '>', buffer, 60);
    Serial.println(len);
    strncpy (verifyStart, buffer, 6);//6 bytes
    verifyStart[6] = 0; //null terminate
    Serial.println(verifyStart);
    if (strcmp(verifyStart, "ABCDEF") == 0) {
      memcpy(&b, buffer + 6 , sizeof(b));
      Serial.println(b.a);
    }
  }
}

Im open to suggestions, i know there's probably a better way to do this.

Using > to indicate end of bytes, but what happens when the terminating/">" char not seen. does sketch block until timeout?

Use can use strcat to concatenate strings.


const char header[]  = "ABCDEF";
const char trailer[] = "ABCDE>";
char myData[]        = "123456";

void setup()
{
  Serial.begin(115200);

  char bufferToSend[30]= "";
  strcat(bufferToSend, header);
  strcat(bufferToSend, myData);
  strcat(bufferToSend, trailer);

  Serial.println(bufferToSend);
}

void loop()
{
  
}

19:05:25.352 -> ABCDEF123456ABCDE>

1 Like

Is it okay to use strcat first. What happens if there is no null terminator at first for strcat to find and overwrite when appending to the c_str

Would this be valid?

  char bufferToSend[30]= "";
  strcat(bufferToSend, "chars");
  strcat(bufferToSend, myData);
  strcat(bufferToSend, "chars");

There is no initial terminator.

Not sure what you mean by "initial terminator" ?

String (character arrays) literals always include an implied terminator.

1 Like

Okay now im having strange problem. when i send 16 bytes to the receiver buffer then the struct, then another 16 bytes. i copy the first and last 16 bytes into verifyStart and verifyEnd null terminate it. but if i try to print both "verifyStart & verifyEnd the serial monitor only prints verifyEnd.

If i comment out verifyEnd then verifyStart prints correctly. What did i do wrong this time?

recv,

struct a {
  int a;
  uint32_t var[50];
};
a b;
unsigned long bps = 0;
char buffer[803];
void setup() {
  Serial.begin(500000);
  Serial.println("Boot");
}

void loop() {
  if (Serial.available()) {
    char verifyStart[16];
    char verifyEnd[16];

    int len = Serial.readBytesUntil( '>', buffer, 803);
    bps += len;
    Serial.println(len);
    strncpy (verifyStart, buffer, 16);//6 bytes
    strncpy (verifyEnd, buffer + (len - 16) , 16 );//6 bytes
    verifyStart[16] = 0; //null terminate4
    verifyEnd[16] = 0; //null terminate
    Serial.println(verifyStart);
    Serial.println(verifyEnd);
    if (strcmp(verifyStart, "reqDataStruct001") == 0) {
      if (strcmp(verifyEnd, "ENDOFBYTESTREAMS") == 0) {
       // memcpy(&b, buffer + 16 , sizeof(b));  
       Serial.println("cmd");
       Serial.println(b.a);
      }
      }
    }
  }

send,

struct a {
  int a = 25;
  uint32_t var[50];
};
a b;
bool c = 1;
unsigned long bps = 0;
unsigned long now = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(500000);
  Serial.println(sizeof(b));
}

void loop() {
  // put your main code here, to run repeatedly:
 // 
delay(1000);
// if(c){
    Serial.print("reqDataStruct001");
    Serial.write((byte*)&b, sizeof(b));
    Serial.print("ENDOFBYTESTREAMS>");
    bps++;
    
 //}
//    if (millis() - now >= 1000) {
//      //Serial.println(bps);
//      c = 0;3
 //   now = millis();
 // }
}
14:41:30.613 -> ENDOFBYTESTREAMS
14:41:31.612 -> 234
14:41:31.612 -> 
14:41:31.612 -> ENDOFBYTESTREAMS
14:41:32.612 -> 234
14:41:32.612 -> 
14:41:32.612 -> ENDOFBYTESTREAMS
14:41:33.611 -> 234
14:41:33.611 -> 
14:41:33.611 -> ENDOFBYTESTREAMS
14:41:34.609 -> 234
14:41:34.609 -> 
14:41:34.609 -> ENDOFBYTESTREAMS

Im afraid ill get some undefined behavior because im getting unexplained results in the serial monitor already.

i revised the code to use 1 buffer for the verify string and the results in the serial monitor are as expected. Is this acceptable? i think i am extracting the bytes from the buffer right? but i thought i was last time to. and the problem on happened when using serial print.

struct a {
  int a;
  uint32_t var[50];
};
a b;
unsigned long bps = 0;
char buffer[803];
void setup() {
  Serial.begin(500000);
  Serial.println("Boot");
}

void loop() {
  if (Serial.available()) {
  //  char verifyStart[16];
  //  char verifyEnd[16];
    char verify[32];
    int len = Serial.readBytesUntil( '>', buffer, 803);
    bps += len;
    Serial.println(len);
    strncpy (verify, buffer, 16);//6 bytes
    strncpy (verify + 16, buffer + (len - 16) , 16 );//6 bytes
    Serial.println(verify);

  }
}

EDIT: I think i forgot the null terminator

The C library function **char *strncpy(char dest, const char src, size_t n) copies up to n characters from the string pointed to, by src to dest . In a case where the length of src is less than that of n, the remainder of dest will be padded with null bytes.

Does this mean i don't need to null terminate "verify" manually when using strncpy?

Yes.

char verify[32];
strncpy (verify, buffer, 16);//16 bytes
strncpy (verify + 16, buffer + (len - 16) , 16 );//16 bytes

You are copying 32 bytes into the array. verify needs to be one longer to hold the null terminator.

1 Like

Please help me clear up this confusion. im copying over 32bytes in the array. but the array starts at [0] right? so when i initialize char array[32] this gies me 33 bytes?

If i increase the size of the array by one byte does the null terminator go at 32 or 33? I think 32. b ut am confused if array starts a 0 then [32] i thought would be 33 0-32

No, there are 32 elements in the array with indexes from 0 to 31.

If i increase the size of the array by one byte does the null terminator go at 32 or 33?

The null terminator goes in element 32. There is no element 33.

Zero based counting is sometimes not intuitive because we have 10 fingers and always start counting at 1 and go to ten, instead of starting at 0 and going to 9.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.