Using serial.print to debug a library

First question is why are you using a c file? The Arduino is programmed in C++, which uses cpp as the extension. There is a huge difference in the way the c compiler produces object code and the way that the cpp compiler produces object code.

C doesn't have classes, so putting the class implementation in a c file doesn't make sense.

Well That's embarrassing, I've been working on Vex robots mostly, and when using the Arduino just worked in a single file. I did switch to .cpp file extension and I get different (but somewhat similar) errors. I also noticed I posted the wrong example of my Library split amongst files.

The corrected posting is below:

.ino file

#include "MyLibrary.h"
MyLibrary myLibrary(Serial);

void setup() {
  myLibrary.test();
}
void loop() {}

.h file

#ifndef _EXAMPLE_SPLIT_H
#define _EXAMPLE_SPLIT_H
#endif
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "HardwareSerial.h"

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print );
    void test();
  private:
    HardwareSerial* printer;
};

.cpp file

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print ) { 
      printer = &print; //operate on the adress of print
      printer->begin(9600);
    }
    void test() {
      printer->println("Hello library with serial connectivity!");
    }
  private:
    HardwareSerial* printer;
};

Errors reported by the compiler:
MyLibrary.cpp:3: error: expected `)' before '&' token
MyLibrary.cpp:11: error: ISO C++ forbids declaration of 'HardwareSerial' with no type
MyLibrary.cpp:11: error: expected ';' before '*' token
MyLibrary.cpp: In member function 'void MyLibrary::test()':
MyLibrary.cpp:8: error: 'printer' was not declared in this scope

I would appreciate any help resolving the first 2-3 errors The last error looks to be caused by the first error not being resolved.

Thanks - Kb

The cpp file has no idea what a HardwareSerial is. You need to include the header file in the source file.

Thanks for your help PaulS,

I've included the Hardware serial header in the file but I still get errors.

HardwareSerialClassExampleSplit.cpp.o: In function __static_initialization_and_destruction_0': C:\Users\Kb\AppData\Local\Temp\build6312645766259194773.tmp/HardwareSerialClassExampleSplit.cpp:5: undefined reference to MyLibrary::MyLibrary(HardwareSerial&)'
HardwareSerialClassExampleSplit.cpp.o: In function setup': C:\Users\Kb\AppData\Local\Temp\build6312645766259194773.tmp/HardwareSerialClassExampleSplit.cpp:8: undefined reference to MyLibrary::test()'

I had another window open and had a typo including the MyLibrary.cpp file vs the MyLibray.h file and that version compiles. I don't think that what I'm supposed to do though is it?

So the version which includes the .h file and spits out the above errors is:

#include "MyLibrary.h"
MyLibrary myLibrary(Serial);

void setup() {
  myLibrary.test();
}
void loop() {}

The one that compiled clean is:

#include "myLibrary.cpp"

MyLibrary myLibrary(Serial);

void setup() {

  myLibrary.test();  
}
void loop() {
  delay(10);
  myLibrary.test();

}

In both cases I modified the .cpp file to read

#include "HardwareSerial.h"
class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print ) { 
      printer = &print; //operate on the adress of print
      printer->begin(9600);
    }
    void test() {
      printer->println("Hello library with serial connectivity!");
    }
  private:
    HardwareSerial* printer;
};
#include "myLibrary.cpp"

You should not be including source files in sketches. You only include header files.

File names are case sensitive. myLibrary.cpp and MyLibrary.h don't play together.

PaulS:

#include "myLibrary.cpp"

You should not be including source files in sketches. You only include header files.

File names are case sensitive. myLibrary.cpp and MyLibrary.h don't play together.

Agreed, That is not what I intended, so back to the current compilation errors;

HardwareSerialClassExampleSplit.cpp.o: In function setup': C:\Users\Kb\AppData\Local\Temp\build6312645766259194773.tmp/HardwareSerialClassExampleSplit.cpp:7: undefined reference to MyLibrary::MyLibrary(HardwareSerial&)'
C:\Users\Kb\AppData\Local\Temp\build6312645766259194773.tmp/HardwareSerialClassExampleSplit.cpp:9: undefined reference to `MyLibrary::test()'

