System (pocketmage_sys, pocketmage_globals)
System API
The system module owns the board bring-up, the CPU clock, deep sleep, the power button, and the shared globals (battState, allLines, CurrentAppState, the SPI buses, and NVS prefs). Apps use it for power management and boot-time configuration; the OS uses it for full bring-up.
Access
#include <pocketmage.h>
Shared globals
pocketmage_globals defines the state both the OS and apps link against.
SPI and filesystem
extern SPIClass* vspi; // the global SPI on SPI_SCK/SPI_MOSI
extern SPIClass* hspi;
extern fs::FS* global_fs; // active filesystem (SD_MMC or SD)
PocketMage_INIT wires vspi = &SPI and pins the pins documented in configuration.
NVS
extern Preferences prefs; // "PocketMage" namespace
The shared Preferences handle. pocketmage::loadSettings() reads the persistent toggles into the config.h globals (TIMEOUT, SAVE_POWER, FAST_REFRESH, OLED_BRIGHTNESS, the UI language, …); an app that reads preferences uses prefs directly with the same namespace.
App state
enum AppState { HOME, TXT, FILEWIZ, USB_APP, COMM, SETTINGS, TASKS,
CALENDAR, JOURNAL, LEXICON, APPLOADER, TERMINAL,
ONBOARDING, ELFAPP };
extern AppState CurrentAppState;
The OS’s app dispatch enum. ELFAPP is the state set while a loaded ELF app is running; the OS restores HOME when it exits.
Keyboard state
enum KBState { NORMAL, SHIFT, FUNC, FN_SHIFT };
The keyboard modifier state, mirrored by KB().setKeyboardState().
pocketmage:: namespace
namespace pocketmage {
void loadSettings(); // load NVS settings into the config.h globals
void recoverFromCrash(); // reset app state after a panic/watchdog
void checkRTCPowerLoss(); // baseline the RTC when it has lost power
}
loadSettings()reads every persistent toggle fromprefsand sets the UI language. Apps call it duringAPP_INIT(the OS reaches it viaPocketMage_INITon the host path).recoverFromCrash()checks the ESP reset reason and, on panic or watchdog reset, resetsCurrentAppStatetoHOMEand clears the editing-file pointer so the device boots clean.checkRTCPowerLoss()re-baselines the RTC when its power was lost.
Battery helper
inline float getBatteryVoltage() {
return (analogRead(BAT_SENS) * (3.3 / 4095.0) * 2) + 0.2;
}
battState (0 through 5) indexes the battery bitmaps used by the OLED status line (oled, assets).
CPU speed
void pocketmage::setCpuSpeed(int newFreq);
Clamps to the valid S3 frequencies {240, 160, 80, 40, 20, 10} and returns early if the CPU is already there. WiFi stalls below 240 MHz on the S3, so a request that would drop the clock below WIFI_CPU_FREQ_MHZ (240) while P_WIFI is not Off is ignored. POWER_SAVE_FREQ (40) is the OS’s idle speed; sysMessage and the WiFi service bump back to 240 when they need it.
Scope guard
class pocketmage::ScopedCpuBoost {
public:
ScopedCpuBoost(); // raises to 240 MHz if not already there
~ScopedCpuBoost(); // restores the previous frequency
};
Non-copyable RAII. Usable as a stack local around a latency-critical section.
Deep sleep
void pocketmage::deepSleep(bool alternateScreenSaver = false);
Full power-down sequence:
- Power-saves the OLED.
- Stops the
einkHandlerTaskunder the panel lock, so an in-flight refresh completes. - Plays
Jingles::Shutdown. - Draws a screensaver (custom
/assets/backgrounds/*.bin, else a random built-in) at rotation 3, or the alternate screensaver when asked.SAVE_POWERdrops the CPU toPOWER_SAVE_FREQfor the draw. - Clears the buffer, hibernates the panel, unlocks it.
- Persists
CurrentAppState, the editing file, and clears the seamless reboot flag. - On production hardware, isolates the peripheral pins with
setLoadSwitch(false)(GPIO hold +gpio_deep_sleep_hold_en). esp_deep_sleep_start().
Wake is on the KB_IRQ falling edge (configured in PocketMage_INIT). Resume re-runs PocketMage_INIT, which clears the pin holds and re-inits peripherals.
Power button
void IRAM_ATTR pocketmage::PWR_BTN_irq();
extern volatile bool PWR_BTN_event;
The FALLING-edge interrupt service routine sets PWR_BTN_event. The OS consumes it for wake/shutdown handling; holding PWR_BTN for 3 seconds while awake raises the hard-reset-to-home path (resetRequested, see the hardReset task). SDActive, mscEnabled, and sinkEnabled are the status-line indicators apps toggle for long I/O.
Bring-up
void PocketMage_INIT();
The one-call bring-up: release GPIO holds, enable the load switch (production), read the seamless reboot flag, FontEngine::init(), Serial, Wire (plus Wire1 on production), the global SPI, the keyboard wake pin, setupOled(), setupKB(), setupEink(), setupSD(), power-button interrupt + MP2722 power init, the hard-reset task, the power-save clock, setupTouch(), setupClock(), the random seed, settings load, crash recovery, setupBZ() + startup jingle, the WiFi service (host only), key flush, then the app hook APP_INIT() (app builds). Apps do not call it; it runs as part of the OS or the app entry shim.
Text line buffer
extern volatile bool resetRequested;
extern volatile bool newLineAdded;
extern std::vector<String> allLines; // the text editor's line list
extern bool noTimeout;
extern void setLoadSwitch(bool state);
allLines is the shared text buffer the OS’s TXT flow and vectorToString / stringToVector operate on; noTimeout suppresses the auto-sleep timeout. setLoadSwitch(false) is the production deep-sleep pin isolation path described above.
Example
#include <pocketmage.h>
void onUserExit() {
{
pocketmage::ScopedCpuBoost boost; // 240 MHz for the save
// write the document...
} // back to the previous speed
pocketmage::deepSleep(); // and go to sleep
}