Make variable global in class

I am new to programming in C++ with classes. For initializing a PN532 module via SPI i am creating a class with function “initCardreader”;

void Cardreader::initCardreader() {
    PN532_SPI pn532spi(SPI, 5);
    PN532 nfc(pn532spi);

    nfc.begin();

    uint32_t versiondata = nfc.getFirmwareVersion();
    if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
    }
    // Got ok data, print it out!
    Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
    Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
    Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

    // configure board to read RFID tags
    nfc.SAMConfig();

    Serial.println("Waiting for an ISO14443A Card ...");
}

When the module is initialized i want to read a card via an ESP32 task. The function which is called is “scanCard”:

void Cardreader::scanCard(void) {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
    
  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

}

The problem is that the nfc variable cannot be found. What is the best way to make the variable not undefined in the scanCard function? How can i make the nfc a private variable or is there a better way?

I am using header files and cpp files (and i am new to this)

lib\Cardreader\Cardreader.cpp: In member function 'void Cardreader::scanCard()':
lib\Cardreader\Cardreader.cpp:44:13: error: 'nfc' was not declared in this scope
   success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
             ^

Thanks a lot!

You create this variable in a scope of a function, when function is finished, the variable is destroyed. Make it CardReader class member variable and initialise it in CardReader constructor

Can you help me a bit on how to do it?

I did this in the header file but i am not able to get it working:

class Cardreader
{
  private:
    PN532 nfc(pn532spi);
};

Which gives me 2 errors:
identifier “PN532” is undefined
identifier “pn532spi” is undefined

Also, the initCardreader is called within the setup function, otherwise it won’t work and the nfc returns 0 (probably my fault that i am initializing something wrong?)

post your complete code

Have you included the PN532 include file at the top of your header file? You need to so the compiler knows what a ‘PN532’ is.

If i include these:

#include <PN532_SPI.h>
#include <PN532.h>

only the parameter pn532spi is still undefined

My whole code is:

Cardreader.h:

#ifndef Cardreader_h
#define Cardreader_h

#include <Arduino.h>
#include <IPSDisplay.h>
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>

class Cardreader
{
  public:
    Cardreader(IPSDisplay ipsDisplay);
    void initCardreader();
    static void scanCard(void * parameter);
  private:
    TaskHandle_t task_ScanCard;
    IPSDisplay _ipsDisplay;
    PN532 nfc(pn532spi);
};

#endif

Cardreader.cpp:

#include <Arduino.h>
#include <Cardreader.h>
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>
#include <IPSDisplay.h>

Cardreader::Cardreader(IPSDisplay ipsDisplay) 
{
    _ipsDisplay = ipsDisplay;
}

void Cardreader::initCardreader() {
    PN532_SPI pn532spi(SPI, 5);
    PN532 nfc(pn532spi);

    nfc.begin();

    uint32_t versiondata = nfc.getFirmwareVersion();
    if (! versiondata) {
        Serial.print("Didn't find PN53x board");
        _ipsDisplay.show("/i003");
        delay(5000);
        initCardreader();
    }
    else {
        // Got ok data, print it out!
        Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
        Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
        Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

        // configure board to read RFID tags
        nfc.SAMConfig();

        Serial.println("Waiting for an ISO14443A Card ...");
        xTaskCreatePinnedToCore(this->scanCard, "scanCard", 5000, this, 1, &task_ScanCard, 0);
    }
}

void Cardreader::scanCard(void * parameter) {
  for(;;) {
    uint8_t success;
    uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
    uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
        
    // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
    // 'uid' will be populated with the UID, and uidLength will indicate
    // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
    success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
    
    if (success) {
        // Display some basic information about the card
        Serial.println("Found an ISO14443A card");
        Serial.print("  UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
        Serial.print("  UID Value: ");
        nfc.PrintHex(uid, uidLength);
        Serial.println("");
        
        if (uidLength == 7)
        {
            // We probably have a Mifare Ultralight card ...
            Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)");
            
            // Try to read the first general-purpose user page (#4)
            Serial.println("Reading page 4");
            uint8_t data[32];
            success = nfc.mifareultralight_ReadPage (4, data);
            if (success)
            {
                // Data seems to have been read ... spit it out
                nfc.PrintHexChar(data, 4);
                Serial.println("");
                
                // Wait a bit before reading the card again
                delay(1000);
            }
            else
            {
                Serial.println("Ooops ... unable to read the requested page!?");
            }
        }
    }
  }
}

