Variable refreshment only works once

This sketch sends a package of data to another radio using nRF24L01/UNO Tx/Rx setup. The other radio reads the transmission and sends the package straight back again. When this radio receives that response it checks to see that the received data is what was originally sent. Then it is supposed to blank the variable into which the data is received so the check starts clean each time. Sadly, this only works once. Once the variable has been refreshed once it seems to become a constant.

The offending refreshment is 12 lines from the bottom of the loop.

#include <printf.h>
#include <RF24.h>
#include <SPI.h>;

/*
 * This block of code creates the radio which will be used for the Rx/Tx work,
 */
 // set up nRF24L01 radio on SPI bus pins 7 & 8
 RF24 radio(7,8);
 // create addresses for the radios
 byte addresses[][6] = {"console", "trolley"};  // {0, 1}

 /*
  *  This block of code defines the datablocks we will be tossing around
  */
  String sentDatablock        = "datablock";
  String receivedDatablock    = "         ";
  String blankDatablock = "         ";

void setup() 
{
  // start Serial
  Serial.begin(9600);
  // turn on the radio
  radio.begin();
  // set radio power to low while testing the system
  radio.setPALevel(RF24_PA_LOW);
  // open pipes for reading and writing
  // in this case this radio is 'console' and it communicates with 'trolley'
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1,addresses[1]);
} // end setup()

void loop() 
{
  // get ready to transmit
  radio.stopListening();
  // debug
  Serial.print(F("Now sending "));
  // send message
  if (radio.write(&sentDatablock, sizeof(sentDatablock)))
  {
    Serial.println(sentDatablock);
  }else{
    Serial.println(F("but failed to do so"));
  } // end if (radio.write(&sentDatablock,

  // change to listen mode
  radio.startListening();
  
  if (radio.available())
  {
    while (radio.available())
    {
      // read response
      radio.read(&receivedDatablock, sizeof(receivedDatablock));
      // debug
      Serial.print(F("Got an acknowledgement - >"));   
      Serial.print(receivedDatablock);   
      Serial.println("<");   
    } // end while (radio.available())

    if (sentDatablock == receivedDatablock)
    {
      Serial.println(F("Received data matched"));
    }else{
      Serial.println(F("Received data did not match"));
    } // end if (dummyDatablock ==

    // I want to blank receivedDatablock so that I know the value
    // the program shows as received next is, in fact, new data
    // reblank receivedDatablock
    receivedDatablock = blankDatablock;  

    // debug
    Serial.print(F("Now receivedDatablock has the value >"));
    Serial.print(receivedDatablock);
    Serial.println("<");
      
  }  // end if (radio.available())

  // just to keep things orderly
  delay(2000);
} // end loop()

A Serial printout of the debug messages is attached.

What is causing the refreshment of receivedDatablock to become permanent?

COM4printout.PNG

I doubt if you can do this with String and get a usable answer:

sizeof(receivedDatablock)

Edit:
and I can't see how a String datatype can be compatible with the read method of RF24 as used here

String receivedDatablock    = "         ";
....
....
radio.read(&receivedDatablock, sizeof(receivedDatablock));

It is not a good idea to use the String (capital S) class as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

Also, it appears that you don't have confidence in the return code of the RF24 write method, which should tell you if the packet was correctly received. You have built your own 'ack' mechanism to check.

According to the nrf24L01 datasheet, it does a cyclic redundancy check (CRC) on the transmitted data. I assume the library you are using for the radio module respects this mechanism.

Thanks to you both robin2 and 6v6gt. I wasn't aware of the CRC, I am not so sophisticated to even think of looking for that :disappointed_relieved: so that makes me feel a lot safer. I take the point about the Strings. I'll get into that tomorrow. It's been a long day :sleeping:

6v6gt:
I doubt if you can do this with String and get a usable answer:

sizeof(receivedDatablock)

Six is the constant, usable answer.
Obviously, it's not a useful answer.

I think I pointed the OP to this Simple nRF24L01+ Tutorial in one of his other Threads on the same subject.

It is much easier when there is only one Thread for a project and all the info is one place - especially when the Forum is running very slowly.

...R

