2

I'm trying to send some data using nRF24L01+ transceivers, but I need to use 8 byte payloads for reliability. The data I'm sending is much bigger than that, so I need to split it into 8 byte packets and then reassembly on the receiving end. I wrote the following code to test it, but to no success.

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
RF24 radio(9,10);
const byte pipes[][7] = { "master", "slaves" };
#define PayLoad 8

void setup() {
  Serial.begin(9600);
  while(!Serial){}
  radio.begin();
  radio.setRetries(15,15);
  radio.setPayloadSize(PayLoad);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_1MBPS);
  radio.setCRCLength(RF24_CRC_16);
  delay(100);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.startListening();
  radio.printDetails(); //RF Debug
  delay(1000);
  //sendRF("Payload splitting test. 1234567890");
}

void loop() {
  if (radio.available()){
    fromRF();
  }
  if (Serial.available()){
    String dataIn = Serial.readString();
    sendRF(dataIn);
  }
}

void fromRF(){
  byte numPkgs;
  radio.read(&numPkgs,1);
  Serial.println(numPkgs);
  char rcvBuffer[numPkgs*PayLoad];
  for (byte pkg=1; pkg<=numPkgs; pkg++){
    char payloadBuff[PayLoad];
    radio.read(&payloadBuff,PayLoad);
    for (int charpos=0; charpos<PayLoad; charpos++){
      rcvBuffer[((pkg-1)*PayLoad)+charpos] = payloadBuff[charpos];
    }
    if (pkg < numPkgs){
      int timeout = 0;
      while(!radio.available() && timeout<100){
        timeout++;
        delay(1);
      }
      if (timeout >= 100){
        Serial.println("Package timed out.");
        return;
      }
    }
  }
  String msgRcvd(rcvBuffer);
  Serial.println(msgRcvd);
}

void sendRF(String msg){
  byte msgLen = msg.length();
  Serial.println(msg);
  Serial.println(msgLen);
  char msgBuff[msgLen];
  msg.toCharArray(msgBuff,msgLen);
  radio.stopListening();
  byte numIters = msgLen/PayLoad;
  if (msgLen%PayLoad > 0)
    numIters++;
  radio.write(&numIters, 1);
  Serial.println(numIters);
  char payloadBuff[PayLoad];
  for (byte iter = 1; iter <= numIters; iter++){
    for (byte i=0; i<=PayLoad; i++){
      payloadBuff[i] = (char)0;
    }
    byte initchar = (iter-1)*PayLoad;
    byte lastchar = (iter*PayLoad)-1;
    if (lastchar > msgLen)
      lastchar = msgLen;
    byte counter = 0;
    for (byte nextchar = initchar; nextchar <= lastchar; nextchar++){
      payloadBuff[counter] = msgBuff[nextchar];
      counter++;
    }
    radio.write(&payloadBuff, PayLoad);
    Serial.println(payloadBuff);
    delay(50);
  }
  radio.startListening();
  delay(100);
}

This code is intended to work for both master and slave, except that writing and reading pipes change places.

My splitting is working fine (as shown by the serial monitor), but it looks like I'm not able to receive it well. Any help would be greatly appreciated!!

EDIT:

I've got it working! (kind of). It still lacks managing lost packages, but it's working quite fine.

void fromRF(){
  byte numPkgs;
  radio.read(&numPkgs,1);
  //Serial.println(numPkgs);
  String rcvdStr = "";
  for (byte pkg=1; pkg<=numPkgs; pkg++){
    char rcvBuffer[PayLoad+1];
    delay(100);
    radio.read(&rcvBuffer,PayLoad);
    rcvBuffer[PayLoad] = '\0';
    String strBuffer(rcvBuffer);
    rcvdStr += strBuffer;
  }
  Serial.println(rcvdStr);
  //sendRF(rcvdStr);
}

void sendRF(String msg){
  byte msgLen = msg.length();
  Serial.println(msg);
  //Serial.println(msgLen);
  char msgBuff[msgLen];
  msg.toCharArray(msgBuff,msgLen);
  radio.stopListening();
  byte numIters = msgLen/PayLoad;
  if (msgLen%PayLoad > 0)
    numIters++;
  radio.write(&numIters, 1);
  Serial.println(numIters);
  char payloadBuff[PayLoad];
  for (byte iter = 1; iter <= numIters; iter++){
    for (byte i=0; i<=PayLoad; i++){
      payloadBuff[i] = (char)0;
    }
    byte initchar = (iter-1)*PayLoad;
    byte lastchar = (iter*PayLoad)-1;
    if (lastchar > msgLen)
      lastchar = msgLen;
    byte counter = 0;
    for (byte nextchar = initchar; nextchar <= lastchar; nextchar++){
      payloadBuff[counter] = msgBuff[nextchar];
      counter++;
    }
    radio.write(&payloadBuff, PayLoad);
    Serial.println(payloadBuff);
    delay(50);
  }
  radio.startListening();
  delay(100);
}

Gotta give a look at RF24Mesh.

  • What do you mean by not able to receive it "well"? – Majenko Sep 14 '16 at 17:21
  • I'm not that into C but in the case of char rcvBuffer[numPkgs*PayLoad];, I'm not entirely sure that you can create an array with a dynamic size. Also, you method relies on never missing a single packet, and not turning on the receiver in the middle of a transmission of packets. – Gerben Sep 14 '16 at 18:23
  • It would be maybe a good idea to use an existing solution like RF24Mesh that does it for you? – Avamander Sep 14 '16 at 19:18
  • 1
    @Gerben Actually at the moment of creating the array, numPkgs*PayLoad acts as a constant. Anyway, I'm doing it differently now. And nope, still no lost package management. :S – Christian Rodriguez Sep 14 '16 at 19:48
  • 2
    @Gerben You only need to provide a constant as an array size when the array is global (or maybe static). When it's local it gets allocated on the stack dynamically and the size can be given at runtime, not compile time. Only when it needs to be allocated in the .bss or .data sections does the compiler need to know the size beforehand. – Majenko Sep 14 '16 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.