RF24mesh received payload structure values reversed

Hi all,

Just testing the RF24mesh library using UNO boards and NRF24L01+ transceiver modules.

Communications is working.

But (maybe I’ve done something wrong) – I’ve notice something not quite right in the order of internal payload member values at the slave (receiver) side.

When I set up a payload structure containing just two simple arbitrary values… eg. the value 9 and the value 663 … structured like this in the payload {9, 663}, which is of a form of {count, value} … so ‘count’ is 9, and ‘value’ is 663.

…then, when I use the MASTER to send this payload to the slave, then the slave (with the same defined payload structure) unexpectedly gets the values in the reversed order.

So, on the slave side, “count” ends up being 663, and “value” ends up being 9.

Eg… the master is sending {9, 663} payloads continuously… but the slave is receiving this…

:below is received by the slave…

Send OK: 1482000
Received packet #663 at 9
Send OK: 1483000
Received packet #663 at 9
Send OK: 1484000
Received packet #663 at 9
Send OK: 1485000
Received packet #663 at 9

I expected the ordering to be like “Received packet #9 at 663” … instead of “Received packet #663 at 9”.

Does anybody here tinker with RF24mesh library? Just in the middle of trying to figure out where I’ve gone wrong here (with coding or thinking, or both).

The code I’m using comes from online examples in using the RF24mesh library. One code is for the uno MASTER. The other is for the uno SLAVE. For both uno, the CE and CS pins are 9 and 10 (respectively).

First… UNO MASTER code:

 /** RF24Mesh_Example_Master.ino by TMRh20
  * 
  *
  * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which
  * will receive all data from sensor nodes.
  *
  * The nodes can change physical or logical position in the network, and reconnect through different
  * routing nodes as required. The master node manages the address assignments for the individual nodes
  * in a manner similar to DHCP.
  *
  */
  
  
#include "RF24Network.h"
#include "RF24.h"
#include "RF24Mesh.h"
#include <SPI.h>
//Include eeprom.h for AVR (Uno, Nano) etc. except ATTiny
#include <EEPROM.h>


// Payload from MASTER

struct payload_to_slave {
  unsigned long pktnum;
  unsigned long counter;

};



/***** Configure the chosen CE,CS pins *****/
RF24 radio(9,10);
RF24Network network(radio);
RF24Mesh mesh(radio,network);

uint32_t displayTimer = 0;

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


  // Set the nodeID to 0 for the master node
  mesh.setNodeID(0);
  Serial.println(mesh.getNodeID());
  // Connect to the mesh
  mesh.begin();

}


void loop() {    
  payload_to_slave payload = {9 , 663};
  // Call mesh.update to keep the network updated
  mesh.update();
  
  // In addition, keep the 'DHCP service' running on the master node so addresses will
  // be assigned to the sensor nodes
  mesh.DHCP();
  
  
  // Check for incoming data from the sensors
  if(network.available()){
    RF24NetworkHeader header;
    network.peek(header);
    
    uint32_t dat=0;
    switch(header.type){
      // Display the incoming millis() values from the sensor nodes
      case 'M': network.read(header,&dat,sizeof(dat)); Serial.println(dat); break;
      default: network.read(header,0,0); Serial.println(header.type);break;
    }
  }


  
  if(millis() - displayTimer > 1000){
  RF24NetworkHeader header1(5, OCT);  //network address '5'.... converted to OCTAL
  network.write(header1, &payload, sizeof(payload));  //a NETWORK WRITE is used by master to send information to slaves (as compared with mesh.write)
    
    displayTimer = millis();
    Serial.println(" ");
    Serial.println(F("********Assigned Addresses********"));
     for(int i=0; i<mesh.addrListTop; i++){
       Serial.print("NodeID: ");
       Serial.print(mesh.addrList[i].nodeID);
       Serial.print(" RF24Network Address: 0");
       Serial.println(mesh.addrList[i].address,OCT);
     }
    Serial.println(F("**********************************"));
  }
}

Next… the UNO SLAVE code:

/*NOTE: for multiple slaves, it is necessary to manually set a different nodeID value in the sketch code before uploading to the slave*/
/* eg. find the line that says #definie nodeID XX and use a unique value. For testing with just a single slave in the network, then any value is ok*/


/** RF24Mesh_Example.ino by TMRh20

   This example sketch shows how to manually configure a node via RF24Mesh, and send data to the
   master node.
   The nodes will refresh their network address as soon as a single write fails. This allows the
   nodes to change position in relation to each other and the master node.
*/


#include "RF24.h"
#include "RF24Network.h"
#include "RF24Mesh.h"
#include <SPI.h>
//#include <printf.h>


/**** Configure the nrf24l01 CE and CS pins ****/
RF24 radio(9, 10);
RF24Network network(radio);
RF24Mesh mesh(radio, network);

