Skip to content

Commit

Permalink
Revert most examples to using "new" for variable pointer creation
Browse files Browse the repository at this point in the history
  • Loading branch information
SRGDamia1 committed Mar 5, 2019
1 parent a2ae555 commit b1a619e
Show file tree
Hide file tree
Showing 10 changed files with 659 additions and 685 deletions.
45 changes: 21 additions & 24 deletions examples/DRWI_CitSci/DRWI_CitSci.ino
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ const int8_t modemStatusPin = 19; // MCU pin used to read modem status (-1 if
// Create a reference to the serial port for the modem
HardwareSerial &modemSerial = Serial1; // Use hardware serial if possible

// Create a TinyGSM modem to run on that serial port
TinyGsm tinyModem(modemSerial);
// Create a new TinyGSM modem to run on that serial port and return a pointer to it
TinyGsm *tinyModem = new TinyGsm(modemSerial);

// Create a TCP client on that modem
TinyGsmClient tinyClient(tinyModem);
TinyGsmClient *tinyClient = new TinyGsmClient(*tinyModem);


// ==========================================================================
Expand All @@ -107,20 +107,19 @@ const bool modemStatusLevel = HIGH; // The level of the status pin when the mod

// Create the wake and sleep methods for the modem
// These can be functions of any type and must return a boolean
bool modemSleepFxn(void)
{
digitalWrite(modemSleepRqPin, LOW);
digitalWrite(redLED, LOW);
return true;
}
bool modemWakeFxn(void)
{
digitalWrite(modemSleepRqPin, HIGH);
digitalWrite(redLED, HIGH); // A light just for show
return true;
}


bool modemSleepFxn(void)
{
digitalWrite(modemSleepRqPin, LOW);
digitalWrite(redLED, LOW);
return true;
}
void extraModemSetup(void){}
// ==========================================================================
// Network Information and LoggerModem Object
// ==========================================================================
Expand All @@ -131,7 +130,7 @@ const char *apn = "hologram"; // The APN for the gprs connection, unnecessary f

// Create the loggerModem instance
// A "loggerModem" is a combination of a TinyGSM Modem, a Client, and functions for wake and sleep
loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, modemSleepFxn, &tinyModem, &tinyClient, apn);
loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, modemSleepFxn, tinyModem, tinyClient, apn);
// ^^ Use this for cellular


Expand All @@ -140,7 +139,7 @@ loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, m
// ==========================================================================
#include <sensors/MaximDS3231.h>

// Create the DS3231 sensor object
// Create a DS3231 sensor object
MaximDS3231 ds3231(1);


Expand All @@ -158,7 +157,7 @@ const float OBSLow_A = 0.000E+00; // The "A" value (X^2) from the low range cal
const float OBSLow_B = 1.000E+00; // The "B" value (X) from the low range calibration
const float OBSLow_C = 0.000E+00; // The "C" value from the low range calibration

// Create the Campbell OBS3+ LOW RANGE sensor object
// Create a Campbell OBS3+ LOW RANGE sensor object
CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C, ADSi2c_addr, OBS3numberReadings);


Expand All @@ -168,7 +167,7 @@ const float OBSHigh_A = 0.000E+00; // The "A" value (X^2) from the high range c
const float OBSHigh_B = 1.000E+00; // The "B" value (X) from the high range calibration
const float OBSHigh_C = 0.000E+00; // The "C" value from the high range calibration

// Create the Campbell OBS3+ HIGH RANGE sensor object
// Create a Campbell OBS3+ HIGH RANGE sensor object
CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B, OBSHigh_C, ADSi2c_addr, OBS3numberReadings);


Expand All @@ -182,7 +181,7 @@ const uint8_t CTDnumberReadings = 6; // The number of readings to average
const int8_t SDI12Power = sensorPowerPin; // Pin to switch power on and off (-1 if unconnected)
const int8_t SDI12Data = 7; // The SDI12 data pin

// Create the Decagon CTD sensor object
// Create a Decagon CTD sensor object
DecagonCTD ctd(*CTDSDI12address, SDI12Power, SDI12Data, CTDnumberReadings);


