NRF24L01+ (TMRH20 library): How read a string sent?

Basically I have a PI that sends a string (“get”) to an Arduino.

I did edit the gettingstarted_caller.cpp example, but I cannot receive the ACK from Arduino.

It seems that Arduino cannot read the text sent.

This is my arduino code:

#include <SPI.h>
#include "RF24.h"

const int LED = 6;

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
// Topology
byte addresses[][6] = {"1Node","2Node"};              // Radio pipe addresses for the 2 nodes to communicate.

byte counter = 1;                                                          // A single byte to keep track of the data being sent back and forth

void setup(){

  Serial.begin(115200);

  pinMode(LED, OUTPUT);
  digitalWrite(LED,HIGH);
  
  // Setup and configure radio
  radio.begin();

  radio.enableAckPayload();                     // Allow optional ack payloads
  radio.enableDynamicPayloads();                // Ack payloads are dynamic payloads
  
  if(radioNumber){
    radio.openWritingPipe(addresses[1]);        // Both radios listen on the same pipes by default, but opposite addresses
    radio.openReadingPipe(1,addresses[0]);      // Open a reading pipe on address 0, pipe 1
  }else{
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
  }
  radio.startListening();                       // Start listening  
  
  radio.writeAckPayload(1,&counter,1);          // Pre-load an ack-paylod into the FIFO buffer for pipe 1
  radio.printDetails();
}

void loop() {

  byte pipe;
  
  //if (radio.available(&pipe)) {
  while(radio.available(&pipe)) {
    
    char text[32] = {0};
    radio.read(&text, sizeof(text));

    if (text=="get") {
      Serial.println("TEXT == GET");
      int state = digitalRead(LED);
      radio.writeAckPayload(pipe,&state,sizeof(state));              // This can be commented out to send empty payloads.  
    }

    if (text=="1") {
      digitalWrite(LED,HIGH);
      int state = digitalRead(LED);
      radio.writeAckPayload(pipe,&state,sizeof(state));               // This can be commented out to send empty payloads. 
    }

    if (text=="0") {
      digitalWrite(LED,LOW);
      int state = digitalRead(LED);
      radio.writeAckPayload(pipe,&state,sizeof(state));              // This can be commented out to send empty payloads. 
    }
    
    
    Serial.println(text);
  }
}

And this is the PI c++ code:

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
#include <RF24/RF24.h>

using namespace std;

// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.

RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);

/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1. Arduino example uses radioNumber 0 by default.
bool radioNumber = 1;

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

// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t addresses[][6] = {"1Node","2Node"};

//uint8_t counter = 1; // A single byte to keep track of the data being sent back and forth
char text_get[] = "get";
char text_set_on[] = "1";
char text_set_off[] = "0";

int main(int argc, char** argv){

  //int size_text = sizeOf(text);

  radio.begin();
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.enableDynamicPayloads();
  radio.printDetails();                   // Dump the configuration of the rf unit for debugging


  /***********************************/
  // This opens two pipes for these two nodes to communicate
  // back and forth.
    if ( !radioNumber )    {
      radio.openWritingPipe(addresses[0]);
      radio.openReadingPipe(1,addresses[1]);
    }else{
      radio.openWritingPipe(addresses[1]);
      radio.openReadingPipe(1,addresses[0]);
    }
    //radio.startListening();
    //radio.writeAckPayload(1,&counter,1);
    // pipeAddress (1), il messaggio e la taglia del messaggio
    //radio.writeAckPayload(1,&text,sizeof(text));

// forever loop
while (1){

    //uint8_t gotByte;                                        // Initialize a variable for the incoming response
    char answer[32];

    radio.stopListening();                                  // First, stop listening so we can talk.
    printf("Now sending %s as payload. ",text_get);          // Use a simple byte counter as payload
    unsigned long time = millis();                          // Record the current microsecond count

    if ( radio.write(&text_get,sizeof(text_get)) ){         // Send the counter variable to the other radio
        if(!radio.available()){                             // If nothing in the buffer, we got an ack but it is blank
            printf("Got blank response. round-trip delay: %lu ms\n\r",millis()-time);
        }else{
            while(radio.available() ){                      // If an ack with payload was received
                radio.read( &answer, sizeof(answer) );                  // Read it, and display the response time
		printf("Got response %s, round-trip delay: %lu ms\n\r",answer,millis()-time);
            }
        }

    } else {
 	printf("Sending failed.\n\r");
    }          // If no ack response, sending failed

    sleep(1);  // Try again later

} //while 1
} //main

PI print every line with a laconic:

Now sending get as payload. Got blank response. round-trip delay: 1 ms

So, PI receives the ACK but is blank… :frowning:

PS Of course with basic example all functions. Radio functions and see every other.

Thank you for your help

I don’t know why you have the complication of bool radioNumber = 0; when you are having difficulty getting basic communication to work. Just write simple programs on the PI and on the Arduino with neither program having any options.

I don’t have a PI so I don’t know how to use an nRF24 with it. I presume it is pretty much the same as for an Arduino and this Simple nRF24L01+ Tutorial may help. Start with the first, simplest example.

…R

You are, for sure, right.
I did start with easy example of the library. Now editing them.

By the way, I saw now your guide, and you make an important affermation for me:

the ackPayoad cannot take account of the data received in the message for which it is the acknowledgment.

In effect I would "respond" with an ACK with the state of a Arduino PIN. But it seems impossible. So, maybe this was my problem.

THank you very much!

sineverba:
the ackPayoad cannot take account of the data received in the message for which it is the acknowledgment.

Yes. The ackPayload must be loaded before the message arrives.

This means that the ackPayload is at least one step behind. For many applications that does not matter - especially if messages are sent several times per second.

...R

@Robin2, I abuse of your knowledge.

In your first example, you trasmit a fixed lenght message.

I.e. in your RX you have:

char dataReceived[10]; // this must match dataToSend in the TX

But... if in receiver I don't know exact length, how I can do? I'm initialize an array of 32?

I'm yet doint in this manner:

while(radio.available(&pipe)) {
    
    char text[32] = {0};
    radio.read(&text, sizeof(text));
    radio.writeAckPayload(pipe,&counter,1);              // This can be commented out to send empty payloads.
    Serial.println(text);
  }

But I would know if is best mode to do.

Thank you very much!

You could (should) use

while(radio.available(&pipe)) {   
    char text[32];

    radio.read(text, radio.getDynamicPayloadSize());

    radio.writeAckPayload(pipe, &counter, 1); // one byte ack-payload
    Serial.println(text);
}

Remember that the '\0' has to be transmitted or added after reception.

If you add the delimiter after reception your buffer needs to be one byte longer.

while(radio.available(&pipe)) {   
    char text[33];
    byte rxLen = radio.getDynamicPayloadSize();

    radio.read(text, rxLen);
    text[rxLen] = 0;

    radio.writeAckPayload(pipe, &counter, 1); // one byte ack-payload
    Serial.println(text);
}

sineverba:
But... if in receiver I don't know exact length, how I can do? I'm initialize an array of 32?

You can use dynamic payloads as @Whandall has said.

However for a beginner it may be easier to use fixed length payloads of the largest size you will need.

Also, as @Whandall has said a cstring needs an extra space for the terminating \0. Again, the simplest thing is probably to limit yourself to a maximum text size of 31 characters to allow for the terminating \0

Because my second example uses the ackPayload feature it automatically uses dynamic payloads - so that might be another simple option.

...R