/**
   User Configuration: nodeID - A unique identifier for each radio. Allows addressing
   to change dynamically with physical changes to the mesh.

   In this example, configuration takes place below, prior to uploading the sketch to the device
   A unique value from 1-255 must be configured for each node.
   This will be stored in EEPROM on AVR devices, so remains persistent between further uploads, loss of power, etc.

 **/
#define nodeID 2


uint32_t displayTimer = 0;

struct payload_t {    //template for payload to be received, comprising a packet number value, and a number for the time information sent by the sender
  unsigned long counter;
  unsigned long ms;
};

void setup() {

  Serial.begin(115200);
  //printf_begin();
  // Set the nodeID manually
  mesh.setNodeID(nodeID);
  // Connect to the mesh
  Serial.println(F("Connecting to the mesh..."));
  mesh.begin();
}



void loop() {

  mesh.update();

  // Send to the master node every second
  if (millis() - displayTimer >= 1000) {
    displayTimer = millis();

    // Send an 'M' type message containing the current millis()
    if (!mesh.write(&displayTimer, 'M', sizeof(displayTimer))) {     //a MESH WRITE is used by slave to send information to master (as compared with network.write)

      // If a write fails, check connectivity to the mesh network
      if ( ! mesh.checkConnection() ) {
        //refresh the network address
        Serial.println("Renewing Address");
        mesh.renewAddress();
      } else {
        Serial.println("Send fail, Test OK");
      }
    } else {
      Serial.print("Send OK: "); Serial.println(displayTimer);
    }
  }

  while (network.available()) {
    RF24NetworkHeader header;
    payload_t payload;
    network.read(header, &payload, sizeof(payload));    //
    Serial.print("Received packet #");
    Serial.print(payload.counter);
    Serial.print(" at ");
    Serial.println(payload.ms);
  }
}

I have no experience of the Mesh library but I wonder could it be as simple as this

// Payload from MASTER

struct payload_to_slave {
  unsigned long pktnum;
  unsigned long counter;

};

SLAVE

struct payload_t {    //template for payload to be received, comprising a packet number value, and a number for the time information sent by the sender
  unsigned long counter;
  unsigned long ms;
};

...R

Hi there Robin,

Thanks for helping me with this. I believe that treating my current question (or described observation) will be the way you showed for now. I think I will go with that. I'll look into it a bit more later on, like delving into the source code to see if I need to swap something in the source library. I'm going to use the method you showed me. Thanks again!

Southpark:
I'm going to use the method you showed me. Thanks again!

I'm a bit confused :slight_smile:

All I did was post two extracts from your programs.

...R

Robin2:
I'm a bit confused :slight_smile:

All I did was post two extracts from your programs.

...R

I had assumed you swapped/reversed the order of the structure members on one side. I might try that (ie. swapping).

At the moment.... the ordering of the members on the master and slave side are aligned properly. But reversing the order on one side.... eg. slave side.... can be a temporary fix. Thanks Robin!

I need to check over things… but this pair of code is now working in the way I expect.
I basically kept the same order, but changed the part in the master to:

struct payload_to_slave {
  unsigned long pktnum;
  unsigned long timeval;
};

Getting the right order at the slave now:

Send OK: 26000
Received packet #9 at 663
Send OK: 27000
Received packet #9 at 663
Send OK: 28000
Received packet #9 at 663
Send OK: 29000
Received packet #9 at 663
Send OK: 30000
Received packet #9 at 663

UNO master side:

 /** RF24Mesh_Example_Master.ino by TMRh20
  * 
  *
  * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which
  * will receive all data from sensor nodes.
  *
  * The nodes can change physical or logical position in the network, and reconnect through different
  * routing nodes as required. The master node manages the address assignments for the individual nodes
  * in a manner similar to DHCP.
  *
  */
  
  
#include "RF24Network.h"
#include "RF24.h"
#include "RF24Mesh.h"
#include <SPI.h>
//Include eeprom.h for AVR (Uno, Nano) etc. except ATTiny
#include <EEPROM.h>


// Payload from MASTER

struct payload_to_slave {
  unsigned long pktnum;
  unsigned long timeval;

};



/***** Configure the chosen CE,CS pins *****/
RF24 radio(9,10);
RF24Network network(radio);
RF24Mesh mesh(radio,network);

uint32_t displayTimer = 0;

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


  // Set the nodeID to 0 for the master node
  mesh.setNodeID(0);
  Serial.println(mesh.getNodeID());
  // Connect to the mesh
  mesh.begin();

}


