5 years, 5 months ago.

Problem creating class that inherits Serial

I am trying to adapt a GPS module library to be used with a STM32 board. My problem is basically when creating the class "class UbxGps : public Serial". It seems Serial is not being recognized and every time I try to use anything from Serial.h, it just does not work.

#ifndef UBXGPS_H_
#define UBXGPS_H_

#include "mbed.h"

const unsigned char UBXGPS_HEADER[] = {0xB5, 0x62};

class UbxGps : public Serial{
public:
  // void begin(long speed);
  bool ready();

protected:
  UbxGps(PinName tx, PinName rx);
  ~UbxGps();
  void setLength(unsigned char length);

private:
  int available();
  uint8_t read();
  void calculateChecksum();

  // Class properties
  unsigned char offsetClassProperties = 8;
  unsigned char offsetHeaders = 4;
  unsigned char size;
  unsigned char carriagePosition;
  unsigned char checksum[2];

  // Headers (common).
  unsigned char headerClass;
  unsigned char headerId;
  unsigned short headerLength;
};

#endif

#include "UbxGps.hh"
#include "mbed.h"

    UbxGps::UbxGps(PinName tx, PinName rx):Serial(tx,rx) {
        this->carriagePosition = 0;
    };

    UbxGps::~UbxGps(){
    }
    
    // void UbxGps::begin(long speed){
    //     return this->baud(speed);
    // };

    bool UbxGps::ready(){
        unsigned char p = this->carriagePosition;

        while (this->readable()){
            uint8_t c = this->read();

            // Carriage is at the first or the second sync byte, should be equals.
            if (p < 2){
                if (c == UBXGPS_HEADER[p]){
                    p++;
                }
                // Reset if not.
                else{
                    p = 0;
                }
            }

            // Sync with header after success.
            else{
                // Put the byte read to a particular address of this object which depends on the carriage position.
                if (p < (this->size + 2)){
                    ((unsigned char *)(this))[p - 2 + this->offsetClassProperties] = c;
                }

                // Move the carriage forward.
                p++;

                // Carriage is at the first checksum byte, we can calculate our checksum, but not compare, because this byte is
                // not read.
                if (p == (this->size + 2)){
                    this->calculateChecksum();
                }
                // Carriage is at the second checksum byte, but only the first byte of checksum read, check if it equals to
                // ours.
                else if (p == (this->size + 3)){
                    // Reset if not.
                    if (c != this->checksum[0]){
                        p = 0;
                    }
                }
                // Carriage is after the second checksum byte, which has been read, check if it equals to ours.
                else if (p == (this->size + 4)){
                    // Reset the carriage.
                        p = 0;

                    // The readings are correct and filled the object, return true.
                    if (c == this->checksum[1]){
                        this->carriagePosition = p;
                        return true;
                    }
                }
                // Reset the carriage if it is out of a packet.
                else if (p > (this->size + 4)){
                    p = 0;
                }
            }
        }

        this->carriagePosition = p;

        return false;
    };

    void UbxGps::setLength(unsigned char length){
        this->size = length + this->offsetHeaders;
    };

    int UbxGps::available(){
        return this->readable();
    };

    uint8_t UbxGps::read(){
        return this->read();
    };

    void UbxGps::calculateChecksum(){
        memset(this->checksum, 0, 2);

    for (int i = 0; i < this->size; i++){
        this->checksum[0] += ((unsigned char *)(this))[i + this->offsetClassProperties];
        this->checksum[1] += this->checksum[0];
        }
    };

1 Answer

5 years, 5 months ago.

Hello Guilherme,

The modified code below compiled with success (although with lot of warnings) both online (with Keil Arm toolchain) and offline (with GNU Arm toolchain). The error messages reported when trying to compile the unmodified version can be found in comments.

main.cpp

#include "mbed.h"

const unsigned char UBXGPS_HEADER[] = { 0xB5, 0x62 };

class UbxGps :
    public Serial
{
public:
    // void begin(long speed);
    bool    ready();
//protected:  Error: "UbxGps::UbxGps(PinName, PinName)" (declared at line 41) is inaccessible in "main.cpp", Line: 143, Col: 16
    UbxGps(PinName tx, PinName rx);
    ~UbxGps();
    void    setLength(unsigned char length);
private:
    int     available();
    uint8_t read();
    void    calculateChecksum();

    // Class properties
    unsigned char   offsetClassProperties;  // = 8; Error: Data member initializer is not allowed in "main.cpp", Line: 21, Col: 44
    unsigned char   offsetHeaders;          // = 4; Error: Data member initializer is not allowed in "main.cpp", Line: 22, Col: 44
    unsigned char   size;
    unsigned char   carriagePosition;
    unsigned char   checksum[2];

    // Headers (common).
    unsigned char   headerClass;
    unsigned char   headerId;
    unsigned short  headerLength;
};

UbxGps::UbxGps(PinName tx, PinName rx) :
    Serial(tx, rx)
{
    offsetClassProperties = 8;  // initializing data member
    offsetHeaders = 4;          // initializing data member
    this->carriagePosition = 0;
};

UbxGps::~UbxGps()
{ }
// void UbxGps::begin(long speed){
//     return this->baud(speed);

// };
bool UbxGps::ready()
{
    unsigned char   p = this->carriagePosition;

    while (this->readable()) {
        uint8_t c = this->read();

        // Carriage is at the first or the second sync byte, should be equals.
        if (p < 2) {
            if (c == UBXGPS_HEADER[p]) {
                p++;
            }

            // Reset if not.
            else {
                p = 0;
            }
        }

        // Sync with header after success.
        else {
            // Put the byte read to a particular address of this object which depends on the carriage position.
            if (p < (this->size + 2)) {
                ((unsigned char*)(this))[p - 2 + this->offsetClassProperties] = c;
            }

            // Move the carriage forward.
            p++;

            // Carriage is at the first checksum byte, we can calculate our checksum, but not compare, because this byte is
            // not read.
            if (p == (this->size + 2)) {
                this->calculateChecksum();
            }

            // Carriage is at the second checksum byte, but only the first byte of checksum read, check if it equals to
            // ours.
            else
            if (p == (this->size + 3)) {
                // Reset if not.
                if (c != this->checksum[0]) {
                    p = 0;
                }
            }

            // Carriage is after the second checksum byte, which has been read, check if it equals to ours.
            else
            if (p == (this->size + 4)) {
                // Reset the carriage.
                p = 0;

                // The readings are correct and filled the object, return true.
                if (c == this->checksum[1]) {
                    this->carriagePosition = p;
                    return true;
                }
            }

            // Reset the carriage if it is out of a packet.
            else
            if (p > (this->size + 4)) {
                p = 0;
            }
        }
    }

    this->carriagePosition = p;

    return false;
};

void UbxGps::setLength(unsigned char length)
{
    this->size = length + this->offsetHeaders;
};

int UbxGps::available()
{
    return this->readable();
};

uint8_t UbxGps::read()
{
    return this->read();
};

void UbxGps::calculateChecksum()
{
    memset(this->checksum, 0, 2);

    for (int i = 0; i < this->size; i++) {
        this->checksum[0] += ((unsigned char*)(this))[i + this->offsetClassProperties];
        this->checksum[1] += this->checksum[0];
    }
};

UbxGps ubxGps(USBTX, USBRX);

int main()
{
    while (true) {
        wait(0.5);
    }
}

Advise: You dont have to use the this pointer (you can delete this->) in class methods when using data members unless you want to resolve a name clash with other variables.