I don't know C/C++ very well and I am getting seriously flogged here!
I have a config object that is a little complicated:
Config getDefaultConfig() {
Config config;
config.checksum = 0;
config.mustRunInitialSetup = true;
strncpy(config.deviceName, "YOUR FEEDER", sizeof(config.deviceName));
config.deviceName[sizeof(config.deviceName) - 1] = '\0';
config.soilDryValue = 0;
config.soilLittleMoistValue = 0;
config.soilMoistValue = 0;
config.soilVeryMoistValue = 0;
config.trayNeedsEmptying = false;
config.moistSensorCalibrationWet = 0;
config.emptyTraySensorCalibrationWet = 0;
config.emptyTraySensorCalibrationWellWet = 0;
// Set default checksum
config.checksum = calculateConfigChecksum(config);
// Define default actions
config.actions[0] = Action {
"EMPTY TRAY",
{ WateringStyle::TOP_AND_BOTTOM },
{ },
{ Op::WATER_OUT },
{ Conditions::TRAY_EMPTY, Conditions::SOIL_IGNORED, Conditions::NO_LOGIC },
true
};
// ...for 12 more actions objects
// Define default active actions
for (int i = 0; i < 4; ++i) {
config.activeActions[i].actionIndex = i;
config.activeActions[i].everyNFeeds = 0;
config.activeActions[i].maxNTimesPerHour = 0;
}
return config;
}
This is what the config object looks like:
typedef struct {
enum { P1, S1 } what;
} WaterSources;
typedef struct {
enum { NO_WATER, WATER_IN, WATER_OUT, WATER_IN_AND_OUT} what;
} Op;
typedef struct {
enum { NEITHER_TOP_OR_BOTTOM, TOP_AND_BOTTOM, ONLY_TOP, ONLY_BOTTOM } style;
} WateringStyle;
typedef struct {
enum { TRAY_IGNORED, TRAY_EMPTY, TRAY_AT_MOST_WET, TRAY_AT_LEAST_WET, TRAY_AT_MOST_HALF_FULL, TRAY_AT_LEAST_HALF_FULL, TRAY_FULL } tray;
enum { SOIL_IGNORED, SOIL_DRY, SOIL_AT_MOST_DAMP, SOIL_AT_LEAST_DAMP, SOIL_AT_MOST_WET, SOIL_AT_LEAST_WET, SOIL_VERY_WET } soil;
enum { NO_LOGIC, TRAY_OR_SOIL, TRAY_AND_SOIL } logic;
} Conditions;
typedef struct {
char name[15];
WateringStyle wateringStyle;
Conditions triggerConditions;
Op op;
Conditions endConditions;
bool active;
} Action;
typedef struct {
int actionIndex;
int everyNFeeds; // 0 for every time
int maxNTimesPerHour; // 0 for every time
} ActiveAction;
typedef struct {
uint8_t checksum;
bool mustRunInitialSetup;
char deviceName[20];
int soilDryValue;
int soilLittleMoistValue;
int soilMoistValue;
int soilVeryMoistValue;
bool trayNeedsEmptying;
int moistSensorCalibrationWet;
int emptyTraySensorCalibrationWet;
int emptyTraySensorCalibrationWellWet;
Action actions[12];
ActiveAction activeActions[4];
} Config;
In my setup()
I have this:
Config config; // Global file-wide variable. I need it in setup() and loop()
void setup() {
// ...
if (!loadConfig(config)) { // This is always true BTW, I don't even know why (yet)
config = getDefaultConfig(); // in THEORY the global variable should be copied over
alert("EEPROM Error!");
}
Since Config getDefaultConfig()
returns a Config
object, I assumed that writing this: config = getDefaultConfig();
would overwrite the global variable config
with whatever is returned.
However, when I do this, there is clearly corruption -- screen blinks, in a weird death loop. Variations in the function will give you variations in the weirdness. All of them smelling like buffer overflows.
I kind of "know" how to make it work. Allocating config
and then overwriting it is the only way I know NOT to cause buffer overflows.
Having this in my loop:
Config config; // Global file-wide variable.
void setup() {
// ...
if (!loadConfig(config)) {
setAsDefaultConfig(config);
alert("EEPROM Error!");
}
And changing the function into:
void setAsDefaultConfig(Config &config) {
It works. Well, this is the only way I know to make sure there can't be any memory funkiness: I allocate config
, and then I pass that config variable as is to the function, and then I make sure it's overwritten with the "clean" stuff.
What really bugs me is... WHY doesn't the other way work, and -- worse -- it leads to horrible memory overwriting?
What am I doing wrong?