void loop() {    
  payload_to_slave payload = {9 , 663};
  // Call mesh.update to keep the network updated
  mesh.update();
  
  // In addition, keep the 'DHCP service' running on the master node so addresses will
  // be assigned to the sensor nodes
  mesh.DHCP();
  
  
  // Check for incoming data from the sensors
  if(network.available()){
    RF24NetworkHeader header;
    network.peek(header);
    
    uint32_t dat=0;
    switch(header.type){
      // Display the incoming millis() values from the sensor nodes
      case 'M': network.read(header,&dat,sizeof(dat)); Serial.println(dat); break;
      default: network.read(header,0,0); Serial.println(header.type);break;
    }
  }


  
  if(millis() - displayTimer > 1000){
    RF24NetworkHeader header1(5, OCT);  //network address '5'.... converted to OCTAL
    //network.write(header1, &payload, sizeof(payload));  //a NETWORK WRITE is used by master to send information to slaves (as compared with mesh.write)
    network.multicast(header1, &payload, sizeof(payload), 01); 
    
    displayTimer = millis();
    Serial.println(" ");
    Serial.println(F("********Assigned Addresses********"));
     for(int i=0; i<mesh.addrListTop; i++){
       Serial.print("NodeID: ");
       Serial.print(mesh.addrList[i].nodeID);
       Serial.print(" RF24Network Address: 0");
       Serial.println(mesh.addrList[i].address,OCT);
     }
    Serial.println(F("**********************************"));
  }
}

In the code for the master, I am now using the “network.multicast” function to broadcast out to all nodes (from the master).

network.multicast(header1, &payload, sizeof(payload), 01);

And… the UNO slave code is:

/*NOTE: for multiple slaves, it is necessary to manually set a different nodeID value in the sketch code before uploading to the slave*/
/* eg. find the line that says #definie nodeID XX and use a unique value. For testing with just a single slave in the network, then any value is ok*/


/** RF24Mesh_Example.ino by TMRh20

   This example sketch shows how to manually configure a node via RF24Mesh, and send data to the
   master node.
   The nodes will refresh their network address as soon as a single write fails. This allows the
   nodes to change position in relation to each other and the master node.
*/


#include "RF24.h"
#include "RF24Network.h"
#include "RF24Mesh.h"
#include <SPI.h>
//#include <printf.h>


/**** Configure the nrf24l01 CE and CS pins ****/
RF24 radio(9, 10);
RF24Network network(radio);
RF24Mesh mesh(radio, network);

/**
   User Configuration: nodeID - A unique identifier for each radio. Allows addressing
   to change dynamically with physical changes to the mesh.

   In this example, configuration takes place below, prior to uploading the sketch to the device
   A unique value from 1-255 must be configured for each node.
   This will be stored in EEPROM on AVR devices, so remains persistent between further uploads, loss of power, etc.

 **/
#define nodeID 2


uint32_t displayTimer = 0;

struct payload_t {    //template for payload to be received, comprising a packet number value, and a number for the time information sent by the sender
  unsigned long counter;
  unsigned long ms;
};

void setup() {

  Serial.begin(115200);
  //printf_begin();
  // Set the nodeID manually
  mesh.setNodeID(nodeID);
  // Connect to the mesh
  Serial.println(F("Connecting to the mesh..."));
  mesh.begin();
}



void loop() {

  mesh.update();

  // Send to the master node every second
  if (millis() - displayTimer >= 1000) {
    displayTimer = millis();

    // Send an 'M' type message containing the current millis()
    if (!mesh.write(&displayTimer, 'M', sizeof(displayTimer))) {     //a MESH WRITE is used by slave to send information to master (as compared with network.write)

      // If a write fails, check connectivity to the mesh network
      if ( ! mesh.checkConnection() ) {
        //refresh the network address
        Serial.println("Renewing Address");
        mesh.renewAddress();
      } else {
        Serial.println("Send fail, Test OK");
      }
    } else {
      Serial.print("Send OK: "); Serial.println(displayTimer);
    }
  }

  while (network.available()) {
    RF24NetworkHeader header;
    payload_t payload;
    network.read(header, &payload, sizeof(payload));    //
    Serial.print("Received packet #");
    Serial.print(payload.counter);
    Serial.print(" at ");
    Serial.println(payload.ms);
  }
}

Southpark:
I had assumed you swapped/reversed the order of the structure members on one side.

I was just trying to point out that you do not have them in same order when you should have. I find it is a good practice to copy the struct code from the Tx program to the Rx program to ensure they are identical. Or let both programs draw for a common shared file with the struct definition.

...R

Robin2:
I was just trying to point out that you do not have them in same order when you should have. I find it is a good practice to copy the struct code from the Tx program to the Rx program to ensure they are identical. Or let both programs draw for a common shared file with the struct definition.

...R

You are right about that Robin. I should have copied the structure code from the receiving side (- in this case, the slave side) to the sending side (- in this case the master side). That would have looked a lot better. I need to check over that code I had first pasted into this thread, and upload to my UNOs again, to see what's going on. At the moment, it just appears that the second lot of code has the same ordering of members (even if the labeling looks out of place)...... and everything is being received in the proper order. I'll update the situation after checking things out.