Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NRF24L01 Packet Queueing Problem #13

Open
JamesLenz opened this issue Jun 2, 2017 · 4 comments
Open

NRF24L01 Packet Queueing Problem #13

JamesLenz opened this issue Jun 2, 2017 · 4 comments

Comments

@JamesLenz
Copy link

JamesLenz commented Jun 2, 2017

I am trying to create a simple TCP-like sending protocol by sending, waiting for an ack, and if no ack is received in a certain amount of time, try again.

I got it mostly working except for a frequent, but random occurring problem. The recipient will randomly miss a packet, but when the next packet is received, it receives the previous missed packet. I have tried clearing and flusing the rx buffer, but to no avail. It appears as if the rx queue is receiving it, but it cannot be detected until another packet is received.

Perhaps a packet is available, but available() is returning an incorrect value?

Here is thread from the arduino forum that mentions a similar issue:

Here is the output that demonstrates this issue
screen shot 2017-06-01 at 1 16 01 pm

Sender Code

#include <SPI.h>
#include <RH_NRF24.h>

// Singleton instance of the radio driver
RH_NRF24 nrf24(9, 8); //my implementation

void setup() {
  Serial.begin(9600);
  while (!Serial) 
    ; // wait for serial port to connect. Needed for Leonardo only
  if (!nrf24.init())
    Serial.println("init failed");
  // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
  if (!nrf24.setChannel(1))
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");
}

void loop() {
  delay(2000);
  uint8_t data1[] = "testtesttest";
  sendTCP(data1, sizeof(data1));
}

int timeout = 200;
byte maxAttempts = 1;
bool sendTCP(uint8_t *data, uint8_t len) {
  static uint8_t packetId = 0;
  byte attempts = 0;

  Serial.print(millis());
  Serial.println(": TCP sending");
  Serial.print("  packet id: ");
  Serial.println(packetId);
  
  while(attempts < maxAttempts) {
    //send data
    nrf24.setHeaderId(packetId);  //set packet id in order to differentiate between packets and their ack
    nrf24.send(data, len);        //send data
    nrf24.waitPacketSent();       //block while data is sending
    
    //wait for ack
    //Serial.println("  waiting for ack");
    uint8_t temp_buf[RH_NRF24_MAX_MESSAGE_LEN];
    uint8_t temp_len = sizeof(temp_buf);
    if(nrf24.waitAvailableTimeout(timeout) && nrf24.recv(temp_buf, &temp_len)) {
      Serial.print("  ack received...");
      if(nrf24.headerId() == packetId) {
        Serial.println("id match");
        break;
      }
      Serial.print("no id match ");
      Serial.print(nrf24.headerId());
      Serial.println(", clearing buffer");
      while(nrf24.available() && nrf24.recv(temp_buf, &temp_len)) { //clear buffer in case there is more than 1 packet
        ; //no-op
      }
    }
    attempts++;

    Serial.print("  ack timeout, sending again ");
    Serial.print(attempts);
    Serial.print(" / ");
    Serial.println(maxAttempts);
  }

  packetId++;

  if(attempts >= maxAttempts) {
    Serial.println("  sending failed");
    return false;
  }
  Serial.println("  sending succeeded");
  return true;
}

Receiver Code

#include <SPI.h>
#include <RH_NRF24.h>

// Singleton instance of the radio driver
RH_NRF24 nrf24(9, 8); //my implementation

void setup() {
  Serial.begin(9600);
  while (!Serial) 
    ; // wait for serial port to connect. Needed for Leonardo only
  if (!nrf24.init())
    Serial.println("init failed");
  // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
  if (!nrf24.setChannel(1))
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");
}

void loop() {
  uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if(nrf24.available() && recvTCP(buf, &len)) {
    ;
  }
}

bool recvTCP(uint8_t* buf, uint8_t* len) {
  static int packetId = -1;
  Serial.print(millis());
  Serial.print(": Checking if data available...");
  if(nrf24.recv(buf, len)) {
    //send ack
    uint8_t data[] = "";
    nrf24.setHeaderId(nrf24.headerId()); //set packet id to received packet's header id
    nrf24.send(data, sizeof(data));      //send data (ack)
    nrf24.waitPacketSent();              //block while ack is sending

    //repeat packet
    if(nrf24.headerId() == packetId) {   //server didn't get our ack, so it sent the packet again, just ack again and ignore
      Serial.print("yes, repeat packet: ");
      Serial.println(packetId);
      nrf24.flushRx();
      nrf24.clearRxBuf();
      return false;
    }
    
    packetId = nrf24.headerId();         //remember our last received packet id
    
    Serial.print("yes: ");
    Serial.println(packetId);
    Serial.print("   Received message: ");
    Serial.println((char*)buf);
  } else {
    Serial.println("no");
    nrf24.flushRx();
    nrf24.clearRxBuf();
    return false;
  }
  nrf24.flushRx();
  nrf24.clearRxBuf();
  return true;
}
@dangerverma
Copy link

Don't ask my why, i am just a technology enthusiast but when i put in

TX:
nrf24.setChannel(1);
(in setup())

and
RX:
nrf24.setChannel(5);
(again in setup())

it works brilliantly and consistently each time without any queuing.

Some radio genius should be able to answer it.

Try and see if it works for you!

@JamesLenz
Copy link
Author

I will probably give it another go after finals, I have NO time to mess with this right now
but if this does indeed fix the problem, thank you

@iwasz
Copy link

iwasz commented Jan 14, 2018

I had similar problem. I wired two nRFs to a STM32F4 board, where one was sending and the other receiving and I compared what was sent with the data received. And to my surprise data I was receiving sometimes would arrive in wrong order (BTW the same code on much slower STM32F0 board was fine)! My problem proved to be due to wrong CE pin code in my transmit function (I use my own nRF lib). So faulty code looked like that :

void Nrf24L01P::transmit (uint8_t *data, size_t len)
{
        setCe (true);
        spi->setNss (false);
        spi->transmit8 (W_TX_PAYLOAD);
        spi->transmit8 (data, len, nullptr, bogoDelay);
        spi->setNss (true);
        setCe (false);
}

And the code that fixed my problem :

void Nrf24L01P::transmit (uint8_t *data, size_t len)
{
        spi->setNss (false);
        spi->transmit8 (W_TX_PAYLOAD);
        spi->transmit8 (data, len, nullptr, bogoDelay);
        spi->setNss (true);
        setCe (true);
        HAL_Delay (1);
        setCe (false);
}

Only after the data to be transmitted is put into the RX FIFO, I make a HI pulse on CE pin. Diagram on page 35 of nRF24L01+ pointed me in the right direction. PS of course 1ms is too long and this delay is to be modified. Full code is here : https://github.com/iwasz/libmicro/tree/master/src/rf

@rmolinowski
Copy link

Greetings, great library, but I have this issue as well. Since I'm sending a joystick control position several times a second over RF, it's not too big an issue, but the "solution" by dangerverma, above makes no sense, and Radiohead uses spiburstwrite and not the method shown by iwasz. Any assistance on this would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants