-4

I'm trying to pass a single instance of my "Status" class to all my other classes so that they can all set and get the status.

I've been trying to do this by passing the "Status" class by reference into my "BaseStation" class. The code compiles fine but when I set the status from main and then get the status in "BaseStation" it has not changed.

I think this should be possible so I must be missing something.

Here is my main class

#include "mbed.h"
#include "Global.h"
#include "MODSERIAL.h"
#include "Status.h"
#include "Sensors.h"
#include "BaseStation.h"
#include "Rc.h"
#include "FlightController.h"
#include "NavigationController.h"

MODSERIAL                           _debug(USBTX, USBRX);

//Unused analog pins
DigitalOut                          _spare1(p16);
DigitalOut                          _spare2(p17);
DigitalOut                          _spare3(p18);
DigitalOut                          _spare4(p19);

//Classes
Status                              _status;
Sensors                             _sensors;
BaseStation                         _baseStation;
Rc                                  _rc;
FlightController                    _flightController;
NavigationController                _navigationController;           

int main()
{
    _debug.baud(115200);

    DEBUG("\r\n");  
    DEBUG("********************************************************************************\r\n");
    DEBUG("Starting Setup\r\n");
    DEBUG("********************************************************************************\r\n");

    //Set Status
    _status.initialise();

    //Initialise RC
    //_rc.initialise(_status, p8);

    //Initialise Sensors
    //_sensors.initialise(p13, p14, p28, p27);

    //Initialise Navigation
    //_navigationController.initialise(_status, _sensors, _rc);

    //Initialise Flight Controller
    //_flightController.initialise(_status, _sensors, _navigationController, p21, p22, p23, p24);

    //Initalise Base Station
    _baseStation.initialise(_status, _rc, _sensors, _navigationController, _flightController, p9, p10);

    DEBUG("********************************************************************************\r\n");
    DEBUG("Finished Setup\r\n");
    DEBUG("********************************************************************************\r\n"); 

    _status.setState(Status::STANDBY);
    int state = _status.getState();
    printf("Main State %d\r\n", state);
}

Here is my Status.cpp

#include "Status.h"

Status::Status(){}

Status::~Status(){}

bool Status::initialise()
{
    setState(PREFLIGHT);
    DEBUG("Status initialised\r\n");
    return true;
}

bool Status::setState(State state)
{
    switch(state)
    {
        case PREFLIGHT:
            setFlightMode(NOT_SET);
            setBaseStationMode(STATUS);
            setBatteryLevel(0);
            setArmed(false);
            setInitialised(false);
            _state = PREFLIGHT;
            DEBUG("State set to PREFLIGHT\r\n");
            return true;

        case STANDBY:

            _state = STANDBY;
            DEBUG("State set to STANDBY\r\n");
            return true;


        case GROUND_READY:

            return true;


        case MANUAL:

            return true;


        case STABILISED:

            return true;


        case AUTO:

            return true;


        case ABORT:

            return true;


        case EMG_LAND:

            return true;


        case EMG_OFF:

            return true;


        case GROUND_ERROR:

            return true;


        default:

            return false;

    }    
}

Status::State Status::getState()
{
    return _state;    
}

bool Status::setFlightMode(FlightMode flightMode)
{
    _flightMode = flightMode;
    return true;
}

Status::FlightMode Status::getFlightMode()
{
    return _flightMode;
}

bool Status::setBaseStationMode(BaseStationMode baseStationMode)
{
    _baseStationMode = baseStationMode;
    DEBUG("Base station mode set\r\n");
    return true;
}

Status::BaseStationMode Status::getBaseStationMode()
{
    return _baseStationMode;
}

bool Status::setBatteryLevel(float batteryLevel)
{
    _batteryLevel = batteryLevel;
    return true;
}

float Status::getBatteryLevel()
{
    return _batteryLevel;
}

bool Status::setArmed(bool armed)
{
    _armed = armed;
    return true;
}

bool Status::getArmed()
{
    return _armed;
}

bool Status::setInitialised(bool initialised)
{
    _initialised = initialised;
    return true;
}

bool Status::getInitialised()
{
    return _initialised;
}

bool Status::setRcConnected(bool rcConnected)
{
    _rcConnected = rcConnected;
    return true;
}

bool Status::getRcConnected()
{
    return _rcConnected;
}

Here is my status.h

#include "mbed.h"
#include "Global.h"

#ifndef Status_H
#define Status_H

class Status                   // begin declaration of the class
{
  public:                    // begin public section
    Status();     // constructor
    ~Status();                  // destructor

    enum State
    {
        PREFLIGHT,
        STANDBY,
        GROUND_READY,
        MANUAL,
        STABILISED,
        AUTO,
        ABORT,
        EMG_LAND,
        EMG_OFF,
        GROUND_ERROR     
    };

    enum FlightMode
    {
        RATE,
        STAB,
        NOT_SET  
    };