Say what you like about Six, AWOL, everybody knows that 42 is the meaning of life. :grinning:

Robin2:
It is much easier when there is only one Thread for a project and all the info is one place

Hi robin2 - it is easier, but as an Australian Prime Minister pointed out, "Life wasn't meant to be easy!". :sunglasses:

TO WORK!
I changed to char:

#include <string.h>;
#include <RF24.h>
#include <SPI.h>;

/*
 * This block of code creates the radio which will be used for the Rx/Tx work,
 */
 // set up nRF24L01 radio on SPI bus pins 7 & 8
 RF24 radio(7,8);
 // create addresses for the radios
 byte addresses[][6] = {"console", "trolley"};  // {0, 1}

 /*
  *  This block of code defines the datablocks we will be tossing around
  */
  char sentDatablock1[]     = "datablock";
  char sentDatablock2[]     = "***---***";
  char receivedDatablock[]  = "         ";
  char blankDatablock[]     = "         ";

  int whichOne = 1;

void setup() 
{
  // start Serial
  Serial.begin(9600);
  // turn on the radio
  radio.begin();
  // set radio power to low while testing the system
  radio.setPALevel(RF24_PA_LOW);
  // open pipes for reading and writing
  // in this case this radio is 'console' and it communicates with 'trolley'
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1,addresses[1]);
} // end setup()

void loop() 
{
  // get ready to transmit
  radio.stopListening();

  // send message
  if (whichOne == 1)
  {
    if (radio.write(&sentDatablock1, sizeof(sentDatablock1)))
    {
      // debug
      Serial.println(""); // blank line
      Serial.print(F("Now sending >"));
      Serial.print(sentDatablock1);
      Serial.println(F("<"));

      whichOne = 2;
    }else{
      Serial.println(F("Failed to transmit"));
    } // end if (radio.write(&sentDatablock1,
  }else{
    if (radio.write(&sentDatablock2, sizeof(sentDatablock2)))
    {
      // debug
      Serial.println("");  // blank line
      Serial.print(F("Now sending >"));
      Serial.print(sentDatablock2);
      Serial.println(F("<"));

      whichOne = 1;
    }else{
      Serial.println(F("Failed to transmit"));
    } // end if (radio.write(&sentDatablock2,  
  } // end if-else (whichOne == 1)

  // change to listen mode
  radio.startListening();
  
  if (radio.available())
  {
    while (radio.available())
    {
      // read response
      radio.read(&receivedDatablock, sizeof(receivedDatablock));
      // debug
      Serial.print(F("Got an acknowledgement - >"));   
      Serial.print(receivedDatablock);   
      Serial.println("<");   
    } // end while (radio.available())

    // debug
    Serial.print(F("Now receivedDatablock has the value >"));
    Serial.print(receivedDatablock);
    Serial.println(F("<"));
      
  }  // end if (radio.available())

  // just to keep things orderly
  delay(2000);
} // end loop()

and got the result shown in the attachment.

Two issues now:

  1. How to avoid the false start you see at the top of the printout. The transmitter sent one package without response before the whole system kicked in.
  2. When things settle down the response returned is different from the package sent (or so it seems).

Since both of these things could really cause problems running a machine, what is wrong, and how to fix it.

FTR: the Trolley sketch is

#include <string.h>;
#include <printf.h>
#include <RF24.h>
#include <SPI.h>;

/*
 * This block of code creates the radio which will be used for the Rx/Tx work,
 */
 // set up nRF24L01 radio on SPI bus pins 7 & 8
 RF24 radio(7,8);
 // create addresses for the radios
 byte addresses[][6] = {"console", "trolley"};  // {0, 1}

/*
 *  This block of code defines the datablocks we will be tossing around
 */
  char receivedDatablock[] = "         ";
  char blankDatablock[]    = "         ";

void setup() 
{
  // start Serial
  Serial.begin(9600);
  // turn on the radio
  radio.begin();
  // set radio power to low while testing the system
  radio.setPALevel(RF24_PA_LOW);
  // open pipes for reading and writing
  // in this case this radio is 'trolley' and it communicates with 'console'
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1,addresses[0]);
} // end setup()

