Software serial sending struct to esp8266 from arduino

I want to send a struct from an arduino mega2560 to an esp8266. so far my code sometimes will send the valid bytes 1 time and the esp8266 will stop receiving any more messages. other times the data is invalid.

how can i successfully send the struct from the arduino to the esp?

Arduino send code,

#include <SoftwareSerial.h>

SoftwareSerial swSerial(30, 31); // RX, TX

unsigned long structTimerMillis = 0;

struct testStruct {
  uint32_t    var0 = 123;
  float var1 = 12.34;
  uint32_t var2 = 123321;
//  String message = "It Worked";
};
testStruct ts1;

int structSize[(sizeof(ts1))];


void setup() {
  Serial.begin(115200);
  swSerial.begin(9600);
}

void loop() {
  if (millis() - structTimerMillis >= 1000) {
    Write();
    structTimerMillis = millis();
  }
}

void Write() {
  Serial.println("write");
  swSerial.write((byte*)&ts1, sizeof(structSize));
}

esp receive struct,

//#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>

SoftwareSerial swSerial(13, 15); // RX, TX

unsigned long now = 0;


struct testStruct {
  uint32_t    var0 = 0;
  float var1 = 0.0;
  uint32_t var2 = 0;
  // String message = "N/A";
};
testStruct ts1;
int structSize[(sizeof(ts1))];
void setup() {
  Serial.begin(115200);
  swSerial.begin(9600);
  Serial.println("booting");
}

void loop() {
  // put your main code here, to run repeatedly:
  ReadData();
  if(millis()-now>=1000){
    Serial.println("running");
    now = millis();
  }
  
}

void ReadData()
{
  byte *ptr = (byte*)&ts1;
  if (swSerial.available() >= sizeof(structSize))
  {
    for (byte lp = 0; lp < sizeof (structSize); lp++) {
      ptr[lp] = swSerial.read();
    }
    Serial.println("var0:");
    Serial.println(ts1.var0);
    Serial.println("var1:");
    Serial.println(ts1.var1);
    Serial.println("var2:");
    Serial.println(ts1.var2);

  }
}

Is there a method i could do this with memcpy?

This declares an array. Is that what you intended?

Take a look at the SerialTransfer library, posted by a forum member, which can be used to transmit things like image files, etc.
https://www.arduino.cc/reference/en/libraries/serialtransfer/

Okay i have confirmed i tried the code 2 different way, each way same result. the data is valid for a while. then the data printed in serial becomes incorrect. why?

//#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>

SoftwareSerial swSerial(13, 15); // RX, TX

unsigned long now = 0;


struct testStruct {
  uint32_t    var0 = 0;
  float var1 = 0.0;
  uint32_t var2 = 0;
  // String message = "N/A";
};
testStruct ts1;
int structSize = sizeof(ts1);
void setup() {
  Serial.begin(115200);
  swSerial.begin(9600);
  Serial.println("booting");
}

void loop() {
  // put your main code here, to run repeatedly:
  ReadData();
  if (millis() - now >= 1000) {
    Serial.println("running");
    now = millis();
  }

}
//bool receive(structTable* table)
//{
//    return (Serial.readBytes((char*)&ts1, sizeof(ts1)) == sizeof(ts1));
//}

void ReadData()
{

  byte *ptr = (byte*)&ts1;
  //  memcpy(&ts1, buf, sizeof(ts1));
  if (swSerial.available() >= sizeof(ts1))
  {
    //    for (byte lp = 0; lp <= sizeof (ts1); lp++) {
    //  //    ptr[lp] = swSerial.read();
    //    }
    //    Serial.println("var0:");
    //    Serial.println(ts1.var0);
    //    Serial.println("var1:");
    //    Serial.println(ts1.var1);
    //    Serial.println("var2:");
    //    Serial.println(ts1.var2);
    //
    //  }
    swSerial.readBytes((char*)&ts1, sizeof(ts1)) == sizeof(ts1);
    for (byte lp = 0; lp <= sizeof (ts1); lp++) {
      //    ptr[lp] = swSerial.read();
    }
    Serial.println("var0:");
    Serial.println(ts1.var0);
    Serial.println("var1:");
    Serial.println(ts1.var1);
    Serial.println("var2:");
    Serial.println(ts1.var2);
  }
}

is this because there is no check if the data is valid at all? how could i do this? but this wouldn't make sense because im still sending the correct data. the new incoming bytes should overwrite the incorrect bytes in the struct. i don't know whats going on here

RFM69/Examples at master · LowPowerLab/RFM69 · GitHub

I've used these routines, but only from 32-bit hardware. I have not tested between mixed-architecture, so feedback would be useful.

There needs to be an example of this imsuprised to not really find one. The code you shaved looks pretty intense ill see if I can make somthing out of it.

I dont know why my values become corrupted.

First I'd like to know why the vaules are corrupted. Then id like to maybe add some bytes to the beginning and end of the message for verification.

Aparently I've asked this before. I couldn't find the program until now.

Hopefully I can make that work. But It appears to be almost the same program.

If someone wants to answer why I'm getting errors after a while, that would help still

