diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f6ba28193c..1586712eb2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -31,6 +31,13 @@ static_assert(MAX_NUM_SEGMENTS >= WLED_MAX_BUSSES, "Max segments must be at least max number of busses!"); +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// json.cpp only ever reads it for status reporting, so it gets a by-value +// getter rather than a mutable reference. +static uint8_t currentLedmap = 0; +uint8_t getCurrentLedmap() { return currentLedmap; } + /////////////////////////////////////////////////////////////////////////////// // Segment class implementation diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 18327eb877..8f91d36663 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -122,6 +122,7 @@ bool writeObjectToFile(const char* file, const char* key, const JsonDocument* co bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest, const JsonDocument* filter = nullptr); bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, const JsonDocument* filter = nullptr); void updateFSInfo(); +bool isDoCloseFile(); void closeFile(); inline bool writeObjectToFileUsingId(const String &file, uint16_t id, const JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); }; inline bool writeObjectToFile(const String &file, const char* key, const JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); }; @@ -134,6 +135,9 @@ bool checkBackupExists(const char* filename); bool validateJsonFile(const char* filename); void dumpFilesToSerial(); +//FX_fcn.cpp +uint8_t getCurrentLedmap(); + //hue.cpp void handleHue(); void reconnectHue(); @@ -141,6 +145,9 @@ void onHueError(void* arg, AsyncClient* client, int8_t error); void onHueConnect(void* arg, AsyncClient* client); void sendHuePoll(); void onHueData(void* arg, AsyncClient* client, void *data, size_t len); +#ifndef WLED_DISABLE_HUESYNC +byte getHueError(); +#endif //image_loader.cpp class Segment; @@ -169,6 +176,7 @@ void sendImprovInfoResponse(); void startImprovWifiScan(); void handleImprovWifiScan(); void sendImprovIPRPCResult(ImprovRPCType type); +byte getImprovError(); //ir.cpp void initIR(); @@ -205,6 +213,7 @@ void updateInterfaces(uint8_t callMode); void handleTransitions(); void handleNightlight(); byte scaledBri(byte in); +uint32_t getNightlightDelayMs(); #ifdef WLED_ENABLE_LOXONE //lx_parser.cpp @@ -294,6 +303,14 @@ bool isAsterisksOnly(const char* str, byte maxLen); void handleSettingsSet(AsyncWebServerRequest *request, byte subPage); bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true); +//wled.cpp +int8_t getSelectedWiFi(); +bool isSerialCanRX(); +uint16_t getNtpLocalPort(); +#ifndef WLED_DISABLE_ESPNOW +byte getStatusESPNow(); +#endif + //udp.cpp void notify(byte callMode, bool followUp=false); uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false); @@ -438,6 +455,11 @@ void userLoop(); #define inoise8 perlin8 // fastled legacy alias #define inoise16 perlin16 // fastled legacy alias #define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0) +#if WLED_MAX_LEDMAPS>16 +uint32_t getLedMaps(); +#else +uint16_t getLedMaps(); +#endif [[gnu::pure]] int getNumVal(const String &req, uint16_t pos); void parseNumber(const char* str, byte &val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte &val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) diff --git a/wled00/file.cpp b/wled00/file.cpp index 5a169d6450..a9ad290b05 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -12,6 +12,13 @@ #define FS_BUFSIZE 256 +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// wled.cpp only ever reads it (to decide whether to call closeFile() from the +// main loop), so it gets a by-value getter rather than a mutable reference. +static bool doCloseFile = false; +bool isDoCloseFile() { return doCloseFile; } + /* * Structural requirements for files managed by writeObjectToFile() and readObjectFromFile() utilities: * 1. File must be a string representation of a valid JSON object diff --git a/wled00/hue.cpp b/wled00/hue.cpp index d5fcb7cb93..a58adf2ce3 100644 --- a/wled00/hue.cpp +++ b/wled00/hue.cpp @@ -6,6 +6,13 @@ #ifndef WLED_DISABLE_HUESYNC +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// xml.cpp only ever reads it for settings-page status reporting, so it gets +// a by-value getter rather than a mutable reference. +static byte hueError = HUE_ERROR_INACTIVE; +byte getHueError() { return hueError; } + void handleHue() { if (hueReceived) diff --git a/wled00/improv.cpp b/wled00/improv.cpp index ea2664a21d..a65d3960d1 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -10,6 +10,13 @@ #define DIMPROV_PRINTF(x...) #endif +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// wled.cpp only ever reads it (to decide whether to send an Improv RPC +// result), so it gets a by-value getter rather than a mutable reference. +static byte improvError = 0; +byte getImprovError() { return improvError; } + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32S3) // ToDO check if C6, C61, P4 support this #undef WLED_DISABLE_IMPROV_WIFISCAN #define WLED_DISABLE_IMPROV_WIFISCAN diff --git a/wled00/json.cpp b/wled00/json.cpp index d68b76f59b..0c32d6ccbe 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -658,7 +658,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme root["ps"] = (currentPreset > 0) ? currentPreset : -1; root[F("pl")] = currentPlaylist; - root[F("ledmap")] = currentLedmap; + root[F("ledmap")] = getCurrentLedmap(); UsermodManager::addToJsonState(root); @@ -667,7 +667,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme nl["dur"] = nightlightDelayMins; nl["mode"] = nightlightMode; nl[F("tbri")] = nightlightTargetBri; - nl[F("rem")] = nightlightActive ? (int)(nightlightDelayMs - (millis() - nightlightStartTime)) / 1000 : -1; // seconds remaining + nl[F("rem")] = nightlightActive ? (int)(getNightlightDelayMs() - (millis() - nightlightStartTime)) / 1000 : -1; // seconds remaining JsonObject udpn = root.createNestedObject("udpn"); udpn[F("send")] = sendNotificationsRT; @@ -809,7 +809,7 @@ void serializeInfo(JsonObject root) JsonArray ledmaps = root.createNestedArray(F("maps")); for (size_t i=0; i>i) & 0x00000001U) { + if ((getLedMaps()>>i) & 0x00000001U) { JsonObject ledmaps0 = ledmaps.createNestedObject(); ledmaps0["id"] = i; #ifndef ESP8266 diff --git a/wled00/led.cpp b/wled00/led.cpp index 131ff95bab..b96e5363d6 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -4,6 +4,13 @@ * LED methods */ +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// json.cpp only ever reads it for status reporting, so it gets a by-value +// getter rather than a mutable reference. +static uint32_t nightlightDelayMs = 10; +uint32_t getNightlightDelayMs() { return nightlightDelayMs; } + // applies chosen setment properties to legacy values void setValuesFromSegment(uint8_t s) { const Segment& seg = strip.getSegment(s); diff --git a/wled00/network.cpp b/wled00/network.cpp index eed19aaff3..e03cd5fda6 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -360,7 +360,7 @@ int findWiFi(bool doScan) { } else if (status >= 0) { // status contains number of found networks (including duplicate SSIDs with different BSSID) DEBUG_PRINTF_P(PSTR("WiFi: Found %d SSIDs. @ %lus\n"), status, millis()/1000); int rssi = -9999; - size_t selected = (static_cast(selectedWiFi) < multiWiFi.size()) ? static_cast(selectedWiFi) : 0; // ensure valid starting index + size_t selected = (static_cast(getSelectedWiFi()) < multiWiFi.size()) ? static_cast(getSelectedWiFi()) : 0; // ensure valid starting index for (int o = 0; o < status; o++) { DEBUG_PRINTF_P(PSTR(" SSID: %s (BSSID: %s) RSSI: %ddB\n"), WiFi.SSID(o).c_str(), WiFi.BSSIDstr(o).c_str(), WiFi.RSSI(o)); for (unsigned n = 0; n < multiWiFi.size(); n++) diff --git a/wled00/set.cpp b/wled00/set.cpp index dee8d00378..7ed2270cd1 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -559,7 +559,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) utcOffsetSecs = request->arg(F("UO")).toInt(); //start ntp if not already connected - if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); + if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(getNtpLocalPort()); ntpLastSyncTime = NTP_NEVER; // force new NTP query longitude = request->arg(F("LN")).toFloat(); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index ac5554df40..1a091e2883 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -150,7 +150,7 @@ void notify(byte callMode, bool followUp) //next value to be added has index: udpOut[offs + 0] #ifndef WLED_DISABLE_ESPNOW - if (enableESPNow && useESPNowSync && statusESPNow == ESP_NOW_STATE_ON) { + if (enableESPNow && useESPNowSync && getStatusESPNow() == ESP_NOW_STATE_ON) { partial_packet_t buffer = {'W', 0, 1, {0}}; // send global data DEBUG_PRINTLN(F("ESP-NOW sending first packet.")); diff --git a/wled00/util.cpp b/wled00/util.cpp index 8ac46c77df..649017cf84 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -684,6 +684,19 @@ um_data_t* simulateSound(uint8_t simulationId) return um_data; } +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// json.cpp only ever reads it for status reporting, so it gets a by-value +// getter rather than a mutable reference. Type matches the original +// WLED_MAX_LEDMAPS-dependent conditional. +#if WLED_MAX_LEDMAPS>16 +static uint32_t ledMaps = 0; // bitfield representation of available ledmaps +uint32_t getLedMaps() { return ledMaps; } +#else +static uint16_t ledMaps = 0; // bitfield representation of available ledmaps +uint16_t getLedMaps() { return ledMaps; } +#endif + static const char s_ledmap_tmpl[] PROGMEM = "ledmap%d.json"; // enumerate all ledmapX.json files on FS and extract ledmap names if existing void enumerateLedmaps() { diff --git a/wled00/wled.cpp b/wled00/wled.cpp index d5125c30e2..5ad2d45f0f 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -25,6 +25,25 @@ #endif extern "C" void usePWMFixedNMI(); +// Runtime state private to this file - previously WLED_GLOBAL, a leftover from +// when all state lived in one big extern block regardless of who used it. +// Each is read-only from outside this file, so each gets a by-value getter +// rather than a mutable reference: an accidental write from elsewhere is now +// a build error instead of a silent bug. +static int8_t selectedWiFi = 0; +static bool serialCanRX = false; +// nobody in the codebase writes ntpLocalPort at runtime beyond this default, +// so it's a constexpr rather than a mutable static. +static constexpr uint16_t ntpLocalPort = 2390; +int8_t getSelectedWiFi() { return selectedWiFi; } +bool isSerialCanRX() { return serialCanRX; } +uint16_t getNtpLocalPort() { return ntpLocalPort; } + +#ifndef WLED_DISABLE_ESPNOW +static byte statusESPNow = ESP_NOW_STATE_UNINIT; // state of ESP-NOW stack (0 uninitialised, 1 initialised, 2 error) +byte getStatusESPNow() { return statusESPNow; } +#endif + /* * Main WLED class implementation. Mostly initialization and connection logic */ @@ -113,7 +132,7 @@ void WLED::loop() handleAlexa(); #endif - if (doCloseFile) { + if (isDoCloseFile()) { closeFile(); yield(); } @@ -1069,7 +1088,7 @@ void WLED::handleConnection() #endif if (improvActive) { - if (improvError == 3) sendImprovStateResponse(0x00, true); + if (getImprovError() == 3) sendImprovStateResponse(0x00, true); sendImprovStateResponse(0x04); if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi); } diff --git a/wled00/wled.h b/wled00/wled.h index 9bafb49196..ebf1c51e03 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -342,7 +342,7 @@ WLED_GLOBAL std::vector multiWiFi; WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) -WLED_GLOBAL int8_t selectedWiFi _INIT(0); +// selectedWiFi is private to wled.cpp - use getSelectedWiFi() instead. WLED_GLOBAL byte apChannel _INIT(6); // 2.4GHz WiFi AP channel (1-13) WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default @@ -512,12 +512,12 @@ WLED_GLOBAL bool hueApplyColor _INIT(true); #endif WLED_GLOBAL uint16_t serialBaud _INIT(1152); // serial baud rate, multiply by 100 -WLED_GLOBAL bool serialCanRX _INIT(false); +// serialCanRX is private to wled.cpp - use isSerialCanRX() instead. WLED_GLOBAL bool serialCanTX _INIT(false); #ifndef WLED_DISABLE_ESPNOW WLED_GLOBAL bool enableESPNow _INIT(false); // global on/off for ESP-NOW -WLED_GLOBAL byte statusESPNow _INIT(ESP_NOW_STATE_UNINIT); // state of ESP-NOW stack (0 uninitialised, 1 initialised, 2 error) +// statusESPNow is private to wled.cpp - use getStatusESPNow() instead. WLED_GLOBAL bool useESPNowSync _INIT(false); // use ESP-NOW wireless technology for sync //WLED_GLOBAL char linked_remote[13] _INIT(""); // MAC of ESP-NOW remote (Wiz Mote) WLED_GLOBAL std::vector> linked_remotes; // MAC of ESP-NOW remotes (Wiz Mote) @@ -603,7 +603,7 @@ WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmon // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); WLED_GLOBAL bool nightlightActiveOld _INIT(false); -WLED_GLOBAL uint32_t nightlightDelayMs _INIT(10); +// nightlightDelayMs is private to led.cpp - use getNightlightDelayMs() instead. WLED_GLOBAL byte nightlightDelayMinsDefault _INIT(nightlightDelayMins); WLED_GLOBAL unsigned long nightlightStartTime; WLED_GLOBAL unsigned long lastNlUpdate; @@ -691,7 +691,7 @@ WLED_GLOBAL bool showWelcomePage _INIT(false); // hue #ifndef WLED_DISABLE_HUESYNC -WLED_GLOBAL byte hueError _INIT(HUE_ERROR_INACTIVE); +// hueError is private to hue.cpp - use getHueError() instead. // WLED_GLOBAL uint16_t hueFailCount _INIT(0); WLED_GLOBAL float hueXLast _INIT(0), hueYLast _INIT(0); WLED_GLOBAL uint16_t hueHueLast _INIT(0), hueCtLast _INIT(0); @@ -712,7 +712,7 @@ WLED_GLOBAL bool doAdvancePlaylist _INIT(false); //improv WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning -WLED_GLOBAL byte improvError _INIT(0); +// improvError is private to improv.cpp - use getImprovError() instead. //playlists WLED_GLOBAL int16_t currentPlaylist _INIT(-1); @@ -757,7 +757,7 @@ WLED_GLOBAL time_t localTime _INIT(0); WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(NTP_NEVER); WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(NTP_NEVER); WLED_GLOBAL IPAddress ntpServerIP; -WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390); +// ntpLocalPort is private to wled.cpp - use getNtpLocalPort() instead. WLED_GLOBAL uint16_t rolloverMillis _INIT(0); WLED_GLOBAL float longitude _INIT(WLED_LON); WLED_GLOBAL float latitude _INIT(WLED_LAT); @@ -769,7 +769,7 @@ WLED_GLOBAL Toki toki _INIT(Toki()); WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0); WLED_GLOBAL unsigned long presetsModifiedTime _INIT(0L); -WLED_GLOBAL bool doCloseFile _INIT(false); +// doCloseFile is private to file.cpp - use isDoCloseFile() instead. // presets WLED_GLOBAL byte currentPreset _INIT(0); @@ -811,15 +811,11 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); WLED_GLOBAL std::vector busConfigs; //temporary, to remember values from network callback until after WLED_GLOBAL bool doInitBusses _INIT(false); WLED_GLOBAL int8_t loadLedmap _INIT(-1); -WLED_GLOBAL uint8_t currentLedmap _INIT(0); +// currentLedmap is private to FX_fcn.cpp - use getCurrentLedmap() instead. #ifndef ESP8266 WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr})); #endif -#if WLED_MAX_LEDMAPS>16 -WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available ledmaps -#else -WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps -#endif +// ledMaps is private to util.cpp - use getLedMaps() instead. // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN diff --git a/wled00/wled_serial.cpp b/wled00/wled_serial.cpp index dd04788df3..589ff3440c 100644 --- a/wled00/wled_serial.cpp +++ b/wled00/wled_serial.cpp @@ -72,7 +72,7 @@ static void sendBytes(){ void handleSerial() { - if (!(serialCanRX && Serial)) return; // arduino docs: `if (Serial)` indicates whether or not the USB CDC serial connection is open. For all non-USB CDC ports, this will always return true + if (!(isSerialCanRX() && Serial)) return; // arduino docs: `if (Serial)` indicates whether or not the USB CDC serial connection is open. For all non-USB CDC ports, this will always return true static auto state = AdaState::Header_A; static uint16_t count = 0; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 04d57ebeb7..720bc34276 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -571,7 +571,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormCheckbox(settingsScript,PSTR("HB"),hueApplyBri); printSetFormCheckbox(settingsScript,PSTR("HC"),hueApplyColor); char hueErrorString[25]; - switch (hueError) + switch (getHueError()) { case HUE_ERROR_INACTIVE : strcpy_P(hueErrorString,PSTR("Inactive")); break; case HUE_ERROR_ACTIVE : strcpy_P(hueErrorString,PSTR("Active")); break; @@ -580,7 +580,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) case HUE_ERROR_PUSHLINK : strcpy_P(hueErrorString,PSTR("Link button not pressed")); break; case HUE_ERROR_JSON_PARSING : strcpy_P(hueErrorString,PSTR("JSON parsing error")); break; case HUE_ERROR_TIMEOUT : strcpy_P(hueErrorString,PSTR("Timeout")); break; - default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),hueError); + default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),getHueError()); } printSetClassElementHTML(settingsScript,PSTR("sip"),0,hueErrorString);