void loop() {
  // get ready to receive
  radio.startListening();

  if (radio.available())
  {
    //get message
    while (radio.available())
    {
      radio.read(&receivedDatablock, sizeof(receivedDatablock));

      // debug
      Serial.print(F("Got a message - >"));  
      Serial.print(receivedDatablock);  
      Serial.println("<");    
    } // end while (radio.available())

    // change to sending mode
    radio.stopListening();
    // debug
    Serial.print(F("Now sending >"));
    Serial.print(receivedDatablock);   
    Serial.print("<"); 
    // send acknowledgement
    if (radio.write(&receivedDatablock, sizeof(receivedDatablock)))
    {
        // debug
        Serial.println(F(" and succeeded"));
    }else{
      Serial.println(F(" but failed to do so"));
    } // end if (radio.write(&receivedDatablock
  
  } // end if (radio.available())   
} // end loop()

To use the vernacular "bugger the Australian PM"

Image from Reply #7 so we don't have to download it. See this Image Guide

...R

If you get the message "Now sending" it actually means that the data has actually been sent and an acknowledgemnt has been received.

That suggests to me that your appearance of getting the wrong response is just because the Tx and Rx get out of sync. I don't know if that would explain your initial extra message.

For the initial message problem have you tried a delay() at the end of setup().

Speaking personally I would design my system so it would just ignore initial messages until a suitable exchange of messages had taken place indicating that proper communication had been estabished.

Have you tried the examples in my Simple nRF24L01+ Tutorial - I am not aware that they give rise to either of your problems.

...R

I believe also you have a problem with your delays.

  1. There should be a short delay between the "Trolley" receiving a packet and sending it back as an acknowledgement because the main sketch may not be immediately able to process it.
  2. There should be no delay in the main sketch because it should, apart from the time it is actually transmitting, be in receive mode to get any packets the "Trolley" is sending back.

6v6gt:
2) There should be no delay in the main sketch because it should, apart from the time it is actually transmitting, be in receive mode to get any packets the "Trolley" is sending back.

Yes.

I had not quite got my head around that and then I ignored it. There needs to be an interval between transmissions, but not during listening.

...R

 if (radio.write(&sentDatablock1, sizeof(sentDatablock1)))

Do you really need to transmit the string's terminator?
Or did you mean strlen, instead of sizeof?

Actually, what the OP is doing is very ambitious (IMHO) because he is building his own protocol for handling transmission errors (which should also include timeouts, retries, etc. etc. if it is taken to its full extent).
All this logic appears anyway to be already implemented in the nrf24l01 ("ShockBurst" protocol), although I am not sure to what extent the library he is using supports that with the standard default settings.

Gentlemen,

Thanks for those contributions. Sad to say, again it's been a long day and I am packing up for the night. I'll get into these things tomorrow. In the meantime - just quick comments -

robin2 : the message 'Now sending >' is part of my debugging code, but I think you're right and the Tx and Rx are out of sync. I'll see if the pause fixes it. I think I'll try sending half a dozen dummy messages before I go into the loop and see if that settles down the initial link problem.

AWOL : I'll give strlen a go, but does it work with char variables?

6v6gt : you flatter me by suggesting that I am trying to develop my own protocol. I am only trying to see what the TMRh20 version of RF24 does.

As the nice man said, "I'll be back!" :sleeping:

AWOL:

 if (radio.write(&sentDatablock1, sizeof(sentDatablock1)))

Do you really need to transmit the string's terminator?
Or did you mean strlen, instead of sizeof?

The library examples use the following example construct:

 radio.write( &time, sizeof(unsigned long) );

So I guess it is OK. Important is that the sender and receiver use exactly representation of the data.

AWOL : I'll give strlen a go, but does it work with char variables?

No, it works on arrays of char, sometimes known as strings

6v6gt:
All this logic appears anyway to be already implemented in the nrf24l01 ("ShockBurst" protocol),

I agree.

And using the nRF24 ackPayload technique makes it very simple to send and recieve short messages (up to 32 bytes) without any concerns abot Tx and Rx getting out of sync and with no need for Arduino code to cause either device to switch roles between sending and listening.

The use of ackPayload is illustrated in my Simple nRF24L01+ Tutorial

...R