Creating a Library Using Other Libraries

Hi All!

I'm relatively new to Arduino and C++. I'm working on creating a library for my LCD to perform some of the basic LCD functions. My plan was to use NewSoftSerial.h to do the actual communication on the back end. After some reading, I found that I can't directly include the NewSoftSerial.h file in my library, but I should instead include it in the sketch. Well, I tried that, and I still can't get the library to work. I get the following error

(path to libraries)\libraries\LCDSoftSerial\/LCDSoftSerial.h:17: error: 'NewSoftSerial' does not name a type

Any idea what's going on? I'm at the bare minimum of code right now
Sketch

#include <NewSoftSerial.h>
#include <LCDSoftSerial.h>

LCDSoftSerial.h

#ifndef LCD_H
#define LCD_H

class LCDSoftSerial{
  public:
    LCDSoftSerial(int, int);
    void selectLineOne();
    void selectLineTwo();
    void goTo(int);
    void clearLCD();
    void backlightOn();
    void backlightOff();
    void serCommand();
    void init(int txPin, int baud);
    
  private:
    NewSoftSerial test; // Errors here
};
#endif

LCDSoftSerial.cpp

#include "LCDSoftSerial.h"

void LCDSoftSerial::selectLineOne(){  //puts the cursor at line 0 char 0.
   lcd.print(0xFE, BYTE);   //command flag
   lcd.print(128, BYTE);    //position
}
void LCDSoftSerial::selectLineTwo(){  //puts the cursor at line 0 char 0.
   lcd.print(0xFE, BYTE);   //command flag
   lcd.print(192, BYTE);    //position
}
void LCDSoftSerial::goTo(int position) { //position = line 1: 0-15, line 2: 16-31, 31+ defaults back to 0
  if (position<16){ lcd.print(0xFE, BYTE);   //command flag
                lcd.print((position+128), BYTE);    //position
  }else if (position<32){lcd.print(0xFE, BYTE);   //command flag
                lcd.print((position+48+128), BYTE);    //position 
  } else { goTo(0); }
}

void LCDSoftSerial::clearLCD(){
   lcd.print(0xFE, BYTE);   //command flag
   lcd.print(0x01, BYTE);   //clear command.
}
void LCDSoftSerial::backlightOn(){  //turns on the backlight
    lcd.print(0x7C, BYTE);   //command flag for backlight stuff
    lcd.print(157, BYTE);    //light level.
}
void LCDSoftSerial::backlightOff(){  //turns off the backlight
    lcd.print(0x7C, BYTE);   //command flag for backlight stuff
    lcd.print(128, BYTE);     //light level for off.
}
void LCDSoftSerial::serCommand(){   //a general function to call the command flag for issuing all other commands   
  lcd.print(0xFE, BYTE);
}
/*
LCDSoftSerial::LCDSoftSerial(int txPin, int baud){
  lcd = NewSoftSerial(0, txPin);
  lcd.begin(baud);
}
*/

#include "..\NewSoftSerial\NewSoftSerial.h"
...in your library source file.

#include <NewSoftSerial.h>
...in your Sketch.

I read a lot of people saying "you can't instantiate an object form an object (class within a class)". But you can, and you should. You're almost there!

Search the forum for "initializer list" initializer list site:http://www.arduino.cc/cgi-bin/yabb2/ - Google Search

I have code I can post (but not from here) where I've included my GPS.h in my main sketch. Then in GPS.cpp, I've included SoftSerial.h. The trick is that the GPS constructor has an initializer list that calls the SoftSerial constructor. You're ensuring the constructors get called in the right order, or else inscrutable errors result.

So I would recommend you don't include both header files in the main sketch, but cascade them. Include the header in the class where you're going to use it. You don't need to include every class at the main sketch level.

Post back if you don't crack it, I'll post my code. :wink:

Thanks Coding Badly - that worked! It does seem a bit clunky to have to do that though. I'll look into your method Prawnhead!

I read a lot of people saying "you can't instantiate an object form an object (class within a class)". But you can, and you should. You're almost there!

The problem with this approach is that you have absolutely no control over the order in which the constructors are called.

If you need to use a Serial object in your class' instance, and your constructor calls Serial.begin(), and your constructor gets called AFTER the Serial constructor, your instance will work, and will talk to the serial port.

On the other hand, if your constructor is called BEFORE the Serial constructor, the Serial.begin() call will NOT initialize the non-existing serial object, and your instance will NOT be able to talk to the serial port, and you will have no idea why it does not work.

By putting the stuff that normally goes in the constructor in a begin() method, when setup() or loop() finally call the begin() methods, all the constructors have been called, and all the objects have been created. You have control, this way, over the order in which the begin() methods are called.