Expand All @@ -206,16 +205,16 @@ Variable *variableList[] = {
int variableCount = sizeof(variableList) / sizeof(variableList[0]);

// Create the VariableArray object
VariableArray varArray;
VariableArray varArray(variableCount, variableList);


// ==========================================================================
// The Logger Object[s]
// ==========================================================================
#include <LoggerBase.h>

// Create a logger instance
Logger dataLogger;
// Create a new logger instance
Logger dataLogger(LoggerID, loggingInterval, sdCardPin, wakePin, &varArray);


// ==========================================================================
Expand All @@ -228,7 +227,7 @@ const char *samplingFeature = "12345678-abcd-1234-efgh-1234567890ab"; // Sam

// Create a data publisher for the EnviroDIY/WikiWatershed POST endpoint
#include <publishers/EnviroDIYPublisher.h>
EnviroDIYPublisher EnviroDIYPOST;
EnviroDIYPublisher EnviroDIYPOST(dataLogger, registrationToken, samplingFeature);


// ==========================================================================
Expand Down Expand Up @@ -321,10 +320,8 @@ void setup()
dataLogger.attachModem(modem);
dataLogger.setLoggerPins(sdCardPin, wakePin, greenLED, buttonPin);

// Begin the variable array[s], logger[s], and publisher[s]
varArray.begin(variableCount, variableList);
dataLogger.begin(LoggerID, loggingInterval, &varArray);
EnviroDIYPOST.begin(dataLogger, registrationToken, samplingFeature);
// Begin the logger
dataLogger.begin();

// Note: Please change these battery voltages to match your battery
// Check that the battery is OK before powering the modem
Expand Down
93 changes: 49 additions & 44 deletions examples/DRWI_LTE/DRWI_LTE.ino
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ const int8_t modemStatusPin = 19; // MCU pin used to read modem status (-1 if
HardwareSerial &modemSerial = Serial1; // Use hardware serial if possible

// Create a TinyGSM modem to run on that serial port
TinyGsm tinyModem(modemSerial);
TinyGsm *tinyModem = new TinyGsm(modemSerial);

// Create a TCP client on that modem
TinyGsmClient tinyClient(tinyModem);
// Create a new TCP client on that modem and return a pointer to it
TinyGsmClient *tinyClient = new TinyGsmClient(*tinyModem);


// ==========================================================================
Expand All @@ -119,7 +119,10 @@ bool modemSleepFxn(void)
digitalWrite(redLED, LOW);
return true;
}
else return true;
else
{
return true;
}
}
bool modemWakeFxn(void)
{
Expand All @@ -131,36 +134,39 @@ bool modemWakeFxn(void)
digitalWrite(redLED, HIGH); // Because the XBee doesn't have any lights
return true;
}
else return true;
else
{
return true;
}
}
// An extra function to set up pin sleep and other preferences on the XBee
// NOTE: This will only succeed if the modem is turned on and awake!
void setupXBee(void)
void extraModemSetup(void)
{
delay(1000); // Guard time for command mode
tinyModem.streamWrite(GF("+++")); // enter command mode
tinyModem.waitResponse(2000, F("OK\r"));
tinyModem.sendAT(F("SM"),1); // Pin sleep
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("DO"),0); // Disable remote manager, USB Direct, and LTE PSM
tinyModem->streamWrite(GF("+++")); // enter command mode
tinyModem->waitResponse(2000, F("OK\r"));
tinyModem->sendAT(F("SM"),1); // Pin sleep
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("DO"),0); // Disable remote manager, USB Direct, and LTE PSM
// NOTE: LTE-M's PSM (Power Save Mode) sounds good, but there's no
// easy way on the LTE-M Bee to wake the cell chip itself from PSM,
// so we'll use the Digi pin sleep instead.
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("SO"),0); // For Cellular - disconnected sleep
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("N#"),2); // Cellular network technology - LTE-M Only
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("SO"),0); // For Cellular - disconnected sleep
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("N#"),2); // Cellular network technology - LTE-M Only
// LTE-M XBee connects much faster on AT&T/Hologram when set to LTE-M only (instead of LTE-M/NB IoT)
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("AP5")); // Turn on bypass mode
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("WR")); // Write changes to flash
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("AC")); // Apply changes
tinyModem.waitResponse(F("OK\r"));
tinyModem.sendAT(F("FR")); // Force reset to enter bypass mode
tinyModem.waitResponse(F("OK\r"));
tinyModem.init(); // initialize
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("AP5")); // Turn on bypass mode
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("WR")); // Write changes to flash
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("AC")); // Apply changes
tinyModem->waitResponse(F("OK\r"));
tinyModem->sendAT(F("FR")); // Force reset to enter bypass mode
tinyModem->waitResponse(F("OK\r"));
tinyModem->init(); // initialize
}


