Merge remote-tracking branch 'upstream/0_15' into 0_15__speed_improvements

This commit is contained in:
Damian Schneider 2024-09-26 18:07:33 +02:00
commit c44b9f8659
53 changed files with 763 additions and 899 deletions

17
tools/all_xml.sh Normal file
View File

@ -0,0 +1,17 @@
#!/bin/bash
# Pull all settings pages for comparison
HOST=$1
TGT_PATH=$2
CURL_ARGS="--compressed"
# Replicate one target many times
function replicate() {
for i in {0..10}
do
echo -n " http://${HOST}/settings.js?p=$i -o ${TGT_PATH}/$i.xml"
done
}
read -a TARGETS <<< $(replicate)
mkdir -p ${TGT_PATH}
curl ${CURL_ARGS} ${TARGETS[@]}

View File

@ -332,7 +332,7 @@ class Animated_Staircase : public Usermod {
}; };
// NOTE: this *WILL* return TRUE if all the pins are set to -1. // NOTE: this *WILL* return TRUE if all the pins are set to -1.
// this is *BY DESIGN*. // this is *BY DESIGN*.
if (!pinManager.allocateMultiplePins(pins, 4, PinOwner::UM_AnimatedStaircase)) { if (!PinManager::allocateMultiplePins(pins, 4, PinOwner::UM_AnimatedStaircase)) {
topPIRorTriggerPin = -1; topPIRorTriggerPin = -1;
topEchoPin = -1; topEchoPin = -1;
bottomPIRorTriggerPin = -1; bottomPIRorTriggerPin = -1;
@ -513,10 +513,10 @@ class Animated_Staircase : public Usermod {
(oldBottomAPin != bottomPIRorTriggerPin) || (oldBottomAPin != bottomPIRorTriggerPin) ||
(oldBottomBPin != bottomEchoPin)) { (oldBottomBPin != bottomEchoPin)) {
changed = true; changed = true;
pinManager.deallocatePin(oldTopAPin, PinOwner::UM_AnimatedStaircase); PinManager::deallocatePin(oldTopAPin, PinOwner::UM_AnimatedStaircase);
pinManager.deallocatePin(oldTopBPin, PinOwner::UM_AnimatedStaircase); PinManager::deallocatePin(oldTopBPin, PinOwner::UM_AnimatedStaircase);
pinManager.deallocatePin(oldBottomAPin, PinOwner::UM_AnimatedStaircase); PinManager::deallocatePin(oldBottomAPin, PinOwner::UM_AnimatedStaircase);
pinManager.deallocatePin(oldBottomBPin, PinOwner::UM_AnimatedStaircase); PinManager::deallocatePin(oldBottomBPin, PinOwner::UM_AnimatedStaircase);
} }
if (changed) setup(); if (changed) setup();
} }

View File