The program in my other thread does not work. either

As pointed out, this creates an array of int with the number of elements equal to the number of bytes in the struct. You then use the size of this array (in bytes) when sending the struct over Serial, resulting in writing twice as many bytes as the struct actually contains (because an int on a mega is two bytes, and the array contains an int for every byte in the struct).

void Write() {
  Serial.println("write");
  swSerial.write((byte*)&ts1, sizeof(structSize));
}

I have been trying different methods.

right now this is my sending code,

#include <SoftwareSerial.h>

SoftwareSerial swSerial(30, 31); // RX, TX

unsigned long structTimerMillis = 0;

struct testStruct {
  uint32_t    var0 = 123;
  uint32_t var1 = 1234;
  uint32_t var2 = 123321;
};
testStruct ts1;

void setup() {
  Serial.begin(115200);
  swSerial.begin(9600);
}

void loop() {
  if (millis() - structTimerMillis >= 200) {
    Write();
    structTimerMillis = millis();
  }
}

void Write() {
  Serial.println("write");
  swSerial.write((const char*)&ts1, sizeof(ts1));  
}

Is it okay to use sizeof like this?

Here is my receiving code,

//#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>

SoftwareSerial swSerial(13, 15); // RX, TX

unsigned long now = 0;


struct testStruct {
  uint32_t    var0 = 0;
  uint32_t var1 = 0;
  uint32_t var2 = 0;
  // String message = "N/A";
};
testStruct ts1;

void setup() {
  Serial.begin(115200);
  swSerial.begin(9600);
  Serial.println("booting");
}
char messageBuffer[sizeof(ts1)];
void loop() {
  // put your main code here, to run repeatedly:
  ReadData();
  if (millis() - now >= 1000) {
    // Serial.println("running");
    now = millis();
  }

}

void ReadData()
{

//  byte *ptr = (byte*)&ts1;
      if (swSerial.available() >= sizeof(ts1)) {
        swSerial.readBytes(messageBuffer , sizeof(ts1));
        memcpy(&ts1, &messageBuffer, sizeof(ts1));
          Serial.println("var0:");
      Serial.println(ts1.var0);
      Serial.println("var1:");
      Serial.println(ts1.var1);
      Serial.println("var2:");
      Serial.println(ts1.var2);
  }
}

this set of programs works fine for a few moments until the number become very corrupted.

i have not been using structSize but i still get error after a while. it all seems to work perfect until it dont..

Im starting to think this might be a problem with SoftwareSerial

In answer to your PM: When transferring data between mixed platforms, say 8bit and 32bit , you have to consider how the data is represented on both platforms. Also look here for an example: Serial structure data transfer between an Arduino and a Linux PC - Arduino Stack Exchange

So far i have tried 2 methods of sending the bytes to the esp8266.

method 1,

swSerial.write((const char*)&ts1, sizeof(ts1));  

method 2,

 swSerial.write((byte*)&ts1, sizeof(ts1));

when i try to send like this:

swSerial.write((uint8_t*)&ts1, sizeof(ts1));

I stop receiving data on the esp and im assuming because the cast to uint_8 changes the required decoding on the receiver.

the first two methods received data correctly. Changing the SoftwareSerial baud rate to 1200 seemed make things work longer. Could you help me with the receiving code. I think int is 4bytes on esp and 2bytes on arduino. Just for simplicity i declare all uint32_t on bothe sides.

Im wondering if there is a bug with the software serial. i have only rx and gnd wire hooked up on the esp between arduino.

With the baud rate set to 1200 its been a few minutes and the values have not become corrupt. Previously i had it set to 9600. I just realized the arduino mega has multiple hardware serial ports. but im not confident im my coding skills so i assumed i had a bug in my code besides

int structSize[(sizeof(ts1))];

When the values would become corrupted they did not go back to the right values after receiving a new message with the struct , the stayed corrupted until i restart the esp at which time, the value are correct momentarily

how can i add a few bytes to the beginning of the message. i do this with udp but i don't know how to with serial

void sendStruct() {
  Udp.beginPacket(_EEPROM.masterIP, ServerPort);
  Udp.write(nodeID0);
  Udp.write((uint8_t*)&_packet, sizeof(_packet)); //cast to bytes
  Udp.write(nodeID1);
  Udp.endPacket();
}

How can i convert,

swSerial.write((uint8_t*)&ts1, sizeof(ts1));

so i can Serial.print(receivedSerialMessage);

EDIT: after some time the values became corrupted even at 1200 baud rate. I tried to use hardware serial 2 on the mega and software serial on the esp. still the same problem. at 9600 baud rate the problems happens ALOT faster

Try with one of the Hardware UART Ports (UART) of MEGA.

I just tried that and i'm getting the same results.

Initialize the member variables outside the struct.

You mean like this?

//#include <SoftwareSerial.h>

//SoftwareSerial swSerial(30, 31); // RX, TX

unsigned long structTimerMillis = 0;

struct testStruct {
  uint32_t    var0 = 0;
  uint32_t var1 = 0;
  uint32_t var2 = 0;
//  String message = "It Worked";
};
testStruct ts1;




