Skip to content

Commit

Permalink
Bangle.js: Add Bangle.showRecoveryMenu, and if storage is corrupt the…
Browse files Browse the repository at this point in the history
…n show it rather than automatically doing factory reset
  • Loading branch information
gfwilliams committed Jun 5, 2023
1 parent 38cb910 commit 85872e6
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 49 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
2v19 : Fix Object.values/entries for numeric keys after 2v18 regression (fix #2375)
nRF52: for SD>5 use static buffers for advertising and scan response data (#2367)
Bangle.js: Add Bangle.showRecoveryMenu, and if storage is corrupt then show it rather than automatically doing factory reset

2v18 : Fix drawString with setClipRect with 90/270-degree rotation (fix #2343)
Pico/Wifi: Enabled JIT compiler
Expand Down
129 changes: 80 additions & 49 deletions libs/banglejs/jswrap_bangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -3388,6 +3388,8 @@ NO_INLINE void jswrap_banglejs_init() {
#endif
#endif

bool recoveryMode = false;

//jsiConsolePrintf("bangleFlags %d\n",bangleFlags);
if (firstRun) {
bangleFlags = JSBF_DEFAULT | JSBF_LCD_ON | JSBF_LCD_BL_ON; // includes bangleFlags
Expand All @@ -3396,6 +3398,13 @@ NO_INLINE void jswrap_banglejs_init() {
healthStateClear(&healthCurrent);
healthStateClear(&healthLast);
healthStateClear(&healthDaily);

/* If first run and button is held down, enter recovery mode. During this
we will try not to access storage */
#ifndef DICKENS
if (jshPinGetValue(HOME_BTN_PININDEX))
recoveryMode = true;
#endif
}
bangleFlags |= JSBF_POWER_SAVE; // ensure we turn power-save on by default every restart
inactivityTimer = 0; // reset the LCD timeout timer
Expand All @@ -3417,65 +3426,67 @@ NO_INLINE void jswrap_banglejs_init() {
buzzAmt = 0;
beepFreq = 0;
// Read settings and change beep/buzz behaviour...
JsVar *settingsFN = jsvNewFromString("setting.json");
JsVar *settings = jswrap_storage_readJSON(settingsFN,true);
jsvUnLock(settingsFN);
JsVar *v;
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"beep") : 0;
if (v && jsvGetBool(v)==false) {
bangleFlags &= ~JSBF_ENABLE_BEEP;
} else {
bangleFlags |= JSBF_ENABLE_BEEP;
#ifdef SPEAKER_PIN
if (!v || jsvIsStringEqual(v,"vib")) // default to use vibration for beep
if (!recoveryMode) {
JsVar *settingsFN = jsvNewFromString("setting.json");
JsVar *settings = jswrap_storage_readJSON(settingsFN,true);
jsvUnLock(settingsFN);
JsVar *v;
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"beep") : 0;
if (v && jsvGetBool(v)==false) {
bangleFlags &= ~JSBF_ENABLE_BEEP;
} else {
bangleFlags |= JSBF_ENABLE_BEEP;
#ifdef SPEAKER_PIN
if (!v || jsvIsStringEqual(v,"vib")) // default to use vibration for beep
bangleFlags |= JSBF_BEEP_VIBRATE;
else
bangleFlags &= ~JSBF_BEEP_VIBRATE;
#else
bangleFlags |= JSBF_BEEP_VIBRATE;
else
bangleFlags &= ~JSBF_BEEP_VIBRATE;
#else
bangleFlags |= JSBF_BEEP_VIBRATE;
#endif
}
jsvUnLock(v);
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"vibrate") : 0;
if (v && jsvGetBool(v)==false) {
bangleFlags &= ~JSBF_ENABLE_BUZZ;
} else {
bangleFlags |= JSBF_ENABLE_BUZZ;
}
jsvUnLock(v);
#endif
}
jsvUnLock(v);
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"vibrate") : 0;
if (v && jsvGetBool(v)==false) {
bangleFlags &= ~JSBF_ENABLE_BUZZ;
} else {
bangleFlags |= JSBF_ENABLE_BUZZ;
}
jsvUnLock(v);

// If enabled, load battery 'full' voltage
#ifdef ESPR_BATTERY_FULL_VOLTAGE
batteryFullVoltage = ESPR_BATTERY_FULL_VOLTAGE;
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"batFullVoltage") : 0;
if (jsvIsNumeric(v)) batteryFullVoltage = jsvGetFloatAndUnLock(v);
#endif // ESPR_BATTERY_FULL_VOLTAGE
// If enabled, load battery 'full' voltage
#ifdef ESPR_BATTERY_FULL_VOLTAGE
batteryFullVoltage = ESPR_BATTERY_FULL_VOLTAGE;
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"batFullVoltage") : 0;
if (jsvIsNumeric(v)) batteryFullVoltage = jsvGetFloatAndUnLock(v);
#endif // ESPR_BATTERY_FULL_VOLTAGE

// Load themes from the settings.json file
jswrap_banglejs_setTheme();
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"theme") : 0;
if (jsvIsObject(v)) {
graphicsTheme.fg = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fg"));
graphicsTheme.bg = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bg"));
graphicsTheme.fg2 = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fg2"));
graphicsTheme.bg2 = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bg2"));
graphicsTheme.fgH = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fgH"));
graphicsTheme.bgH = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bgH"));
graphicsTheme.dark = jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(v,"dark"));
}
jsvUnLock(v);
#ifdef TOUCH_DEVICE
// load touchscreen calibration
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"touch") : 0;
// Load themes from the settings.json file
jswrap_banglejs_setTheme();
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"theme") : 0;
if (jsvIsObject(v)) {
graphicsTheme.fg = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fg"));
graphicsTheme.bg = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bg"));
graphicsTheme.fg2 = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fg2"));
graphicsTheme.bg2 = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bg2"));
graphicsTheme.fgH = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"fgH"));
graphicsTheme.bgH = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"bgH"));
graphicsTheme.dark = jsvGetBoolAndUnLock(jsvObjectGetChildIfExists(v,"dark"));
}
jsvUnLock(v);
#ifdef TOUCH_DEVICE
// load touchscreen calibration
v = jsvIsObject(settings) ? jsvObjectGetChildIfExists(settings,"touch") : 0;
if (jsvIsObject(v)) {
touchMinX = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"x1"));
touchMinY = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"y1"));
touchMaxX = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"x2"));
touchMaxY = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(v,"y2"));
}
jsvUnLock(v);
#endif
#endif
jsvUnLock(settings);
} // recoveryMode