    enum BaseStationMode
    {
        MOTOR_POWER,
        PID_OUTPUTS,
        IMU_OUTPUTS,
        STATUS,
        RC,
        PID_TUNING,
        GPS,
        ZERO,
        RATE_TUNING,
        STAB_TUNING,
        ALTITUDE,
        VELOCITY   
    };

    bool initialise();
    bool setState(State state);
    State getState();
    bool setFlightMode(FlightMode flightMode);
    FlightMode getFlightMode();
    bool setBaseStationMode(BaseStationMode baseStationMode);
    BaseStationMode getBaseStationMode();
    bool setBatteryLevel(float batteryLevel);
    float getBatteryLevel();
    bool setArmed(bool armed);
    bool getArmed();
    bool setInitialised(bool initialised);
    bool getInitialised();
    bool setRcConnected(bool rcConnected);
    bool getRcConnected();

  private:             
    State _state; 
    FlightMode _flightMode;             
    BaseStationMode _baseStationMode;
    float _batteryLevel;
    bool _armed;
    bool _initialised;
    bool _rcConnected;
};

#endif

Here is my BaseStation.cpp

#include "BaseStation.h"

BaseStation::BaseStation() : _status(status){}

BaseStation::~BaseStation(){}

bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{   
    _status = status;
    _rc = rc;
    _sensors = sensors;
    _navigationController = navigationController;
    _flightController = flightController;
    _wireless = new MODSERIAL(wirelessPinTx, wirelessPinRx);
    _wireless->baud(57600);
    _wirelessSerialRxPos = 0;

    _thread = new Thread(&BaseStation::threadStarter, this, osPriorityHigh);
    DEBUG("Base Station initialised\r\n");
    return true; 
}

void BaseStation::threadStarter(void const *p)
{
    BaseStation *instance = (BaseStation*)p;
    instance->threadWorker();
}

void BaseStation::threadWorker()
{
    while(_status.getState() == Status::PREFLIGHT)
    {
        int state = _status.getState();
        printf("State %d\r\n", state);
        Thread::wait(100);
    }

    _status.setBaseStationMode(Status::RC);
}

Here is my BaseStation.h

#include "mbed.h"
#include "Global.h"
#include "rtos.h"
#include "MODSERIAL.h"
#include "Rc.h"
#include "Sensors.h"
#include "Status.h"
#include "NavigationController.h"
#include "FlightController.h"

#ifndef BaseStation_H
#define BaseStation_H

class BaseStation                
{
  public:             
    BaseStation();    
    ~BaseStation();

    struct Velocity
    {
       float accelX;
       float accelY;
       float accelZ;
       float gps;
       float gpsZ;
       float barometerZ;
       float lidarLiteZ;
       float computedX;
       float computedY;
       float computedZ;
    };    

    bool initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx);

  private:
    static void threadStarter(void const *p);
    void threadWorker();
    void checkCommand();

    Thread* _thread;
    MODSERIAL* _wireless;
    Status& _status;
    Status status;
    Rc _rc;
    Sensors _sensors;
    NavigationController _navigationController;
    FlightController _flightController;
    char _wirelessSerialBuffer[255];
    int _wirelessSerialRxPos;
};

#endif

The output when I run this is

********************************************************************************
Starting Setup
********************************************************************************
Base station mode set
State set to PREFLIGHT
Status initialised
Rc initialised
HMC5883L failed id check.IMU initialised
Sensors initialised
State 0
Base Station initialised
********************************************************************************
Finished Setup
********************************************************************************
State set to STANDBY
Main State 1
State 0
State 0

I think this is because I'm not in fact passing a single instance of "Status" but copying it.

How can I pass by reference properly?

Thanks Joe

Joseph Roberts
  • 569
  • 3
  • 8
  • 29

2 Answers2

1
int  x = 42;
int  y = 9001;

int& r = x;
r = y;

Now x is 9001. You have not changed anything about r.

Similarly, in your code, although you accept a Status by reference, you then assign its value to a different object.

You may only initialise references. In your case you want to chain them.

Here's how you do what you want to do:

struct Status {};
struct T
{
   T(Status& _ref)  // 1. Accept parameter by reference;
      : ref(_ref)   // 2. Initialise member reference;
   {}               // now this->ref is a reference to whatever _ref was a reference to

   Status& ref;
};

int main()
{
    Status s;
    T obj(s);  // now obj holds a reference to s
}
Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
0

You completely misunderstand how reference works in C++. You can set reference only in constructor and only in member initialization list, any other place you do assignment to object where that reference points to. So

BaseStation::BaseStation() : _status(status){}

Now your reference points to member status

bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{   
    _status = status;

Now you do assignment to object, where _status points to. So this code is actually equivalent to:

bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{   
    this->status = status;

It is not a good idea to replace constructor by initialize method in general, but in case you have reference, it is even worse. You need to either change it to a pointer, or initialize your objects properly - in constructor.

Slava
  • 40,641
  • 1
  • 38
  • 81