Any idea why I am getting an undefined reference to `MyLibrary::MyLibrary(HardwareSerial&) error?

Cheers Kb

So just to recap I seem to be having linker errors for this example to use the Serial.print function from a library as coded in multiple tabs in a sketch:
.ino file

#include "MyLibrary.h"

MyLibrary myLibrary(Serial);

void setup() {

  myLibrary.test();
}
void loop() {}

.cpp file

#include "HardwareSerial.h"

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print ) { 
      printer = &print; //operate on the address of print
      printer->begin(9600);
    }
    void test() {
      printer->println("Hello library with serial connectivity!");
    }
  private:
    HardwareSerial* printer;
};

.h file

#ifndef _EXAMPLE_SPLIT_H
#define _EXAMPLE_SPLIT_H
#endif
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print );
    void test();
  private:
    HardwareSerial* printer;
};

Errors:

HardwareSerialClassExampleSplit.cpp.o: In function __static_initialization_and_destruction_0': C:\Users\Kb\AppData\Local\Temp\build5255053454461430477.tmp/HardwareSerialClassExampleSplit.cpp:7: undefined reference to MyLibrary::MyLibrary(HardwareSerial&)'
HardwareSerialClassExampleSplit.cpp.o: In function setup': C:\Users\Kb\AppData\Local\Temp\build5255053454461430477.tmp/HardwareSerialClassExampleSplit.cpp:11: undefined reference to MyLibrary::test()'

Thanks in advance for advice on how to resolve this or if this is not allowed for some reason.

Cheers Kb

There are many bugs in that last stuff you posted. The sketch looks fine. The source file looks like a header file. The header file has an include guard that is useless.

MyLibrary.h should look like:

#ifndef _MYLIBRARY_H
#define _MYLIBRARY_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print );
    void test();
  private:
    HardwareSerial* printer;
};
#endif

It's hard to say what MyLibrary.cpp should look like, at this point. At a minimum, it needs to #include MyLibrary.h.

Your .cpp file should not have the class definition. It should look like this:

#include "HardwareSerial.h"
//pass a reference to a Print object
MyLibrary::MyLibrary( HardwareSerial &print ) { 
  printer = &print; //operate on the address of print
  printer->begin(9600);
}
MyLibrary::void test() {
  printer->println("Hello library with serial connectivity!");
}

It should look like this:

Really? No need to include MyLibrary.h?

Thanks I will try these and re-post. Just a quick response, when I included the MyLibrary.h file in the .cpp file I got duplicate class definitions. That should have been telling in the first place. but I haven't used C++ in almost 15 years.

Just a quick response, when I included the MyLibrary.h file in the .cpp file I got duplicate class definitions.

The #ifndef/#define/#endif statements prevent multiple inclusions of the same code. That is why the class definition is between the ifndef statement and the endif statement. Moving the endif statement to the top of the file made the guard useless, since it was no longer guarding anything.

O.k. Got the point on the guard, I actually needed 2 #endif at the end. I got the code to compile, but it does not print to the serial port. I had to change the baud rate from the previous example to match my current setup:

Here's the final three pieces which compile.
.ino ( I added a call to test and a delay in the loop)

#include "MyLibrary.h"

MyLibrary myLibrary(Serial);

void setup() {

  myLibrary.test();
}
void loop() {
  myLibrary.test();
  delay(1000);
}

.cpp (Corrected, thanks for the corrections, I did need to include MyLibrary.h)

#include "MyLibrary.h"
#include "HardwareSerial.h"

    //pass a reference to a Print object
    MyLibrary::MyLibrary( HardwareSerial &print ) { 
      printer = &print; //operate on the address of print
      printer->begin(115200);
    }
    void MyLibrary::test() {
      printer->println("Hello library with serial connectivity!");
    }

And Header with the second #endif added to the bottom of the file

#ifndef _MYLIBRARY_H
#define _MYLIBRARY_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary( HardwareSerial &print );
    void test();
  private:
    HardwareSerial* printer;
};
#endif

Now to try to find out why it doesn't output anything to the port. - Thanks again - Kb

Now to try to find out why it doesn't output anything to the port.

Well, that's easy. When is your class constructor called? When is the HardwareSerial constructor called? You don't know, do you? Therefore, you should not write code that relies on them being called in the correct order.

You need a begin() method in your class. You pass nothing to the constructor. You pass a serial instance to the begin method. You call the begin method in the setup() function.

Ah Thanks I will clean that up, That would be better practice eh? I appreciate the feedback. - Kb

That would be better practice eh?

Well, it's better in the sense that it is absolutely necessary, so, yeah.

PaulS:

Now to try to find out why it doesn't output anything to the port.

Well, that's easy. When is your class constructor called? When is the HardwareSerial constructor called? You don't know, do you? Therefore, you should not write code that relies on them being called in the correct order.

You need a begin() method in your class. You pass nothing to the constructor. You pass a serial instance to the begin method. You call the begin method in the setup() function.

So I'm trying to learn and I appreciate your patience and help, but I don't quite follow the recommendation to pass nothing to the constructor. I went to the C++ tutorial website here: http://www.cplusplus.com/doc/tutorial/ and reviewed examples of constructors and destructors for classes. I tested a few things. I Thought the constructor, being outside of setup() or loop(), is called first. and therefore passing the Serial object to the library when declaring an instance seemed reasonable.

I tried to construct an example where I did not pass Serial in the constructor, but I could not get it to compile. However I was successful in creating an example where I pass Serial in the constructor (for the instance myLibrary) and later calling a begin() function.

This code works, Is there some reason it is incorrect?
.ino

#include "MyLibrary.h"

MyLibrary myLibrary(Serial);

void setup() {
  myLibrary.begin();
  myLibrary.test();
}
void loop() {
  myLibrary.test();
  delay(1000);
}

.cpp

#include "MyLibrary.h"
#include "HardwareSerial.h"
    //pass a reference to a Print object
    MyLibrary::MyLibrary( HardwareSerial &print ) { 
      printer = &print; //operate on the address of print
    }
    void MyLibrary::begin() {
      printer->begin(115200);
    }
    void MyLibrary::test() {
      printer->println("Hello library with serial connectivity!");
    }

and .h

#ifndef _MYLIBRARY_H
#define _MYLIBRARY_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary(HardwareSerial &print);
    void begin( );
    void test();
  private:
    HardwareSerial* printer;
};
#endif

My Other code does not But I was unsure what to put in the coonstructor I tried it 2 ways, with nothing (assuming the pointer to HardwareSerial has storage already assigned so it could safely be pointed to, and one declaring storage for the Hardware serial, but I get compiler errors trying to pass Serial in the begin call.

Here's the last round of my attempt to not pass anything in the constructor and pass the reference in the call to begin. I'm not following how to code what you suggested.
.ino

#include "MyLibrary.h"

MyLibrary myLibrary();

void setup() {
  myLibrary.begin(Serial);
  myLibrary.test();
}
void loop() {
  myLibrary.test();
  delay(1000);
}

.cpp

#include "MyLibrary.h"
#include "HardwareSerial.h"
    //pass a reference to a Print object
    MyLibrary::MyLibrary(  ) { 
    printer = new HardwareSerial;
    }

    MyLibrary::~MyLibrary(  ) { 
    delete printer;
    }

    void MyLibrary::begin(HardwareSerial &print) {
      printer = &print; //operate on the address of print
      printer->begin(115200);
    }

    void MyLibrary::test() {
      printer->println("Hello library with serial connectivity!");
    }

.h

#ifndef _MYLIBRARY_H
#define _MYLIBRARY_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class MyLibrary {
  public:
    //pass a reference to a Print object
    MyLibrary();
    ~MyLibrary();
    void begin(HardwareSerial &print);
    void test();
  private:
    HardwareSerial* printer;
};
#endif

Errors:
HardwareSerialClassExampleSplit_V2.cpp: In function 'void setup()':
HardwareSerialClassExampleSplit_V2:6: error: request for member 'begin' in 'myLibrary', which is of non-class type 'MyLibrary ()()'
HardwareSerialClassExampleSplit_V2:7: error: request for member 'test' in 'myLibrary', which is of non-class type 'MyLibrary ()()'
HardwareSerialClassExampleSplit_V2.cpp: In function 'void loop()':
HardwareSerialClassExampleSplit_V2:10: error: request for member 'test' in 'myLibrary', which is of non-class type 'MyLibrary ()()'

Note if the example I posted first is 'safe' I'm happy to code it per that example. if there is something inherently dangerous in that approach even though it works please point that out. - Thanks again - Kb

I tested a few things. I Thought the constructor, being outside of setup() or loop(), is called first. and therefore passing the Serial object to the library when declaring an instance seemed reasonable.

It does, and it would, IF you knew that the HardwareSerial instance had been created. Do you KNOW that? Or, are you only hoping that your constructor gets called after the HardwareSerial constructor?

MyLibrary myLibrary(Serial);

Here you are passing a possibly unvalued variable to the constructor of your class. Does that really seem like a good idea?

It would be so much easier to pass a pointer to your class than to pass an instance to your class. Why is that not an acceptable possibility?

Paul
If you passed a pointer instead of a instance would you test to see if the pointer = NULL in the class member Begin()? before trying to use it. I'm trying to follow along here so get more experience.
I wonder of possible use myself.
Don

If you passed a pointer instead of a instance would you test to see if the pointer = NULL in the class member Begin()? before trying to use it.

Yes, and anywhere else you want to dereference the pointer:

if(printer)
  printer->print("whatever");