@ -18,7 +18,7 @@ Before compiling, you have to make the following modifications:
Edit `usermods_list.cpp`: Edit `usermods_list.cpp`:
1. Open `wled00/usermods_list.cpp` 1. Open `wled00/usermods_list.cpp`
2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file 2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file
3. add `usermods.add(new Animated_Staircase());` to the end of the `void registerUsermods()` function. 3. add `UsermodManager::add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
You can configure usermod using the Usermods settings page. You can configure usermod using the Usermods settings page.
Please enter GPIO pins for PIR or ultrasonic sensors (trigger and echo). Please enter GPIO pins for PIR or ultrasonic sensors (trigger and echo).

View File

@ -200,7 +200,7 @@ class UsermodBattery : public Usermod
bool success = false; bool success = false;
DEBUG_PRINTLN(F("Allocating battery pin...")); DEBUG_PRINTLN(F("Allocating battery pin..."));
if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0) if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0)
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) { if (PinManager::allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
DEBUG_PRINTLN(F("Battery pin allocation succeeded.")); DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
success = true; success = true;
} }
@ -561,7 +561,7 @@ class UsermodBattery : public Usermod
if (newBatteryPin != batteryPin) if (newBatteryPin != batteryPin)
{ {
// deallocate pin // deallocate pin
pinManager.deallocatePin(batteryPin, PinOwner::UM_Battery); PinManager::deallocatePin(batteryPin, PinOwner::UM_Battery);
batteryPin = newBatteryPin; batteryPin = newBatteryPin;
// initialise // initialise
setup(); setup();

View File

@ -71,7 +71,7 @@ class MyExampleUsermod : public Usermod {
// #endif // #endif
// in setup() // in setup()
// #ifdef USERMOD_EXAMPLE // #ifdef USERMOD_EXAMPLE
// UM = (MyExampleUsermod*) usermods.lookup(USERMOD_ID_EXAMPLE); // UM = (MyExampleUsermod*) UsermodManager::lookup(USERMOD_ID_EXAMPLE);
// #endif // #endif
// somewhere in loop() or other member method // somewhere in loop() or other member method
// #ifdef USERMOD_EXAMPLE // #ifdef USERMOD_EXAMPLE

View File

@ -59,10 +59,10 @@ void registerUsermods()
* || || || * || || ||
* \/ \/ \/ * \/ \/ \/
*/ */
//usermods.add(new MyExampleUsermod()); //UsermodManager::add(new MyExampleUsermod());
//usermods.add(new UsermodTemperature()); //UsermodManager::add(new UsermodTemperature());
//usermods.add(new UsermodRenameMe()); //UsermodManager::add(new UsermodRenameMe());
usermods.add(new FixUnreachableNetServices()); UsermodManager::add(new FixUnreachableNetServices());
} }
``` ```

View File

@ -30,7 +30,7 @@ class LDR_Dusk_Dawn_v2 : public Usermod {
void setup() { void setup() {
// register ldrPin // register ldrPin
if ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)) { if ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)) {
if(!pinManager.allocatePin(ldrPin, false, PinOwner::UM_LDR_DUSK_DAWN)) ldrEnabled = false; // pin already in use -> disable usermod if(!PinManager::allocatePin(ldrPin, false, PinOwner::UM_LDR_DUSK_DAWN)) ldrEnabled = false; // pin already in use -> disable usermod
else pinMode(ldrPin, INPUT); // alloc success -> configure pin for input else pinMode(ldrPin, INPUT); // alloc success -> configure pin for input
} else ldrEnabled = false; // invalid pin -> disable usermod } else ldrEnabled = false; // invalid pin -> disable usermod
initDone = true; initDone = true;
@ -110,7 +110,7 @@ class LDR_Dusk_Dawn_v2 : public Usermod {
if (initDone && (ldrPin != oldLdrPin)) { if (initDone && (ldrPin != oldLdrPin)) {
// pin changed - un-register previous pin, register new pin // pin changed - un-register previous pin, register new pin
if (oldLdrPin >= 0) pinManager.deallocatePin(oldLdrPin, PinOwner::UM_LDR_DUSK_DAWN); if (oldLdrPin >= 0) PinManager::deallocatePin(oldLdrPin, PinOwner::UM_LDR_DUSK_DAWN);
setup(); // setup new pin setup(); // setup new pin
} }
return configComplete; return configComplete;
@ -139,7 +139,7 @@ class LDR_Dusk_Dawn_v2 : public Usermod {
//LDR_Off_Count.add(ldrOffCount); //LDR_Off_Count.add(ldrOffCount);
//bool pinValid = ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0)); //bool pinValid = ((ldrPin >= 0) && (digitalPinToAnalogChannel(ldrPin) >= 0));
//if (pinManager.getPinOwner(ldrPin) != PinOwner::UM_LDR_DUSK_DAWN) pinValid = false; //if (PinManager::getPinOwner(ldrPin) != PinOwner::UM_LDR_DUSK_DAWN) pinValid = false;
//JsonArray LDR_valid = user.createNestedArray(F("LDR pin")); //JsonArray LDR_valid = user.createNestedArray(F("LDR pin"));
//LDR_valid.add(ldrPin); //LDR_valid.add(ldrPin);
//LDR_valid.add(pinValid ? F(" OK"): F(" invalid")); //LDR_valid.add(pinValid ? F(" OK"): F(" invalid"));

View File

@ -52,7 +52,7 @@ class MyUsermod : public Usermod {
void togglePIRSensor() { void togglePIRSensor() {
#ifdef USERMOD_PIR_SENSOR_SWITCH #ifdef USERMOD_PIR_SENSOR_SWITCH
PIRsensorSwitch *PIRsensor = (PIRsensorSwitch::*) usermods.lookup(USERMOD_ID_PIRSWITCH); PIRsensorSwitch *PIRsensor = (PIRsensorSwitch::*) UsermodManager::lookup(USERMOD_ID_PIRSWITCH);
if (PIRsensor != nullptr) { if (PIRsensor != nullptr) {
PIRsensor->EnablePIRsensor(!PIRsensor->PIRsensorEnabled()); PIRsensor->EnablePIRsensor(!PIRsensor->PIRsensorEnabled());
} }

View File

@ -375,7 +375,7 @@ void PIRsensorSwitch::setup()
sensorPinState[i] = LOW; sensorPinState[i] = LOW;
if (PIRsensorPin[i] < 0) continue; if (PIRsensorPin[i] < 0) continue;
// pin retrieved from cfg.json (readFromConfig()) prior to running setup() // pin retrieved from cfg.json (readFromConfig()) prior to running setup()
if (pinManager.allocatePin(PIRsensorPin[i], false, PinOwner::UM_PIR)) { if (PinManager::allocatePin(PIRsensorPin[i], false, PinOwner::UM_PIR)) {
// PIR Sensor mode INPUT_PULLDOWN // PIR Sensor mode INPUT_PULLDOWN
#ifdef ESP8266 #ifdef ESP8266
pinMode(PIRsensorPin[i], PIRsensorPin[i]==16 ? INPUT_PULLDOWN_16 : INPUT_PULLUP); // ESP8266 has INPUT_PULLDOWN on GPIO16 only pinMode(PIRsensorPin[i], PIRsensorPin[i]==16 ? INPUT_PULLDOWN_16 : INPUT_PULLUP); // ESP8266 has INPUT_PULLDOWN on GPIO16 only
@ -564,7 +564,7 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
DEBUG_PRINTLN(F(" config loaded.")); DEBUG_PRINTLN(F(" config loaded."));
} else { } else {
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++)
if (oldPin[i] >= 0) pinManager.deallocatePin(oldPin[i], PinOwner::UM_PIR); if (oldPin[i] >= 0) PinManager::deallocatePin(oldPin[i], PinOwner::UM_PIR);
setup(); setup();
DEBUG_PRINTLN(F(" config (re)loaded.")); DEBUG_PRINTLN(F(" config (re)loaded."));
} }

View File

@ -75,7 +75,7 @@ class PWMFanUsermod : public Usermod {
static const char _lock[]; static const char _lock[];
void initTacho(void) { void initTacho(void) {
if (tachoPin < 0 || !pinManager.allocatePin(tachoPin, false, PinOwner::UM_Unspecified)){ if (tachoPin < 0 || !PinManager::allocatePin(tachoPin, false, PinOwner::UM_Unspecified)){
tachoPin = -1; tachoPin = -1;
return; return;
} }
@ -88,7 +88,7 @@ class PWMFanUsermod : public Usermod {
void deinitTacho(void) { void deinitTacho(void) {
if (tachoPin < 0) return; if (tachoPin < 0) return;
detachInterrupt(digitalPinToInterrupt(tachoPin)); detachInterrupt(digitalPinToInterrupt(tachoPin));
pinManager.deallocatePin(tachoPin, PinOwner::UM_Unspecified); PinManager::deallocatePin(tachoPin, PinOwner::UM_Unspecified);
tachoPin = -1; tachoPin = -1;
} }
@ -111,7 +111,7 @@ class PWMFanUsermod : public Usermod {
// https://randomnerdtutorials.com/esp32-pwm-arduino-ide/ // https://randomnerdtutorials.com/esp32-pwm-arduino-ide/
void initPWMfan(void) { void initPWMfan(void) {
if (pwmPin < 0 || !pinManager.allocatePin(pwmPin, true, PinOwner::UM_Unspecified)) { if (pwmPin < 0 || !PinManager::allocatePin(pwmPin, true, PinOwner::UM_Unspecified)) {
enabled = false; enabled = false;
pwmPin = -1; pwmPin = -1;
return; return;
@ -121,7 +121,7 @@ class PWMFanUsermod : public Usermod {
analogWriteRange(255); analogWriteRange(255);
analogWriteFreq(WLED_PWM_FREQ); analogWriteFreq(WLED_PWM_FREQ);
#else #else
pwmChannel = pinManager.allocateLedc(1); pwmChannel = PinManager::allocateLedc(1);
if (pwmChannel == 255) { //no more free LEDC channels if (pwmChannel == 255) { //no more free LEDC channels
deinitPWMfan(); return; deinitPWMfan(); return;
} }
@ -136,9 +136,9 @@ class PWMFanUsermod : public Usermod {
void deinitPWMfan(void) { void deinitPWMfan(void) {
if (pwmPin < 0) return; if (pwmPin < 0) return;
pinManager.deallocatePin(pwmPin, PinOwner::UM_Unspecified); PinManager::deallocatePin(pwmPin, PinOwner::UM_Unspecified);
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(pwmChannel, 1); PinManager::deallocateLedc(pwmChannel, 1);
#endif #endif
pwmPin = -1; pwmPin = -1;
} }
@ -191,9 +191,9 @@ class PWMFanUsermod : public Usermod {
void setup() override { void setup() override {
#ifdef USERMOD_DALLASTEMPERATURE #ifdef USERMOD_DALLASTEMPERATURE
// This Usermod requires Temperature usermod // This Usermod requires Temperature usermod
tempUM = (UsermodTemperature*) usermods.lookup(USERMOD_ID_TEMPERATURE); tempUM = (UsermodTemperature*) UsermodManager::lookup(USERMOD_ID_TEMPERATURE);
#elif defined(USERMOD_SHT) #elif defined(USERMOD_SHT)
tempUM = (ShtUsermod*) usermods.lookup(USERMOD_ID_SHT); tempUM = (ShtUsermod*) UsermodManager::lookup(USERMOD_ID_SHT);
#endif #endif
initTacho(); initTacho();
initPWMfan(); initPWMfan();

View File

@ -9,6 +9,6 @@
void registerUsermods() void registerUsermods()
{ {
#ifdef USERMOD_SN_PHOTORESISTOR #ifdef USERMOD_SN_PHOTORESISTOR
usermods.add(new Usermod_SN_Photoresistor()); UsermodManager::add(new Usermod_SN_Photoresistor());
#endif #endif
} }

View File

@ -138,10 +138,10 @@ class St7789DisplayUsermod : public Usermod {
void setup() override void setup() override
{ {
PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } }; PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } };
if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; } if (!PinManager::allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; }
PinManagerPinType displayPins[] = { { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } }; PinManagerPinType displayPins[] = { { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
if (!pinManager.allocateMultiplePins(displayPins, sizeof(displayPins)/sizeof(PinManagerPinType), PinOwner::UM_FourLineDisplay)) { if (!PinManager::allocateMultiplePins(displayPins, sizeof(displayPins)/sizeof(PinManagerPinType), PinOwner::UM_FourLineDisplay)) {
pinManager.deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI); PinManager::deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI);
enabled = false; enabled = false;
return; return;
} }

View File

@ -73,7 +73,7 @@ class UsermodTemperature : public Usermod {
void publishHomeAssistantAutodiscovery(); void publishHomeAssistantAutodiscovery();
#endif #endif
static UsermodTemperature* _instance; // to overcome nonstatic getTemperatureC() method and avoid usermods.lookup(USERMOD_ID_TEMPERATURE); static UsermodTemperature* _instance; // to overcome nonstatic getTemperatureC() method and avoid UsermodManager::lookup(USERMOD_ID_TEMPERATURE);
public: public:
@ -223,14 +223,14 @@ void UsermodTemperature::setup() {
// config says we are enabled // config says we are enabled
DEBUG_PRINTLN(F("Allocating temperature pin...")); DEBUG_PRINTLN(F("Allocating temperature pin..."));
// pin retrieved from cfg.json (readFromConfig()) prior to running setup() // pin retrieved from cfg.json (readFromConfig()) prior to running setup()
if (temperaturePin >= 0 && pinManager.allocatePin(temperaturePin, true, PinOwner::UM_Temperature)) { if (temperaturePin >= 0 && PinManager::allocatePin(temperaturePin, true, PinOwner::UM_Temperature)) {
oneWire = new OneWire(temperaturePin); oneWire = new OneWire(temperaturePin);
if (oneWire->reset()) { if (oneWire->reset()) {
while (!findSensor() && retries--) { while (!findSensor() && retries--) {
delay(25); // try to find sensor delay(25); // try to find sensor
} }
} }
if (parasite && pinManager.allocatePin(parasitePin, true, PinOwner::UM_Temperature)) { if (parasite && PinManager::allocatePin(parasitePin, true, PinOwner::UM_Temperature)) {
pinMode(parasitePin, OUTPUT); pinMode(parasitePin, OUTPUT);
digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET) digitalWrite(parasitePin, LOW); // deactivate power (close MOSFET)
} else { } else {
@ -423,9 +423,9 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) {
DEBUG_PRINTLN(F("Re-init temperature.")); DEBUG_PRINTLN(F("Re-init temperature."));
// deallocate pin and release memory // deallocate pin and release memory
delete oneWire; delete oneWire;
pinManager.deallocatePin(temperaturePin, PinOwner::UM_Temperature); PinManager::deallocatePin(temperaturePin, PinOwner::UM_Temperature);
temperaturePin = newTemperaturePin; temperaturePin = newTemperaturePin;
pinManager.deallocatePin(parasitePin, PinOwner::UM_Temperature); PinManager::deallocatePin(parasitePin, PinOwner::UM_Temperature);
// initialise // initialise
setup(); setup();
} }

View File

@ -194,8 +194,8 @@ class I2SSource : public AudioSource {
virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE) { virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN(F("I2SSource:: initialize().")); DEBUGSR_PRINTLN(F("I2SSource:: initialize()."));
if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) { if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) {
if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) || if (!PinManager::allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) ||
!pinManager.allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206 !PinManager::allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206
DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pins: ws=%d, sd=%d\n", i2swsPin, i2ssdPin); DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pins: ws=%d, sd=%d\n", i2swsPin, i2ssdPin);
return; return;
} }
@ -203,7 +203,7 @@ class I2SSource : public AudioSource {
// i2ssckPin needs special treatment, since it might be unused on PDM mics // i2ssckPin needs special treatment, since it might be unused on PDM mics
if (i2sckPin != I2S_PIN_NO_CHANGE) { if (i2sckPin != I2S_PIN_NO_CHANGE) {
if (!pinManager.allocatePin(i2sckPin, true, PinOwner::UM_Audioreactive)) { if (!PinManager::allocatePin(i2sckPin, true, PinOwner::UM_Audioreactive)) {
DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pins: sck=%d\n", i2sckPin); DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pins: sck=%d\n", i2sckPin);
return; return;
} }
@ -249,7 +249,7 @@ class I2SSource : public AudioSource {
// Reserve the master clock pin if provided // Reserve the master clock pin if provided
_mclkPin = mclkPin; _mclkPin = mclkPin;
if (mclkPin != I2S_PIN_NO_CHANGE) { if (mclkPin != I2S_PIN_NO_CHANGE) {
if(!pinManager.allocatePin(mclkPin, true, PinOwner::UM_Audioreactive)) { if(!PinManager::allocatePin(mclkPin, true, PinOwner::UM_Audioreactive)) {
DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pin: MCLK=%d\n", mclkPin); DEBUGSR_PRINTF("\nAR: Failed to allocate I2S pin: MCLK=%d\n", mclkPin);
return; return;
} else } else
@ -307,11 +307,11 @@ class I2SSource : public AudioSource {
DEBUGSR_PRINTF("Failed to uninstall i2s driver: %d\n", err); DEBUGSR_PRINTF("Failed to uninstall i2s driver: %d\n", err);
return; return;
} }
if (_pinConfig.ws_io_num != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_pinConfig.ws_io_num, PinOwner::UM_Audioreactive); if (_pinConfig.ws_io_num != I2S_PIN_NO_CHANGE) PinManager::deallocatePin(_pinConfig.ws_io_num, PinOwner::UM_Audioreactive);
if (_pinConfig.data_in_num != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_pinConfig.data_in_num, PinOwner::UM_Audioreactive); if (_pinConfig.data_in_num != I2S_PIN_NO_CHANGE) PinManager::deallocatePin(_pinConfig.data_in_num, PinOwner::UM_Audioreactive);
if (_pinConfig.bck_io_num != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_pinConfig.bck_io_num, PinOwner::UM_Audioreactive); if (_pinConfig.bck_io_num != I2S_PIN_NO_CHANGE) PinManager::deallocatePin(_pinConfig.bck_io_num, PinOwner::UM_Audioreactive);
// Release the master clock pin // Release the master clock pin
if (_mclkPin != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_mclkPin, PinOwner::UM_Audioreactive); if (_mclkPin != I2S_PIN_NO_CHANGE) PinManager::deallocatePin(_mclkPin, PinOwner::UM_Audioreactive);
} }
virtual void getSamples(float *buffer, uint16_t num_samples) { virtual void getSamples(float *buffer, uint16_t num_samples) {
@ -589,7 +589,7 @@ class I2SAdcSource : public I2SSource {
void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN(F("I2SAdcSource:: initialize().")); DEBUGSR_PRINTLN(F("I2SAdcSource:: initialize()."));
_myADCchannel = 0x0F; _myADCchannel = 0x0F;
if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) { if(!PinManager::allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) {
DEBUGSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin); DEBUGSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin);
return; return;
} }
@ -717,7 +717,7 @@ class I2SAdcSource : public I2SSource {
} }
void deinitialize() { void deinitialize() {
pinManager.deallocatePin(_audioPin, PinOwner::UM_Audioreactive); PinManager::deallocatePin(_audioPin, PinOwner::UM_Audioreactive);
_initialized = false; _initialized = false;
_myADCchannel = 0x0F; _myADCchannel = 0x0F;

View File

@ -86,6 +86,6 @@ Example **usermods_list.cpp**:
void registerUsermods() void registerUsermods()
{ {
usermods.add(new MPU6050Driver()); UsermodManager::add(new MPU6050Driver());
} }
``` ```

View File

@ -163,7 +163,7 @@ class GyroSurge : public Usermod {
void loop() { void loop() {
// get IMU data // get IMU data
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_IMU)) { if (!UsermodManager::getUMData(&um_data, USERMOD_ID_IMU)) {
// Apply max // Apply max
strip.getSegment(0).fadeToBlackBy(max); strip.getSegment(0).fadeToBlackBy(max);
return; return;

View File

@ -164,7 +164,7 @@ class MPU6050Driver : public Usermod {
if (i2c_scl<0 || i2c_sda<0) { DEBUG_PRINTLN(F("MPU6050: I2C is no good.")); return; } if (i2c_scl<0 || i2c_sda<0) { DEBUG_PRINTLN(F("MPU6050: I2C is no good.")); return; }
// Check the interrupt pin // Check the interrupt pin
if (config.interruptPin >= 0) { if (config.interruptPin >= 0) {
irqBound = pinManager.allocatePin(config.interruptPin, false, PinOwner::UM_IMU); irqBound = PinManager::allocatePin(config.interruptPin, false, PinOwner::UM_IMU);
if (!irqBound) { DEBUG_PRINTLN(F("MPU6050: IRQ pin already in use.")); return; } if (!irqBound) { DEBUG_PRINTLN(F("MPU6050: IRQ pin already in use.")); return; }
pinMode(config.interruptPin, INPUT); pinMode(config.interruptPin, INPUT);
}; };
@ -408,7 +408,7 @@ class MPU6050Driver : public Usermod {
// Previously loaded and config changed // Previously loaded and config changed
if (irqBound && ((old_cfg.interruptPin != config.interruptPin) || !config.enabled)) { if (irqBound && ((old_cfg.interruptPin != config.interruptPin) || !config.enabled)) {
detachInterrupt(old_cfg.interruptPin); detachInterrupt(old_cfg.interruptPin);
pinManager.deallocatePin(old_cfg.interruptPin, PinOwner::UM_IMU); PinManager::deallocatePin(old_cfg.interruptPin, PinOwner::UM_IMU);
irqBound = false; irqBound = false;
} }

View File

@ -19,7 +19,7 @@ Example `usermods_list.cpp`:
void registerUsermods() void registerUsermods()
{ {
usermods.add(new UsermodMqttSwitch()); UsermodManager::add(new UsermodMqttSwitch());
} }
``` ```

View File

@ -41,7 +41,7 @@ When a relay is switched, a message is published:
## Usermod installation ## Usermod installation
1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `usermods.add(new MultiRelay());` at the bottom of `usermods_list.cpp`. 1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `UsermodManager::add(new MultiRelay());` at the bottom of `usermods_list.cpp`.
or or
2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini 2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini
@ -90,9 +90,9 @@ void registerUsermods()
* || || || * || || ||
* \/ \/ \/ * \/ \/ \/
*/ */
//usermods.add(new MyExampleUsermod()); //UsermodManager::add(new MyExampleUsermod());
//usermods.add(new UsermodTemperature()); //UsermodManager::add(new UsermodTemperature());
usermods.add(new MultiRelay()); UsermodManager::add(new MultiRelay());
} }
``` ```

View File

@ -516,7 +516,7 @@ void MultiRelay::setup() {
if (!_relay[i].external) _relay[i].state = !offMode; if (!_relay[i].external) _relay[i].state = !offMode;
state |= (uint8_t)(_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin; state |= (uint8_t)(_relay[i].invert ? !_relay[i].state : _relay[i].state) << pin;
} else if (_relay[i].pin<100 && _relay[i].pin>=0) { } else if (_relay[i].pin<100 && _relay[i].pin>=0) {
if (pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) { if (PinManager::allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
if (!_relay[i].external) _relay[i].state = !offMode; if (!_relay[i].external) _relay[i].state = !offMode;
switchRelay(i, _relay[i].state); switchRelay(i, _relay[i].state);
_relay[i].active = false; _relay[i].active = false;
@ -817,7 +817,7 @@ bool MultiRelay::readFromConfig(JsonObject &root) {
// deallocate all pins 1st // deallocate all pins 1st
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++)
if (oldPin[i]>=0 && oldPin[i]<100) { if (oldPin[i]>=0 && oldPin[i]<100) {
pinManager.deallocatePin(oldPin[i], PinOwner::UM_MultiRelay); PinManager::deallocatePin(oldPin[i], PinOwner::UM_MultiRelay);
} }
// allocate new pins // allocate new pins
setup(); setup();

View File

@ -112,15 +112,15 @@ class PixelsDiceTrayUsermod : public Usermod {
SetSPIPinsFromMacros(); SetSPIPinsFromMacros();
PinManagerPinType spiPins[] = { PinManagerPinType spiPins[] = {
{spi_mosi, true}, {spi_miso, false}, {spi_sclk, true}}; {spi_mosi, true}, {spi_miso, false}, {spi_sclk, true}};
if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { if (!PinManager::allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) {
enabled = false; enabled = false;
} else { } else {
PinManagerPinType displayPins[] = { PinManagerPinType displayPins[] = {
{TFT_CS, true}, {TFT_DC, true}, {TFT_RST, true}, {TFT_BL, true}}; {TFT_CS, true}, {TFT_DC, true}, {TFT_RST, true}, {TFT_BL, true}};
if (!pinManager.allocateMultiplePins( if (!PinManager::allocateMultiplePins(
displayPins, sizeof(displayPins) / sizeof(PinManagerPinType), displayPins, sizeof(displayPins) / sizeof(PinManagerPinType),
PinOwner::UM_FourLineDisplay)) { PinOwner::UM_FourLineDisplay)) {
pinManager.deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI); PinManager::deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI);
enabled = false; enabled = false;
} }
} }

View File

@ -29,13 +29,13 @@ class PwmOutput {
return; return;
DEBUG_PRINTF("pwm_output[%d]: setup to freq %d\n", pin_, freq_); DEBUG_PRINTF("pwm_output[%d]: setup to freq %d\n", pin_, freq_);
if (!pinManager.allocatePin(pin_, true, PinOwner::UM_PWM_OUTPUTS)) if (!PinManager::allocatePin(pin_, true, PinOwner::UM_PWM_OUTPUTS))
return; return;
channel_ = pinManager.allocateLedc(1); channel_ = PinManager::allocateLedc(1);
if (channel_ == 255) { if (channel_ == 255) {
DEBUG_PRINTF("pwm_output[%d]: failed to quire ledc\n", pin_); DEBUG_PRINTF("pwm_output[%d]: failed to quire ledc\n", pin_);
pinManager.deallocatePin(pin_, PinOwner::UM_PWM_OUTPUTS); PinManager::deallocatePin(pin_, PinOwner::UM_PWM_OUTPUTS);
return; return;
} }
@ -49,9 +49,9 @@ class PwmOutput {
DEBUG_PRINTF("pwm_output[%d]: close\n", pin_); DEBUG_PRINTF("pwm_output[%d]: close\n", pin_);
if (!enabled_) if (!enabled_)
return; return;
pinManager.deallocatePin(pin_, PinOwner::UM_PWM_OUTPUTS); PinManager::deallocatePin(pin_, PinOwner::UM_PWM_OUTPUTS);
if (channel_ != 255) if (channel_ != 255)
pinManager.deallocateLedc(channel_, 1); PinManager::deallocateLedc(channel_, 1);
channel_ = 255; channel_ = 255;
duty_ = 0.0f; duty_ = 0.0f;
enabled_ = false; enabled_ = false;

View File

@ -129,7 +129,7 @@ class QuinLEDAnPentaUsermod : public Usermod
void initOledDisplay() void initOledDisplay()
{ {
PinManagerPinType pins[5] = { { oledSpiClk, true }, { oledSpiData, true }, { oledSpiCs, true }, { oledSpiDc, true }, { oledSpiRst, true } }; PinManagerPinType pins[5] = { { oledSpiClk, true }, { oledSpiData, true }, { oledSpiCs, true }, { oledSpiDc, true }, { oledSpiRst, true } };
if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_QuinLEDAnPenta)) { if (!PinManager::allocateMultiplePins(pins, 5, PinOwner::UM_QuinLEDAnPenta)) {
DEBUG_PRINTF("[%s] OLED pin allocation failed!\n", _name); DEBUG_PRINTF("[%s] OLED pin allocation failed!\n", _name);
oledEnabled = oledInitDone = false; oledEnabled = oledInitDone = false;
return; return;
@ -164,11 +164,11 @@ class QuinLEDAnPentaUsermod : public Usermod
oledDisplay->clear(); oledDisplay->clear();
} }
pinManager.deallocatePin(oledSpiClk, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(oledSpiClk, PinOwner::UM_QuinLEDAnPenta);
pinManager.deallocatePin(oledSpiData, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(oledSpiData, PinOwner::UM_QuinLEDAnPenta);
pinManager.deallocatePin(oledSpiCs, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(oledSpiCs, PinOwner::UM_QuinLEDAnPenta);
pinManager.deallocatePin(oledSpiDc, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(oledSpiDc, PinOwner::UM_QuinLEDAnPenta);
pinManager.deallocatePin(oledSpiRst, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(oledSpiRst, PinOwner::UM_QuinLEDAnPenta);
delete oledDisplay; delete oledDisplay;
@ -184,7 +184,7 @@ class QuinLEDAnPentaUsermod : public Usermod
void initSht30TempHumiditySensor() void initSht30TempHumiditySensor()
{ {
PinManagerPinType pins[2] = { { shtSda, true }, { shtScl, true } }; PinManagerPinType pins[2] = { { shtSda, true }, { shtScl, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::UM_QuinLEDAnPenta)) { if (!PinManager::allocateMultiplePins(pins, 2, PinOwner::UM_QuinLEDAnPenta)) {
DEBUG_PRINTF("[%s] SHT30 pin allocation failed!\n", _name); DEBUG_PRINTF("[%s] SHT30 pin allocation failed!\n", _name);
shtEnabled = shtInitDone = false; shtEnabled = shtInitDone = false;
return; return;
@ -212,8 +212,8 @@ class QuinLEDAnPentaUsermod : public Usermod
sht30TempHumidSensor->reset(); sht30TempHumidSensor->reset();
} }
pinManager.deallocatePin(shtSda, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(shtSda, PinOwner::UM_QuinLEDAnPenta);
pinManager.deallocatePin(shtScl, PinOwner::UM_QuinLEDAnPenta); PinManager::deallocatePin(shtScl, PinOwner::UM_QuinLEDAnPenta);
delete sht30TempHumidSensor; delete sht30TempHumidSensor;

View File

@ -40,7 +40,7 @@ class RgbRotaryEncoderUsermod : public Usermod
void initRotaryEncoder() void initRotaryEncoder()
{ {
PinManagerPinType pins[2] = { { eaIo, false }, { ebIo, false } }; PinManagerPinType pins[2] = { { eaIo, false }, { ebIo, false } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::UM_RGBRotaryEncoder)) { if (!PinManager::allocateMultiplePins(pins, 2, PinOwner::UM_RGBRotaryEncoder)) {
eaIo = -1; eaIo = -1;
ebIo = -1; ebIo = -1;
cleanup(); cleanup();
@ -108,11 +108,11 @@ class RgbRotaryEncoderUsermod : public Usermod
{ {
// Only deallocate pins if we allocated them ;) // Only deallocate pins if we allocated them ;)
if (eaIo != -1) { if (eaIo != -1) {
pinManager.deallocatePin(eaIo, PinOwner::UM_RGBRotaryEncoder); PinManager::deallocatePin(eaIo, PinOwner::UM_RGBRotaryEncoder);
eaIo = -1; eaIo = -1;
} }
if (ebIo != -1) { if (ebIo != -1) {
pinManager.deallocatePin(ebIo, PinOwner::UM_RGBRotaryEncoder); PinManager::deallocatePin(ebIo, PinOwner::UM_RGBRotaryEncoder);
ebIo = -1; ebIo = -1;
} }
@ -303,8 +303,8 @@ class RgbRotaryEncoderUsermod : public Usermod
} }
if (eaIo != oldEaIo || ebIo != oldEbIo || stepsPerClick != oldStepsPerClick || incrementPerClick != oldIncrementPerClick) { if (eaIo != oldEaIo || ebIo != oldEbIo || stepsPerClick != oldStepsPerClick || incrementPerClick != oldIncrementPerClick) {
pinManager.deallocatePin(oldEaIo, PinOwner::UM_RGBRotaryEncoder); PinManager::deallocatePin(oldEaIo, PinOwner::UM_RGBRotaryEncoder);
pinManager.deallocatePin(oldEbIo, PinOwner::UM_RGBRotaryEncoder); PinManager::deallocatePin(oldEbIo, PinOwner::UM_RGBRotaryEncoder);
delete rotaryEncoder; delete rotaryEncoder;
initRotaryEncoder(); initRotaryEncoder();

View File

@ -45,7 +45,7 @@ class UsermodSdCard : public Usermod {
{ configPinPico, true } { configPinPico, true }
}; };
if (!pinManager.allocateMultiplePins(pins, 4, PinOwner::UM_SdCard)) { if (!PinManager::allocateMultiplePins(pins, 4, PinOwner::UM_SdCard)) {
DEBUG_PRINTF("[%s] SD (SPI) pin allocation failed!\n", _name); DEBUG_PRINTF("[%s] SD (SPI) pin allocation failed!\n", _name);
sdInitDone = false; sdInitDone = false;
return; return;
@ -75,10 +75,10 @@ class UsermodSdCard : public Usermod {
SD_ADAPTER.end(); SD_ADAPTER.end();
DEBUG_PRINTF("[%s] deallocate pins!\n", _name); DEBUG_PRINTF("[%s] deallocate pins!\n", _name);
pinManager.deallocatePin(configPinSourceSelect, PinOwner::UM_SdCard); PinManager::deallocatePin(configPinSourceSelect, PinOwner::UM_SdCard);
pinManager.deallocatePin(configPinSourceClock, PinOwner::UM_SdCard); PinManager::deallocatePin(configPinSourceClock, PinOwner::UM_SdCard);
pinManager.deallocatePin(configPinPoci, PinOwner::UM_SdCard); PinManager::deallocatePin(configPinPoci, PinOwner::UM_SdCard);
pinManager.deallocatePin(configPinPico, PinOwner::UM_SdCard); PinManager::deallocatePin(configPinPico, PinOwner::UM_SdCard);
sdInitDone = false; sdInitDone = false;
} }

View File

@ -385,7 +385,7 @@ public:
_setAllFalse(); _setAllFalse();
#ifdef USERMOD_SN_PHOTORESISTOR #ifdef USERMOD_SN_PHOTORESISTOR
ptr = (Usermod_SN_Photoresistor*) usermods.lookup(USERMOD_ID_SN_PHOTORESISTOR); ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR);
#endif #endif
DEBUG_PRINTLN(F("Setup done")); DEBUG_PRINTLN(F("Setup done"));
} }

View File

@ -103,7 +103,7 @@ class AutoSaveUsermod : public Usermod {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
// This Usermod has enhanced functionality if // This Usermod has enhanced functionality if
// FourLineDisplayUsermod is available. // FourLineDisplayUsermod is available.
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP); display = (FourLineDisplayUsermod*) UsermodManager::lookup(USERMOD_ID_FOUR_LINE_DISP);
#endif #endif
initDone = true; initDone = true;
if (enabled && applyAutoSaveOnBoot) applyPreset(autoSavePreset); if (enabled && applyAutoSaveOnBoot) applyPreset(autoSavePreset);

View File

@ -543,7 +543,7 @@ void FourLineDisplayUsermod::setup() {
type = NONE; type = NONE;
} else { } else {
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } }; PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type = NONE; } if (!PinManager::allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type = NONE; }
} }
} else { } else {
if (i2c_scl<0 || i2c_sda<0) { type=NONE; } if (i2c_scl<0 || i2c_sda<0) { type=NONE; }
@ -569,7 +569,7 @@ void FourLineDisplayUsermod::setup() {
if (nullptr == u8x8) { if (nullptr == u8x8) {
DEBUG_PRINTLN(F("Display init failed.")); DEBUG_PRINTLN(F("Display init failed."));
if (isSPI) { if (isSPI) {
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay); PinManager::deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay);
} }
type = NONE; type = NONE;
return; return;
@ -1307,7 +1307,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64); bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SSD1309_SPI64);
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64); bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64 || newType == SSD1309_SPI64);
if (isSPI) { if (isSPI) {
if (pinsChanged || !newSPI) pinManager.deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay); if (pinsChanged || !newSPI) PinManager::deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay);
if (!newSPI) { if (!newSPI) {
// was SPI but is no longer SPI // was SPI but is no longer SPI
if (i2c_scl<0 || i2c_sda<0) { newType=NONE; } if (i2c_scl<0 || i2c_sda<0) { newType=NONE; }
@ -1315,7 +1315,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
// still SPI but pins changed // still SPI but pins changed
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } }; PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; } if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; } else if (!PinManager::allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
} }
} else if (newSPI) { } else if (newSPI) {
// was I2C but is now SPI // was I2C but is now SPI
@ -1324,7 +1324,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
} else { } else {
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } }; PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; } if (ioPin[0]<0 || ioPin[1]<0 || ioPin[1]<0) { newType=NONE; }
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; } else if (!PinManager::allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
} }
} else { } else {
// just I2C type changed // just I2C type changed

View File

@ -489,7 +489,7 @@ void RotaryEncoderUIUsermod::setup()
enabled = false; enabled = false;
return; return;
} else { } else {
if (pinIRQ >= 0 && pinManager.allocatePin(pinIRQ, false, PinOwner::UM_RotaryEncoderUI)) { if (pinIRQ >= 0 && PinManager::allocatePin(pinIRQ, false, PinOwner::UM_RotaryEncoderUI)) {
pinMode(pinIRQ, INPUT_PULLUP); pinMode(pinIRQ, INPUT_PULLUP);
attachInterrupt(pinIRQ, i2cReadingISR, FALLING); // RISING, FALLING, CHANGE, ONLOW, ONHIGH attachInterrupt(pinIRQ, i2cReadingISR, FALLING); // RISING, FALLING, CHANGE, ONLOW, ONHIGH
DEBUG_PRINTLN(F("Interrupt attached.")); DEBUG_PRINTLN(F("Interrupt attached."));
@ -502,7 +502,7 @@ void RotaryEncoderUIUsermod::setup()
} }
} else { } else {
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } }; PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
if (pinA<0 || pinB<0 || !pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) { if (pinA<0 || pinB<0 || !PinManager::allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
pinA = pinB = pinC = -1; pinA = pinB = pinC = -1;
enabled = false; enabled = false;
return; return;
@ -525,7 +525,7 @@ void RotaryEncoderUIUsermod::setup()
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
// This Usermod uses FourLineDisplayUsermod for the best experience. // This Usermod uses FourLineDisplayUsermod for the best experience.
// But it's optional. But you want it. // But it's optional. But you want it.
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP); display = (FourLineDisplayUsermod*) UsermodManager::lookup(USERMOD_ID_FOUR_LINE_DISP);
if (display != nullptr) { if (display != nullptr) {
display->setMarkLine(1, 0); display->setMarkLine(1, 0);
} }
@ -1138,14 +1138,14 @@ bool RotaryEncoderUIUsermod::readFromConfig(JsonObject &root) {
if (oldPcf8574) { if (oldPcf8574) {
if (pinIRQ >= 0) { if (pinIRQ >= 0) {
detachInterrupt(pinIRQ); detachInterrupt(pinIRQ);
pinManager.deallocatePin(pinIRQ, PinOwner::UM_RotaryEncoderUI); PinManager::deallocatePin(pinIRQ, PinOwner::UM_RotaryEncoderUI);
DEBUG_PRINTLN(F("Deallocated old IRQ pin.")); DEBUG_PRINTLN(F("Deallocated old IRQ pin."));
} }
pinIRQ = newIRQpin<100 ? newIRQpin : -1; // ignore PCF8574 pins pinIRQ = newIRQpin<100 ? newIRQpin : -1; // ignore PCF8574 pins
} else { } else {
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI); PinManager::deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI); PinManager::deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);
pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI); PinManager::deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI);
DEBUG_PRINTLN(F("Deallocated old pins.")); DEBUG_PRINTLN(F("Deallocated old pins."));
} }
pinA = newDTpin; pinA = newDTpin;

View File

@ -75,7 +75,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
static um_data_t* getAudioData() { static um_data_t* getAudioData() {
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio // add support for no audio
um_data = simulateSound(SEGMENT.soundSim); um_data = simulateSound(SEGMENT.soundSim);
} }
@ -6298,7 +6298,7 @@ static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale
uint8_t *fftResult = nullptr; uint8_t *fftResult = nullptr;
float *fftBin = nullptr; float *fftBin = nullptr;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
volumeSmth = *(float*) um_data->u_data[0]; volumeSmth = *(float*) um_data->u_data[0];
volumeRaw = *(float*) um_data->u_data[1]; volumeRaw = *(float*) um_data->u_data[1];
fftResult = (uint8_t*) um_data->u_data[2]; fftResult = (uint8_t*) um_data->u_data[2];
@ -6911,7 +6911,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low. uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low.
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
um_data = simulateSound(SEGMENT.soundSim); um_data = simulateSound(SEGMENT.soundSim);
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
@ -7494,7 +7494,7 @@ uint16_t mode_2DAkemi(void) {
const float normalFactor = 0.4f; const float normalFactor = 0.4f;
um_data_t *um_data; um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (!UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
um_data = simulateSound(SEGMENT.soundSim); um_data = simulateSound(SEGMENT.soundSim);
} }
uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; uint8_t *fftResult = (uint8_t*)um_data->u_data[2];

View File

@ -183,11 +183,7 @@ void IRAM_ATTR_YN Segment::deallocateData() {
if ((Segment::getUsedSegmentData() > 0) && (_dataLen > 0)) { // check that we don't have a dangling / inconsistent data pointer if ((Segment::getUsedSegmentData() > 0) && (_dataLen > 0)) { // check that we don't have a dangling / inconsistent data pointer
free(data); free(data);
} else { } else {
DEBUG_PRINT(F("---- Released data ")); DEBUG_PRINTF_P(PSTR("---- Released data (%p): inconsistent UsedSegmentData (%d/%d), cowardly refusing to free nothing.\n"), this, _dataLen, Segment::getUsedSegmentData());
DEBUG_PRINTF_P(PSTR("(%p): "), this);
DEBUG_PRINT(F("inconsistent UsedSegmentData "));
DEBUG_PRINTF_P(PSTR("(%d/%d)"), _dataLen, Segment::getUsedSegmentData());
DEBUG_PRINTLN(F(", cowardly refusing to free nothing."));
} }
data = nullptr; data = nullptr;
Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData()); Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData());
@ -1034,7 +1030,6 @@ void Segment::refreshLightCapabilities() {
if (bus->getStart() >= segStopIdx) continue; if (bus->getStart() >= segStopIdx) continue;
if (bus->getStart() + bus->getLength() <= segStartIdx) continue; if (bus->getStart() + bus->getLength() <= segStartIdx) continue;
//uint8_t type = bus->getType();
if (bus->hasRGB() || (strip.cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB; if (bus->hasRGB() || (strip.cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB;
if (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT; if (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider) if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
@ -1254,7 +1249,7 @@ void WS2812FX::finalizeInit() {
// When booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware // When booting without config (1st boot) we need to make sure GPIOs defined for LED output don't clash with hardware
// i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc. // i.e. DEBUG (GPIO1), DMX (2), SPI RAM/FLASH (16&17 on ESP32-WROVER/PICO), read/only pins, etc.
// Pin should not be already allocated, read/only or defined for current bus // Pin should not be already allocated, read/only or defined for current bus
while (pinManager.isPinAllocated(defPin[j]) || !pinManager.isPinOk(defPin[j],true)) { while (PinManager::isPinAllocated(defPin[j]) || !PinManager::isPinOk(defPin[j],true)) {
if (validPin) { if (validPin) {
DEBUG_PRINTLN(F("Some of the provided pins cannot be used to configure this LED output.")); DEBUG_PRINTLN(F("Some of the provided pins cannot be used to configure this LED output."));
defPin[j] = 1; // start with GPIO1 and work upwards defPin[j] = 1; // start with GPIO1 and work upwards
@ -1298,7 +1293,7 @@ void WS2812FX::finalizeInit() {
// if we have less counts than pins and they do not align, use last known count to set current count // if we have less counts than pins and they do not align, use last known count to set current count
unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
// analog always has length 1 // analog always has length 1
if (Bus::isPWM(dataType)) count = 1; if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1;
prevLen += count; prevLen += count;
BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer);
if (BusManager::add(defCfg) == -1) break; if (BusManager::add(defCfg) == -1) break;
@ -1570,7 +1565,7 @@ uint16_t WS2812FX::getLengthPhysical() const {
unsigned len = 0; unsigned len = 0;
for (size_t b = 0; b < BusManager::getNumBusses(); b++) { for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
Bus *bus = BusManager::getBus(b); Bus *bus = BusManager::getBus(b);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses if (bus->isVirtual()) continue; //exclude non-physical network busses
len += bus->getLength(); len += bus->getLength();
} }
return len; return len;

View File

@ -130,11 +130,11 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
, _colorOrderMap(com) , _colorOrderMap(com)
{ {
if (!isDigital(bc.type) || !bc.count) return; if (!isDigital(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
_frequencykHz = 0U; _frequencykHz = 0U;
_pins[0] = bc.pins[0]; _pins[0] = bc.pins[0];
if (is2Pin(bc.type)) { if (is2Pin(bc.type)) {
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup(); cleanup();
return; return;
} }
@ -422,8 +422,8 @@ void BusDigital::cleanup() {
_valid = false; _valid = false;
_busPtr = nullptr; _busPtr = nullptr;
if (_data != nullptr) freeData(); if (_data != nullptr) freeData();
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital); PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital); PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
} }
@ -464,16 +464,16 @@ BusPwm::BusPwm(BusConfig &bc)
managed_pin_type pins[numPins]; managed_pin_type pins[numPins];
for (unsigned i = 0; i < numPins; i++) pins[i] = {(int8_t)bc.pins[i], true}; for (unsigned i = 0; i < numPins; i++) pins[i] = {(int8_t)bc.pins[i], true};
if (!pinManager.allocateMultiplePins(pins, numPins, PinOwner::BusPwm)) return; if (!PinManager::allocateMultiplePins(pins, numPins, PinOwner::BusPwm)) return;
#ifdef ESP8266 #ifdef ESP8266
analogWriteRange((1<<_depth)-1); analogWriteRange((1<<_depth)-1);
analogWriteFreq(_frequency); analogWriteFreq(_frequency);
#else #else
// for 2 pin PWM CCT strip pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer // for 2 pin PWM CCT strip pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer
_ledcStart = pinManager.allocateLedc(numPins); _ledcStart = PinManager::allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels if (_ledcStart == 255) { //no more free LEDC channels
pinManager.deallocateMultiplePins(pins, numPins, PinOwner::BusPwm); PinManager::deallocateMultiplePins(pins, numPins, PinOwner::BusPwm);
return; return;
} }
// if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor)
@ -640,8 +640,8 @@ std::vector<LEDType> BusPwm::getLEDTypes() {
void BusPwm::deallocatePins() { void BusPwm::deallocatePins() {
unsigned numPins = getPins(); unsigned numPins = getPins();
for (unsigned i = 0; i < numPins; i++) { for (unsigned i = 0; i < numPins; i++) {
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm); PinManager::deallocatePin(_pins[i], PinOwner::BusPwm);
if (!pinManager.isPinOk(_pins[i])) continue; if (!PinManager::isPinOk(_pins[i])) continue;
#ifdef ESP8266 #ifdef ESP8266
digitalWrite(_pins[i], LOW); //turn off PWM interrupt digitalWrite(_pins[i], LOW); //turn off PWM interrupt
#else #else
@ -649,7 +649,7 @@ void BusPwm::deallocatePins() {
#endif #endif
} }
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(_ledcStart, numPins); PinManager::deallocateLedc(_ledcStart, numPins);
#endif #endif
} }
@ -661,7 +661,7 @@ BusOnOff::BusOnOff(BusConfig &bc)
if (!Bus::isOnOff(bc.type)) return; if (!Bus::isOnOff(bc.type)) return;
uint8_t currentPin = bc.pins[0]; uint8_t currentPin = bc.pins[0];
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusOnOff)) { if (!PinManager::allocatePin(currentPin, true, PinOwner::BusOnOff)) {
return; return;
} }
_pin = currentPin; //store only after allocatePin() succeeds _pin = currentPin; //store only after allocatePin() succeeds
@ -830,7 +830,7 @@ static String LEDTypesToJson(const std::vector<LEDType>& types) {
String json; String json;
for (const auto &type : types) { for (const auto &type : types) {
// capabilities follows similar pattern as JSON API // capabilities follows similar pattern as JSON API
int capabilities = Bus::hasRGB(type.id) | Bus::hasWhite(type.id)<<1 | Bus::hasCCT(type.id)<<2 | Bus::is16bit(type.id)<<4; int capabilities = Bus::hasRGB(type.id) | Bus::hasWhite(type.id)<<1 | Bus::hasCCT(type.id)<<2 | Bus::is16bit(type.id)<<4 | Bus::mustRefresh(type.id)<<5;
char str[256]; char str[256];
sprintf_P(str, PSTR("{i:%d,c:%d,t:\"%s\",n:\"%s\"},"), type.id, capabilities, type.type, type.name); sprintf_P(str, PSTR("{i:%d,c:%d,t:\"%s\",n:\"%s\"},"), type.id, capabilities, type.type, type.name);
json += str; json += str;
@ -904,7 +904,7 @@ void BusManager::esp32RMTInvertIdle() {
void BusManager::on() { void BusManager::on() {
#ifdef ESP8266 #ifdef ESP8266
//Fix for turning off onboard LED breaking bus //Fix for turning off onboard LED breaking bus
if (pinManager.getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
for (unsigned i = 0; i < numBusses; i++) { for (unsigned i = 0; i < numBusses; i++) {
uint8_t pins[2] = {255,255}; uint8_t pins[2] = {255,255};
if (busses[i]->isDigital() && busses[i]->getPins(pins)) { if (busses[i]->isDigital() && busses[i]->getPins(pins)) {
@ -926,7 +926,7 @@ void BusManager::off() {
#ifdef ESP8266 #ifdef ESP8266
// turn off built-in LED if strip is turned off // turn off built-in LED if strip is turned off
// this will break digital bus so will need to be re-initialised on On // this will break digital bus so will need to be re-initialised on On
if (pinManager.getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return; for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return;
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);

View File

@ -104,6 +104,7 @@ class Bus {
inline bool isPWM() const { return isPWM(_type); } inline bool isPWM() const { return isPWM(_type); }
inline bool isVirtual() const { return isVirtual(_type); } inline bool isVirtual() const { return isVirtual(_type); }
inline bool is16bit() const { return is16bit(_type); } inline bool is16bit() const { return is16bit(_type); }
inline bool mustRefresh() const { return mustRefresh(_type); }
inline void setReversed(bool reversed) { _reversed = reversed; } inline void setReversed(bool reversed) { _reversed = reversed; }
inline void setStart(uint16_t start) { _start = start; } inline void setStart(uint16_t start) { _start = start; }
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
@ -142,6 +143,7 @@ class Bus {
static constexpr bool isPWM(uint8_t type) { return (type >= TYPE_ANALOG_MIN && type <= TYPE_ANALOG_MAX); } static constexpr bool isPWM(uint8_t type) { return (type >= TYPE_ANALOG_MIN && type <= TYPE_ANALOG_MAX); }
static constexpr bool isVirtual(uint8_t type) { return (type >= TYPE_VIRTUAL_MIN && type <= TYPE_VIRTUAL_MAX); } static constexpr bool isVirtual(uint8_t type) { return (type >= TYPE_VIRTUAL_MIN && type <= TYPE_VIRTUAL_MAX); }
static constexpr bool is16bit(uint8_t type) { return type == TYPE_UCS8903 || type == TYPE_UCS8904 || type == TYPE_SM16825; } static constexpr bool is16bit(uint8_t type) { return type == TYPE_UCS8903 || type == TYPE_UCS8904 || type == TYPE_SM16825; }
static constexpr bool mustRefresh(uint8_t type) { return type == TYPE_TM1814; }
static constexpr int numPWMPins(uint8_t type) { return (type - 40); } static constexpr int numPWMPins(uint8_t type) { return (type - 40); }
static inline int16_t getCCT() { return _cct; } static inline int16_t getCCT() { return _cct; }
@ -280,7 +282,7 @@ class BusOnOff : public Bus {
uint32_t getPixelColor(uint16_t pix) const override; uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getPins(uint8_t* pinArray) const override; uint8_t getPins(uint8_t* pinArray) const override;
void show() override; void show() override;
void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); } void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
static std::vector<LEDType> getLEDTypes(); static std::vector<LEDType> getLEDTypes();

View File

@ -267,7 +267,7 @@ void handleButton()
if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue; if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue;
#endif #endif
if (usermods.handleButton(b)) continue; // did usermod handle buttons if (UsermodManager::handleButton(b)) continue; // did usermod handle buttons
if (buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { // button is not a button but a potentiometer if (buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { // button is not a button but a potentiometer
if (now - lastAnalogRead > ANALOG_BTN_READ_CYCLE) { if (now - lastAnalogRead > ANALOG_BTN_READ_CYCLE) {

View File

@ -261,12 +261,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray hw_btn_ins = btn_obj["ins"]; JsonArray hw_btn_ins = btn_obj["ins"];
if (!hw_btn_ins.isNull()) { if (!hw_btn_ins.isNull()) {
// deallocate existing button pins // deallocate existing button pins
for (unsigned b = 0; b < WLED_MAX_BUTTONS; b++) pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button for (unsigned b = 0; b < WLED_MAX_BUTTONS; b++) PinManager::deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button
unsigned s = 0; unsigned s = 0;
for (JsonObject btn : hw_btn_ins) { for (JsonObject btn : hw_btn_ins) {
CJSON(buttonType[s], btn["type"]); CJSON(buttonType[s], btn["type"]);
int8_t pin = btn["pin"][0] | -1; int8_t pin = btn["pin"][0] | -1;
if (pin > -1 && pinManager.allocatePin(pin, false, PinOwner::Button)) { if (pin > -1 && PinManager::allocatePin(pin, false, PinOwner::Button)) {
btnPin[s] = pin; btnPin[s] = pin;
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
// ESP32 only: check that analog button pin is a valid ADC gpio // ESP32 only: check that analog button pin is a valid ADC gpio
@ -275,7 +275,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
// not an ADC analog pin // not an ADC analog pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n"), btnPin[s], s); DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n"), btnPin[s], s);
btnPin[s] = -1; btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button); PinManager::deallocatePin(pin,PinOwner::Button);
} else { } else {
analogReadResolution(12); // see #4040 analogReadResolution(12); // see #4040
} }
@ -286,7 +286,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
// not a touch pin // not a touch pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not a touch pin!\n"), btnPin[s], s); DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not a touch pin!\n"), btnPin[s], s);
btnPin[s] = -1; btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button); PinManager::deallocatePin(pin,PinOwner::Button);
} }
//if touch pin, enable the touch interrupt on ESP32 S2 & S3 //if touch pin, enable the touch interrupt on ESP32 S2 & S3
#ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state but need to attach an interrupt to do so #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state but need to attach an interrupt to do so
@ -331,7 +331,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (fromFS) { if (fromFS) {
// relies upon only being called once with fromFS == true, which is currently true. // relies upon only being called once with fromFS == true, which is currently true.
for (size_t s = 0; s < WLED_MAX_BUTTONS; s++) { for (size_t s = 0; s < WLED_MAX_BUTTONS; s++) {
if (buttonType[s] == BTN_TYPE_NONE || btnPin[s] < 0 || !pinManager.allocatePin(btnPin[s], false, PinOwner::Button)) { if (buttonType[s] == BTN_TYPE_NONE || btnPin[s] < 0 || !PinManager::allocatePin(btnPin[s], false, PinOwner::Button)) {
btnPin[s] = -1; btnPin[s] = -1;
buttonType[s] = BTN_TYPE_NONE; buttonType[s] = BTN_TYPE_NONE;
} }
@ -358,8 +358,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4 int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
if (hw_ir_pin > -2) { if (hw_ir_pin > -2) {
pinManager.deallocatePin(irPin, PinOwner::IR); PinManager::deallocatePin(irPin, PinOwner::IR);
if (pinManager.allocatePin(hw_ir_pin, false, PinOwner::IR)) { if (PinManager::allocatePin(hw_ir_pin, false, PinOwner::IR)) {
irPin = hw_ir_pin; irPin = hw_ir_pin;
} else { } else {
irPin = -1; irPin = -1;
@ -374,8 +374,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
rlyOpenDrain = relay[F("odrain")] | rlyOpenDrain; rlyOpenDrain = relay[F("odrain")] | rlyOpenDrain;
int hw_relay_pin = relay["pin"] | -2; int hw_relay_pin = relay["pin"] | -2;
if (hw_relay_pin > -2) { if (hw_relay_pin > -2) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay); PinManager::deallocatePin(rlyPin, PinOwner::Relay);
if (pinManager.allocatePin(hw_relay_pin,true, PinOwner::Relay)) { if (PinManager::allocatePin(hw_relay_pin,true, PinOwner::Relay)) {
rlyPin = hw_relay_pin; rlyPin = hw_relay_pin;
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT); pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
} else { } else {
@ -394,7 +394,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(i2c_sda, hw_if_i2c[0]); CJSON(i2c_sda, hw_if_i2c[0]);
CJSON(i2c_scl, hw_if_i2c[1]); CJSON(i2c_scl, hw_if_i2c[1]);
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } }; PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) { if (i2c_scl >= 0 && i2c_sda >= 0 && PinManager::allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
#ifdef ESP32 #ifdef ESP32
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initialised (Wire.begin() called prior) if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initialised (Wire.begin() called prior)
else Wire.begin(); else Wire.begin();
@ -410,7 +410,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(spi_sclk, hw_if_spi[1]); CJSON(spi_sclk, hw_if_spi[1]);
CJSON(spi_miso, hw_if_spi[2]); CJSON(spi_miso, hw_if_spi[2]);
PinManagerPinType spi[3] = { { spi_mosi, true }, { spi_miso, true }, { spi_sclk, true } }; PinManagerPinType spi[3] = { { spi_mosi, true }, { spi_miso, true }, { spi_sclk, true } };
if (spi_mosi >= 0 && spi_sclk >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) { if (spi_mosi >= 0 && spi_sclk >= 0 && PinManager::allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
#ifdef ESP32 #ifdef ESP32
SPI.begin(spi_sclk, spi_miso, spi_mosi); // SPI global uses VSPI on ESP32 and FSPI on C3, S3 SPI.begin(spi_sclk, spi_miso, spi_mosi); // SPI global uses VSPI on ESP32 and FSPI on C3, S3
#else #else
@ -663,7 +663,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
DEBUG_PRINTLN(F("Starting usermod config.")); DEBUG_PRINTLN(F("Starting usermod config."));
JsonObject usermods_settings = doc["um"]; JsonObject usermods_settings = doc["um"];
if (!usermods_settings.isNull()) { if (!usermods_settings.isNull()) {
needsSave = !usermods.readFromConfig(usermods_settings); needsSave = !UsermodManager::readFromConfig(usermods_settings);
} }
if (fromFS) return needsSave; if (fromFS) return needsSave;
@ -699,7 +699,7 @@ void deserializeConfigFromFS() {
// save default values to /cfg.json // save default values to /cfg.json
// call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving // call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving
JsonObject empty = JsonObject(); JsonObject empty = JsonObject();
usermods.readFromConfig(empty); UsermodManager::readFromConfig(empty);
serializeConfig(); serializeConfig();
// init Ethernet (in case default type is set at compile time) // init Ethernet (in case default type is set at compile time)
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
@ -1120,7 +1120,7 @@ void serializeConfig() {
#endif #endif
JsonObject usermods_settings = root.createNestedObject("um"); JsonObject usermods_settings = root.createNestedObject("um");
usermods.addToConfig(usermods_settings); UsermodManager::addToConfig(usermods_settings);
File f = WLED_FS.open(FPSTR(s_cfg_json), "w"); File f = WLED_FS.open(FPSTR(s_cfg_json), "w");
if (f) serializeJson(root, f); if (f) serializeJson(root, f);

View File

@ -22,6 +22,7 @@
function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel
function hasCCT(t) { return !!(gT(t).c & 0x04); } // is white CCT enabled function hasCCT(t) { return !!(gT(t).c & 0x04); } // is white CCT enabled
function is16b(t) { return !!(gT(t).c & 0x10); } // is digital 16 bit type function is16b(t) { return !!(gT(t).c & 0x10); } // is digital 16 bit type
function mustR(t) { return !!(gT(t).c & 0x20); } // Off refresh is mandatory
function numPins(t){ return Math.max(gT(t).t.length, 1); } // type length determines number of GPIO pins function numPins(t){ return Math.max(gT(t).t.length, 1); } // type length determines number of GPIO pins
function S() { function S() {
getLoc(); getLoc();
@ -255,7 +256,7 @@
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1; d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250; d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250;
} }
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814 gId("rf"+n).onclick = mustR(t) ? (()=>{return false}) : (()=>{}); // prevent change change of "Refresh" checkmark when mandatory
gRGBW |= hasW(t); // RGBW checkbox gRGBW |= hasW(t); // RGBW checkbox
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
@ -457,9 +458,9 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
}); });
// disable inappropriate LED types // disable inappropriate LED types
let sel = d.getElementsByName("LT"+s)[0] let sel = d.getElementsByName("LT"+s)[0]
if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); // NOTE: see isDig()
if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]'); if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P()
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM()
sel.selectedIndex = sel.querySelector('option:not(:disabled)').index; sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
} }
if (n==-1) { if (n==-1) {

View File

@ -331,7 +331,7 @@ class Usermod {
virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here
virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects]
virtual void connected() {} // called when WiFi is (re)connected virtual void connected() {} // called when WiFi is (re)connected
virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields virtual void appendConfigData(Print& settingsScript); // helper function called from usermod settings page to add metadata for entry fields
virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state
virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page
virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server
@ -343,38 +343,48 @@ class Usermod {
virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
// API shims
private:
static Print* oappend_shim;
// old form of appendConfigData; called by default appendConfigData(Print&) with oappend_shim set up
// private so it is not accidentally invoked except via Usermod::appendConfigData(Print&)
virtual void appendConfigData() {}
protected:
// Shim for oappend(), which used to exist in utils.cpp
template<typename T> static inline void oappend(const T& t) { oappend_shim->print(t); };
}; };
class UsermodManager { class UsermodManager {
private: private:
Usermod* ums[WLED_MAX_USERMODS]; static Usermod* ums[WLED_MAX_USERMODS];
byte numMods = 0; static byte numMods;
public: public:
void loop(); static void loop();
void handleOverlayDraw(); static void handleOverlayDraw();
bool handleButton(uint8_t b); static bool handleButton(uint8_t b);
bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
void setup(); static void setup();
void connected(); static void connected();
void appendConfigData(); static void appendConfigData(Print&);
void addToJsonState(JsonObject& obj); static void addToJsonState(JsonObject& obj);
void addToJsonInfo(JsonObject& obj); static void addToJsonInfo(JsonObject& obj);
void readFromJsonState(JsonObject& obj); static void readFromJsonState(JsonObject& obj);
void addToConfig(JsonObject& obj); static void addToConfig(JsonObject& obj);
bool readFromConfig(JsonObject& obj); static bool readFromConfig(JsonObject& obj);
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
void onMqttConnect(bool sessionPresent); static void onMqttConnect(bool sessionPresent);
bool onMqttMessage(char* topic, char* payload); static bool onMqttMessage(char* topic, char* payload);
#endif #endif
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len); static bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
#endif #endif
void onUpdateBegin(bool); static void onUpdateBegin(bool);
void onStateChange(uint8_t); static void onStateChange(uint8_t);
bool add(Usermod* um); static bool add(Usermod* um);
Usermod* lookup(uint16_t mod_id); static Usermod* lookup(uint16_t mod_id);
byte getModCount() {return numMods;}; static inline byte getModCount() {return numMods;};
}; };
//usermods_list.cpp //usermods_list.cpp
@ -391,10 +401,11 @@ void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255);
bool getBoolVal(JsonVariant elem, bool dflt); bool getBoolVal(JsonVariant elem, bool dflt);
bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255);
bool oappend(const char* txt); // append new c string to temp buffer efficiently size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val);
bool oappendi(int i); // append new number to temp buffer efficiently size_t printSetFormValue(Print& settingsScript, const char* key, int val);
void sappend(char stype, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, const char* val);
void sappends(char stype, const char* key, char* val); size_t printSetFormIndex(Print& settingsScript, const char* key, int index);
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val);
void prepareHostname(char* hostname); void prepareHostname(char* hostname);
bool isAsterisksOnly(const char* str, byte maxLen); bool isAsterisksOnly(const char* str, byte maxLen);
bool requestJSONBufferLock(uint8_t module=255); bool requestJSONBufferLock(uint8_t module=255);
@ -473,7 +484,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
void sendDataWs(AsyncWebSocketClient * client = nullptr); void sendDataWs(AsyncWebSocketClient * client = nullptr);
//xml.cpp //xml.cpp
void XML_response(AsyncWebServerRequest *request, char* dest = nullptr); void XML_response(Print& dest);
void getSettingsJS(byte subPage, char* dest); void getSettingsJS(byte subPage, Print& dest);
#endif #endif

View File

@ -433,7 +433,7 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){
} }
#endif #endif
if(WLED_FS.exists(path) || WLED_FS.exists(path + ".gz")) { if(WLED_FS.exists(path) || WLED_FS.exists(path + ".gz")) {
request->send(WLED_FS, path, String(), request->hasArg(F("download"))); request->send(request->beginResponse(WLED_FS, path, {}, request->hasArg(F("download")), {}));
return true; return true;
} }
return false; return false;

View File

@ -436,7 +436,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
} }
strip.resume(); strip.resume();
usermods.readFromJsonState(root); UsermodManager::readFromJsonState(root);
loadLedmap = root[F("ledmap")] | loadLedmap; loadLedmap = root[F("ledmap")] | loadLedmap;
@ -592,7 +592,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
root[F("pl")] = currentPlaylist; root[F("pl")] = currentPlaylist;
root[F("ledmap")] = currentLedmap; root[F("ledmap")] = currentLedmap;
usermods.addToJsonState(root); UsermodManager::addToJsonState(root);
JsonObject nl = root.createNestedObject("nl"); JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive; nl["on"] = nightlightActive;
@ -784,7 +784,7 @@ void serializeInfo(JsonObject root)
getTimeString(time); getTimeString(time);
root[F("time")] = time; root[F("time")] = time;
usermods.addToJsonInfo(root); UsermodManager::addToJsonInfo(root);
uint16_t os = 0; uint16_t os = 0;
#ifdef WLED_DEBUG #ifdef WLED_DEBUG

View File

@ -131,7 +131,7 @@ void stateUpdated(byte callMode) {
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false; if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
// notify usermods of state change // notify usermods of state change
usermods.onStateChange(callMode); UsermodManager::onStateChange(callMode);
if (fadeTransition) { if (fadeTransition) {
if (strip.getTransition() == 0) { if (strip.getTransition() == 0) {

View File

@ -45,7 +45,7 @@ static void onMqttConnect(bool sessionPresent)
mqtt->subscribe(subuf, 0); mqtt->subscribe(subuf, 0);
} }
usermods.onMqttConnect(sessionPresent); UsermodManager::onMqttConnect(sessionPresent);
DEBUG_PRINTLN(F("MQTT ready")); DEBUG_PRINTLN(F("MQTT ready"));
publishMqtt(); publishMqtt();
@ -89,7 +89,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
topic += topicPrefixLen; topic += topicPrefixLen;
} else { } else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic. // Non-Wled Topic used here. Probably a usermod subscribed to this topic.
usermods.onMqttMessage(topic, payloadStr); UsermodManager::onMqttMessage(topic, payloadStr);
delete[] payloadStr; delete[] payloadStr;
payloadStr = nullptr; payloadStr = nullptr;
return; return;
@ -115,7 +115,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
} }
} else if (strlen(topic) != 0) { } else if (strlen(topic) != 0) {
// non standard topic, check with usermods // non standard topic, check with usermods
usermods.onMqttMessage(topic, payloadStr); UsermodManager::onMqttMessage(topic, payloadStr);
} else { } else {
// topmost topic (just wled/MAC) // topmost topic (just wled/MAC)
parseMQTTBriPayload(payloadStr); parseMQTTBriPayload(payloadStr);
@ -124,6 +124,32 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
payloadStr = nullptr; payloadStr = nullptr;
} }
// Print adapter for flat buffers
namespace {
class bufferPrint : public Print {
char* _buf;
size_t _size, _offset;
public:
bufferPrint(char* buf, size_t size) : _buf(buf), _size(size), _offset(0) {};
size_t write(const uint8_t *buffer, size_t size) {
size = std::min(size, _size - _offset);
memcpy(_buf + _offset, buffer, size);
_offset += size;
return size;
}
size_t write(uint8_t c) {
return this->write(&c, 1);
}
char* data() const { return _buf; }
size_t size() const { return _offset; }
size_t capacity() const { return _size; }
};
}; // anonymous namespace
void publishMqtt() void publishMqtt()
{ {
@ -148,11 +174,13 @@ void publishMqtt()
strcat_P(subuf, PSTR("/status")); strcat_P(subuf, PSTR("/status"));
mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
char apires[1024]; // allocating 1024 bytes from stack can be risky // TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API.
XML_response(nullptr, apires); DynamicBuffer buf(1024);
bufferPrint pbuf(buf.data(), buf.size());
XML_response(pbuf);
strlcpy(subuf, mqttDeviceTopic, 33); strlcpy(subuf, mqttDeviceTopic, 33);
strcat_P(subuf, PSTR("/v")); strcat_P(subuf, PSTR("/v"));
mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263)
#endif #endif
} }

View File

@ -88,7 +88,7 @@ void _overlayAnalogCountdown()
} }
void handleOverlayDraw() { void handleOverlayDraw() {
usermods.handleOverlayDraw(); UsermodManager::handleOverlayDraw();
if (analogClockSolidBlack) { if (analogClockSolidBlack) {
const Segment* segments = strip.getSegments(); const Segment* segments = strip.getSegments();
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {

View File

@ -13,34 +13,16 @@
#endif #endif
#endif #endif
#ifdef WLED_DEBUG
static void DebugPrintOwnerTag(PinOwner tag)
{
uint32_t q = static_cast<uint8_t>(tag);
if (q) {
DEBUG_PRINTF_P(PSTR("0x%02x (%d)"), q, q);
} else {
DEBUG_PRINT(F("(no owner)"));
}
}
#endif
/// Actual allocation/deallocation routines /// Actual allocation/deallocation routines
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag) bool PinManager::deallocatePin(byte gpio, PinOwner tag)
{ {
if (gpio == 0xFF) return true; // explicitly allow clients to free -1 as a no-op if (gpio == 0xFF) return true; // explicitly allow clients to free -1 as a no-op
if (!isPinOk(gpio, false)) return false; // but return false for any other invalid pin if (!isPinOk(gpio, false)) return false; // but return false for any other invalid pin
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided // if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) { if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN DEALLOC: FAIL GPIO %d allocated by 0x%02X, but attempted de-allocation by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]), static_cast<int>(tag));
DEBUG_PRINT(F("PIN DEALLOC: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINT(F(", but attempted de-allocation by "));
DebugPrintOwnerTag(tag);
#endif
return false; return false;
} }
@ -50,7 +32,7 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
} }
// support function for deallocating multiple pins // support function for deallocating multiple pins
bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag) bool PinManager::deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag)
{ {
bool shouldFail = false; bool shouldFail = false;
DEBUG_PRINTLN(F("MULTIPIN DEALLOC")); DEBUG_PRINTLN(F("MULTIPIN DEALLOC"));
@ -66,14 +48,7 @@ bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte array
// if the current pin is allocated by selected owner it is possible to release it // if the current pin is allocated by selected owner it is possible to release it
continue; continue;
} }
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN DEALLOC: FAIL GPIO %d allocated by 0x%02X, but attempted de-allocation by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]), static_cast<int>(tag));
DEBUG_PRINT(F("PIN DEALLOC: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINT(F(", but attempted de-allocation by "));
DebugPrintOwnerTag(tag);
#endif
shouldFail = true; shouldFail = true;
} }
if (shouldFail) { if (shouldFail) {
@ -97,14 +72,14 @@ bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte array
return true; return true;
} }
bool PinManagerClass::deallocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag) bool PinManager::deallocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
{ {
uint8_t pins[arrayElementCount]; uint8_t pins[arrayElementCount];
for (int i=0; i<arrayElementCount; i++) pins[i] = mptArray[i].pin; for (int i=0; i<arrayElementCount; i++) pins[i] = mptArray[i].pin;
return deallocateMultiplePins(pins, arrayElementCount, tag); return deallocateMultiplePins(pins, arrayElementCount, tag);
} }
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag) bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
{ {
bool shouldFail = false; bool shouldFail = false;
// first verify the pins are OK and not already allocated // first verify the pins are OK and not already allocated
@ -116,25 +91,14 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
continue; continue;
} }
if (!isPinOk(gpio, mptArray[i].isOutput)) { if (!isPinOk(gpio, mptArray[i].isOutput)) {
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Invalid pin attempted to be allocated: GPIO %d as %s\n."), gpio, mptArray[i].isOutput ? PSTR("output"): PSTR("input"));
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: GPIO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" as ")); DEBUG_PRINT(mptArray[i].isOutput ? F("output"): F("input"));
DEBUG_PRINTLN(F(""));
#endif
shouldFail = true; shouldFail = true;
} }
if ((tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) && isPinAllocated(gpio, tag)) { if ((tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) && isPinAllocated(gpio, tag)) {
// allow multiple "allocations" of HW I2C & SPI bus pins // allow multiple "allocations" of HW I2C & SPI bus pins
continue; continue;
} else if (isPinAllocated(gpio)) { } else if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
shouldFail = true; shouldFail = true;
} }
} }
@ -158,64 +122,45 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
bitWrite(pinAlloc, gpio, true); bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag; ownerTag[gpio] = tag;
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN ALLOC: Pin %d allocated by 0x%02X.\n"), gpio, static_cast<int>(tag));
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(tag);
DEBUG_PRINTLN(F(""));
#endif
} }
DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
return true; return true;
} }
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag) bool PinManager::allocatePin(byte gpio, bool output, PinOwner tag)
{ {
// HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair // HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair
if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) { if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) {
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if (gpio < 255) { // 255 (-1) is the "not defined GPIO" if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
if (!isPinOk(gpio, output)) { if (!isPinOk(gpio, output)) {
DEBUG_PRINT(F("PIN ALLOC: FAIL for owner ")); DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL for owner 0x%02X: GPIO %d "), static_cast<int>(tag), gpio);
DebugPrintOwnerTag(tag);
DEBUG_PRINT(F(": GPIO ")); DEBUG_PRINT(gpio);
if (output) DEBUG_PRINTLN(F(" cannot be used for i/o on this MCU.")); if (output) DEBUG_PRINTLN(F(" cannot be used for i/o on this MCU."));
else DEBUG_PRINTLN(F(" cannot be used as input on this MCU.")); else DEBUG_PRINTLN(F(" cannot be used as input on this MCU."));
} else { } else {
DEBUG_PRINT(F("PIN ALLOC: FAIL: GPIO ")); DEBUG_PRINT(gpio); DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d - HW I2C & SPI pins have to be allocated using allocateMultiplePins.\n"), gpio);
DEBUG_PRINTLN(F(" - HW I2C & SPI pins have to be allocated using allocateMultiplePins()"));
} }
} }
#endif #endif
return false; return false;
} }
if (isPinAllocated(gpio)) { if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Pin %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
return false; return false;
} }
bitWrite(pinAlloc, gpio, true); bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag; ownerTag[gpio] = tag;
#ifdef WLED_DEBUG DEBUG_PRINTF_P(PSTR("PIN ALLOC: Pin %d successfully allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
DEBUG_PRINT(F("PIN ALLOC: Pin ")); DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" successfully allocated by "));
DebugPrintOwnerTag(tag);
DEBUG_PRINTLN(F(""));
#endif
return true; return true;
} }
// if tag is set to PinOwner::None, checks for ANY owner of the pin. // if tag is set to PinOwner::None, checks for ANY owner of the pin.
// if tag is set to any other value, checks if that tag is the current owner of the pin. // if tag is set to any other value, checks if that tag is the current owner of the pin.
bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const bool PinManager::isPinAllocated(byte gpio, PinOwner tag)
{ {
if (!isPinOk(gpio, false)) return true; if (!isPinOk(gpio, false)) return true;
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false; if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
@ -239,7 +184,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const
*/ */
// Check if supplied GPIO is ok to use // Check if supplied GPIO is ok to use
bool PinManagerClass::isPinOk(byte gpio, bool output) const bool PinManager::isPinOk(byte gpio, bool output)
{ {
if (gpio >= WLED_NUM_PINS) return false; // catch error case, to avoid array out-of-bounds access if (gpio >= WLED_NUM_PINS) return false; // catch error case, to avoid array out-of-bounds access
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
@ -279,7 +224,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const
return false; return false;
} }
bool PinManagerClass::isReadOnlyPin(byte gpio) bool PinManager::isReadOnlyPin(byte gpio)
{ {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
if (gpio < WLED_NUM_PINS) return (digitalPinIsValid(gpio) && !digitalPinCanOutput(gpio)); if (gpio < WLED_NUM_PINS) return (digitalPinIsValid(gpio) && !digitalPinCanOutput(gpio));
@ -287,14 +232,14 @@ bool PinManagerClass::isReadOnlyPin(byte gpio)
return false; return false;
} }
PinOwner PinManagerClass::getPinOwner(byte gpio) const PinOwner PinManager::getPinOwner(byte gpio)
{ {
if (!isPinOk(gpio, false)) return PinOwner::None; if (!isPinOk(gpio, false)) return PinOwner::None;
return ownerTag[gpio]; return ownerTag[gpio];
} }
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
byte PinManagerClass::allocateLedc(byte channels) byte PinManager::allocateLedc(byte channels)
{ {
if (channels > WLED_MAX_ANALOG_CHANNELS || channels == 0) return 255; if (channels > WLED_MAX_ANALOG_CHANNELS || channels == 0) return 255;
unsigned ca = 0; unsigned ca = 0;
@ -321,7 +266,7 @@ byte PinManagerClass::allocateLedc(byte channels)
return 255; //not enough consecutive free LEDC channels return 255; //not enough consecutive free LEDC channels
} }
void PinManagerClass::deallocateLedc(byte pos, byte channels) void PinManager::deallocateLedc(byte pos, byte channels)
{ {
for (unsigned j = pos; j < pos + channels && j < WLED_MAX_ANALOG_CHANNELS; j++) { for (unsigned j = pos; j < pos + channels && j < WLED_MAX_ANALOG_CHANNELS; j++) {
bitWrite(ledcAlloc, j, false); bitWrite(ledcAlloc, j, false);
@ -329,4 +274,12 @@ void PinManagerClass::deallocateLedc(byte pos, byte channels)
} }
#endif #endif
PinManagerClass pinManager = PinManagerClass(); #ifdef ESP8266
uint32_t PinManager::pinAlloc = 0UL;
#else
uint64_t PinManager::pinAlloc = 0ULL;
uint16_t PinManager::ledcAlloc = 0;
#endif
uint8_t PinManager::i2cAllocCount = 0;
uint8_t PinManager::spiAllocCount = 0;
PinOwner PinManager::ownerTag[WLED_NUM_PINS] = { PinOwner::None };

View File

@ -70,61 +70,54 @@ enum struct PinOwner : uint8_t {
}; };
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected"); static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
class PinManagerClass { class PinManager {
private: private:
struct {
#ifdef ESP8266 #ifdef ESP8266
#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) #define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17)
uint32_t pinAlloc : 24; // 24bit, 1 bit per pin, we use first 17bits static uint32_t pinAlloc; // 1 bit per pin, we use first 17bits
#else #else
#define WLED_NUM_PINS (GPIO_PIN_COUNT) #define WLED_NUM_PINS (GPIO_PIN_COUNT)
uint64_t pinAlloc : 56; // 56 bits, 1 bit per pin, we use 50 bits on ESP32-S3 static uint64_t pinAlloc; // 1 bit per pin, we use 50 bits on ESP32-S3
uint16_t ledcAlloc : 16; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS) static uint16_t ledcAlloc; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS)
#endif #endif
uint8_t i2cAllocCount : 4; // allow multiple allocation of I2C bus pins but keep track of allocations static uint8_t i2cAllocCount; // allow multiple allocation of I2C bus pins but keep track of allocations
uint8_t spiAllocCount : 4; // allow multiple allocation of SPI bus pins but keep track of allocations static uint8_t spiAllocCount; // allow multiple allocation of SPI bus pins but keep track of allocations
} __attribute__ ((packed)); static PinOwner ownerTag[WLED_NUM_PINS];
PinOwner ownerTag[WLED_NUM_PINS] = { PinOwner::None };
public: public:
PinManagerClass() : pinAlloc(0ULL), i2cAllocCount(0), spiAllocCount(0) { // De-allocates a single pin
static bool deallocatePin(byte gpio, PinOwner tag);
// De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified)
static bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag);
static bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag);
// Allocates a single pin, with an owner tag.
// De-allocation requires the same owner tag (or override)
static bool allocatePin(byte gpio, bool output, PinOwner tag);
// Allocates all the pins, or allocates none of the pins, with owner tag.
// Provided to simplify error condition handling in clients
// using more than one pin, such as I2C, SPI, rotary encoders,
// ethernet, etc..
static bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag );
[[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]]
static inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
[[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]]
static inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
// will return true for reserved pins
static bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
// will return false for reserved pins
static bool isPinOk(byte gpio, bool output = true);
static bool isReadOnlyPin(byte gpio);
static PinOwner getPinOwner(byte gpio);
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
ledcAlloc = 0; static byte allocateLedc(byte channels);
static void deallocateLedc(byte pos, byte channels);
#endif #endif
}
// De-allocates a single pin
bool deallocatePin(byte gpio, PinOwner tag);
// De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified)
bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag);
bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag);
// Allocates a single pin, with an owner tag.
// De-allocation requires the same owner tag (or override)
bool allocatePin(byte gpio, bool output, PinOwner tag);
// Allocates all the pins, or allocates none of the pins, with owner tag.
// Provided to simplify error condition handling in clients
// using more than one pin, such as I2C, SPI, rotary encoders,
// ethernet, etc..
bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag );
[[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]]
inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
[[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]]
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
// will return true for reserved pins
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None) const;
// will return false for reserved pins
bool isPinOk(byte gpio, bool output = true) const;
static bool isReadOnlyPin(byte gpio);
PinOwner getPinOwner(byte gpio) const;
#ifdef ARDUINO_ARCH_ESP32
byte allocateLedc(byte channels);
void deallocateLedc(byte pos, byte channels);
#endif
}; };
extern PinManagerClass pinManager; //extern PinManager pinManager;
#endif #endif

View File

@ -104,18 +104,18 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{ {
int t = 0; int t = 0;
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin, PinOwner::Relay)) { if (rlyPin>=0 && PinManager::isPinAllocated(rlyPin, PinOwner::Relay)) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay); PinManager::deallocatePin(rlyPin, PinOwner::Relay);
} }
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin, PinOwner::IR)) { if (irPin>=0 && PinManager::isPinAllocated(irPin, PinOwner::IR)) {
deInitIR(); deInitIR();
pinManager.deallocatePin(irPin, PinOwner::IR); PinManager::deallocatePin(irPin, PinOwner::IR);
} }
#endif #endif
for (unsigned s=0; s<WLED_MAX_BUTTONS; s++) { for (unsigned s=0; s<WLED_MAX_BUTTONS; s++) {
if (btnPin[s]>=0 && pinManager.isPinAllocated(btnPin[s], PinOwner::Button)) { if (btnPin[s]>=0 && PinManager::isPinAllocated(btnPin[s], PinOwner::Button)) {
pinManager.deallocatePin(btnPin[s], PinOwner::Button); PinManager::deallocatePin(btnPin[s], PinOwner::Button);
#ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state, detach interrupt #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state, detach interrupt
if (digitalPinToTouchChannel(btnPin[s]) >= 0) // if touch capable pin if (digitalPinToTouchChannel(btnPin[s]) >= 0) // if touch capable pin
touchDetachInterrupt(btnPin[s]); // if not assigned previously, this will do nothing touchDetachInterrupt(btnPin[s]); // if not assigned previously, this will do nothing
@ -233,7 +233,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// update other pins // update other pins
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = request->arg(F("IR")).toInt(); int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) { if (PinManager::allocatePin(hw_ir_pin,false, PinOwner::IR)) {
irPin = hw_ir_pin; irPin = hw_ir_pin;
} else { } else {
irPin = -1; irPin = -1;
@ -244,7 +244,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
irApplyToAllSelected = !request->hasArg(F("MSO")); irApplyToAllSelected = !request->hasArg(F("MSO"));
int hw_rly_pin = request->arg(F("RL")).toInt(); int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true, PinOwner::Relay)) { if (PinManager::allocatePin(hw_rly_pin,true, PinOwner::Relay)) {
rlyPin = hw_rly_pin; rlyPin = hw_rly_pin;
} else { } else {
rlyPin = -1; rlyPin = -1;
@ -259,7 +259,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10) char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
int hw_btn_pin = request->arg(bt).toInt(); int hw_btn_pin = request->arg(bt).toInt();
if (hw_btn_pin >= 0 && pinManager.allocatePin(hw_btn_pin,false,PinOwner::Button)) { if (hw_btn_pin >= 0 && PinManager::allocatePin(hw_btn_pin,false,PinOwner::Button)) {
btnPin[i] = hw_btn_pin; btnPin[i] = hw_btn_pin;
buttonType[i] = request->arg(be).toInt(); buttonType[i] = request->arg(be).toInt();
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
@ -270,7 +270,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// not an ADC analog pin // not an ADC analog pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n"), btnPin[i], i); DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for analog button #%d is not an analog pin!\n"), btnPin[i], i);
btnPin[i] = -1; btnPin[i] = -1;
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button); PinManager::deallocatePin(hw_btn_pin,PinOwner::Button);
} else { } else {
analogReadResolution(12); // see #4040 analogReadResolution(12); // see #4040
} }
@ -282,7 +282,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// not a touch pin // not a touch pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[i], i); DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[i], i);
btnPin[i] = -1; btnPin[i] = -1;
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button); PinManager::deallocatePin(hw_btn_pin,PinOwner::Button);
} }
#ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so
else else
@ -630,10 +630,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) { if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) {
// only if pins changed // only if pins changed
uint8_t old_i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) }; uint8_t old_i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
pinManager.deallocateMultiplePins(old_i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins PinManager::deallocateMultiplePins(old_i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } }; PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) { if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && PinManager::allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
i2c_sda = hw_sda_pin; i2c_sda = hw_sda_pin;
i2c_scl = hw_scl_pin; i2c_scl = hw_scl_pin;
// no bus re-initialisation as usermods do not get any notification // no bus re-initialisation as usermods do not get any notification
@ -657,9 +657,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) { if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) {
// only if pins changed // only if pins changed
uint8_t old_spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) }; uint8_t old_spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
pinManager.deallocateMultiplePins(old_spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins PinManager::deallocateMultiplePins(old_spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } }; PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) { if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && PinManager::allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
spi_mosi = hw_mosi_pin; spi_mosi = hw_mosi_pin;
spi_miso = hw_miso_pin; spi_miso = hw_miso_pin;
spi_sclk = hw_sclk_pin; spi_sclk = hw_sclk_pin;
@ -749,8 +749,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DEBUG_PRINTF_P(PSTR(" = %s\n"), value.c_str()); DEBUG_PRINTF_P(PSTR(" = %s\n"), value.c_str());
} }
} }
usermods.readFromConfig(um); // force change of usermod parameters UsermodManager::readFromConfig(um); // force change of usermod parameters
DEBUG_PRINTLN(F("Done re-init usermods.")); DEBUG_PRINTLN(F("Done re-init UsermodManager::"));
releaseJSONBufferLock(); releaseJSONBufferLock();
} }
@ -1190,7 +1190,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
// internal call, does not send XML response // internal call, does not send XML response
pos = req.indexOf(F("IN")); pos = req.indexOf(F("IN"));
if (pos < 1) XML_response(request); if (pos < 1) {
auto response = request->beginResponseStream("text/xml");
XML_response(*response);
request->send(response);
}
return true; return true;
} }

View File

@ -974,10 +974,8 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
DEBUG_PRINTLN(); DEBUG_PRINTLN();
#endif #endif
#ifndef WLED_DISABLE_ESPNOW
// usermods hook can override processing // usermods hook can override processing
if (usermods.onEspNowMessage(address, data, len)) return; if (UsermodManager::onEspNowMessage(address, data, len)) return;
#endif
// handle WiZ Mote data // handle WiZ Mote data
if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {

View File

@ -8,7 +8,7 @@ void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++
void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); } void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); }
void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); } void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); }
void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); } void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); }
void UsermodManager::appendConfigData() { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(); } void UsermodManager::appendConfigData(Print& dest) { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(dest); }
bool UsermodManager::handleButton(uint8_t b) { bool UsermodManager::handleButton(uint8_t b) {
bool overrideIO = false; bool overrideIO = false;
for (unsigned i = 0; i < numMods; i++) { for (unsigned i = 0; i < numMods; i++) {
@ -68,3 +68,16 @@ bool UsermodManager::add(Usermod* um)
ums[numMods++] = um; ums[numMods++] = um;
return true; return true;
} }
Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr};
byte UsermodManager::numMods = 0;
/* Usermod v2 interface shim for oappend */
Print* Usermod::oappend_shim = nullptr;
void Usermod::appendConfigData(Print& settingsScript) {
assert(!oappend_shim);
oappend_shim = &settingsScript;
this->appendConfigData();
oappend_shim = nullptr;
}

View File

@ -249,225 +249,225 @@ void registerUsermods()
* || || || * || || ||
* \/ \/ \/ * \/ \/ \/
*/ */
//usermods.add(new MyExampleUsermod()); //UsermodManager::add(new MyExampleUsermod());
#ifdef USERMOD_BATTERY #ifdef USERMOD_BATTERY
usermods.add(new UsermodBattery()); UsermodManager::add(new UsermodBattery());
#endif #endif
#ifdef USERMOD_DALLASTEMPERATURE #ifdef USERMOD_DALLASTEMPERATURE
usermods.add(new UsermodTemperature()); UsermodManager::add(new UsermodTemperature());
#endif #endif
#ifdef USERMOD_SN_PHOTORESISTOR #ifdef USERMOD_SN_PHOTORESISTOR
usermods.add(new Usermod_SN_Photoresistor()); UsermodManager::add(new Usermod_SN_Photoresistor());
#endif #endif
#ifdef USERMOD_PWM_FAN #ifdef USERMOD_PWM_FAN
usermods.add(new PWMFanUsermod()); UsermodManager::add(new PWMFanUsermod());
#endif #endif
#ifdef USERMOD_BUZZER #ifdef USERMOD_BUZZER
usermods.add(new BuzzerUsermod()); UsermodManager::add(new BuzzerUsermod());
#endif #endif
#ifdef USERMOD_BH1750 #ifdef USERMOD_BH1750
usermods.add(new Usermod_BH1750()); UsermodManager::add(new Usermod_BH1750());
#endif #endif
#ifdef USERMOD_BME280 #ifdef USERMOD_BME280
usermods.add(new UsermodBME280()); UsermodManager::add(new UsermodBME280());
#endif #endif
#ifdef USERMOD_BME68X #ifdef USERMOD_BME68X
usermods.add(new UsermodBME68X()); UsermodManager::add(new UsermodBME68X());
#endif #endif
#ifdef USERMOD_SENSORSTOMQTT #ifdef USERMOD_SENSORSTOMQTT
usermods.add(new UserMod_SensorsToMQTT()); UsermodManager::add(new UserMod_SensorsToMQTT());
#endif #endif
#ifdef USERMOD_PIRSWITCH #ifdef USERMOD_PIRSWITCH
usermods.add(new PIRsensorSwitch()); UsermodManager::add(new PIRsensorSwitch());
#endif #endif
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
usermods.add(new FourLineDisplayUsermod()); UsermodManager::add(new FourLineDisplayUsermod());
#endif #endif
#ifdef USERMOD_ROTARY_ENCODER_UI #ifdef USERMOD_ROTARY_ENCODER_UI
usermods.add(new RotaryEncoderUIUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY UsermodManager::add(new RotaryEncoderUIUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY
#endif #endif
#ifdef USERMOD_AUTO_SAVE #ifdef USERMOD_AUTO_SAVE
usermods.add(new AutoSaveUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY UsermodManager::add(new AutoSaveUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY
#endif #endif
#ifdef USERMOD_DHT #ifdef USERMOD_DHT
usermods.add(new UsermodDHT()); UsermodManager::add(new UsermodDHT());
#endif #endif
#ifdef USERMOD_VL53L0X_GESTURES #ifdef USERMOD_VL53L0X_GESTURES
usermods.add(new UsermodVL53L0XGestures()); UsermodManager::add(new UsermodVL53L0XGestures());
#endif #endif
#ifdef USERMOD_ANIMATED_STAIRCASE #ifdef USERMOD_ANIMATED_STAIRCASE
usermods.add(new Animated_Staircase()); UsermodManager::add(new Animated_Staircase());
#endif #endif
#ifdef USERMOD_MULTI_RELAY #ifdef USERMOD_MULTI_RELAY
usermods.add(new MultiRelay()); UsermodManager::add(new MultiRelay());
#endif #endif
#ifdef USERMOD_RTC #ifdef USERMOD_RTC
usermods.add(new RTCUsermod()); UsermodManager::add(new RTCUsermod());
#endif #endif
#ifdef USERMOD_ELEKSTUBE_IPS #ifdef USERMOD_ELEKSTUBE_IPS
usermods.add(new ElekstubeIPSUsermod()); UsermodManager::add(new ElekstubeIPSUsermod());
#endif #endif
#ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR #ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR
usermods.add(new RotaryEncoderBrightnessColor()); UsermodManager::add(new RotaryEncoderBrightnessColor());
#endif #endif
#ifdef RGB_ROTARY_ENCODER #ifdef RGB_ROTARY_ENCODER
usermods.add(new RgbRotaryEncoderUsermod()); UsermodManager::add(new RgbRotaryEncoderUsermod());
#endif #endif
#ifdef USERMOD_ST7789_DISPLAY #ifdef USERMOD_ST7789_DISPLAY
usermods.add(new St7789DisplayUsermod()); UsermodManager::add(new St7789DisplayUsermod());
#endif #endif
#ifdef USERMOD_PIXELS_DICE_TRAY #ifdef USERMOD_PIXELS_DICE_TRAY
usermods.add(new PixelsDiceTrayUsermod()); UsermodManager::add(new PixelsDiceTrayUsermod());
#endif #endif
#ifdef USERMOD_SEVEN_SEGMENT #ifdef USERMOD_SEVEN_SEGMENT
usermods.add(new SevenSegmentDisplay()); UsermodManager::add(new SevenSegmentDisplay());
#endif #endif
#ifdef USERMOD_SSDR #ifdef USERMOD_SSDR
usermods.add(new UsermodSSDR()); UsermodManager::add(new UsermodSSDR());
#endif #endif
#ifdef USERMOD_CRONIXIE #ifdef USERMOD_CRONIXIE
usermods.add(new UsermodCronixie()); UsermodManager::add(new UsermodCronixie());
#endif #endif
#ifdef QUINLED_AN_PENTA #ifdef QUINLED_AN_PENTA
usermods.add(new QuinLEDAnPentaUsermod()); UsermodManager::add(new QuinLEDAnPentaUsermod());
#endif #endif
#ifdef USERMOD_WIZLIGHTS #ifdef USERMOD_WIZLIGHTS
usermods.add(new WizLightsUsermod()); UsermodManager::add(new WizLightsUsermod());
#endif #endif
#ifdef USERMOD_WIREGUARD #ifdef USERMOD_WIREGUARD
usermods.add(new WireguardUsermod()); UsermodManager::add(new WireguardUsermod());
#endif #endif
#ifdef USERMOD_WORDCLOCK #ifdef USERMOD_WORDCLOCK
usermods.add(new WordClockUsermod()); UsermodManager::add(new WordClockUsermod());
#endif #endif
#ifdef USERMOD_MY9291 #ifdef USERMOD_MY9291
usermods.add(new MY9291Usermod()); UsermodManager::add(new MY9291Usermod());
#endif #endif
#ifdef USERMOD_SI7021_MQTT_HA #ifdef USERMOD_SI7021_MQTT_HA
usermods.add(new Si7021_MQTT_HA()); UsermodManager::add(new Si7021_MQTT_HA());
#endif #endif
#ifdef USERMOD_SMARTNEST #ifdef USERMOD_SMARTNEST
usermods.add(new Smartnest()); UsermodManager::add(new Smartnest());
#endif #endif
#ifdef USERMOD_AUDIOREACTIVE #ifdef USERMOD_AUDIOREACTIVE
usermods.add(new AudioReactive()); UsermodManager::add(new AudioReactive());
#endif #endif
#ifdef USERMOD_ANALOG_CLOCK #ifdef USERMOD_ANALOG_CLOCK
usermods.add(new AnalogClockUsermod()); UsermodManager::add(new AnalogClockUsermod());
#endif #endif
#ifdef USERMOD_PING_PONG_CLOCK #ifdef USERMOD_PING_PONG_CLOCK
usermods.add(new PingPongClockUsermod()); UsermodManager::add(new PingPongClockUsermod());
#endif #endif
#ifdef USERMOD_ADS1115 #ifdef USERMOD_ADS1115
usermods.add(new ADS1115Usermod()); UsermodManager::add(new ADS1115Usermod());
#endif #endif
#ifdef USERMOD_KLIPPER_PERCENTAGE #ifdef USERMOD_KLIPPER_PERCENTAGE
usermods.add(new klipper_percentage()); UsermodManager::add(new klipper_percentage());
#endif #endif
#ifdef USERMOD_BOBLIGHT #ifdef USERMOD_BOBLIGHT
usermods.add(new BobLightUsermod()); UsermodManager::add(new BobLightUsermod());
#endif #endif
#ifdef SD_ADAPTER #ifdef SD_ADAPTER
usermods.add(new UsermodSdCard()); UsermodManager::add(new UsermodSdCard());
#endif #endif
#ifdef USERMOD_PWM_OUTPUTS #ifdef USERMOD_PWM_OUTPUTS
usermods.add(new PwmOutputsUsermod()); UsermodManager::add(new PwmOutputsUsermod());
#endif #endif
#ifdef USERMOD_SHT #ifdef USERMOD_SHT
usermods.add(new ShtUsermod()); UsermodManager::add(new ShtUsermod());
#endif #endif
#ifdef USERMOD_ANIMARTRIX #ifdef USERMOD_ANIMARTRIX
usermods.add(new AnimartrixUsermod("Animartrix", false)); UsermodManager::add(new AnimartrixUsermod("Animartrix", false));
#endif #endif
#ifdef USERMOD_INTERNAL_TEMPERATURE #ifdef USERMOD_INTERNAL_TEMPERATURE
usermods.add(new InternalTemperatureUsermod()); UsermodManager::add(new InternalTemperatureUsermod());
#endif #endif
#ifdef USERMOD_HTTP_PULL_LIGHT_CONTROL #ifdef USERMOD_HTTP_PULL_LIGHT_CONTROL
usermods.add(new HttpPullLightControl()); UsermodManager::add(new HttpPullLightControl());
#endif #endif
#ifdef USERMOD_MPU6050_IMU #ifdef USERMOD_MPU6050_IMU
static MPU6050Driver mpu6050; usermods.add(&mpu6050); static MPU6050Driver mpu6050; UsermodManager::add(&mpu6050);
#endif #endif
#ifdef USERMOD_GYRO_SURGE #ifdef USERMOD_GYRO_SURGE
static GyroSurge gyro_surge; usermods.add(&gyro_surge); static GyroSurge gyro_surge; UsermodManager::add(&gyro_surge);
#endif #endif
#ifdef USERMOD_LDR_DUSK_DAWN #ifdef USERMOD_LDR_DUSK_DAWN
usermods.add(new LDR_Dusk_Dawn_v2()); UsermodManager::add(new LDR_Dusk_Dawn_v2());
#endif #endif
#ifdef USERMOD_STAIRCASE_WIPE #ifdef USERMOD_STAIRCASE_WIPE
usermods.add(new StairwayWipeUsermod()); UsermodManager::add(new StairwayWipeUsermod());
#endif #endif
#ifdef USERMOD_MAX17048 #ifdef USERMOD_MAX17048
usermods.add(new Usermod_MAX17048()); UsermodManager::add(new Usermod_MAX17048());
#endif #endif
#ifdef USERMOD_TETRISAI #ifdef USERMOD_TETRISAI
usermods.add(new TetrisAIUsermod()); UsermodManager::add(new TetrisAIUsermod());
#endif #endif
#ifdef USERMOD_AHT10 #ifdef USERMOD_AHT10
usermods.add(new UsermodAHT10()); UsermodManager::add(new UsermodAHT10());
#endif #endif
#ifdef USERMOD_INA226 #ifdef USERMOD_INA226
usermods.add(new UsermodINA226()); UsermodManager::add(new UsermodINA226());
#endif #endif
#ifdef USERMOD_LD2410 #ifdef USERMOD_LD2410
usermods.add(new LD2410Usermod()); UsermodManager::add(new LD2410Usermod());
#endif #endif
#ifdef USERMOD_POV_DISPLAY #ifdef USERMOD_POV_DISPLAY
usermods.add(new PovDisplayUsermod()); UsermodManager::add(new PovDisplayUsermod());
#endif #endif
} }

View File

@ -87,90 +87,30 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv
return true; return true;
} }
static size_t printSetFormInput(Print& settingsScript, const char* key, const char* selector, int value) {
//append a numeric setting to string buffer return settingsScript.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value);
void sappend(char stype, const char* key, int val)
{
char ds[] = "d.Sf.";
switch(stype)
{
case 'c': //checkbox
oappend(ds);
oappend(key);
oappend(".checked=");
oappendi(val);
oappend(";");
break;
case 'v': //numeric
oappend(ds);
oappend(key);
oappend(".value=");
oappendi(val);
oappend(";");
break;
case 'i': //selectedIndex
oappend(ds);
oappend(key);
oappend(SET_F(".selectedIndex="));
oappendi(val);
oappend(";");
break;
}
} }
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val) {
//append a string setting to buffer return printSetFormInput(settingsScript, key, PSTR("checked"), val);
void sappends(char stype, const char* key, char* val) }
{ size_t printSetFormValue(Print& settingsScript, const char* key, int val) {
switch(stype) return printSetFormInput(settingsScript, key, PSTR("value"), val);
{ }
case 's': {//string (we can interpret val as char*) size_t printSetFormIndex(Print& settingsScript, const char* key, int index) {
String buf = val; return printSetFormInput(settingsScript, key, PSTR("selectedIndex"), index);
//convert "%" to "%%" to make EspAsyncWebServer happy
//buf.replace("%","%%");
oappend("d.Sf.");
oappend(key);
oappend(".value=\"");
oappend(buf.c_str());
oappend("\";");
break;}
case 'm': //message
oappend(SET_F("d.getElementsByClassName"));
oappend(key);
oappend(SET_F(".innerHTML=\""));
oappend(val);
oappend("\";");
break;
}
} }
size_t printSetFormValue(Print& settingsScript, const char* key, const char* val) {
bool oappendi(int i) return settingsScript.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val);
{
char s[12]; // 32bit signed number can have 10 digits plus - sign
sprintf(s, "%d", i);
return oappend(s);
} }
size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val) {
bool oappend(const char* txt) return settingsScript.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val);
{
unsigned len = strlen(txt);
if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks
#ifdef WLED_DEBUG
DEBUG_PRINT(F("oappend() buffer overflow. Cannot append "));
DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\""));
DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\""));
#endif
return false; // buffer full
}
strcpy(obuf + olen, txt);
olen += len;
return true;
} }
void prepareHostname(char* hostname) void prepareHostname(char* hostname)
{ {
sprintf_P(hostname, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); sprintf_P(hostname, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6);

View File

@ -72,7 +72,7 @@ void WLED::loop()
unsigned long usermodMillis = millis(); unsigned long usermodMillis = millis();
#endif #endif
userLoop(); userLoop();
usermods.loop(); UsermodManager::loop();
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
usermodMillis = millis() - usermodMillis; usermodMillis = millis() - usermodMillis;
avgUsermodMillis += usermodMillis; avgUsermodMillis += usermodMillis;
@ -410,10 +410,10 @@ void WLED::setup()
#endif #endif
#if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST)
pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output PinManager::allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output
#endif #endif
#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin
pinManager.allocatePin(2, true, PinOwner::DMX); PinManager::allocatePin(2, true, PinOwner::DMX);
#endif #endif
DEBUG_PRINTLN(F("Registering usermods ...")); DEBUG_PRINTLN(F("Registering usermods ..."));
@ -452,7 +452,7 @@ void WLED::setup()
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
#if defined(STATUSLED) && STATUSLED>=0 #if defined(STATUSLED) && STATUSLED>=0
if (!pinManager.isPinAllocated(STATUSLED)) { if (!PinManager::isPinAllocated(STATUSLED)) {
// NOTE: Special case: The status LED should *NOT* be allocated. // NOTE: Special case: The status LED should *NOT* be allocated.
// See comments in handleStatusLed(). // See comments in handleStatusLed().
pinMode(STATUSLED, OUTPUT); pinMode(STATUSLED, OUTPUT);
@ -465,7 +465,7 @@ void WLED::setup()
DEBUG_PRINTLN(F("Usermods setup")); DEBUG_PRINTLN(F("Usermods setup"));
userSetup(); userSetup();
usermods.setup(); UsermodManager::setup();
DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap());
if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0) if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0)
@ -479,8 +479,8 @@ void WLED::setup()
findWiFi(true); // start scanning for available WiFi-s findWiFi(true); // start scanning for available WiFi-s
// all GPIOs are allocated at this point // all GPIOs are allocated at this point
serialCanRX = !pinManager.isPinAllocated(hardwareRX); // Serial RX pin (GPIO 3 on ESP32 and ESP8266) serialCanRX = !PinManager::isPinAllocated(hardwareRX); // Serial RX pin (GPIO 3 on ESP32 and ESP8266)
serialCanTX = !pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut; // Serial TX pin (GPIO 1 on ESP32 and ESP8266) serialCanTX = !PinManager::isPinAllocated(hardwareTX) || PinManager::getPinOwner(hardwareTX) == PinOwner::DebugOut; // Serial TX pin (GPIO 1 on ESP32 and ESP8266)
#ifdef WLED_ENABLE_ADALIGHT #ifdef WLED_ENABLE_ADALIGHT
//Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused //Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused
@ -685,7 +685,7 @@ bool WLED::initEthernet()
return false; return false;
} }
if (!pinManager.allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) {
DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins"));
return false; return false;
} }
@ -719,7 +719,7 @@ bool WLED::initEthernet()
DEBUG_PRINTLN(F("initC: ETH.begin() failed")); DEBUG_PRINTLN(F("initC: ETH.begin() failed"));
// de-allocate the allocated pins // de-allocate the allocated pins
for (managed_pin_type mpt : pinsToAllocate) { for (managed_pin_type mpt : pinsToAllocate) {
pinManager.deallocatePin(mpt.pin, PinOwner::Ethernet); PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet);
} }
return false; return false;
} }
@ -1010,7 +1010,7 @@ void WLED::handleConnection()
} }
initInterfaces(); initInterfaces();
userConnected(); userConnected();
usermods.connected(); UsermodManager::connected();
lastMqttReconnectAttempt = 0; // force immediate update lastMqttReconnectAttempt = 0; // force immediate update
// shut down AP // shut down AP
@ -1033,7 +1033,7 @@ void WLED::handleStatusLED()
uint32_t c = 0; uint32_t c = 0;
#if STATUSLED>=0 #if STATUSLED>=0
if (pinManager.isPinAllocated(STATUSLED)) { if (PinManager::isPinAllocated(STATUSLED)) {
return; //lower priority if something else uses the same pin return; //lower priority if something else uses the same pin
} }
#endif #endif

View File

@ -839,10 +839,6 @@ WLED_GLOBAL time_t sunrise _INIT(0);
WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL time_t sunset _INIT(0);
WLED_GLOBAL Toki toki _INIT(Toki()); WLED_GLOBAL Toki toki _INIT(Toki());
// Temp buffer
WLED_GLOBAL char* obuf;
WLED_GLOBAL uint16_t olen _INIT(0);
// General filesystem // General filesystem
WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesUsed _INIT(0);
WLED_GLOBAL size_t fsBytesTotal _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0);

View File

@ -396,7 +396,7 @@ void initServer()
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().disableWatchdog(); WLED::instance().disableWatchdog();
#endif #endif
usermods.onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init) UsermodManager::onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init)
lastEditTime = millis(); // make sure PIN does not lock during update lastEditTime = millis(); // make sure PIN does not lock during update
strip.suspend(); strip.suspend();
#ifdef ESP8266 #ifdef ESP8266
@ -412,7 +412,7 @@ void initServer()
} else { } else {
DEBUG_PRINTLN(F("Update Failed")); DEBUG_PRINTLN(F("Update Failed"));
strip.resume(); strip.resume();
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init) UsermodManager::onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().enableWatchdog(); WLED::instance().enableWatchdog();
#endif #endif
@ -520,27 +520,23 @@ void serveSettingsJS(AsyncWebServerRequest* request)
handleStaticContent(request, FPSTR(_common_js), 200, FPSTR(CONTENT_TYPE_JAVASCRIPT), JS_common, JS_common_length); handleStaticContent(request, FPSTR(_common_js), 200, FPSTR(CONTENT_TYPE_JAVASCRIPT), JS_common, JS_common_length);
return; return;
} }
char buf[SETTINGS_STACK_BUF_SIZE+37];
buf[0] = 0;
byte subPage = request->arg(F("p")).toInt(); byte subPage = request->arg(F("p")).toInt();
if (subPage > 10) { if (subPage > 10) {
strcpy_P(buf, PSTR("alert('Settings for this request are not implemented.');")); request->send_P(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('Settings for this request are not implemented.');"));
request->send(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
return; return;
} }
if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) { if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) {
strcpy_P(buf, PSTR("alert('PIN incorrect.');")); request->send_P(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('PIN incorrect.');"));
request->send(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
return; return;
} }
strcat_P(buf,PSTR("function GetV(){var d=document;"));
getSettingsJS(subPage, buf+strlen(buf)); // this may overflow by 35bytes!!!
strcat_P(buf,PSTR("}"));
AsyncWebServerResponse *response; AsyncResponseStream *response = request->beginResponseStream(FPSTR(CONTENT_TYPE_JAVASCRIPT));
response = request->beginResponse(200, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf);
response->addHeader(F("Cache-Control"), F("no-store")); response->addHeader(F("Cache-Control"), F("no-store"));
response->addHeader(F("Expires"), F("0")); response->addHeader(F("Expires"), F("0"));
response->print(F("function GetV(){var d=document;"));
getSettingsJS(subPage, *response);
response->print(F("}"));
request->send(response); request->send(response);
} }

File diff suppressed because it is too large Load Diff