You need two private variables in your class, one for the interface to the card and one for the card itself.
Cardreader.h

class Cardreader
{
  public:
    Cardreader(IPSDisplay ipsDisplay);
    void initCardreader();
    static void scanCard(void * parameter);
  private:
    TaskHandle_t task_ScanCard;
    IPSDisplay _ipsDisplay;
    PN532_SPI pn532spi(SPI, 5);
    PN532 nfc(pn532spi);
};

Then, inside initCardreader(), you just need

void Cardreader::initCardreader() {
    nfc.begin();
    ...

Note: if you really want to follow a more typical convention, your initCardreader() function should be called begin() , but you can call it whatever

Thanks for the help,

After doing that i get these errors:

In file included from src\main.cpp:7:0:
lib\Cardreader/Cardreader.h:19:24: error: 'SPI' is not a type
     PN532_SPI pn532spi(SPI, 5);
                        ^
lib\Cardreader/Cardreader.h:19:29: error: expected identifier before numeric constant
     PN532_SPI pn532spi(SPI, 5);
                             ^
lib\Cardreader/Cardreader.h:19:29: error: expected ',' or '...' before numeric constant
lib\Cardreader/Cardreader.h:20:15: error: 'pn532spi' is not a type
     PN532 nfc(pn532spi);
               ^
Compiling .pio\build\esp32dev\lib5d8\Cardreader\Cardreader.cpp.o
In file included from lib\Cardreader\Cardreader.cpp:2:0:
lib\Cardreader/Cardreader.h:19:24: error: 'SPI' is not a type
     PN532_SPI pn532spi(SPI, 5);
                        ^
lib\Cardreader/Cardreader.h:19:29: error: expected identifier before numeric constant
     PN532_SPI pn532spi(SPI, 5);
                             ^
lib\Cardreader/Cardreader.h:19:29: error: expected ',' or '...' before numeric constant
lib\Cardreader/Cardreader.h:20:15: error: 'pn532spi' is not a type
     PN532 nfc(pn532spi);
               ^
lib\Cardreader\Cardreader.cpp: In member function 'void Cardreader::initCardreader()':
lib\Cardreader\Cardreader.cpp:15:5: error: '((Cardreader*)this)->Cardreader::nfc' does not have class type
     nfc.begin();
     ^
lib\Cardreader\Cardreader.cpp:17:28: error: '((Cardreader*)this)->Cardreader::nfc' does not have class type
     uint32_t versiondata = nfc.getFirmwareVersion();
                            ^
lib\Cardreader\Cardreader.cpp:31:9: error: '((Cardreader*)this)->Cardreader::nfc' does not have class type
         nfc.SAMConfig();
         ^
*** [.pio\build\esp32dev\src\main.cpp.o] Error 1
*** [.pio\build\esp32dev\lib5d8\Cardreader\Cardreader.cpp.o] Error 1

I added

#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>

in both Cardreader.h and Cardreader.cpp

The error says from file main.cpp... Are you using the IDE to compile this or something else? SPI gets defined in the esp32/SPI.h file that would automatically be included if you have selected an esp32 board. If you are outside the IDE, I don't know...

Thank you for the tip, i updated my code!

I use platformio

These are my main.cpp first lines:

#include <Arduino.h>
#include <configuration.h>
#include <SPI.h>
#include <Internet.h>
#include <IPSDisplay.h>
#include <SPIFFS.h>
#include <Cardreader.h>

Line 7 is #include <Cardreader.h> so i think that is why it shows the error on main.cpp line 7

Sorry, I don't use platformIO so I'm not much help there... You should probably be using

#include "Cardreader.h"

unless it is in the library folder with all the other libraries vs. the project folder.

Okay no problem, thanks for the help so far!
The Cardreader.h file is in the library folder