Help sending memcpyed buffer over XBee's S2C in AT Mode in one pass

Hello all. The goal of my following code snippets is to send a byte_buffer over two XBees (S2C) in AT mode in one go, or at the very least successfully, even if not in one go.

In total there are 3 teensys. Two of them are connected to each other through a CAN transceiver (sn65hvd230). The code I have for these two has been thoroughly tested and is working. Essentially, I am hard coding the data of one can_message_t (from the FLEXCAN_T4 library on github) and sending it through one CAN IC to another and reading it on the second Teensy which is connected to the XBee. THe last teensy is simply plugged into another computer and the serial is read through XCTU/Arduino Serial monitor after being transmitted over teensy. (have also tested just sending with XBees and had no problem, although that was serial input, not a hard coded byte/char array, ie string)

The can_message_t is read by code on the second teensy and populates a byte buffer of length 24 (size of can_msg_t) using memcpy. I have tested this and found memcpy works fine and populates the buffer array (and on the other side a can_msg_t) struct just fine. The problem, however, is that the data is not coming through in one go, or is being jumbled up. This is where I get lost so pardon if my understanding is lacking.

I have tried to only send when XBee.availableForWrite (and also read) are > 23, implying the entire can frame (byte buffer) can be sent, however I am not getting the byte buffer sent correctly. The data differs (partly because of the timestamp member of Can_message_t as that is the only variable updated) however other members are also changed which is where my confusion begins.

I understand XBee can send bytes in little packets until a size is reached and also spent time trying to use readBytesUntil using a delimiter and increasing my buffer array by one, however that was unsuccessful.

So in short, I am trying to send an entire 24 bytes in one go, or at the very least read them in one go and somewhere along the transmission or reading, there are errors that misplace or do not send all of the data resulting in erroneous data.

I have tried many things, minus changing the baud rate of CAN IC, and at some point got the message to get through, but it does not happen consistently.

If you are taking the time to read this and assist, thank you in advance!

----- this is the last teensy that just displays what is received on the Serial monitor
#include
#define XBeeSerial Serial1

CAN_message_t msg;
unsigned long baud = 19200;
const int led_pin = 13;
const int reset_pin = 4;
const int buffer_len = 24;
byte buffer[buffer_len];
unsigned char dtr;
int read_var, write_var, data;
unsigned char prev_dtr;
int count;

void setup()
{
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, LOW);
digitalWrite(reset_pin, HIGH);
pinMode(reset_pin, OUTPUT);
Serial.begin(baud);
XBeeSerial.begin(baud);
}

void dtr_method() {
dtr = Serial.dtr();
if (dtr && !prev_dtr) {
digitalWrite(reset_pin, LOW);
delayMicroseconds(250);
digitalWrite(reset_pin, HIGH);
}
prev_dtr = dtr;
}
void print_buf(){
for(int i=0; i < buffer_len; i++){
Serial.print(buffer[i]);
}
Serial.println();
}

