For reference: here is most of my code, I haven't included a derived class that I created (hence the protected variables). Also this is in C++ tested on code::blocks that I will translate into arduinoc++ (assuming I can get it working). It my first attempt at using OOP.
#define VERYHIGHTEMPERATURE 200
#define VERYLOWTEMPERATURE -200
#define minValidtemp -50
#define maxValidtemp 50
#define MAXSENSORS 6 // set the number of sensors rth
union OneWireAddress
{
uint64_t ow_address_64;
uint32_t ow_address_32[2];
uint8_t ow_address_byte[8];
};
class SensorData
{
private:
const char preamble[2] = {'T','P'}; //TP = temperature probe, no space. 2
OneWireAddress ow_addr[MAXSENSORS]; // array of MAXSENSORS 64bit addresses 8*10
char label[MAXSENSORS][5]; //quick access to label for printing 5*10
protected:
float currentTemp[MAXSENSORS];
time_t timeofCurrentTemp[MAXSENSORS];
uint8_t statusByte[MAXSENSORS];
uint16_t PktSize; // 2
const char postamble[2] = {'z','Z'}; // 2
uint32_t CRC32; // must be the last bit of the struct. 4
public:
int set_ID(OneWireAddress); // set Id from reading of address label
OneWireAddress get_ID(int) const; // read lable to idenfiy which sensor
int find_ID(OneWireAddress) const; //find index of crrent oneWireaddress, return -1 if not found (new)
bool checkValidAddress(OneWireAddress) const;
//bool del_Id(int);
//bool del_Id(OneWireAddress);
//void setroom_ID(OneWireAddress);
void setLabel(char);
char getLabel(void) const;
uint16_t getPktSize(void) const;
//void setCRC32(uint32_t);
uint32_t getCRC32(void) const;
friend setPktSize(SensorData&);
friend setCRC32(SensorData*)
SensorData();
};
uint32_t crc32b(byte *message, uint16_t messageLen )
{
int i, j;
unsigned int cur_byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (i < messageLen)
{
cur_byte = message[i]; // Get next byte.
crc = crc ^ cur_byte;
for (j = 7; j >= 0; j--)
{ // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i++;
}
return ~crc;
}
int main
{
}
void setPktSize(SensorData& rawDatainput)
{
rawDatainput.PktSize = sizeof(rawDatainput);
}
void setCRC32(SensorData* rawDatainput)
{
rawDatainput.PktSize = sizeof(rawDatainput);
newCRC = crc32b((byte *) rawDatainput, ( structSize - 4))
}
my issue is this: I want to keep SensorData.Pktsize and SensorData.CRC32 private, but I need to be able to set it outside of the class, and you can't self-reference the class within the definition.
So I made friend functions to set pktsize, and I'm assuming that to get the size of the class I need the class structure and I can't pass it by pointer or dereferenced pointer. So here I assumed that I can use a reference and set that.
Then to set the SensorData.crc32b I need to know the size of the class first. If this is unset, I could return an error, but I wanted the CRC32 setter to then set the pktsize instead. But I am passing a pointer to the function in order to cast it as a byte value, so I can't think of a way to use the sizeof function from a pointer. Not sure if the arrow operator works with sizeof.
A simpler solution would be just to make the PktSize and CRC32 variables both public, which is what I have been doing, but as its my first OOP attempt I would at least like to try to "Encapslate" the code.
Raj
Have you thought of making the data private and using protected or public 'get' and 'set' methods? For each VariableName you want outside access to you create a getVariableName() method that returns the value and a setVariableName() method that takes a value as an argument.
Arduino software is just C++ with some added (and handy) utility functions.
this is true, but in my experience it is missing a lot too, though not without reason.
I found that using new and delete added 60K to the compile
johnwasser:
Have you thought of making the data private and using protected or public 'get' and 'set' methods? For each VariableName you want outside access to you create a getVariableName() method that returns the value and a setVariableName() method that takes a value as an argument.
I have the get and set functions set up but I needed access to the base class but after instantiating a derived class.
My mistake was the assumptions about sizeof.
SensorSetup1 is an instantiated version of the class NameMinMaxAveBreachVals which is derived from SensorData.
ptrSensors1 points to just the base of the of the SensorSetup1 object.
this function:
rajdarge:
I found that using new and delete added 60K to the compile
That is absolutely ridiculous! new and delete are absolutely essential parts of the language and run-time environment, and using them consumes no more space than required by the object being created.
vaj4088:
The size of a pointer will always be the same regardless of the size of what it points to.
but I am dereferencing the pointer as a class object so the compiler can then use the sizeof operator
RayLivingston:
That is absolutely ridiculous! new and delete are absolutely essential parts of the language and run-time environment, and using them consumes no more space than required by the object being created.
Regards,
Ray L.
I wish it were true, but you can try them yourself.
I modified a blink program by creating a "new int a; delete a" in the setup part (forgot the syntax so correct me if needed).
The compile size on the microcontroller went from just under 4k to 64k
RayLivingston:
new and delete are absolutely essential parts of the language and run-time environment, and using them consumes no more space than required by the object being created.
Sorry, that's incorrect in several ways:
* They are not essential; they are even considered detrimental in the embedded environment. * Objects allocated with new actually use 6 extra bytes for heap management, IIRC. * The usage of new/delete pulls in malloc/free, adding more than 600 bytes to the program space and a few RAM bytes for the heap pointers.
I would agree that going from 4K to 64K is not correct. Perhaps it's going from 4K to 6.4K?
An empty sketch uses 459 program and 9 RAM bytes:
void setup() {}
void loop() {}
With new/delete, this sketch uses 1116 program and 21 RAM bytes:
volatile int *a;
void setup() { a = new int; }
void loop() { if (a) { delete a; a = (int *) NULL; } }
* They are not essential; they are even considered detrimental in the embedded environment. * Objects allocated with new actually use 6 extra bytes for heap management, IIRC. * The usage of new/delete pulls in malloc/free, adding more than 600 bytes to the program space and a few RAM bytes for the heap pointers.
I would agree that going from 4K to 64K is not correct. Perhaps it's going from 4K to 6.4K?
An empty sketch uses 459 program and 9 RAM bytes:
void setup() {}
void loop() {}
With `new/delete`, this sketch uses 1116 program and 21 RAM bytes:
volatile int *a;
void setup() { a = new int; }
void loop() { if (a) { delete a; a = (int *) NULL; } }
Cheers,
/dev
I guess it depends on the particular Microcontroller:
5524 bytes (empty) 65,888 bytes with your code on an STM32F103.
but only 1116 bytes as you mentioned on a uno.
9948(empty) vs 12004 on a due
221,991(empty) vs 222,101 on an esp8266
i will have to test it on a teensy and a Dragonfly STM32L4 - but I haven't got those boards setup properly at the moment.
So it seems dynamic memory management is possible without malloc/free
anyway I did solve the problem of sizeof.
I just have to get all of the code working now with all those pesky sets and gets and child classes etc.
It adds a level of complexity to the implementation when I had it working perfectly with a ton of global variables and mostly in-line code with a few functions.