Expand All @@ -174,7 +180,7 @@ const char *apn = "hologram"; // The APN for the gprs connection, unnecessary f

// Create the loggerModem instance
// A "loggerModem" is a combination of a TinyGSM Modem, a Client, and functions for wake and sleep
loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, modemSleepFxn, &tinyModem, &tinyClient, apn);
loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, modemSleepFxn, tinyModem, tinyClient, apn);
// ^^ Use this for cellular


Expand All @@ -183,7 +189,7 @@ loggerModem modem(modemVccPin, modemStatusPin, modemStatusLevel, modemWakeFxn, m
// ==========================================================================
#include <sensors/MaximDS3231.h>

// Create the DS3231 sensor object
// Create a DS3231 sensor object
MaximDS3231 ds3231(1);


Expand All @@ -201,7 +207,7 @@ const float OBSLow_A = 0.000E+00; // The "A" value (X^2) from the low range cal
const float OBSLow_B = 1.000E+00; // The "B" value (X) from the low range calibration
const float OBSLow_C = 0.000E+00; // The "C" value from the low range calibration

// Create the Campbell OBS3+ LOW RANGE sensor object
// Create a Campbell OBS3+ LOW RANGE sensor object
CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C, ADSi2c_addr, OBS3numberReadings);


Expand All @@ -211,7 +217,7 @@ const float OBSHigh_A = 0.000E+00; // The "A" value (X^2) from the high range c
const float OBSHigh_B = 1.000E+00; // The "B" value (X) from the high range calibration
const float OBSHigh_C = 0.000E+00; // The "C" value from the high range calibration

// Create the Campbell OBS3+ HIGH RANGE sensor object
// Create a Campbell OBS3+ HIGH RANGE sensor object
CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B, OBSHigh_C, ADSi2c_addr, OBS3numberReadings);


Expand All @@ -225,7 +231,7 @@ const uint8_t CTDnumberReadings = 6; // The number of readings to average
const int8_t SDI12Power = sensorPowerPin; // Pin to switch power on and off (-1 if unconnected)
const int8_t SDI12Data = 7; // The SDI12 data pin

// Create the Decagon CTD sensor object
// Create a Decagon CTD sensor object
DecagonCTD ctd(*CTDSDI12address, SDI12Power, SDI12Data, CTDnumberReadings);


