nRF24L01 - Link status update...

I am looking for a method to display on two LEDs the status of link between a RF24 TX module and RF24 RX module.

I am sending the display data from a 4 Line x 20 Char LCD in Base unit to a Remote Rx unit and the remote unit sends back Key data to the Base unit. Thus the Base and Remote are in Sync always.

Since this is part of a much large code i have stripped only the relevant portions of code pertaining to the RF24 section. The problem I have is the unreliable status indication - like for instance when the Rx unit is powered down or out of range, i want the RF_Flt_Out LED to come ON. Surprisingly this is not so … there are times when RF_OK_Out LED is ON even when the Rx is not even switched ON.

Just wanted to know if my method of checking the status is OK ??

#include <RF24.h>

/* Set up nRF24L01 radio on SPI bus plus pins for CE and CSN */
RF24 radio(40, 41);                           // First pin (40) is CE and Next pin (41) is CSN

byte radioAddress[][6] = {"1_PRX", "2_PTX"}; // Radio pipe addresses for RemoteUnit, ThisUnit.

byte RF_OK_Out      = 34;
byte RF_FLT_Out     = 33;
char firstLineMsg[21] , secondLineMsg[21] , thirdLineMsg[21] , fourthLineMsg[21] ;
bool firstLine, secondLine, thirdLine, fourthLine;
byte copy_RFID[4];
char copy_KeyVal;
long copy_GFMData;

struct tx_dataStruct {                       // Configure your transmission data into this structure
  char lcdMessage[21];
  byte cursorRow;
  boolean gotTheKey;
} txDataToRemUnit;

struct rx_dataStruct {                      // Configure your reception data into this structure
  char keyVal;
  boolean tokenKey;
} rxDataFromRemUnit;

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void setup() {

  pinMode(RF_OK_Out, OUTPUT);
  pinMode(RF_FLT_Out, OUTPUT);

  // Setup and configure radio
  radio.begin();
  radio.setChannel(108);                         // Above most Wifi Channels
  radio.setDataRate( RF24_250KBPS );
  radio.enableAckPayload();                      // Allow optional ack payloads
  radio.enableDynamicPayloads();                 // Ack payloads are dynamic payloads
  radio.setRetries(5, 10);                       // Delay, count

}

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void loop() {

  // Dummy messages to be sent..

  strcpy(firstLineMsg, " This is Line 01") ;
  strcpy(secondLineMsg, " This is Line 02") ;
  strcpy(thirdLineMsg, " This is Line 03") ;
  strcpy(fourthLineMsg, " This is Line 04") ;

  // Now Send them to the Rx unit

  rfCommWithRemUnit();

  delay(1000);

  strcpy(firstLineMsg, "************* ") ;
  strcpy(secondLineMsg,"************* ") ;
  strcpy(thirdLineMsg, "************* ") ;
  strcpy(fourthLineMsg, "************* ") ;

  // Now Send them to the Rx unit

  rfCommWithRemUnit();

  delay(1000);

}

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void rfCommWithRemUnit()
{

  radio.openWritingPipe(radioAddress[1]);                          // Writing Pipe with This unit address. Remote will read it on Pipe 1
  delay(5);

  strcpy(txDataToRemUnit.lcdMessage, firstLineMsg);
  txDataToRemUnit.cursorRow  = 0;
  firstLine = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit))); // Send first Line of LCD..
  delay(5);
  readAckPayLoad(firstLine);

  // Place code here to copy all data from AckPayload to local variables //

  strcpy(txDataToRemUnit.lcdMessage, secondLineMsg);
  txDataToRemUnit.cursorRow  = 1;
  secondLine = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit)));// Send second Line of LCD..
  delay(5);
  readAckPayLoad(secondLine);

  strcpy(txDataToRemUnit.lcdMessage, thirdLineMsg);
  txDataToRemUnit.cursorRow  = 2;
  thirdLine = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit))); // Send third Line of LCD..
  delay(5);
  readAckPayLoad(thirdLine);


  strcpy(txDataToRemUnit.lcdMessage, fourthLineMsg);
  txDataToRemUnit.cursorRow  = 3;
  fourthLine = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit))); // Send fourth Line of LCD..
  delay(5);
  readAckPayLoad(fourthLine);

  // All four lines of LCD have been sent ... now check if all Ack data were received back..

  if ( firstLine & secondLine & thirdLine & fourthLine)
  {
    digitalWrite(RF_OK_Out, HIGH);
    digitalWrite(RF_FLT_Out, LOW);
  }
  else
  {
    digitalWrite(RF_OK_Out, LOW);
    digitalWrite(RF_FLT_Out, HIGH);
  }
}

//*************************************************

//FUNCTION TO READ ACK PAYLOAD AND STORE DATA TO LOCAL VARIABLES..

void readAckPayLoad (boolean txResult)
{
  if (txResult)
  {
    while ( radio.available())
    {
      radio.read( &rxDataFromRemUnit, sizeof(rxDataFromRemUnit));
    }
  }
}

Mogaraghu:
the status of link between a RF24 TX module and RF24 RX module.

