1

On my NodeMCU V3 I get a string, convert it to two longs, one int and two bytes, save them in a union and send the whole union to an Arduino Mega, which is supposed to read it in an equal union.

When the NodeMCU prints the bytes to the serial monitor of my laptop it shows their exact value, but after sending them I just get two 0s. Still I think it has something to do with the conversion of the bytes but can't figure out what.

I tried:

  • Using atol instead of strtol for converting the string, but discarded that after reading about the disadvantages. atol() v/s. strtol()
    It didn't work anyway.
  • I tried to convert the bytes with lowByte((int) int1).

Here is the relevant part of my code. I made up a string, instead of receiving one for test purposes.

#include <ESP8266WiFi.h>

union Serial {          //Union to place the numbers in.
  byte by[12];              
  struct  {
    long vsollneu;         
    long ssollneu;        
    int phisollneu;         
    byte priosollneu;       
    byte typsollneu;        
  } Befehlssammlung;        
} Befehle;

long a1,pr1,ty1;

char str[]="2049714 -1927461000 17 80 4"; //String to be seperated

void convert(char*);

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

void loop(){
  convert(str);
  //Serial.write(Befehle.by,12);  //Send the Bytes of the Union to the Arduino MEGA
  delay(5555);
}

  void convert(char* str){     //Converting the String with strtol
    char* ende;

    Befehle.Befehlssammlung.vsollneu =strtol(str,&ende,10);
    Befehle.Befehlssammlung.ssollneu =strtol(ende,&ende,10);
    a1 = strtol(ende,&ende,10);   
    pr1= strtol(ende,&ende,10);
    ty1= strtol(ende,NULL,10);

   Befehle.Befehlssammlung.phisollneu=(int) a1;     //Converting the long to an int
   Befehle.Befehlssammlung.priosollneu=(byte) pr1;  //Probably that's somehow wrong???
   Befehle.Befehlssammlung.typsollneu=(byte) ty1;

      // Serial.println(Befehle.Befehlssammlung.vsollneu);
      // Serial.println(Befehle.Befehlssammlung.ssollneu);
      // Serial.println(Befehle.Befehlssammlung.phisollneu);
      // Serial.println(Befehle.Befehlssammlung.priosollneu);
      // Serial.println(Befehle.Befehlssammlung.typsollneu);
}

Here is the receiving part of the Arduino Mega:

union IZweiCkontainer {
  byte by[12];              
  struct  {                 
    long vsollneu;          
    long ssollneu ;         
    int phisollneu;         
    byte priosollneu;       
    byte typsollneu;        
  } Befehlssammlung;        
} Befehle;

void setup(){
Serial.begin(115200);   //Serial for debugging
Serial3.begin(9600);    //Serial for conncetion the the Mcu
}

void loop(){

  if(Serial3.available()>0){
      while(Serial3.available()){
      Serial3.readBytes(Befehle.by,12);     //receiving the Bytes and writing them in the "same" union
    }
  }
      Serial.println(Befehle.Befehlssammlung.vsollneu);
      Serial.println(Befehle.Befehlssammlung.ssollneu);
      Serial.println(Befehle.Befehlssammlung.phisollneu);
      Serial.println(Befehle.Befehlssammlung.priosollneu);
      Serial.println(Befehle.Befehlssammlung.typsollneu);
}

What bucks me is that everything is fine on the NodeMCU but after sending I get the following output from the Arduino Mega:

2049714
-1927461000
17
0
0
gre_gor
  • 6,669
  • 9
  • 47
  • 52
  • You should check, in `Serial3.readBytes(Befehle.by,12)`, how many bytes you actually have read. Default timeout for reading (they say) is 1 second, but... better check. – linuxfan says Reinstate Monica May 25 '17 at 16:55
  • You are not only using structs across compile domains but a union. and expect this to work? Is what you are saying? Doable but not usually worth the effort and cost of regular maintenance. quick and dirty check your lengths on both ends, with some hardcoded answers, if the length doesnt match the hardcoded value then bail/fail on the data (and go back into maintenance mode). – old_timer May 25 '17 at 17:17
  • @linuxfan Thanks, for the idea. Unfortunately `Serial.readBytes(Befehl.by,12)` returns 12, so that seems fine. – DeniseBryson May 25 '17 at 17:26
  • Then you should check packing of structs. Maybe arduino uses some filler to align data, so the two bytes at the end of the struct are not where you think they are. You can easily confirm by asking the address of them (compared to the address of the previous field). – linuxfan says Reinstate Monica May 25 '17 at 17:41
  • @old_timer You were right!!! Apparently integers are 4 bytes on the NodeMCU which pushes the two bytes out of the structure! I changed it to a short and now it works! Thanks a lot for that hint. I spent a day and a half looking for the mistake! Definitely won't happen to me again! – DeniseBryson May 25 '17 at 18:07
  • I consider using structs across compile domains (hardware is a separate compile domain) a cardinal sin. But when I have done it I do a sizeof printf at one point then hardcode that check into the code, then down the road when the check fails, time for maintenance. Repeat until the software/project dies as it will continue to require maintenance over time (if you need to recompile at some point) – old_timer May 25 '17 at 18:13
  • I used to think this was ghee whiz cool, but then saw the problem, now I use this kind of thing as an interview question, not to weed out, but to just see if they know what the problems are and why, adding bitfields makes it significantly worse. – old_timer May 25 '17 at 18:15

1 Answers1

1

ints and longs on an Arduino and ESP8266 are not the same size.

Use int16_t and int32_t to make sure they are the same size across different architectures.

union {
  byte by[12];              
  struct  {                 
    int32_t vsollneu;          
    int32_t ssollneu;         
    int16_t phisollneu;         
    byte priosollneu;       
    byte typsollneu;        
  } Befehlssammlung;        
} Befehle;
gre_gor
  • 6,669
  • 9
  • 47
  • 52