eduherminio
eduherminio

Reputation: 1684

Multiple classes in multiple files - C++ / Arduino

I have to code a the library motorIR, which uses NECIRrcv to extract the IR code from a sensor. Initially I tried doing it using two libraries, but that doesn't seem to be easy as I read, so I decide to include both the header and the source file of NECIRrcv in my Arduino library motorIR.

I'm having some trouble with defining NECIRrcv sensor in motorIR. If I do it where it's placed in the code, no signal is available (while(sensor.available())is never entered).

I can understand that's logical, since it redefines sensor every time I call motorIR::control(). My real problem is that I have no clue of where I should declare sensor, the object of NECIRrcv class, in motorIR.

I did a little research about it, and since I haven't worked with extern classes before, I've ended up even more confused about if using one it's necessary.

I'd be very grateful if someone can invest a few minutes helping me with this subject. Hope you can understand my explanations.

Here you are the different files:

File motorIR.h

#ifndef motorIR_h
#define motorIR_h

#include "Arduino.h"
#include "NECIRrcv.h"


#define STANDBY 999
#define inputIR 2

#define PWM_1   3
#define MI_1    4
#define MD_1    5

#define PWM_2   6
#define MI_2    7
#define MD_2    8

#define FORWARD 
#define BACKWARD

class motorIR
{
public:     // Funciones públicas

    motorIR(int pPWM_1, int pMI_1, int pMD_1, int pPWM_2, int pMI_2, int pMD_2);

    void setMotor(int PWM, int MI, int MD);

    void begin();

    void control();

    void translate();

    void serialPrint();

private:    // Variables privadas
    int _PWM= STANDBY;
    int _MI;
    int _MD;
    unsigned long _IRcode;


     // static NECIRrcv & getSensor()    //  <---  getSensor() added
     // {
         // static NECIRrcv sensor(4);

         // return sensor;
     // }
     // static NECIRrcv & getSensor()
 // {
   // static NECIRrcv sensor(4);
   // static bool firstRun(true);

   // if ( firstRun )
    // {
      // sensor.begin();
      // firstRun = false;
    // }

   // return sensor;
 // }
};

#endif

File motorIR.cpp

#include "Arduino.h"
#include "motorIR.h"
#include <string.h>

motorIR::motorIR(int PWM, int MI, int MD)     // Constructor
{
    _MI=    MI      +A0;
    _PWM=   PWM     +A0;
    _MD=    MD      +A0;
}

void motorIR::beginner()
{
    Serial.begin(9600);
    Serial.print("Begin");
}


void motorIR::control(int i)
{
    NECIRrcv sensor(4) ;        // I doesn't work as expected if placed here
    sensor.begin();

    Serial.println("Checkpoint");     
     while (sensor.available())
     {
        Serial.print("Detection");
        IRcode= sensor.read();
        Serial.print(IRcode, DEC);
        Serial.print(IRcode, HEX);
        Serial.print(IRcode, BIN);
     }
}

File NECIRrcv.h (given)

#ifndef NECIRrcv_h
#define NECIRrcv_h

#include <Arduino.h>
#include "motorIR.h"

#define USECPERTICK 50  // microseconds per clock interrupt tick
#define CLKFUDGE 5      // fudge factor for clock interrupt overhead
#define CLKMAX 256      // max value for clock (timer 2)
#define PRESCALE 8      // timer2 clock prescale
#define SYSCLOCK 16000000  // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000)   // timer clocks per microsecond

#define MAXBUF 8       // IR command code buffer length (circular buffer)

// IR detector output is active low
#define MARK  0
#define SPACE 1

#define NBITS 32         // bits in IR code

#define BLINKLED 13

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// clock timer reset value
#define INIT_TIMER_COUNT2 (CLKMAX - USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2

// pulse parameters -- nominal usec
#define STARTNOM      9000
#define SPACENOM      4500
#define BITMARKNOM    620
#define ONESPACENOM   1600
#define ZEROSPACENOM  480
#define RPTSPACENOM   2180

#define TOLERANCE 20  // percent
#define LTOL (1.0 - TOLERANCE/100.) 
#define UTOL (1.0 + TOLERANCE/100.) 

// pulse parameters (tick counts)
#define STARTMIN (int)((STARTNOM/USECPERTICK)*LTOL) // start MARK
#define STARTMAX (int)((STARTNOM/USECPERTICK)*UTOL) 
#define SPACEMIN (int)((SPACENOM/USECPERTICK)*LTOL) 
#define SPACEMAX (int)((SPACENOM/USECPERTICK)*UTOL) 
#define BITMARKMIN (int)((BITMARKNOM/USECPERTICK)*LTOL-2) // extra tolerance for low counts
#define BITMARKMAX (int)((BITMARKNOM/USECPERTICK)*UTOL+2) 
#define ONESPACEMIN (int)((ONESPACENOM/USECPERTICK)*LTOL) 
#define ONESPACEMAX (int)((ONESPACENOM/USECPERTICK)*UTOL) 
#define ZEROSPACEMIN (int)((ZEROSPACENOM/USECPERTICK)*LTOL-2) 
#define ZEROSPACEMAX (int)((ZEROSPACENOM/USECPERTICK)*UTOL+2) 
#define RPTSPACEMIN (int)((RPTSPACENOM/USECPERTICK)*LTOL) 
#define RPTSPACEMAX (int)((RPTSPACENOM/USECPERTICK)*UTOL) 