This is a meaningless concept. A link only exists for the few millisecs that it takes to send a message and get the acknowledgement.

You could send a message at a regular interval (say 5 per second) and then if there is no message or no acknowledgement both sides could tell if a problem arose. I use this idea for controlling a model train. If the Rx gets no message for a certain length of time it stops the train.

...R

Possibly it is meaningless in the context of the actual transmission duration as it is only a few milliseconds.

But if you look at the code, the Booleans firstLine, secondLine, thirdLine, fourthLine are used to hold status of the last radio.write()

And assuming I am sending once every second, the status LED should reflect the status till a failure occurs. This has worked in other projects - but in this project, since I was getting a wrong OK status, just wanted to know if there was any basic goof up that is missing the eye.

Maybe its time to look at the module itself ..

This code is either confusing or not robust or both

  firstLine = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit))); // Send first Line of LCD..
  delay(5);
  readAckPayLoad(firstLine);

have a look at how I do it in my second example in this Simple nRF24L01+ Tutorial

firstLine is a crap name for a variable that records the success of the write() - even something like firstLineOK would make more sense.

If you treat sending the data and checking the response as a single action I think the code will be much easier to follow.

Duplicating code in the way you have done for the 4 messages is a bad idea because it is so easy to make mistakes. Just create one send/checkResponse function and call it 4 times with the different data to be sent.

...R

Ok Robin… let me remove confusion…! Good points. I have reworked the code now and I guess this is what you hinted at … would be glad to know if it still can be improved. Of course it already has become compact compared to earlier version.

#include <RF24.h>

/* Set up nRF24L01 radio on SPI bus plus pins for CE and CSN */
RF24 radio(40, 41);                           // First pin (40) is CE and Next pin (41) is CSN

byte radioAddress[][6] = {"1_PRX", "2_PTX"}; // Radio pipe addresses for RemoteUnit, ThisUnit.

byte RF_OK_Out      = 34;
byte RF_FLT_Out     = 33;

char copy_KeyVal;

struct tx_dataStruct {                       // Configure your transmission data into this structure
  char lcdMessage[21];
  byte cursorRow;
  boolean gotTheKey;
} txDataToRemUnit;

struct rx_dataStruct {                       // Configure your reception data into this structure
  char keyVal;
  boolean tokenKey;
} rxDataFromRemUnit;

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void setup() {

  pinMode(RF_OK_Out, OUTPUT);
  pinMode(RF_FLT_Out, OUTPUT);

  // Setup and configure radio
  radio.begin();
  radio.setChannel(108);                         // Above most Wifi Channels
  radio.setDataRate( RF24_250KBPS );
  radio.enableAckPayload();                      // Allow optional ack payloads
  radio.enableDynamicPayloads();                 // Ack payloads are dynamic payloads
  radio.setRetries(5, 10);                       // Delay, count

  radio.openWritingPipe(radioAddress[1]);        // Writing Pipe with This unit address. Remote will read it on Pipe

}

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void loop() {

  sendLcdInfo( "This is line01", 0);
  sendLcdInfo( "This is line02", 1);
  sendLcdInfo( "This is line03", 2);
  sendLcdInfo( "This is line04", 3);
  
  delay(1000);

}

//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

// FUNCTION TO TRANSMIT ONE LINE OF LCD DISPLAY

void sendLcdInfo ( char lcdMsg[21], byte cursorRow)
{
  strcpy(txDataToRemUnit.lcdMessage, lcdMsg);
  txDataToRemUnit.cursorRow  = cursorRow;
  
  bool writeResult = (radio.write(&txDataToRemUnit, sizeof(txDataToRemUnit)));       // Send OneLine of LCD..
  
  delay(5);
  if (writeResult)
  {
    if ( radio.isAckPayloadAvailable())
    {
      radio.read( &rxDataFromRemUnit, sizeof(rxDataFromRemUnit));
      
      digitalWrite(RF_OK_Out, HIGH);         // Success
      digitalWrite(RF_FLT_Out, LOW);
    }
    else
    {
      digitalWrite(RF_OK_Out, LOW);          // Failure
      digitalWrite(RF_FLT_Out, HIGH);
    }
  }
}

Thanks for the tips !

That's what I had in mind - does it work?

What is the purpose of delay(5) where it is? I would be inclined to have a short interval between transmissions, but not between sending data and checking the response.

...R

Robin2:
That's what I had in mind - does it work?

What is the purpose of delay(5) where it is? I would be inclined to have a short interval between transmissions, but not between sending data and checking the response.

...R

Ah...yes that one. Actually I noticed that the OK_LED lit steady when this delay is there and starts to flicker when the delay is removed. Of course it was something I noticed a few times and cannot vouch for it. Will try after removing it.

And I guess the way this code is structured, the RF24 module will most of the time spend in Standby-I state and thus not eat up the battery too much.

Mogaraghu:
And I guess the way this code is structured, the RF24 module will most of the time spend in Standby-I state and thus not eat up the battery too much.

I would have to study the library code and the Nordic datasheet to answer that and I would much prefer it if you do all that reading :slight_smile:

...R