void print_can(){
Serial.print("CAN1 “);
Serial.print(“MB: “); Serial.print(msg.mb);
Serial.print(” ID: 0x”); Serial.print(msg.id, HEX );
Serial.print(” EXT: “); Serial.print(msg.flags.extended );
Serial.print(” LEN: “); Serial.print(msg.len);
Serial.print(” DATA: “);
for ( uint8_t i = 0; i < 8; i++ ) {
Serial.print(msg.buf[i]); Serial.print(” “);
}
Serial.print(” TS: "); Serial.println(msg.timestamp);
}
// done
void baud_update(){
if (Serial.baud() != baud) {
baud = Serial.baud();
if (baud == 57600) {
XBeeSerial.begin(58824);
} else {
XBeeSerial.begin(baud);
}
}
}

void loop() {
unsigned char prev_dtr = 0;
// first check if there is data coming from the Serial Monitor (transmitter)
// Note: this is not used in this demonstration but here to work with XCTU for debugging pps
read_var = Serial.available();
if (read_var > 0) {
write_var = XBeeSerial.availableForWrite();
if (write_var > 0) {
if (read_var > write_var) read_var = write_var;
if (read_var > buffer_len) read_var = buffer_len;
data = Serial.readBytes((char *)buffer, read_var);
XBeeSerial.write(buffer, data);
}
}

// check if there is data going to receiver
read_var = XBeeSerial.available();
if (read_var > 23) {
write_var = Serial.availableForWrite();
if (write_var > 0) {
if (read_var > write_var) read_var = write_var;
if (read_var > buffer_len) read_var = buffer_len;
memset(buffer, 0, buffer_len);
data = XBeeSerial.readBytes((char *)buffer, read_var);
memcpy(&msg, buffer, data);
//print_buf();
print_can();
digitalWrite(led_pin, HIGH);
}
}
//method that keeps teensy awake
dtr_method();
// shown above
baud_update();
}

—this is the code that receives the can message and then sends it over xbee
NOTE: i originally had Can1.read(msg) in an if statement with availablewritebytes > 23, but that resulted in the same three numbers being sent over and over. Not sure if this is because of baud rate, blocking functions or what. I get lost here.

#include
#define XBeeSerial Serial1

FlexCAN_T4 Can1;
CAN_message_t msg;
unsigned long baud = 19200;
const int led_pin = 13;
const int reset_pin = 4;
const int buffer_len = 24;
byte buffer[buffer_len];
int count;

void setup()
{
// turn led
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, LOW);
digitalWrite(reset_pin, HIGH);
pinMode(reset_pin, OUTPUT);
// being serial communication
Serial.begin(baud);
XBeeSerial.begin(baud);
Can1.begin();
Can1.setBaudRate(250000);
}

void print_can(){
Serial.print("CAN1 “);
Serial.print(“MB: “); Serial.print(msg.mb);
Serial.print(” ID: 0x”); Serial.print(msg.id, HEX );
Serial.print(” EXT: “); Serial.print(msg.flags.extended );
Serial.print(” LEN: “); Serial.print(msg.len);
Serial.print(” DATA: “);
for ( uint8_t i = 0; i < 8; i++ ) {
Serial.print(msg.buf[i]); Serial.print(” “);
}
Serial.print(” TS: "); Serial.println(msg.timestamp);
}

void loop()
{
unsigned char dtr;
int read_var = 0, write_var, data;
unsigned char prev_dtr = 0;

     Can1.read(msg);

// LOOK here ignore next xbeeserial
write_var = XBeeSerial.availableForWrite();
if (write_var > 23) {
if (read_var > write_var) read_var = write_var;
if (read_var > buffer_len) read_var = buffer_len;
memset(buffer, 0, buffer_len);
memcpy(buffer, &msg, buffer_len);
XBeeSerial.write(buffer, buffer_len);

}

//serial and baud rate functions omitted for char count, same as previous code

EDIT – added the hardcoded can_message_t and example of what is being received

-----hard code can_msg struct
msg.flags.ext = 0;
msg.id = 0x100;
msg.len = 8;
msg.buf[0] = 10;
msg.buf[1] = 20;
msg.buf[2] = 0;
msg.buf[3] = 100;
msg.buf[4] = 128;
msg.buf[5] = 64;
msg.buf[6] = 32;
msg.buf[7] = 16;

– what should be received -----
CAN1 MB: 0 ID: 0x100 EXT: 0 LEN: 8 DATA: 10 20 0 100 128 64 32 16 TS: 1088 (ts will differ)

– example what is being received –
CAN1 MB: 8 ID: 0x4000008 EXT: 72 LEN: 4 DATA: 0 0 72 4 4 4 0 0 TS: 1088
CAN1 MB: 8 ID: 0x48 EXT: 0 LEN: 0 DATA: 4 0 0 0 156 2 0 4 TS: 8
CAN1 MB: 8 ID: 0x4840401 EXT: 0 LEN: 1 DATA: 0 0 4 0 10 8 156 0 TS: 1028
CAN1 MB: 0 ID: 0x400 EXT: 72 LEN: 0 DATA: 4 4 128 4 4 4 10 0 TS: 72
CAN1 MB: 2 ID: 0x1A1C0000 EXT: 0 LEN: 0 DATA: 74 1 10 10 70 66 38 66 TS: 4

I don’t think this is something that can be addressed by Digi. But you might want to try using API mode. API mode is a framed based interface on the XBee that would allow what ever data you want to be sent as one packet.

If you are looking for help in your code for the 3rd party processor, you really should be contacting the 3rd party processor manufacture instead.

My guess is that you are sending data to the Xbee faster that it can be transmitted and therefore the Tx buffer gets corrupted. In transparent mode you either need to use CTS flow control or limit the data rate so that the Tx buffer never overflows.