Problem with object instantiation - NewSoftSerial

hello there.. i have a bit of a problem with the c syntax.. im trying to write a wrapper class for my GPS chip so I can read out Latitude and Longitude easily within the main loop function..

I'm getting the following error message:

error: no matching function for call to 'NewSoftSerial::NewSoftSerial()'hardware\libraries\NewSoftSerial/NewSoftSerial.h:62: note: candidates are: NewSoftSerial::NewSoftSerial(uint8_t, uint8_t)

which doesn't really seem to make sense, im coming from a java background but i thought an object is instantiated when you, well.. instantiate it and not when you declare the type of a variable:

class GPS {
  NewSoftSerial gpsSerial;
  public:
    GPS(byte rxPin, byte txPin) {
      // Instantiate serial connection to gps
      gpsSerial = NewSoftSerial(rxPin, txPin);
    }
    
    void begin() {
      gpsSerial.begin(4800);
    }
    
    boolean available() {
      // This is nonsense at the moment but the idea is to put all the parsing
      // code in here and only return true if a complete NMEA sentence has been
      // received and latitude / longitude have been updated
      return gpsSerial.available();
    }
    char read() {
      return gpsSerial.read();
    }
    
    long getLatitude() {
      return 510000;
    }
    long getLongitude() {
      return 0;
    }
};
GPS gps = GPS(GPS_RX_PIN, GPS_TX_PIN);

void setup() {
  Serial.begin(9600);

  // Initialize serial connection to gps
  gps.begin();
}

void loop() {
  if ( gps.available() ) {
    int latitude = gps.getLatitude();
    int longitude = gps.getLongitude();
    Serial.println(latitude);
    Serial.println(longitude);
  }
}

any advice on how to takle this? or am i missing something obvious? im using the NewSoftSerial class which doesnt have a constructor with zero arguments so there's not much i can do on that front..

i know this example on it's own doesn't really need the wrapper but this is just a trimmed down version, there are more sensors and actuators involved and im trying to keep the code clean and easily changeable..

cheers,
thom

This line tries to initiate the NewSoftSerial without using the appropriate constructor:

class GPS {
NewSoftSerial gpsSerial;

This causes:

candidates are: NewSoftSerial::NewSoftSerial(uint8_t, uint8_t)

You could change the lines to:

class GPS {
  NewSoftSerial* gpsSerial;

and later

gpsSerial = new NewSoftSerial(rxPin, txPin);

brilliant! works perfectly.. thanks so much.. however calling one of NewSoftSerial's methods through the instantiated object causes a compiling error now:

In member function 'void GPS::begin()':
error: request for member 'begin' in '((GPS*)this)->GPS::gpsSerial', which is of non-class type 'NewSoftSerial*' In member function 'boolean GPS::available()':
In member function 'char GPS::read()':

gpsSerial.begin(4800);

Do i need to use a different syntax?

"which is of non-class type NewSoftSerial" seems a bit odd..

thanks again,
thom

ah, interesting: php-style method calls:

gpsSerial->begin(4800);

however (ugh) im getting the following error now:

o: In function GPS': C:\###\Temp\build48477.tmp/Temporary_8589_9968.cpp:136: undefined reference to operator new(unsigned int)'

Couldn't determine program size: C:###\arduino-0012\hardware/tools/avr/bin/avr-size: 'C:###\Temp\build48477.tmp\timer_compass_and_gps_OOP.hex': No such file

is there anything i can do about that? google seems inclonclusive..

Try this:)

gpsSerial->begin(4800);

ok.. according to:

that operator is only supported in c++ and i think the arduino runs c.. i guess im out of luck then?

EDIT: oups, actually it is supported.. i've looked at a->*b rather than a->b - that leaves the question about the weird compiler error message

this compiles fine ('new' keyword isn't supported in c):

gpsSerial = &NewSoftSerial(rxPin, txPin);

however it's still not working.. the arduino seems to restart when i call NewSoftSerial::begin():

    void begin() {
      Serial.println("BEGIN");
      gpsSerial->begin(4800);
      Serial.println("AFTER");
    }

Serial Monitor:

BOOT
BEGIN?
BOOT
BEGIN?
BOOT
BEGIN?
BOOT

the syntax does work with another class ive tried though so that's not the issue.. it might have something to do with NewSoftSerial's architecture? singlet?

it might have something to do with NewSoftSerial's architecture? singlet?

No.

cyberthorn, when you use the syntax

gpsSerial = &NewSoftSerial(rxPin, txPin);

you are creating a temporary object that immediately disappears. But not before you capture a pointer to it. Yikes! You now have a pointer to a non-existent object. This might work-- but only if you're very lucky. The results are extremely unpredictable. NEVER use this syntax.

If you have a member object inside your class, but that member doesn't provide a default (parameter-less) constructor, like NewSoftSerial, then you initialize it in the parent's constructor like this:

class GPS {
  NewSoftSerial gpsSerial;
  public:
    // constructor with 2 parameters calls NewSoftSerial's 2-parameter constructor too
    GPS(byte rxPin, byte txPin) : gpsSerial(rxPin, txPin) // Instantiate serial connection to gps
    {
    }
    
    void begin() {
      gpsSerial.begin(4800);
    }
    ...

I do not advise using pointers and dynamic memory allocation in this case. And have you tried TinyGPS?

Mikal

Brilliant! Thanks for the explanation Mikal - C is so different to anything I've done before. This works perfectly.

I did try TinyGPS but I only need Lat/Long readings so I thought it might be more resource friendly not to parse any of the other data and calculate NMEA checksums like TinyGPS does. Am I on the wrong track here?

C is so different to anything I've done before.

And I'm afraid you've stumbled into some fairly subtle syntax for a beginner. I know some self-described C++ "professionals" that haven't figured out that member initialization stuff.

Am I on the wrong track here?

My first instinct was to advise you to use TinyGPS anyway. It is Tiny after all. But you could probably make it somewhat smaller by ignoring all but lat/long and avoiding the checksum calculation. And frankly, it will be more fun, and you'll learn more about C++, if you build that little GPS class on your own. Go for it! Post questions, and we'll all try to help answer them.

Make sure you parse both $GPRMC and $GPGGA -- both of which supply lat and long -- because some receivers disable one or the other by default. (Of course you may be targeting a specific model of GPS, in which case this advice may not apply.)

Good luck, and as mem says, "have fun".

Mikal