Hi,
I want to have global access to certain objects in my code and guarantee there is only ever one instance. This is mainly for access to hardware peripherals as I have gotten bored of all the boiler plate code needed for dependency injection.
I am looking for something like the EEPROM functionality provided by Particle that allows me to call EEPROM.write() etc
from anywhere in my code.
Should I be using global objects, singletons or something else?
Thanks
Something like a singleton is best in this case.
I usually create a separate cpp/h file for this object, and have all members be static.
A good example is the spark_wiring_rgb.cpp/h files. Take a look:
/**
Copyright (c) 2013-2015 Particle Industries, Inc. All rights reserved.
Copyright (c) 2011 Adrian McEwen
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
*/
#include "spark_wiring_rgb.h"
This file has been truncated. show original
/**
******************************************************************************
* @file spark_wiring_rgb.h
* @author Satish Nair, Zachary Crockett, Matthew McGowan
******************************************************************************
Copyright (c) 2013-2015 Particle Industries, Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
This file has been truncated. show original
Just remember to create your object, i would usually do it in the cpp file.
ie: RGBClass RGB ;
usually goes at the end of my cpp file. Now any file that I #include "spark_wiring_rgb.h"
knows that the object RGB exists and can access it.
1 Like
Thanks for the link, I will definitely create an object.
I don’t think I quite understand how it should be used though…
Where should the constructor/deconstructor go (public/private) and how do I ensure it gets called on first use only?
What does the extern RGBClass RGB;
line do and do I need it?
Does adding RGBClass RGB;
at the end of the cpp file instantiate an instance and allow me to access it like RGB.control()
?
Cheers
joe4465:
Where should the constructor/deconstructor go (public/private) and how do I ensure it gets called on first use only?
What does the extern RGBClass RGB; line do and do I need it?
Does adding RGBClass RGB; at the end of the cpp file instantiate an instance and allow me to access it like RGB.control()?
These three questions answer eachother when just look at them last to first
Q3
RGBClass RGB; // at the end of the cpp file instantiates AND constructs a global object
Q2
extern RGBClass RGB; // in the header tells everybody who uses it that there already is a global object to use
application.h
includes it, hence every module including it (so all) will be informed
Q1
answered by above
1 Like
joe4465
January 29, 2016, 10:58am
5
OK its starting to make sense.
When will the constructor get called? I ask because my code seems to be working but does not printf
any messages from the constructor.
Cheers
EDIT
Here is my class, please let me know if I have done anything incorrectly, if there is a better way to do it and any potential issues I may have - mainly around the order constructors are called.
ExternalEeprom.cpp
#ifndef __EXTERNAL_EEPROM_CPP_
#define __EXTERNAL_EEPROM_CPP_
#include "ExternalEeprom.h"
ExternalEeprom::ExternalEeprom()
{
_spieep = new SPIEEP(24, 256, 131072);
_spieep->begin_spi(A2);
if(!_spieep->test_chip()) Serial.printf("Eeprom NOT FOUND!!\r\n");
else Serial.printf( "Finished Eeprom initialisation\r\n");
}
ExternalEeprom::~ExternalEeprom() {}
void ExternalEeprom::readSettings(byte* settings, uint16_t size)
{
_spieep->readn(0, settings, size);
}
void ExternalEeprom::writeSettings(byte* settings, uint16_t size)
{
_spieep->writen(0, settings, size);
}
ExternalEeprom _externalEeprom;
#endif
ExternalEeprom.h
#ifndef __EXTERNAL_EEPROM_H_
#define __EXTERNAL_EEPROM_H_
#include "application.h"
#include "SPIEEP.h"
class ExternalEeprom
{
public:
ExternalEeprom();
virtual ~ExternalEeprom();
void readSettings(byte* settings, uint16_t size);
void writeSettings(byte* settings, uint16_t size);
private:
SPIEEP* _spieep;
};
extern ExternalEeprom _externalEeprom;
#endif
I use this from other classes like this: _externalEeprom.readSettings(_buffer, 64);
Thanks for your advice )
ScruffR
January 29, 2016, 11:14am
6
Constructors of seperate modules will be executed in an “unpredictable” order.
So your constructor might be called before Serial
object gets instantiated.
This is the reason why you should initialize your object but not do work in the constructor on these devices - hence most classes feature a begin()
methode to be called in setup()
or before first use.
joe4465
January 29, 2016, 11:25am
7
OK cool, so with a begin()
method controlling init order is this pattern generally accepted to be correct and safe?
Is there any way to throw a compile time error if the class is used before begin()
has been called?
mdma
January 29, 2016, 11:27am
8
unfortunately not at compile time. That would be equivalent to solving the halting problem.
joe4465
January 29, 2016, 11:27am
9
any other workaround or solutions? I can check that a begin flag has been set in every function but then i’m back to boiler plate code.
Cheers