// receiver states
#define IDLE     1
#define STARTH   2
#define STARTL   3
#define BIT      4
#define ONE      5
#define ZERO     6
#define STOP     7
#define BITMARK  8
#define RPTMARK  9

// macros
#define GETIR(X) ((byte)digitalRead(X))    // used to read IR pin
#define nextstate(X) (irparams.rcvstate = X)

// state machine variables irparams
static volatile struct {
  byte rcvstate ;          // IR receiver state
  byte bitcounter ;        // bit counter
  byte irdata ;            // MARK or SPACE read from IR input pin
  byte fptr ;              // irbuf front pointer
  byte rptr ;              // irbuf rear pointer
  byte irpin ;             // pin for IR data from detector
  byte blinkflag ;         // TRUE to enable blinking of pin 13 on IR processing
  unsigned int timer ;     // state timer
  unsigned long irmask ;   // one-bit mask for constructing IR code
  unsigned long ircode ;   // IR code
  unsigned long irbuf[MAXBUF] ;    // circular buffer for IR codes
} irparams ;

// main class
class NECIRrcv
{
  public:
    NECIRrcv(int irpin);
    unsigned long read();
    void begin();
    int available() ;
    void flush() ;
    void blink13(int blinkflag) ;
  private:
} ;

extern NECIRrcv sensor; // <-------- declaring object as extern
#endif  

File NECIRrcv.cpp (given)

#include <Arduino.h>
#include "NECIRrcv.h"
#include "motorIR.h"

NECIRrcv::NECIRrcv(int irpin)
{
  irparams.irpin = irpin ;
}

void NECIRrcv::begin() {
//(...)
}

unsigned long NECIRrcv::read()
{
  unsigned long ircode ;

//(...)
    return((unsigned long)-1) ;
}

// (...)

Eduardo

Upvotes: 1

Views: 1966

Answers (2)

max66
max66

Reputation: 66200

If you need only a sensor for all instances of motorIR, I suppose that it could be a static member of the class.

Or a static variable in a static method; like this

class motorIR
{
public:     // Funciones públicas

    motorIR(int PWM, int MI, int MD);

    void beginner();

    void control(int i);


private:    // Variables privadas
    int _PWM= STANDBY;
    int _MI;
    int _MD;
    int pin_IR;
    unsigned long IRcode;

    static NECIRrcv & getSensor()    //  <---  getSensor() added
     { static NECIRrsv sensor(4); return sensor; }
};

You can use it in this way

void motorIR::control(int i)
{
    // NECIRrcv sensor(4) ; no more here
    getSensor().begin();

    Serial.println("Checkpoint");     
    while (getSensor().available())
     {
        Serial.print("Detection");
        IRcode= getSensor().read();
        Serial.print(IRcode, DEC);
        Serial.print(IRcode, HEX);
        Serial.print(IRcode, BIN);
     }
}

p.s.: caution: not tested

p.s.2: sorry for my bad English

--- EDIT ---

The error is "'NECIRrcv' does not name a type" or "'NECIRrcs' does not name a type"?

In my example I've written, by mistake "NECIRrcs" instead of "NECIRrcv"; sorry.

About your need to begin() only one time the sensor, you can modify the getSensor() method in this way

static NECIRrcv & getSensor()
 {
   static NECIRrsv sensor(4);
   static bool firstRun(true);

   if ( firstRun )
    {
      sensor.begin();
      firstRun = false;
    }

   return sensor;
 }

Caution: not tested.

Upvotes: 1

eduherminio
eduherminio

Reputation: 1684

I loved the idea of declaring the object NECIRrcv::sensor as part of class motorIR though, but trying to define NECIRrcv sensor(4) anywhere in motorIR.h leads to error: 'NECIRrcv' does not name a type; so it would be interesting to solve this problem in order to be able to implement @max66 's idea (or eve just to figure out why motorIR.h doesn't recognize NECIRrcv properly).

In spite of that, I think I've run into an alternative solution: using an extern object (as it's described here).

It can be implemented as it follows:

In NECIRrcv header:

#ifndef NECIRrcv_h
#define NECIRrcv_h

#include <Arduino.h>

// (...)

class NECIRrcv
{
  public:
    NECIRrcv(int irpin);

// (...)

  private:
} ;

extern NECIRrcv sensor; // <-------- declaring object as extern

#endif

In motorIR source file:

#include "Arduino.h"
#include "motorIR.h"
#include <string.h>

NECIRrcv sensor(4); // <--------- defining object

motorIR::motorIR(int PWM, int MI, int MD)
{
    _MI=    MI      +A0;
    _PWM=   PWM     +A0;
    _MD=    MD      +A0;
}

void motorIR::beginner()
{
    Serial.begin(9600);
    Serial.print("Begin");
    sensor.begin(); //  <-------- now I can initialize sensor here
}


void motorIR::control(int i)
{
    // NECIRrcv sensor(4) ;
    // sensor.begin();

    Serial.println("Checkpoint");     
     while (sensor.available()) // <-- method 1
     {
        Serial.print("Detection");
        IRcode= sensor.read(); // <-- method 2
        Serial.print(IRcode, DEC);
        Serial.print(IRcode, HEX);
        Serial.print(IRcode, BIN);
     }
}

Upvotes: 0

Related Questions