Expand All @@ -249,16 +255,16 @@ Variable *variableList[] = {
int variableCount = sizeof(variableList) / sizeof(variableList[0]);

// Create the VariableArray object
VariableArray varArray;
VariableArray varArray(variableCount, variableList);


// ==========================================================================
// The Logger Object[s]
// ==========================================================================
#include <LoggerBase.h>

// Create a logger instance
Logger dataLogger;
// Create a new logger instance
Logger dataLogger(LoggerID, loggingInterval, sdCardPin, wakePin, &varArray);


// ==========================================================================
Expand All @@ -271,7 +277,7 @@ const char *samplingFeature = "12345678-abcd-1234-efgh-1234567890ab"; // Sam

// Create a data publisher for the EnviroDIY/WikiWatershed POST endpoint
#include <publishers/EnviroDIYPublisher.h>
EnviroDIYPublisher EnviroDIYPOST;
EnviroDIYPublisher EnviroDIYPOST(dataLogger, registrationToken, samplingFeature);


// ==========================================================================
Expand Down Expand Up @@ -362,12 +368,11 @@ void setup()

// Attach the modem and information pins to the logger
dataLogger.attachModem(modem);
dataLogger.setLoggerPins(sdCardPin, wakePin, greenLED, buttonPin);
dataLogger.setAlertPin(greenLED);
dataLogger.setTestingModePin(buttonPin);

// Begin the variable array[s], logger[s], and publisher[s]
varArray.begin(variableCount, variableList);
dataLogger.begin(LoggerID, loggingInterval, &varArray);
EnviroDIYPOST.begin(dataLogger, registrationToken, samplingFeature);
// Begin the logger
dataLogger.begin();

// Note: Please change these battery voltages to match your battery
// Check that the battery is OK before powering the modem
Expand All @@ -376,11 +381,10 @@ void setup()
modem.modemPowerUp();
modem.wake();

// Extra pre-set-up for the XBee
Serial.println(F("Setting up sleep mode on the XBee."));
modem.modemPowerUp();
modem.wake(); // Turn it on to talk
setupXBee();
// Run any extra pre-set-up for the modem
Serial.println(F("Running extra modem pre-setup"));
extraModemSetup();
modem.setup();

// At very good battery voltage, or with suspicious time stamp, sync the clock
// Note: Please change these battery voltages to match your battery
Expand Down Expand Up @@ -418,6 +422,7 @@ void setup()
}

// Call the processor sleep
Serial.println(F("Putting processor to sleep"));
dataLogger.systemSleep();
}

Expand Down
Loading

2 comments on commit b1a619e

@SRGDamia1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nearly ever forum and tutorial I've read warns not to use "new" to create objects in Arduino code. Especially if used creating objects in the loop, it could lead to lots of space being taken by objects that are never destroyed which would eventually cause the whole thing to crash because it's out of memory. The modular sensors code has been using "new" for ages to create the sensors and variables at the global scope (not in the loop) and it's never been a problem.

Forums also caution against any constructors that require arguments or call any arguments within the code of the constructor. This is because the order in which objects are created in memory (and assigned an address) cannot be controlled and "may possibly change in future versions." So, potentially, a constructor calling external values (as input arguments) or functions may end up trying to call something that doesn't yet exist. This is why most Arduino classes have useless constructors and require a "begin" function of some sort to do anything. Again, I'd written modular sensors to do all kinds of object linking in the constructor and it's been working fine.

Anyway... so someone pointed out on one of the forums that there was an issue with calculated variables not working. I started looking into it and turned on all kinds of debugging and saw all sorts of objects being recreated where they shouldn't have been right before things crashed and got paranoid that it was one of the two problems above. So I started rewriting everything to have empty constructors and begin functions. Turns out, nope, that was never the problem. It was an attempt to call to a null pointer of the non-existent parent sensor of the calculated variable that I'd missed in one of the timing loops. Ugh. (53a96a3)

Anyway, since I'd done so much work in writing everything to be more "compiler safe" I thought I'd make it backwards compatible (so able to call either a useless (safe) or useful (possibly unsafe) constructor) and I'd do some testing. Well.. after a lot of ironing out bugs, it turns out that.. I can get it to compile either way, it works either way, and contrary to much advice, the compiled program is actually slightly smaller and there is slightly more free RAM available when objects are created via calls to the "new" operator. Go figure. So I'm setting up most of the examples to do things the "unsafe" way and leaving code in place so if things change for some future compiler version or processor, it's ready to go.

@neilh10
Copy link
Contributor

@neilh10 neilh10 commented on b1a619e Mar 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey thanks for the explanation. Embedded C++ has been on quite a journey to describe what is "safe" -and extremely valuable part of arduino discussion is the detail how it operates and problems to be aware with constructor chains.

The really value in any embedded software - especially as it gets larger is ...... testing ..... testing .... and that with good stable tools, and maintains system stability.

IMHO there is value in the process you've gone through, as it can be used to managed the initialization of the machine better.... but that's a very deep subject ...

again many thanks for sharing.

Please sign in to comment.