void setup() {
  Serial.begin(115200);
 // swSerial.begin(1200);
  Serial1.begin(9600);
  ts1.var0 = 1;
  ts1.var1 = 2;
  ts1.var2 = 3;
}

void loop() {
  if (millis() - structTimerMillis >= 500) {
    Write();
    structTimerMillis = millis();
  }
}

void Write() {
 // Serial1.println("write");
  Serial1.write((uint8_t*)&ts1, sizeof(ts1));
}

The only thing that fixes the struct is Powe cycling the esp8266.

It don't matter if i power cycle the Arduino. If it was a bad message the struct data would recover on the next successful received message i would think? is something overflowing?

How can i convert what im sending over Serial1 to character i can read in the serial console. i would like to see the bytes not spaces and symbols

Im gona try an esp32 on hw only and see what happens.

15 minutes now of 9600 baud messages every 70ms i sent the struct to an esp32 hw serial2. so far it hasn't had a hiccup. im leaning towards SoftwareSerial problem. Im keeping my fingers crossed. its too early to tell for sure. if i have anymore problems ill report back

EDIT: Still working 30 minutes later. I guess th problem was softwareSerial after all

@notsolowki
1. Read this thread and hopefully, you will be able to send your struct from MEGA to NodeMCU (ESP8266) using UART1 Port of MEGA and SUART Port D2, D1) of ESP8266 as per Fig-1.
espMega2
Figure-1:

2. Transmitter Sketch (MEGA):

struct testStruct
{
  uint32_t var0;
  float var1;
  uint32_t var2;
};

testStruct ts1 =
{
  123,
  12.34,
  123321
};

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
}

void loop()
{
  byte *ptr;        //purpose is to grasp byte-by-byte of the struct data
  ptr = (byte*)&ts1;    //ptr holds the base address of byte-oriented data array named ts1 
  byte counter = sizeof(ts1);   //number of data bytes in the instance/variable ts1
  
  Serial1.print('<'); //beginning of struct data; care J-M-L's comment in referred thread
  do
  {
    byte m = *ptr;
    Serial1.write(m);
    if(m <0x10)
    {
      Serial.print('0');
    }
    Serial.print(m, HEX);
    Serial.print(' ');
    ptr++;
    counter--;
  }
  while (counter != 0);
  Serial1.write('>');//end of struct data; care J-M-L's comment in referred thread
  Serial.println();      
  delay(2000);
}

3. Transmitter (MEGA)'s Screen Data:

7B 00 00 00 A4 70 45 41 B9 E1 01 00//000007B=123; 414570A4=12.34; 0001E1B9=123321
7B 00 00 00 A4 70 45 41 B9 E1 01 00 

4. Receiver Sketch (ESP8266):

#include <SoftwareSerial.h>
SoftwareSerial swSerial(D2, D1); // D2 = SRX, D1 = STX

struct testStruct
{
  uint32_t var0;
  float var1;
  uint32_t var2;
};

struct testStruct ts1;
byte myData[20];
bool flag = false;

void setup()
{
  Serial.begin(115200);
  swSerial.begin(9600);
}

void loop()
{
  byte n = swSerial.available();
  if (n != 0 )
  {
    if (flag == false)
    {
      char x = swSerial.read();
      if (x == '<')
      {
        flag =  true;   //struct data is coming
      }
    }
    else
    {
      byte m = swSerial.readBytesUntil('>', myData, 20);
      for (int i = 0; i < m; i++)
      {
        byte y = myData[i];
        if (y < 0x10)
        {
          Serial.print('0');
        }
        Serial.print(y, HEX);
        Serial.print(' ');
      }
      //--- recreate structure-------
      ts1.var0 = (myData[3] << 24) | (myData[2] << 16) | (myData[1] <<8) | myData[0];
      //ts1.var1 = (myData[3] << 8) | myData[2];
      ts1.var2 = (myData[11] << 24) | (myData[10] << 16) | (myData[9] <<8) | myData[8];
      Serial.println();
      Serial.println(ts1.var0, DEC);
      Serial.println(ts1.var2, DEC);
      flag = false;
    }
  }
}

5. Receiver (MEGA)'s Screen Data:

7B 00 00 00 A4 70 45 41 B9 E1 01 00 
123
123321

6. Notes for OP:
(1) Read the above codes in consultation with the referred thread mentioned in Step-1.
(2) Try to add codes with receiver to reconstruct the float value 12.34 from the received data bytes and put it in the ts1 variable and show on the screen.
Hints:

 float x;
 long *ptr;//pointer variable to hold base address of RAM containing 32-bit value of x
 ptr = (long*)&x; //getting base address of a 4-byte (32-bit) oriented array space
 *ptr = 0x414570A4;//store binary32 formatted value (in the above space) for 12.34 
 Serial.println(x, 2);

(3) Study the comments of @J-M-L in the referred thread why '<' and '>' were "no good" as the Start-Mark and End-Mark for a binary-based Serial Transmission. To overcome this potential problem, try to make an ASCII-based Serial Transmission or still binary-based transmission with a 3-byte pre-amble and 1-byte Checksum as a last byte of the frame.

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