Arduino – Abstracting module library is causing me issues

I am attempting to learn both the Arduino platform and C++. I feel like the issue is with my code and I don’t think the implementation is too important, but briefly a long range radio (nRF24L01) listens for incoming messages. This functionality works in a simple POC file, but once I attempt to abstract the functionality away, it stops working.

I am assuming this is due to a lack of understanding of C++ on my part.

Below I have code that works, telling me that I have wired my module up correctly and am making correct use of the library to use the module. When I invoke radio.available() in my loop, I only receive true when there is a message waiting in the buffer, which is once every second thanks to the code in my transmitter.

simplerx.ino

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

#define CE_PIN   9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);
const byte thisSlaveAddress[5] = {'R','x','A','A','A'};
char dataReceived[35];

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

void loop() {
    if ( radio.available() ) {
      radio.read( &dataReceived, sizeof(dataReceived) );
      Serial.print("Data received ");
      Serial.println(dataReceived);
  }
}

I’ve now tried to encapsulate this logic as a LongRangeListener below (there is more to this project, hence the file name hub, but I’m isolating the portion I’m currently struggling with):

Hub.h

#include <Arduino.h>
#include <Hub.h>

LongRangeListener::LongRangeListener(const byte cePin, const byte csnPin) : radio(cePin, csnPin)
{
}

void LongRangeListener::start()
{
  Serial.println("Starting Long Range Listener");

  (*radio).begin();
  (*radio).setDataRate(RF24_250KBPS);
  (*radio).openReadingPipe(1, address);
  (*radio).startListening();

  Serial.println("Long Range Listener started.");
}

char *LongRangeListener::listen()
{
  if ((*radio).available())
  {
    (*radio).read(&longRangeBuf, sizeof(longRangeBuf));
    Serial.print("Received Long Range Data : ");
    Serial.println(longRangeBuf);
    return longRangeBuf;
  }
  return nullptr;
}

Hub.cpp

#ifndef Hub_h
#define Hub_h

#include <Arduino.h>
#include <RF24.h>

class LongRangeListener
{
private:
  RF24 *radio;
  const byte address[5] = {'R', 'x', 'A', 'A', 'A'};
  static const uint8_t bufLength = 35;
  char longRangeBuf[bufLength];

public:
  LongRangeListener(const byte cePin, const byte csnPin);
  void start();
  char *listen();
};

#endif

I am invoking this from my ino file:

#include <Hub.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN 9
#define CSN_PIN 10

LongRangeListener* listener;

void setup() {
  Serial.begin(9600);
  Serial.println("Setting up board");

  listener = &LongRangeListener(CE_PIN, CSN_PIN);
  (*listener).start();

  Serial.println("Board setup complete");
}

void loop() {
  (*listener).listen();
}

The experience I get when making use of the LongRangeListener class is the radio.available function returning true every few milliseconds, with no data in it’s buffer. Or at least not data that prints out. I have a post within the Arduino community to cover if it is hardware related, but it is very much feeling like something with my coding.

To try to understand better I have also made attempts at updating LongRangeListener’s constructor to take in an RF24 pointer. I instantiate and begin the radio in my ino file and only attempt to make use of the radio.available function within LongRangerListener, but I get the same experience. I’ve taken it a step further by also invoking the same functionality I’m invoking in the listener… but somehow THAT works. Every 1 second I output the message from the loop.

#include <Hub.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN 9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);
const byte thisSlaveAddress[5] = {'R','x','A','A','A'};
char dataReceived[35];
LongRangeListener* listener;

void setup() {
  Serial.begin(9600);
  Serial.println("Setting up board");
  radio.begin();
  radio.setDataRate( RF24_250KBPS );
  radio.openReadingPipe(1, thisSlaveAddress);
  radio.startListening();

  listener = &LongRangeListener(&radio);
  (*listener).start();

  Serial.println("Board setup complete");
}

void loop() {
  if ( radio.available() ) {
    Serial.println("********* IN LOOP **********");
    radio.read( &dataReceived, sizeof(dataReceived) );
    Serial.print("Data received ");
    Serial.println(dataReceived);
  }
  (*listener).listen();
}

I am really hoping for someone to help me understand what gap I’m missing with how this is supposed to wire up? Any advice is appreciated.

  • listener = &LongRangeListener(CE_PIN, CSN_PIN); — This actually compiled with no errors? You should have received an error

    – 




  • Below I have code that works, telling me that I have wired my module up correctly and am making correct use of the library to use the module — Which makes it more than likely that the issue is incorrect / invalid C++ coding, or a misunderstanding how object lifetimes and construction works. If you made the constructor of LongRangeListener “lazy”, i.e. just set some simple variables (possibly make it a default constructor), and then have start do the “real” initialization work and start, then maybe that’s an option?

    – 




  • Also, doing what my comment suggested would remove the need for a pointer to LongRangeListener, and instead just LongRangeListener listener;

    – 

  • I am not sure how to respond to people directly correctly. @PaulMcKenzie – Compiles and uploads and runs. I am unclear how what I’ve done is different from the second example here. I’m also not following your second comment. I’ve understood it to mean moving the passing of radio to the start function to set my radio variable. I tried that and get the same experience. My invocation of radio.available in my main loop works, my invocation in listen does not.

    – 

  • Disregard. Passing it to the start function did seem to work. I appreciate the help. I’m really hoping to bother you for a bit more of your time to maybe help me understand the why? It has always felt like an issue of scope and lifetimes like you suggested, but I don’t quite understand what I’m missing, coming from java and python. Again, sincerely appreciate all you’ve done already.

    – 

Leave a Comment