44#include < stdlib.h>
55
66#include " UIState/MainMenu.h"
7+ #include " UIState/ResetEEPROM.h"
78#include " UIState/UIState.h"
89#include " Version.h"
910#include " model/DataLogger.h"
2728
2829const char TANK_CONTROLLER_VERSION [] = VERSION ;
2930
31+ // ------------ Early Boot Watchdog Disable ------------
32+ /* *
33+ * Disable the watchdog timer immediately on boot, before main()/setup() runs.
34+ *
35+ * After a watchdog reset on AVR, the WDT remains enabled with whatever timeout
36+ * triggered the reset (e.g. the 15 ms used by ResetEEPROM). The stock Mega2560
37+ * bootloader does not clear MCUSR or call wdt_disable(), and it takes longer
38+ * than 15 ms to hand control to the sketch -- so the WDT fires again inside
39+ * the bootloader, looping forever and appearing as a "freeze." Clearing MCUSR
40+ * and disabling the WDT from .init3 runs before the C runtime / main() and
41+ * breaks that loop. See avr-libc <avr/wdt.h> documentation.
42+ */
43+ #if !defined(ARDUINO_CI_COMPILATION_MOCKS)
44+ void disableWatchdogAtBoot (void ) __attribute__((naked, used, section(" .init3" )));
45+ void disableWatchdogAtBoot (void ) {
46+ MCUSR = 0 ;
47+ wdt_disable ();
48+ }
49+ #endif
50+
3051// ------------ Class Methods ------------
3152/* *
3253 * static variable to hold singleton
3354 */
34- TankController * TankController::_instance = nullptr ;
55+ TankController* TankController::_instance = nullptr ;
3556
3657/* *
3758 * static function to return singleton
3859 */
39- TankController * TankController::instance (const char * remoteLogName, const char * pushingBoxID, int tzOffsetHrs) {
60+ TankController* TankController::instance (const char * remoteLogName, const char * pushingBoxID, int tzOffsetHrs) {
4061 if (!_instance) {
4162 serial (F (" \r\n ##############\r\n TankController %s" ), TANK_CONTROLLER_VERSION );
4263 _instance = new TankController ();
4364 SD_TC::instance ();
4465 RemoteLogPusher::instance ()->setRemoteLogName (remoteLogName);
4566 EEPROM_TC::instance ();
4667 Keypad_TC::instance ();
68+ char key = Keypad_TC::instance ()->getKey ();
69+ if (key == ' 1' ) {
70+ EEPROM_TC::instance ()->setEEPROMAccessEnabled (false );
71+ serial (F (" EEPROM access disabled" ));
72+ };
4773 LiquidCrystal_TC::instance (TANK_CONTROLLER_VERSION );
4874 DataLogger::instance ();
4975 DateTime_TC::rtc ();
50- Ethernet_TC::instance ();
76+ Ethernet_TC::instance (key == NO_KEY ? ( long ) 60000 : ( long ) 1 ); // if a key is held, use a short timeout
5177 EthernetServer_TC::instance ();
5278 ThermalProbe_TC::instance ();
5379 ThermalControl::instance ();
@@ -56,6 +82,9 @@ TankController *TankController::instance(const char *remoteLogName, const char *
5682 PID_TC::instance ();
5783 pinMode (LED_BUILTIN , OUTPUT );
5884 _instance->state = new MainMenu ();
85+ if (key == ' 1' ) {
86+ _instance->setNextState (new ResetEEPROM ());
87+ }
5988 PushingBox::instance (pushingBoxID);
6089 GetTime::instance (tzOffsetHrs);
6190 serial (F (" Free memory = %i" ), _instance->freeMemory ());
@@ -114,7 +143,7 @@ int TankController::freeMemory() {
114143#if defined(ARDUINO_CI_COMPILATION_MOCKS)
115144 return 1024 ;
116145#else
117- extern char * __brkval;
146+ extern char * __brkval;
118147 int topOfStack;
119148
120149 return (int )((size_t )&topOfStack) - ((size_t )__brkval);
@@ -146,7 +175,7 @@ void TankController::handleUI() {
146175 // we already have a next state teed-up, do don't try to return to main menu
147176 } else if (millis () - lastKeypadTime > IDLE_TIMEOUT ) {
148177 // time since last keypress exceeds the idle timeout, so return to main menu
149- setNextState ((UIState *)new MainMenu ());
178+ setNextState ((UIState*)new MainMenu ());
150179 lastKeypadTime = 0 ; // so we don't do this until another keypress!
151180 }
152181 } else {
@@ -211,7 +240,7 @@ void TankController::serialEvent1() {
211240/* *
212241 * Set the next state
213242 */
214- void TankController::setNextState (UIState * newState, bool update) {
243+ void TankController::setNextState (UIState* newState, bool update) {
215244 assert (nextState == nullptr );
216245 nextState = newState;
217246 if (update) {
@@ -231,7 +260,7 @@ void TankController::setup() {
231260 * Public member function used to get the current state name.
232261 * This is primarily used by testing.
233262 */
234- const __FlashStringHelper * TankController::stateName () {
263+ const __FlashStringHelper* TankController::stateName () {
235264 return state->name ();
236265}
237266
@@ -262,13 +291,13 @@ void TankController::updateState() {
262291/* *
263292 * What is the current version?
264293 */
265- const char * TankController::version () {
294+ const char * TankController::version () {
266295 return TANK_CONTROLLER_VERSION ;
267296}
268297
269298#if defined(__CYGWIN__)
270- size_t strnlen (const char * s, size_t n) {
271- void * found = memchr (s, ' \0 ' , n);
272- return found ? (size_t )((char *)found - s) : n;
299+ size_t strnlen (const char * s, size_t n) {
300+ void * found = memchr (s, ' \0 ' , n);
301+ return found ? (size_t )((char *)found - s) : n;
273302}
274303#endif
0 commit comments