Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions wled00/FX_fcn.cpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -1180,14 +1180,17 @@ void WS2812FX::finalizeInit() {

// create buses/outputs
unsigned mem = 0;
for (const auto &bus : busConfigs) {
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer
if (mem <= MAX_LED_MEMORY) {
if (BusManager::add(bus) == -1) break;
} else {
errorFlag = ERR_NORAM_PX; // alert UI
DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount);
for (auto bus : busConfigs) {
bool use_placeholder = false;
unsigned busMemUsage = bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount : 0);
if (mem + busMemUsage > MAX_LED_MEMORY) {
DEBUG_PRINTF_P(PSTR("Bus %d with %d LEDS memory usage exceeds limit\n"), (int)bus.type, bus.count);
use_placeholder = true;
}
if (BusManager::add(bus, use_placeholder) != -1) {
mem += BusManager::busses.back()->getBusSize();
if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) digitalCount++;
} else break;
}
busConfigs.clear();
busConfigs.shrink_to_fit();
Expand Down Expand Up @@ -1804,7 +1807,7 @@ void WS2812FX::makeAutoSegments(bool forceReset) {

for (size_t i = s; i < BusManager::getNumBusses(); i++) {
const Bus *bus = BusManager::getBus(i);
if (!bus || !bus->isOk()) break;
if (!bus) break;

segStarts[s] = bus->getStart();
segStops[s] = segStarts[s] + bus->getLength();
Expand Down
32 changes: 27 additions & 5 deletions wled00/bus_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,26 @@ void BusNetwork::cleanup() {
}


BusPlaceholder::BusPlaceholder(const BusConfig &bc)
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, bc.refreshReq)
, _colorOrder(bc.colorOrder)
, _skipAmount(bc.skipAmount)
, _frequency(bc.frequency)
, _milliAmpsPerLed(bc.milliAmpsPerLed)
, _milliAmpsMax(bc.milliAmpsMax)
, _text(bc.text)
{
memcpy(_pins, bc.pins, sizeof(_pins));
}

size_t BusPlaceholder::getPins(uint8_t* pinArray) const {
size_t nPins = Bus::getNumberOfPins(_type);
if (pinArray) {
for (size_t i = 0; i < nPins; i++) pinArray[i] = _pins[i];
}
return nPins;
}

//utility to get the approx. memory usage of a given BusConfig
size_t BusConfig::memUsage(unsigned nr) const {
if (Bus::isVirtual(type)) {
Expand Down Expand Up @@ -797,7 +817,7 @@ size_t BusManager::memUsage() {
return size + maxI2S;
}

int BusManager::add(const BusConfig &bc) {
int BusManager::add(const BusConfig &bc, bool placeholder) {
DEBUGBUS_PRINTF_P(PSTR("Bus: Adding bus (p:%d v:%d)\n"), getNumBusses(), getNumVirtualBusses());
unsigned digital = 0;
unsigned analog = 0;
Expand All @@ -807,8 +827,10 @@ int BusManager::add(const BusConfig &bc) {
if (bus->isDigital() && !bus->is2Pin()) digital++;
if (bus->is2Pin()) twoPin++;
}
if (digital > WLED_MAX_DIGITAL_CHANNELS || analog > WLED_MAX_ANALOG_CHANNELS) return -1;
if (Bus::isVirtual(bc.type)) {
if (digital > WLED_MAX_DIGITAL_CHANNELS || analog > WLED_MAX_ANALOG_CHANNELS) placeholder = true;
if (placeholder) {
busses.push_back(make_unique<BusPlaceholder>(bc));
} else if (Bus::isVirtual(bc.type)) {
busses.push_back(make_unique<BusNetwork>(bc));
} else if (Bus::isDigital(bc.type)) {
busses.push_back(make_unique<BusDigital>(bc, Bus::is2Pin(bc.type) ? twoPin : digital));
Expand Down Expand Up @@ -907,7 +929,7 @@ void BusManager::on() {
if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
for (auto &bus : busses) {
uint8_t pins[2] = {255,255};
if (bus->isDigital() && bus->getPins(pins)) {
if (bus->isDigital() && bus->getPins(pins) && bus->isOk()) {
if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) {
BusDigital &b = static_cast<BusDigital&>(*bus);
b.begin();
Expand Down Expand Up @@ -1002,7 +1024,7 @@ void BusManager::initializeABL() {
_useABL = true; // at least one bus has ABL set
uint32_t ESPshare = MA_FOR_ESP / numABLbuses; // share of ESP current per ABL bus
for (auto &bus : busses) {
if (bus->isDigital()) {
if (bus->isDigital() && bus->isOk()) {
BusDigital &busd = static_cast<BusDigital&>(*bus);
uint32_t busLength = busd.getLength();
uint32_t busDemand = busLength * busd.getLEDCurrent();
Expand Down
35 changes: 33 additions & 2 deletions wled00/bus_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class Bus {
virtual void setColorOrder(uint8_t co) {}
virtual uint32_t getPixelColor(unsigned pix) const { return 0; }
virtual size_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
virtual uint16_t getLength() const { return _len; }
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
virtual unsigned skippedLeds() const { return 0; }
virtual uint16_t getFrequency() const { return 0U; }
Expand Down Expand Up @@ -363,6 +363,37 @@ class BusNetwork : public Bus {
#endif
};

// Placeholder for buses that we can't construct due to resource limitations
// This preserves the configuration so it can be read back to the settings pages
class BusPlaceholder : public Bus {
public:
BusPlaceholder(const BusConfig &bc);

// Actual calls are stubbed out
void setPixelColor(unsigned pix, uint32_t c) override {};
void show() override {};

// Accessors
uint8_t getColorOrder() const override { return _colorOrder; }
size_t getPins(uint8_t* pinArray) const override;
unsigned skippedLeds() const override { return _skipAmount; }
uint16_t getFrequency() const override { return _frequency; }
uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; }
uint16_t getMaxCurrent() const override { return _milliAmpsMax; }
const String getCustomText() const override { return _text; }

size_t getBusSize() const override { return sizeof(BusPlaceholder); }

private:
uint8_t _colorOrder;
uint8_t _skipAmount;
uint8_t _pins[5];
uint16_t _frequency;
uint8_t _milliAmpsPerLed;
uint16_t _milliAmpsMax;
String _text;
};


//temporary struct for passing bus configuration to bus
struct BusConfig {
Expand Down Expand Up @@ -464,7 +495,7 @@ namespace BusManager {

//do not call this method from system context (network callback)
void removeAll();
int add(const BusConfig &bc);
int add(const BusConfig &bc, bool placeholder);

void on();
void off();
Expand Down
2 changes: 1 addition & 1 deletion wled00/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ void serializeConfig(JsonObject root) {
for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s);
const Bus *bus = BusManager::getBus(s);
if (!bus || !bus->isOk()) break;
if (!bus) break; // Memory corruption, iterator invalid
DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
(int)bus->getStart(), (int)(bus->getStart()+bus->getLength()),
(int)(bus->getType() & 0x7F),
Expand Down
45 changes: 38 additions & 7 deletions wled00/data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,20 @@ function parseInfo(i) {
if (loc) name = "(L) " + name;
d.title = name;
simplifiedUI = i.simplifiedui;
ledCount = i.leds.count;
// safety checks for LED count data to prevent UI crashes
if (i.leds && typeof i.leds.count !== 'undefined') {
ledCount = i.leds.count;
} else {
console.warn('No LED count');
ledCount = 30; // fallback value
}
//syncTglRecv = i.str;
maxSeg = i.leds.maxseg;
if (i.leds && typeof i.leds.maxseg !== 'undefined') {
maxSeg = i.leds.maxseg;
} else {
console.warn('No max segment data');
maxSeg = 16; // Reasonable fallback for max segments
}
pmt = i.fs.pmt;
if (pcMode && !i.wifi.ap) gId('edit').classList.remove("hide"); else gId('edit').classList.add("hide");
gId('buttonNodes').style.display = lastinfo.ndc > 0 ? null:"none";
Expand Down Expand Up @@ -912,12 +923,24 @@ function populateSegments(s)
gId(`segr${i}`).classList.add("hide");
}
if (segCount < 2) {
gId(`segd${lSeg}`).classList.add("hide"); // hide delete if only one segment
if (parseInt(gId("seg0bri").value)==255) gId(`segp0`).classList.add("hide");
// safety check for segment elements to prevent UI crashes
const segdElement = gId(`segd${lSeg}`);
if (segdElement) segdElement.classList.add("hide"); // hide delete if only one segment
const seg0briElement = gId("seg0bri");
const segp0Element = gId(`segp0`);
if (seg0briElement && segp0Element && parseInt(seg0briElement.value)==255) segp0Element.classList.add("hide");
// hide segment controls if there is only one segment in simplified UI
if (simplifiedUI) gId("segcont").classList.add("hide");
}
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).classList.remove("hide");
// safety checks for segment control elements
const segSElement = gId(`seg${lSeg}s`);
const segEElement = gId(`seg${lSeg}e`);
const segrElement = gId(`segr${lSeg}`);
if (!isM && !noNewSegs && segSElement && segEElement && segrElement) {
const segLen = cfg.comp.seglen ? parseInt(segSElement.value) : 0;
const segEnd = parseInt(segEElement.value);
if (segLen + segEnd < ledCount) segrElement.classList.remove("hide");
}
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent

if (Array.isArray(li.maps) && li.maps.length>1) {
Expand Down Expand Up @@ -2253,7 +2276,9 @@ function rptSeg(s)
var rev = gId(`seg${s}rev`).checked;
var mi = gId(`seg${s}mi`).checked;
var sel = gId(`seg${s}sel`).checked;
var pwr = gId(`seg${s}pwr`).classList.contains('act');
// safety check for segment power element to prevent UI crashes
const segPwrElement = gId(`seg${s}pwr`);
var pwr = segPwrElement ? segPwrElement.classList.contains('act') : false;
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": pwr, "bri": parseInt(gId(`seg${s}bri`).value), "sel": sel}};
if (gId(`seg${s}grp`)) {
var grp = parseInt(gId(`seg${s}grp`).value);
Expand Down Expand Up @@ -2380,7 +2405,13 @@ function setGrp(s, g)

function setSegPwr(s)
{
var pwr = gId(`seg${s}pwr`).classList.contains('act');
// safety check for segment power element to prevent UI crashes
const segPwrElement = gId(`seg${s}pwr`);
if (!segPwrElement) {
console.warn('No power elemen');
return;
}
var pwr = segPwrElement.classList.contains('act');
var obj = {"seg": {"id": s, "on": !pwr}};
requestJson(obj);
}
Expand Down
2 changes: 1 addition & 1 deletion wled00/xml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
unsigned sumMa = 0;
for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
const Bus *bus = BusManager::getBus(s);
if (!bus || !bus->isOk()) break; // should not happen but for safety
if (!bus) break; // should not happen but for safety
int offset = s < 10 ? '0' : 'A' - 10;
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
Expand Down