#ifdef LCD_WIDTH
// Just reset any graphics settings that may need updating
Expand Down Expand Up @@ -3519,7 +3530,7 @@ NO_INLINE void jswrap_banglejs_init() {
if (jsiStatus & JSIS_TODO_FLASH_LOAD) {
showSplashScreen = false;
#ifndef ESPR_NO_LOADING_SCREEN
if (!firstRun) {
if (!firstRun && !recoveryMode) {
// Display a loading screen
// Check for a '.loading' file
JsVar *img = jsfReadFile(jsfNameFromString(".loading"),0,0);
Expand Down Expand Up @@ -3559,6 +3570,8 @@ NO_INLINE void jswrap_banglejs_init() {
if (!(jsiStatus & JSIS_COMPLETELY_RESET))
showSplashScreen = false;
#endif
if (recoveryMode)
showSplashScreen = false;
if (showSplashScreen) {
graphicsInternal.data.fontSize = JSGRAPHICS_FONTSIZE_6X8+1; // 4x6 size is default
graphicsClear(&graphicsInternal);
Expand Down Expand Up @@ -3788,6 +3801,12 @@ NO_INLINE void jswrap_banglejs_init() {
if (!firstRun) {
jsvUnLock(jsiSetTimeout(jswrap_banglejs_postInit, 500));
}
#ifdef BANGLEJS
// If this is recovery mode schedule a call to Bangle.jswrap_banglejs_showRecoveryMenu
if (recoveryMode) {
jsvUnLock(jspEvaluate("setTimeout(Bangle.showRecoveryMenu,100)",true));
}
#endif
//jsiConsolePrintf("bangleFlags2 %d\n",bangleFlags);
}

Expand Down Expand Up @@ -5272,6 +5291,18 @@ application to launch.
Load the Bangle.js clock - this has the same effect as calling `Bangle.load()`.
*/

/*JSON{
"type" : "staticmethod",
"class" : "Bangle",
"name" : "showRecoveryMenu",
"generate_js" : "libs/js/banglejs/Bangle_showRecoveryMenu.js",
"ifdef" : "BANGLEJS"
}
Show a 'recovery' menu that allows you to perform certain tasks on your Bangle.
You can also enter this menu by restarting while holding down the `BTN1`
*/

/*JSON{
"type" : "staticmethod",
"class" : "Bangle",
Expand Down
45 changes: 45 additions & 0 deletions libs/js/banglejs/Bangle_showRecoveryMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
(function() {
clearTimeout();
clearInterval();
clearWatch();
Bangle.removeAllListeners();
E.removeAllListeners();
NRF.removeAllListeners();
E.showMenu({"":{title:"Recovery"},
"Attempt Compact": () => {
E.showMessage("Compacting...\nMay take\n5 min.");
if(!NRF.getSecurityStatus().connected)
Terminal.setConsole();
require("Storage").compact();
E.reboot();
},
"Rewrite bootloader": () => {
setTimeout(load,1000);
eval(require("Storage").read("bootupdate.js"));
},
"Factory Reset": () => {
E.showPrompt("Are you sure?\nThis will remove all data.",{title:"Factory Reset"}).then(ok => {
if (!ok) return Bangle.showRecoveryMenu();
E.showMessage("Resetting");
if(!NRF.getSecurityStatus().connected)
Terminal.setConsole();
Bangle.factoryReset();
});
},
"Clean Boot": () => {
reset();
},
"Reboot": () => {
E.reboot();
},
"Turn Off": () => {
Bangle.off();
},
"Exit": () => {
E.showMessage("Loading...");
if(!NRF.getSecurityStatus().connected)
Terminal.setConsole();
load();
},
});
})
13 changes: 13 additions & 0 deletions src/jsinteractive.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,9 @@ void jsiSemiInit(bool autoLoad, JsfFileName *loadedFilename) {
jsiStatus &= JSIS_SOFTINIT_MASK;
#ifndef SAVE_ON_FLASH
pinBusyIndicator = DEFAULT_BUSY_PIN_INDICATOR;
#endif
#ifdef BANGLEJS
bool recoveryMode = false;
#endif
// Set __FILE__ if we have a filename available
if (loadedFilename)
Expand All @@ -802,7 +805,12 @@ void jsiSemiInit(bool autoLoad, JsfFileName *loadedFilename) {
#endif
if (!jsfIsStorageValid(JSFSTT_NORMAL | JSFSTT_FIND_FILENAME_TABLE)) {
jsiConsolePrintf("Storage is corrupt.\n");
#ifdef BANGLEJS // On Bangle.js if Storage is corrupt, show a recovery menu
autoLoad = false; // don't load code
recoveryMode = true; // start recovery menu at end of init
#else
jsfResetStorage();
#endif
} else {
#ifdef BANGLEJS
jsiConsolePrintf("Storage Ok.\n");
Expand Down Expand Up @@ -876,6 +884,11 @@ void jsiSemiInit(bool autoLoad, JsfFileName *loadedFilename) {
jsiConsolePrint("\n"); // output new line
inputLineRemoved = true; // we need to put the input line back...
}

#ifdef BANGLEJS // On Bangle.js if Storage is corrupt, show a recovery menu
if (recoveryMode) // start recovery menu at end of init
jsvUnLock(jspEvaluate("setTimeout(Bangle.showRecoveryMenu,100)",true));
#endif
}

// The 'proper' init function - this should be called only once at bootup
Expand Down

0 comments on commit 85872e6

Please sign in to comment.