Merge branch '0_15' into end_oappend_v2

This commit is contained in:
Blaz Kristan
2024-09-24 21:43:47 +02:00
49 changed files with 338 additions and 394 deletions

View File

@@ -75,7 +75,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
static um_data_t* getAudioData() {
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
um_data = simulateSound(SEGMENT.soundSim);
}
@@ -6298,7 +6298,7 @@ static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale
uint8_t *fftResult = nullptr;
float *fftBin = nullptr;
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];
volumeRaw = *(float*) um_data->u_data[1];
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.
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);
}
float volumeSmth = *(float*) um_data->u_data[0];
@@ -7494,7 +7494,7 @@ uint16_t mode_2DAkemi(void) {
const float normalFactor = 0.4f;
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);
}
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
free(data);
} else {
DEBUG_PRINT(F("---- Released data "));
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."));
DEBUG_PRINTF_P(PSTR("---- Released data (%p): inconsistent UsedSegmentData (%d/%d), cowardly refusing to free nothing.\n"), this, _dataLen, Segment::getUsedSegmentData());
}
data = nullptr;
Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData());
@@ -1034,7 +1030,6 @@ void Segment::refreshLightCapabilities() {
if (bus->getStart() >= segStopIdx) 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 (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
@@ -1251,7 +1246,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
// 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
while (pinManager.isPinAllocated(defPin[j]) || !pinManager.isPinOk(defPin[j],true)) {
while (PinManager::isPinAllocated(defPin[j]) || !PinManager::isPinOk(defPin[j],true)) {
if (validPin) {
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
@@ -1567,7 +1562,7 @@ uint16_t WS2812FX::getLengthPhysical() const {
unsigned len = 0;
for (size_t b = 0; b < BusManager::getNumBusses(); 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();
}
return len;

View File

@@ -130,11 +130,11 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
, _colorOrderMap(com)
{
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;
_pins[0] = bc.pins[0];
if (is2Pin(bc.type)) {
if (!pinManager.allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup();
return;
}
@@ -422,8 +422,8 @@ void BusDigital::cleanup() {
_valid = false;
_busPtr = nullptr;
if (_data != nullptr) freeData();
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
}
@@ -464,16 +464,16 @@ BusPwm::BusPwm(BusConfig &bc)
managed_pin_type pins[numPins];
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
analogWriteRange((1<<_depth)-1);
analogWriteFreq(_frequency);
#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
_ledcStart = pinManager.allocateLedc(numPins);
_ledcStart = PinManager::allocateLedc(numPins);
if (_ledcStart == 255) { //no more free LEDC channels
pinManager.deallocateMultiplePins(pins, numPins, PinOwner::BusPwm);
PinManager::deallocateMultiplePins(pins, numPins, PinOwner::BusPwm);
return;
}
// 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() {
unsigned numPins = getPins();
for (unsigned i = 0; i < numPins; i++) {
pinManager.deallocatePin(_pins[i], PinOwner::BusPwm);
if (!pinManager.isPinOk(_pins[i])) continue;
PinManager::deallocatePin(_pins[i], PinOwner::BusPwm);
if (!PinManager::isPinOk(_pins[i])) continue;
#ifdef ESP8266
digitalWrite(_pins[i], LOW); //turn off PWM interrupt
#else
@@ -649,7 +649,7 @@ void BusPwm::deallocatePins() {
#endif
}
#ifdef ARDUINO_ARCH_ESP32
pinManager.deallocateLedc(_ledcStart, numPins);
PinManager::deallocateLedc(_ledcStart, numPins);
#endif
}
@@ -661,7 +661,7 @@ BusOnOff::BusOnOff(BusConfig &bc)
if (!Bus::isOnOff(bc.type)) return;
uint8_t currentPin = bc.pins[0];
if (!pinManager.allocatePin(currentPin, true, PinOwner::BusOnOff)) {
if (!PinManager::allocatePin(currentPin, true, PinOwner::BusOnOff)) {
return;
}
_pin = currentPin; //store only after allocatePin() succeeds
@@ -830,7 +830,7 @@ static String LEDTypesToJson(const std::vector<LEDType>& types) {
String json;
for (const auto &type : types) {
// 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];
sprintf_P(str, PSTR("{i:%d,c:%d,t:\"%s\",n:\"%s\"},"), type.id, capabilities, type.type, type.name);
json += str;
@@ -904,7 +904,7 @@ void BusManager::esp32RMTInvertIdle() {
void BusManager::on() {
#ifdef ESP8266
//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++) {
uint8_t pins[2] = {255,255};
if (busses[i]->isDigital() && busses[i]->getPins(pins)) {
@@ -926,7 +926,7 @@ void BusManager::off() {
#ifdef ESP8266
// turn off built-in LED if strip is turned off
// 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;
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);

View File

@@ -104,6 +104,7 @@ class Bus {
inline bool isPWM() const { return isPWM(_type); }
inline bool isVirtual() const { return isVirtual(_type); }
inline bool is16bit() const { return is16bit(_type); }
inline bool mustRefresh() const { return mustRefresh(_type); }
inline void setReversed(bool reversed) { _reversed = reversed; }
inline void setStart(uint16_t start) { _start = start; }
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 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 mustRefresh(uint8_t type) { return type == TYPE_TM1814; }
static constexpr int numPWMPins(uint8_t type) { return (type - 40); }
static inline int16_t getCCT() { return _cct; }
@@ -280,7 +282,7 @@ class BusOnOff : public Bus {
uint32_t getPixelColor(uint16_t pix) const override;
uint8_t getPins(uint8_t* pinArray) const override;
void show() override;
void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); }
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
static std::vector<LEDType> getLEDTypes();

View File

@@ -267,7 +267,7 @@ void handleButton()
if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue;
#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 (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"];
if (!hw_btn_ins.isNull()) {
// 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;
for (JsonObject btn : hw_btn_ins) {
CJSON(buttonType[s], btn["type"]);
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;
#ifdef ARDUINO_ARCH_ESP32
// 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
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;
pinManager.deallocatePin(pin,PinOwner::Button);
PinManager::deallocatePin(pin,PinOwner::Button);
} else {
analogReadResolution(12); // see #4040
}
@@ -286,7 +286,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
// 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);
btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button);
PinManager::deallocatePin(pin,PinOwner::Button);
}
//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
@@ -331,7 +331,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (fromFS) {
// relies upon only being called once with fromFS == true, which is currently true.
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;
buttonType[s] = BTN_TYPE_NONE;
}
@@ -358,8 +358,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
#ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
if (hw_ir_pin > -2) {
pinManager.deallocatePin(irPin, PinOwner::IR);
if (pinManager.allocatePin(hw_ir_pin, false, PinOwner::IR)) {
PinManager::deallocatePin(irPin, PinOwner::IR);
if (PinManager::allocatePin(hw_ir_pin, false, PinOwner::IR)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
@@ -374,8 +374,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
rlyOpenDrain = relay[F("odrain")] | rlyOpenDrain;
int hw_relay_pin = relay["pin"] | -2;
if (hw_relay_pin > -2) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay);
if (pinManager.allocatePin(hw_relay_pin,true, PinOwner::Relay)) {
PinManager::deallocatePin(rlyPin, PinOwner::Relay);
if (PinManager::allocatePin(hw_relay_pin,true, PinOwner::Relay)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
} else {
@@ -394,7 +394,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(i2c_sda, hw_if_i2c[0]);
CJSON(i2c_scl, hw_if_i2c[1]);
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
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();
@@ -410,7 +410,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(spi_sclk, hw_if_spi[1]);
CJSON(spi_miso, hw_if_spi[2]);
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
SPI.begin(spi_sclk, spi_miso, spi_mosi); // SPI global uses VSPI on ESP32 and FSPI on C3, S3
#else
@@ -664,7 +664,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
DEBUG_PRINTLN(F("Starting usermod config."));
JsonObject usermods_settings = doc["um"];
if (!usermods_settings.isNull()) {
needsSave = !usermods.readFromConfig(usermods_settings);
needsSave = !UsermodManager::readFromConfig(usermods_settings);
}
if (fromFS) return needsSave;
@@ -700,7 +700,7 @@ void deserializeConfigFromFS() {
// save default values to /cfg.json
// call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving
JsonObject empty = JsonObject();
usermods.readFromConfig(empty);
UsermodManager::readFromConfig(empty);
serializeConfig();
// init Ethernet (in case default type is set at compile time)
#ifdef WLED_USE_ETHERNET
@@ -1121,7 +1121,7 @@ void serializeConfig() {
#endif
JsonObject usermods_settings = root.createNestedObject("um");
usermods.addToConfig(usermods_settings);
UsermodManager::addToConfig(usermods_settings);
File f = WLED_FS.open(FPSTR(s_cfg_json), "w");
if (f) serializeJson(root, f);

View File

@@ -22,6 +22,7 @@
function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel
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 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 S() {
getLoc();
@@ -255,7 +256,7 @@
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
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
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
@@ -457,9 +458,9 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
});
// disable inappropriate LED types
let sel = d.getElementsByName("LT"+s)[0]
if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]');
if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]');
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`);
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"]'); // NOTE: see isD2P()
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM()
sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
}
if (n==-1) {

View File

@@ -328,34 +328,34 @@ class Usermod {
class UsermodManager {
private:
Usermod* ums[WLED_MAX_USERMODS];
byte numMods = 0;
static Usermod* ums[WLED_MAX_USERMODS];
static byte numMods;
public:
void loop();
void handleOverlayDraw();
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
void setup();
void connected();
void appendConfigData(Print&);
void addToJsonState(JsonObject& obj);
void addToJsonInfo(JsonObject& obj);
void readFromJsonState(JsonObject& obj);
void addToConfig(JsonObject& obj);
bool readFromConfig(JsonObject& obj);
static void loop();
static void handleOverlayDraw();
static bool handleButton(uint8_t b);
static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
static void setup();
static void connected();
static void appendConfigData(Print&);
static void addToJsonState(JsonObject& obj);
static void addToJsonInfo(JsonObject& obj);
static void readFromJsonState(JsonObject& obj);
static void addToConfig(JsonObject& obj);
static bool readFromConfig(JsonObject& obj);
#ifndef WLED_DISABLE_MQTT
void onMqttConnect(bool sessionPresent);
bool onMqttMessage(char* topic, char* payload);
static void onMqttConnect(bool sessionPresent);
static bool onMqttMessage(char* topic, char* payload);
#endif
#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
void onUpdateBegin(bool);
void onStateChange(uint8_t);
bool add(Usermod* um);
Usermod* lookup(uint16_t mod_id);
byte getModCount() {return numMods;};
static void onUpdateBegin(bool);
static void onStateChange(uint8_t);
static bool add(Usermod* um);
static Usermod* lookup(uint16_t mod_id);
static inline byte getModCount() {return numMods;};
};
//usermods_list.cpp

View File

@@ -436,7 +436,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
strip.resume();
usermods.readFromJsonState(root);
UsermodManager::readFromJsonState(root);
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("ledmap")] = currentLedmap;
usermods.addToJsonState(root);
UsermodManager::addToJsonState(root);
JsonObject nl = root.createNestedObject("nl");
nl["on"] = nightlightActive;
@@ -784,7 +784,7 @@ void serializeInfo(JsonObject root)
getTimeString(time);
root[F("time")] = time;
usermods.addToJsonInfo(root);
UsermodManager::addToJsonInfo(root);
uint16_t os = 0;
#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;
// notify usermods of state change
usermods.onStateChange(callMode);
UsermodManager::onStateChange(callMode);
if (fadeTransition) {
if (strip.getTransition() == 0) {

View File

@@ -45,7 +45,7 @@ static void onMqttConnect(bool sessionPresent)
mqtt->subscribe(subuf, 0);
}
usermods.onMqttConnect(sessionPresent);
UsermodManager::onMqttConnect(sessionPresent);
DEBUG_PRINTLN(F("MQTT ready"));
publishMqtt();
@@ -89,7 +89,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
topic += topicPrefixLen;
} else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
usermods.onMqttMessage(topic, payloadStr);
UsermodManager::onMqttMessage(topic, payloadStr);
delete[] payloadStr;
payloadStr = nullptr;
return;
@@ -115,7 +115,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
}
} else if (strlen(topic) != 0) {
// non standard topic, check with usermods
usermods.onMqttMessage(topic, payloadStr);
UsermodManager::onMqttMessage(topic, payloadStr);
} else {
// topmost topic (just wled/MAC)
parseMQTTBriPayload(payloadStr);

View File

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

View File

@@ -13,34 +13,16 @@
#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
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 (!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 ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
#ifdef WLED_DEBUG
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
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));
return false;
}
@@ -50,7 +32,7 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
}
// 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;
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
continue;
}
#ifdef WLED_DEBUG
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
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));
shouldFail = true;
}
if (shouldFail) {
@@ -97,14 +72,14 @@ bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte array
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];
for (int i=0; i<arrayElementCount; i++) pins[i] = mptArray[i].pin;
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;
// first verify the pins are OK and not already allocated
@@ -116,25 +91,14 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
continue;
}
if (!isPinOk(gpio, mptArray[i].isOutput)) {
#ifdef WLED_DEBUG
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
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"));
shouldFail = true;
}
if ((tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) && isPinAllocated(gpio, tag)) {
// allow multiple "allocations" of HW I2C & SPI bus pins
continue;
} else if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
shouldFail = true;
}
}
@@ -158,64 +122,45 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag;
#ifdef WLED_DEBUG
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: Pin %d allocated by 0x%02X.\n"), gpio, static_cast<int>(tag));
}
DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
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
if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) {
#ifdef WLED_DEBUG
if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
if (!isPinOk(gpio, output)) {
DEBUG_PRINT(F("PIN ALLOC: FAIL for owner "));
DebugPrintOwnerTag(tag);
DEBUG_PRINT(F(": GPIO ")); DEBUG_PRINT(gpio);
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL for owner 0x%02X: GPIO %d "), static_cast<int>(tag), gpio);
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_PRINT(F("PIN ALLOC: FAIL: GPIO ")); DEBUG_PRINT(gpio);
DEBUG_PRINTLN(F(" - HW I2C & SPI pins have to be allocated using allocateMultiplePins()"));
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d - HW I2C & SPI pins have to be allocated using allocateMultiplePins.\n"), gpio);
}
}
#endif
return false;
}
if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Pin %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
return false;
}
bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag;
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" successfully allocated by "));
DebugPrintOwnerTag(tag);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: Pin %d successfully allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
return true;
}
// 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.
bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const
bool PinManager::isPinAllocated(byte gpio, PinOwner tag)
{
if (!isPinOk(gpio, false)) return true;
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
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
#ifdef ARDUINO_ARCH_ESP32
@@ -279,7 +224,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const
return false;
}
bool PinManagerClass::isReadOnlyPin(byte gpio)
bool PinManager::isReadOnlyPin(byte gpio)
{
#ifdef ARDUINO_ARCH_ESP32
if (gpio < WLED_NUM_PINS) return (digitalPinIsValid(gpio) && !digitalPinCanOutput(gpio));
@@ -287,14 +232,14 @@ bool PinManagerClass::isReadOnlyPin(byte gpio)
return false;
}
PinOwner PinManagerClass::getPinOwner(byte gpio) const
PinOwner PinManager::getPinOwner(byte gpio)
{
if (!isPinOk(gpio, false)) return PinOwner::None;
return ownerTag[gpio];
}
#ifdef ARDUINO_ARCH_ESP32
byte PinManagerClass::allocateLedc(byte channels)
byte PinManager::allocateLedc(byte channels)
{
if (channels > WLED_MAX_ANALOG_CHANNELS || channels == 0) return 255;
unsigned ca = 0;
@@ -321,7 +266,7 @@ byte PinManagerClass::allocateLedc(byte 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++) {
bitWrite(ledcAlloc, j, false);
@@ -329,4 +274,12 @@ void PinManagerClass::deallocateLedc(byte pos, byte channels)
}
#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");
class PinManagerClass {
class PinManager {
private:
struct {
#ifdef ESP8266
#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
#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17)
static uint32_t pinAlloc; // 1 bit per pin, we use first 17bits
#else
#define WLED_NUM_PINS (GPIO_PIN_COUNT)
uint64_t pinAlloc : 56; // 56 bits, 1 bit per pin, we use 50 bits on ESP32-S3
uint16_t ledcAlloc : 16; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS)
#define WLED_NUM_PINS (GPIO_PIN_COUNT)
static uint64_t pinAlloc; // 1 bit per pin, we use 50 bits on ESP32-S3
static uint16_t ledcAlloc; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS)
#endif
uint8_t i2cAllocCount : 4; // 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
} __attribute__ ((packed));
PinOwner ownerTag[WLED_NUM_PINS] = { PinOwner::None };
static uint8_t i2cAllocCount; // allow multiple allocation of I2C bus pins but keep track of allocations
static uint8_t spiAllocCount; // allow multiple allocation of SPI bus pins but keep track of allocations
static PinOwner ownerTag[WLED_NUM_PINS];
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
ledcAlloc = 0;
static byte allocateLedc(byte channels);
static void deallocateLedc(byte pos, byte channels);
#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

View File

@@ -104,18 +104,18 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
int t = 0;
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin, PinOwner::Relay)) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay);
if (rlyPin>=0 && PinManager::isPinAllocated(rlyPin, PinOwner::Relay)) {
PinManager::deallocatePin(rlyPin, PinOwner::Relay);
}
#ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin, PinOwner::IR)) {
if (irPin>=0 && PinManager::isPinAllocated(irPin, PinOwner::IR)) {
deInitIR();
pinManager.deallocatePin(irPin, PinOwner::IR);
PinManager::deallocatePin(irPin, PinOwner::IR);
}
#endif
for (unsigned s=0; s<WLED_MAX_BUTTONS; s++) {
if (btnPin[s]>=0 && pinManager.isPinAllocated(btnPin[s], PinOwner::Button)) {
pinManager.deallocatePin(btnPin[s], PinOwner::Button);
if (btnPin[s]>=0 && PinManager::isPinAllocated(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
if (digitalPinToTouchChannel(btnPin[s]) >= 0) // if touch capable pin
touchDetachInterrupt(btnPin[s]); // if not assigned previously, this will do nothing
@@ -233,7 +233,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// update other pins
#ifndef WLED_DISABLE_INFRARED
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;
} else {
irPin = -1;
@@ -244,7 +244,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
irApplyToAllSelected = !request->hasArg(F("MSO"));
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;
} else {
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 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();
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;
buttonType[i] = request->arg(be).toInt();
#ifdef ARDUINO_ARCH_ESP32
@@ -270,7 +270,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// 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);
btnPin[i] = -1;
pinManager.deallocatePin(hw_btn_pin,PinOwner::Button);
PinManager::deallocatePin(hw_btn_pin,PinOwner::Button);
} else {
analogReadResolution(12); // see #4040
}
@@ -282,7 +282,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// 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);
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
else
@@ -631,10 +631,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) {
// only if pins changed
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 } };
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_scl = hw_scl_pin;
// no bus re-initialisation as usermods do not get any notification
@@ -658,9 +658,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) {
// 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) };
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 } };
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_miso = hw_miso_pin;
spi_sclk = hw_sclk_pin;
@@ -750,8 +750,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DEBUG_PRINTF_P(PSTR(" = %s\n"), value.c_str());
}
}
usermods.readFromConfig(um); // force change of usermod parameters
DEBUG_PRINTLN(F("Done re-init usermods."));
UsermodManager::readFromConfig(um); // force change of usermod parameters
DEBUG_PRINTLN(F("Done re-init UsermodManager::"));
releaseJSONBufferLock();
}

View File

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

View File

@@ -69,6 +69,8 @@ bool UsermodManager::add(Usermod* um)
return true;
}
Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr};
byte UsermodManager::numMods = 0;
/* Usermod v2 interface shim for oappend */
Print* Usermod::oappend_shim = nullptr;

View File

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

View File

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

View File

@@ -396,7 +396,7 @@ void initServer()
#if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().disableWatchdog();
#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
strip.suspend();
#ifdef ESP8266
@@ -412,7 +412,7 @@ void initServer()
} else {
DEBUG_PRINTLN(F("Update Failed"));
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
WLED::instance().enableWatchdog();
#endif

View File

@@ -84,7 +84,7 @@ void appendGPIOinfo(Print& settingsScript) {
if (requestJSONBufferLock(6)) {
// if we can't allocate JSON buffer ignore usermod pins
JsonObject mods = pDoc->createNestedObject(F("um"));
usermods.addToConfig(mods);
UsermodManager::addToConfig(mods);
if (!mods.isNull()) fillUMPins(settingsScript, mods);
releaseJSONBufferLock();
}
@@ -93,7 +93,7 @@ void appendGPIOinfo(Print& settingsScript) {
// add reserved (unusable) pins
settingsScript.print(SET_F("d.rsvd=["));
for (unsigned i = 0; i < WLED_NUM_PINS; i++) {
if (!pinManager.isPinOk(i, false)) { // include readonly pins
if (!PinManager::isPinOk(i, false)) { // include readonly pins
settingsScript.print(i); settingsScript.print(",");
}
}
@@ -130,7 +130,7 @@ void appendGPIOinfo(Print& settingsScript) {
settingsScript.print(SET_F("d.ro_gpio=["));
bool firstPin = true;
for (unsigned i = 0; i < WLED_NUM_PINS; i++) {
if (pinManager.isReadOnlyPin(i)) {
if (PinManager::isReadOnlyPin(i)) {
// No comma before the first pin
if (!firstPin) settingsScript.print(SET_F(","));
settingsScript.print(i);
@@ -309,7 +309,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
int nPins = bus->getPins(pins);
for (int i = 0; i < nPins; i++) {
lp[1] = offset+i;
if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(settingsScript,lp,pins[i]);
if (PinManager::isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(settingsScript,lp,pins[i]);
}
printSetFormValue(settingsScript,lc,bus->getLength());
printSetFormValue(settingsScript,lt,bus->getType());
@@ -612,7 +612,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
if (subPage == SUBPAGE_UM) //usermods
{
appendGPIOinfo(settingsScript);
settingsScript.printf_P(PSTR("numM=%d;"), usermods.getModCount());
settingsScript.printf_P(PSTR("numM=%d;"), UsermodManager::getModCount());
printSetFormValue(settingsScript,PSTR("SDA"),i2c_sda);
printSetFormValue(settingsScript,PSTR("SCL"),i2c_scl);
printSetFormValue(settingsScript,PSTR("MOSI"),spi_mosi);
@@ -625,7 +625,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
"addInfo('SCLK','%d');"),
HW_PIN_SDA, HW_PIN_SCL, HW_PIN_DATASPI, HW_PIN_MISOSPI, HW_PIN_CLOCKSPI
);
usermods.appendConfigData(settingsScript);
UsermodManager::appendConfigData(settingsScript);
}
if (subPage == SUBPAGE_UPDATE) // update