Merge branch '0_15' into blending-styles

This commit is contained in:
Blaz Kristan 2024-07-11 21:30:10 +02:00
commit 13ed78be96
33 changed files with 323 additions and 294 deletions

View File

@ -5,7 +5,7 @@
#include "UMBattery.h" #include "UMBattery.h"
#include "types/UnkownUMBattery.h" #include "types/UnkownUMBattery.h"
#include "types/LionUMBattery.h" #include "types/LionUMBattery.h"
#include "types/LiPoUMBattery.h" #include "types/LipoUMBattery.h"
/* /*
* Usermod by Maximilian Mewes * Usermod by Maximilian Mewes

View File

@ -113,7 +113,7 @@ float UsermodTemperature::readDallas() {
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if (OneWire::crc8(data,8) != data[8]) { if (OneWire::crc8(data,8) != data[8]) {
DEBUG_PRINTLN(F("CRC error reading temperature.")); DEBUG_PRINTLN(F("CRC error reading temperature."));
for (byte i=0; i < 9; i++) DEBUG_PRINTF_P(PSTR("0x%02X "), data[i]); for (unsigned i=0; i < 9; i++) DEBUG_PRINTF_P(PSTR("0x%02X "), data[i]);
DEBUG_PRINT(F(" => ")); DEBUG_PRINT(F(" => "));
DEBUG_PRINTF_P(PSTR("0x%02X\n"), OneWire::crc8(data,8)); DEBUG_PRINTF_P(PSTR("0x%02X\n"), OneWire::crc8(data,8));
} }
@ -133,7 +133,7 @@ float UsermodTemperature::readDallas() {
break; break;
} }
} }
for (byte i=1; i<9; i++) data[0] &= data[i]; for (unsigned i=1; i<9; i++) data[0] &= data[i];
return data[0]==0xFF ? -127.0f : retVal; return data[0]==0xFF ? -127.0f : retVal;
} }

View File

@ -87,11 +87,11 @@ class MPU6050Driver : public Usermod {
int16_t accel_offset[3]; int16_t accel_offset[3];
}; };
config_t config; config_t config;
bool configDirty = true; // does the configuration need an update?
// MPU control/status vars // MPU control/status vars
bool irqBound = false; // set true if we have bound the IRQ pin bool irqBound = false; // set true if we have bound the IRQ pin
bool dmpReady = false; // set true if DMP init was successful bool dmpReady = false; // set true if DMP init was successful
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes) uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer uint8_t fifoBuffer[64]; // FIFO storage buffer
@ -157,7 +157,10 @@ class MPU6050Driver : public Usermod {
um_data.u_type[8] = UMT_UINT32; um_data.u_type[8] = UMT_UINT32;
} }
configDirty = false; // we have now accepted the current configuration, success or not
if (!config.enabled) return; if (!config.enabled) return;
// TODO: notice if these have changed ??
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) {
@ -182,7 +185,7 @@ class MPU6050Driver : public Usermod {
// load and configure the DMP // load and configure the DMP
DEBUG_PRINTLN(F("Initializing DMP...")); DEBUG_PRINTLN(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize(); auto devStatus = mpu.dmpInitialize();
// set offsets (from config) // set offsets (from config)
mpu.setXGyroOffset(config.gyro_offset[0]); mpu.setXGyroOffset(config.gyro_offset[0]);
@ -241,6 +244,8 @@ class MPU6050Driver : public Usermod {
* loop() is called continuously. Here you can check for events, read sensors, etc. * loop() is called continuously. Here you can check for events, read sensors, etc.
*/ */
void loop() { void loop() {
if (configDirty) setup();
// if programming failed, don't try to do anything // if programming failed, don't try to do anything
if (!config.enabled || !dmpReady || strip.isUpdating()) return; if (!config.enabled || !dmpReady || strip.isUpdating()) return;
@ -407,8 +412,8 @@ class MPU6050Driver : public Usermod {
irqBound = false; irqBound = false;
} }
// Just re-init // Re-call setup on the next loop()
setup(); configDirty = true;
} }
return configComplete; return configComplete;

View File

@ -445,8 +445,8 @@ void FourLineDisplayUsermod::setPowerSave(uint8_t save) {
void FourLineDisplayUsermod::center(String &line, uint8_t width) { void FourLineDisplayUsermod::center(String &line, uint8_t width) {
int len = line.length(); int len = line.length();
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line; if (len<width) for (unsigned i=(width-len)/2; i>0; i--) line = ' ' + line;
for (byte i=line.length(); i<width; i++) line += ' '; for (unsigned i=line.length(); i<width; i++) line += ' ';
} }
void FourLineDisplayUsermod::draw2x2GlyphIcons() { void FourLineDisplayUsermod::draw2x2GlyphIcons() {
@ -819,28 +819,28 @@ void FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const c
if (overlayUntil == 0) { if (overlayUntil == 0) {
lockRedraw = true; lockRedraw = true;
// Find the mode name in JSON // Find the mode name in JSON
uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1); unsigned printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1);
if (lineBuffer[0]=='*' && lineBuffer[1]==' ') { if (lineBuffer[0]=='*' && lineBuffer[1]==' ') {
// remove "* " from dynamic palettes // remove "* " from dynamic palettes
for (byte i=2; i<=printedChars; i++) lineBuffer[i-2] = lineBuffer[i]; //include '\0' for (unsigned i=2; i<=printedChars; i++) lineBuffer[i-2] = lineBuffer[i]; //include '\0'
printedChars -= 2; printedChars -= 2;
} else if ((lineBuffer[0]==' ' && lineBuffer[1]>127)) { } else if ((lineBuffer[0]==' ' && lineBuffer[1]>127)) {
// remove note symbol from effect names // remove note symbol from effect names
for (byte i=5; i<=printedChars; i++) lineBuffer[i-5] = lineBuffer[i]; //include '\0' for (unsigned i=5; i<=printedChars; i++) lineBuffer[i-5] = lineBuffer[i]; //include '\0'
printedChars -= 5; printedChars -= 5;
} }
if (lineHeight == 2) { // use this code for 8 line display if (lineHeight == 2) { // use this code for 8 line display
char smallBuffer1[MAX_MODE_LINE_SPACE]; char smallBuffer1[MAX_MODE_LINE_SPACE];
char smallBuffer2[MAX_MODE_LINE_SPACE]; char smallBuffer2[MAX_MODE_LINE_SPACE];
uint8_t smallChars1 = 0; unsigned smallChars1 = 0;
uint8_t smallChars2 = 0; unsigned smallChars2 = 0;
if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits
while (printedChars < (MAX_MODE_LINE_SPACE-1)) lineBuffer[printedChars++]=' '; while (printedChars < (MAX_MODE_LINE_SPACE-1)) lineBuffer[printedChars++]=' ';
lineBuffer[printedChars] = 0; lineBuffer[printedChars] = 0;
drawString(1, row*lineHeight, lineBuffer); drawString(1, row*lineHeight, lineBuffer);
} else { // for long names divide the text into 2 lines and print them small } else { // for long names divide the text into 2 lines and print them small
bool spaceHit = false; bool spaceHit = false;
for (uint8_t i = 0; i < printedChars; i++) { for (unsigned i = 0; i < printedChars; i++) {
switch (lineBuffer[i]) { switch (lineBuffer[i]) {
case ' ': case ' ':
if (i > 4 && !spaceHit) { if (i > 4 && !spaceHit) {
@ -865,8 +865,8 @@ void FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const c
} }
} else { // use this code for 4 ling displays } else { // use this code for 4 ling displays
char smallBuffer3[MAX_MODE_LINE_SPACE+1]; // uses 1x1 icon for mode/palette char smallBuffer3[MAX_MODE_LINE_SPACE+1]; // uses 1x1 icon for mode/palette
uint8_t smallChars3 = 0; unsigned smallChars3 = 0;
for (uint8_t i = 0; i < MAX_MODE_LINE_SPACE; i++) smallBuffer3[smallChars3++] = (i >= printedChars) ? ' ' : lineBuffer[i]; for (unsigned i = 0; i < MAX_MODE_LINE_SPACE; i++) smallBuffer3[smallChars3++] = (i >= printedChars) ? ' ' : lineBuffer[i];
smallBuffer3[smallChars3] = 0; smallBuffer3[smallChars3] = 0;
drawString(1, row*lineHeight, smallBuffer3, true); drawString(1, row*lineHeight, smallBuffer3, true);
} }
@ -1265,7 +1265,7 @@ void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) { bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
bool needsRedraw = false; bool needsRedraw = false;
DisplayType newType = type; DisplayType newType = type;
int8_t oldPin[3]; for (byte i=0; i<3; i++) oldPin[i] = ioPin[i]; int8_t oldPin[3]; for (unsigned i=0; i<3; i++) oldPin[i] = ioPin[i];
JsonObject top = root[FPSTR(_name)]; JsonObject top = root[FPSTR(_name)];
if (top.isNull()) { if (top.isNull()) {
@ -1276,7 +1276,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
enabled = top[FPSTR(_enabled)] | enabled; enabled = top[FPSTR(_enabled)] | enabled;
newType = top["type"] | newType; newType = top["type"] | newType;
for (byte i=0; i<3; i++) ioPin[i] = top["pin"][i] | ioPin[i]; for (unsigned i=0; i<3; i++) ioPin[i] = top["pin"][i] | ioPin[i];
flip = top[FPSTR(_flip)] | flip; flip = top[FPSTR(_flip)] | flip;
contrast = top[FPSTR(_contrast)] | contrast; contrast = top[FPSTR(_contrast)] | contrast;
#ifndef ARDUINO_ARCH_ESP32 #ifndef ARDUINO_ARCH_ESP32
@ -1302,7 +1302,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
DEBUG_PRINTLN(F(" config (re)loaded.")); DEBUG_PRINTLN(F(" config (re)loaded."));
// changing parameters from settings page // changing parameters from settings page
bool pinsChanged = false; bool pinsChanged = false;
for (byte i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; } for (unsigned i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
if (pinsChanged || type!=newType) { if (pinsChanged || type!=newType) {
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);

View File

@ -416,7 +416,7 @@ void RotaryEncoderUIUsermod::sortModesAndPalettes() {
byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) { byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
byte *indexes = (byte *)malloc(sizeof(byte) * numModes); byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
for (byte i = 0; i < numModes; i++) { for (unsigned i = 0; i < numModes; i++) {
indexes[i] = i; indexes[i] = i;
} }
return indexes; return indexes;
@ -700,7 +700,7 @@ void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
effectPaletteIndex = 0; effectPaletteIndex = 0;
DEBUG_PRINTLN(effectPalette); DEBUG_PRINTLN(effectPalette);
for (uint8_t i = 0; i < strip.getPaletteCount()+strip.customPalettes.size(); i++) { for (unsigned i = 0; i < strip.getPaletteCount()+strip.customPalettes.size(); i++) {
if (palettes_alpha_indexes[i] == effectPalette) { if (palettes_alpha_indexes[i] == effectPalette) {
effectPaletteIndex = i; effectPaletteIndex = i;
DEBUG_PRINTLN(F("Found palette.")); DEBUG_PRINTLN(F("Found palette."));
@ -764,7 +764,7 @@ void RotaryEncoderUIUsermod::changeEffect(bool increase) {
effectCurrent = modes_alpha_indexes[effectCurrentIndex]; effectCurrent = modes_alpha_indexes[effectCurrentIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.setMode(effectCurrent); seg.setMode(effectCurrent);
@ -792,7 +792,7 @@ void RotaryEncoderUIUsermod::changeEffectSpeed(bool increase) {
effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0); effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.speed = effectSpeed; seg.speed = effectSpeed;
@ -820,7 +820,7 @@ void RotaryEncoderUIUsermod::changeEffectIntensity(bool increase) {
effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0); effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.intensity = effectIntensity; seg.intensity = effectIntensity;
@ -855,7 +855,7 @@ void RotaryEncoderUIUsermod::changeCustom(uint8_t par, bool increase) {
case 2: val = sid.custom2 = max(min((increase ? sid.custom2+fadeAmount : sid.custom2-fadeAmount), 255), 0); break; case 2: val = sid.custom2 = max(min((increase ? sid.custom2+fadeAmount : sid.custom2-fadeAmount), 255), 0); break;
default: val = sid.custom1 = max(min((increase ? sid.custom1+fadeAmount : sid.custom1-fadeAmount), 255), 0); break; default: val = sid.custom1 = max(min((increase ? sid.custom1+fadeAmount : sid.custom1-fadeAmount), 255), 0); break;
} }
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive() || i == id) continue; if (!seg.isActive() || i == id) continue;
switch (par) { switch (par) {
@ -894,7 +894,7 @@ void RotaryEncoderUIUsermod::changePalette(bool increase) {
effectPalette = palettes_alpha_indexes[effectPaletteIndex]; effectPalette = palettes_alpha_indexes[effectPaletteIndex];
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.setPalette(effectPalette); seg.setPalette(effectPalette);
@ -923,7 +923,7 @@ void RotaryEncoderUIUsermod::changeHue(bool increase){
colorHStoRGB(currentHue1*256, currentSat1, col); colorHStoRGB(currentHue1*256, currentSat1, col);
stateChanged = true; stateChanged = true;
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]); seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
@ -952,7 +952,7 @@ void RotaryEncoderUIUsermod::changeSat(bool increase){
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0); currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
colorHStoRGB(currentHue1*256, currentSat1, col); colorHStoRGB(currentHue1*256, currentSat1, col);
if (applyToAll) { if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]); seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
@ -1012,7 +1012,7 @@ void RotaryEncoderUIUsermod::changeCCT(bool increase){
#endif #endif
currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0); currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0);
// if (applyToAll) { // if (applyToAll) {
for (byte i=0; i<strip.getSegmentsNum(); i++) { for (unsigned i=0; i<strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (!seg.isActive()) continue; if (!seg.isActive()) continue;
seg.setCCT(currentCCT); seg.setCCT(currentCCT);

View File

@ -2367,7 +2367,7 @@ uint16_t mode_meteor() {
} }
// draw meteor // draw meteor
for (int j = 0; j < meteorSize; j++) { for (unsigned j = 0; j < meteorSize; j++) {
int index = (in + j) % SEGLEN; int index = (in + j) % SEGLEN;
int idx = 255; int idx = 255;
int i = trail[index] = max; int i = trail[index] = max;

View File

@ -1295,7 +1295,8 @@ void WS2812FX::finalizeInit(void) {
const unsigned defCounts[] = {PIXEL_COUNTS}; const unsigned defCounts[] = {PIXEL_COUNTS};
const unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0])); const unsigned defNumPins = ((sizeof defDataPins) / (sizeof defDataPins[0]));
const unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); const unsigned defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
const unsigned defNumBusses = defNumPins > defNumCounts && defNumCounts > 1 && defNumPins%defNumCounts == 0 ? defNumCounts : defNumPins; // if number of pins is divisible by counts, use number of counts to determine number of buses, otherwise use pins
const unsigned defNumBusses = defNumPins > defNumCounts && defNumPins%defNumCounts == 0 ? defNumCounts : defNumPins;
const unsigned pinsPerBus = defNumPins / defNumBusses; const unsigned pinsPerBus = defNumPins / defNumBusses;
unsigned prevLen = 0; unsigned prevLen = 0;
for (unsigned i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (unsigned i = 0; i < defNumBusses && i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
@ -1308,6 +1309,7 @@ void WS2812FX::finalizeInit(void) {
while (pinManager.isPinAllocated(defPin[0]) && defPin[0] < WLED_NUM_PINS) defPin[0]++; while (pinManager.isPinAllocated(defPin[0]) && defPin[0] < WLED_NUM_PINS) defPin[0]++;
} }
unsigned start = prevLen; unsigned start = prevLen;
// 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];
prevLen += count; prevLen += count;
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer);

View File

@ -34,7 +34,7 @@ struct NodeStruct
NodeStruct() : age(0), nodeType(0), build(0) NodeStruct() : age(0), nodeType(0), build(0)
{ {
for (uint8_t i = 0; i < 4; ++i) { ip[i] = 0; } for (unsigned i = 0; i < 4; ++i) { ip[i] = 0; }
} }
}; };
typedef std::map<uint8_t, NodeStruct> NodesMap; typedef std::map<uint8_t, NodeStruct> NodesMap;

View File

@ -25,7 +25,7 @@ void alexaInit()
// names are identical as the preset names, switching off can be done by switching off any of them // names are identical as the preset names, switching off can be done by switching off any of them
if (alexaNumPresets) { if (alexaNumPresets) {
String name = ""; String name = "";
for (byte presetIndex = 1; presetIndex <= alexaNumPresets; presetIndex++) for (unsigned presetIndex = 1; presetIndex <= alexaNumPresets; presetIndex++)
{ {
if (!getPresetName(presetIndex, name)) break; // no more presets if (!getPresetName(presetIndex, name)) break; // no more presets
EspalexaDevice* dev = new EspalexaDevice(name.c_str(), onAlexaChange, EspalexaDeviceType::extendedcolor); EspalexaDevice* dev = new EspalexaDevice(name.c_str(), onAlexaChange, EspalexaDeviceType::extendedcolor);
@ -64,7 +64,7 @@ void onAlexaChange(EspalexaDevice* dev)
} else // switch-on behavior for preset devices } else // switch-on behavior for preset devices
{ {
// turn off other preset devices // turn off other preset devices
for (byte i = 1; i < espalexa.getDeviceCount(); i++) for (unsigned i = 1; i < espalexa.getDeviceCount(); i++)
{ {
if (i == dev->getId()) continue; if (i == dev->getId()) continue;
espalexa.getDevice(i)->setValue(0); // turn off other presets espalexa.getDevice(i)->setValue(0); // turn off other presets
@ -87,7 +87,7 @@ void onAlexaChange(EspalexaDevice* dev)
applyPreset(macroAlexaOff, CALL_MODE_ALEXA); applyPreset(macroAlexaOff, CALL_MODE_ALEXA);
// below for loop stops Alexa from complaining if macroAlexaOff does not actually turn off // below for loop stops Alexa from complaining if macroAlexaOff does not actually turn off
} }
for (byte i = 0; i < espalexa.getDeviceCount(); i++) for (unsigned i = 0; i < espalexa.getDeviceCount(); i++)
{ {
espalexa.getDevice(i)->setValue(0); espalexa.getDevice(i)->setValue(0);
} }

View File

@ -80,15 +80,15 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul
uint32_t Bus::autoWhiteCalc(uint32_t c) { uint32_t Bus::autoWhiteCalc(uint32_t c) {
uint8_t aWM = _autoWhiteMode; unsigned aWM = _autoWhiteMode;
if (_gAWM < AW_GLOBAL_DISABLED) aWM = _gAWM; if (_gAWM < AW_GLOBAL_DISABLED) aWM = _gAWM;
if (aWM == RGBW_MODE_MANUAL_ONLY) return c; if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
uint8_t w = W(c); unsigned w = W(c);
//ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0) //ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0)
if (w > 0 && aWM == RGBW_MODE_DUAL) return c; if (w > 0 && aWM == RGBW_MODE_DUAL) return c;
uint8_t r = R(c); unsigned r = R(c);
uint8_t g = G(c); unsigned g = G(c);
uint8_t b = B(c); unsigned b = B(c);
if (aWM == RGBW_MODE_MAX) return RGBW32(r, g, b, r > g ? (r > b ? r : b) : (g > b ? g : b)); // brightest RGB channel if (aWM == RGBW_MODE_MAX) return RGBW32(r, g, b, r > g ? (r > b ? r : b) : (g > b ? g : b)); // brightest RGB channel
w = r < g ? (r < b ? r : b) : (g < b ? g : b); w = r < g ? (r < b ? r : b) : (g < b ? g : b);
if (aWM == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode if (aWM == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode
@ -207,7 +207,7 @@ void BusDigital::show() {
if (!_valid) return; if (!_valid) return;
uint8_t cctWW = 0, cctCW = 0; uint8_t cctWW = 0, cctCW = 0;
uint8_t newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
if (_data) { if (_data) {
@ -215,7 +215,7 @@ void BusDigital::show() {
int16_t oldCCT = Bus::_cct; // temporarily save bus CCT int16_t oldCCT = Bus::_cct; // temporarily save bus CCT
for (size_t i=0; i<_len; i++) { for (size_t i=0; i<_len; i++) {
size_t offset = i * channels; size_t offset = i * channels;
uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder); unsigned co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder);
uint32_t c; uint32_t c;
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3) if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3)
switch (i%3) { switch (i%3) {
@ -234,7 +234,7 @@ void BusDigital::show() {
Bus::_cct = _data[offset+channels-1]; Bus::_cct = _data[offset+channels-1];
Bus::calculateCCT(c, cctWW, cctCW); Bus::calculateCCT(c, cctWW, cctCW);
} }
uint16_t pix = i; unsigned pix = i;
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
pix += _skip; pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW); PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
@ -246,7 +246,7 @@ void BusDigital::show() {
Bus::_cct = oldCCT; Bus::_cct = oldCCT;
} else { } else {
if (newBri < _bri) { if (newBri < _bri) {
uint16_t hwLen = _len; unsigned hwLen = _len;
if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
for (unsigned i = 0; i < hwLen; i++) { for (unsigned i = 0; i < hwLen; i++) {
// use 0 as color order, actual order does not matter here as we just update the channel values as-is // use 0 as color order, actual order does not matter here as we just update the channel values as-is
@ -302,9 +302,9 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
uint16_t pOld = pix; unsigned pOld = pix;
pix = IC_INDEX_WS2812_1CH_3X(pix); pix = IC_INDEX_WS2812_1CH_3X(pix);
uint32_t cOld = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co),_bri); uint32_t cOld = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co),_bri);
switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set) switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set)
@ -333,12 +333,12 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) {
} else { } else {
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
pix += _skip; pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri); uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
uint8_t r = R(c); unsigned r = R(c);
uint8_t g = _reversed ? B(c) : G(c); // should G and B be switched if _reversed? unsigned g = _reversed ? B(c) : G(c); // should G and B be switched if _reversed?
uint8_t b = _reversed ? G(c) : B(c); unsigned b = _reversed ? G(c) : B(c);
switch (pix % 3) { // get only the single channel switch (pix % 3) { // get only the single channel
case 0: c = RGBW32(g, g, g, g); break; case 0: c = RGBW32(g, g, g, g); break;
case 1: c = RGBW32(r, r, r, r); break; case 1: c = RGBW32(r, r, r, r); break;
@ -350,7 +350,7 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) {
} }
uint8_t BusDigital::getPins(uint8_t* pinArray) { uint8_t BusDigital::getPins(uint8_t* pinArray) {
uint8_t numPins = IS_2PIN(_type) ? 2 : 1; unsigned numPins = IS_2PIN(_type) ? 2 : 1;
for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins; return numPins;
} }
@ -382,7 +382,7 @@ BusPwm::BusPwm(BusConfig &bc)
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
{ {
if (!IS_PWM(bc.type)) return; if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type); unsigned numPins = NUM_PWM_PINS(bc.type);
_frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ;
#ifdef ESP8266 #ifdef ESP8266
@ -512,7 +512,7 @@ static const uint16_t cieLUT[256] = {
void BusPwm::show() { void BusPwm::show() {
if (!_valid) return; if (!_valid) return;
uint8_t numPins = NUM_PWM_PINS(_type); unsigned numPins = NUM_PWM_PINS(_type);
unsigned maxBri = (1<<_depth) - 1; unsigned maxBri = (1<<_depth) - 1;
#ifdef ESP8266 #ifdef ESP8266
unsigned pwmBri = (unsigned)(roundf(powf((float)_bri / 255.0f, 1.7f) * (float)maxBri)); // using gamma 1.7 to extrapolate PWM duty cycle unsigned pwmBri = (unsigned)(roundf(powf((float)_bri / 255.0f, 1.7f) * (float)maxBri)); // using gamma 1.7 to extrapolate PWM duty cycle
@ -532,7 +532,7 @@ void BusPwm::show() {
uint8_t BusPwm::getPins(uint8_t* pinArray) { uint8_t BusPwm::getPins(uint8_t* pinArray) {
if (!_valid) return 0; if (!_valid) return 0;
uint8_t numPins = NUM_PWM_PINS(_type); unsigned numPins = NUM_PWM_PINS(_type);
for (unsigned i = 0; i < numPins; i++) { for (unsigned i = 0; i < numPins; i++) {
pinArray[i] = _pins[i]; pinArray[i] = _pins[i];
} }
@ -540,7 +540,7 @@ uint8_t BusPwm::getPins(uint8_t* pinArray) {
} }
void BusPwm::deallocatePins() { void BusPwm::deallocatePins() {
uint8_t numPins = NUM_PWM_PINS(_type); unsigned numPins = NUM_PWM_PINS(_type);
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;
@ -632,7 +632,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
if (!_valid || pix >= _len) return; if (!_valid || pix >= _len) return;
if (_rgbw) c = autoWhiteCalc(c); if (_rgbw) c = autoWhiteCalc(c);
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
uint16_t offset = pix * _UDPchannels; unsigned offset = pix * _UDPchannels;
_data[offset] = R(c); _data[offset] = R(c);
_data[offset+1] = G(c); _data[offset+1] = G(c);
_data[offset+2] = B(c); _data[offset+2] = B(c);
@ -641,7 +641,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
uint32_t BusNetwork::getPixelColor(uint16_t pix) { uint32_t BusNetwork::getPixelColor(uint16_t pix) {
if (!_valid || pix >= _len) return 0; if (!_valid || pix >= _len) return 0;
uint16_t offset = pix * _UDPchannels; unsigned offset = pix * _UDPchannels;
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (_rgbw ? _data[offset+3] : 0)); return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (_rgbw ? _data[offset+3] : 0));
} }
@ -670,9 +670,9 @@ void BusNetwork::cleanup() {
uint32_t BusManager::memUsage(BusConfig &bc) { uint32_t BusManager::memUsage(BusConfig &bc) {
if (bc.type == TYPE_ONOFF || IS_PWM(bc.type)) return 5; if (bc.type == TYPE_ONOFF || IS_PWM(bc.type)) return 5;
uint16_t len = bc.count + bc.skipAmount; unsigned len = bc.count + bc.skipAmount;
uint16_t channels = Bus::getNumberOfChannels(bc.type); unsigned channels = Bus::getNumberOfChannels(bc.type);
uint16_t multiplier = 1; unsigned multiplier = 1;
if (IS_DIGITAL(bc.type)) { // digital types if (IS_DIGITAL(bc.type)) { // digital types
if (IS_16BIT(bc.type)) len *= 2; // 16-bit LEDs if (IS_16BIT(bc.type)) len *= 2; // 16-bit LEDs
#ifdef ESP8266 #ifdef ESP8266
@ -686,6 +686,12 @@ uint32_t BusManager::memUsage(BusConfig &bc) {
return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels;
} }
uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) {
//ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times)
unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2;
return (maxChannels * maxCount * minBuses * multiplier);
}
int BusManager::add(BusConfig &bc) { int BusManager::add(BusConfig &bc) {
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
if (IS_VIRTUAL(bc.type)) { if (IS_VIRTUAL(bc.type)) {
@ -848,7 +854,7 @@ Bus* BusManager::getBus(uint8_t busNr) {
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t BusManager::getTotalLength() { uint16_t BusManager::getTotalLength() {
uint16_t len = 0; unsigned len = 0;
for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength(); for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength();
return len; return len;
} }

View File

@ -356,6 +356,7 @@ class BusManager {
//utility to get the approx. memory usage of a given BusConfig //utility to get the approx. memory usage of a given BusConfig
static uint32_t memUsage(BusConfig &bc); static uint32_t memUsage(BusConfig &bc);
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
static uint16_t currentMilliamps(void) { return _milliAmpsUsed; } static uint16_t currentMilliamps(void) { return _milliAmpsUsed; }
static uint16_t ablMilliampsMax(void) { return _milliAmpsMax; } static uint16_t ablMilliampsMax(void) { return _milliAmpsMax; }

View File

@ -93,7 +93,7 @@ void doublePressAction(uint8_t b)
bool isButtonPressed(uint8_t i) bool isButtonPressed(uint8_t i)
{ {
if (btnPin[i]<0) return false; if (btnPin[i]<0) return false;
uint8_t pin = btnPin[i]; unsigned pin = btnPin[i];
switch (buttonType[i]) { switch (buttonType[i]) {
case BTN_TYPE_NONE: case BTN_TYPE_NONE:
@ -171,20 +171,20 @@ void handleAnalog(uint8_t b)
{ {
static uint8_t oldRead[WLED_MAX_BUTTONS] = {0}; static uint8_t oldRead[WLED_MAX_BUTTONS] = {0};
static float filteredReading[WLED_MAX_BUTTONS] = {0.0f}; static float filteredReading[WLED_MAX_BUTTONS] = {0.0f};
uint16_t rawReading; // raw value from analogRead, scaled to 12bit unsigned rawReading; // raw value from analogRead, scaled to 12bit
DEBUG_PRINT(F("Analog: Reading button ")); DEBUG_PRINTLN(b); DEBUG_PRINT(F("Analog: Reading button ")); DEBUG_PRINTLN(b);
#ifdef ESP8266 #ifdef ESP8266
rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit rawReading = analogRead(A0) << 2; // convert 10bit read to 12bit
#else #else
if ((btnPin[b] < 0) || (digitalPinToAnalogChannel(btnPin[b]) < 0)) return; // pin must support analog ADC - newer esp32 frameworks throw lots of warnings otherwise if ((btnPin[b] < 0) /*|| (digitalPinToAnalogChannel(btnPin[b]) < 0)*/) return; // pin must support analog ADC - newer esp32 frameworks throw lots of warnings otherwise
rawReading = analogRead(btnPin[b]); // collect at full 12bit resolution rawReading = analogRead(btnPin[b]); // collect at full 12bit resolution
#endif #endif
yield(); // keep WiFi task running - analog read may take several millis on ESP8266 yield(); // keep WiFi task running - analog read may take several millis on ESP8266
filteredReading[b] += POT_SMOOTHING * ((float(rawReading) / 16.0f) - filteredReading[b]); // filter raw input, and scale to [0..255] filteredReading[b] += POT_SMOOTHING * ((float(rawReading) / 16.0f) - filteredReading[b]); // filter raw input, and scale to [0..255]
uint16_t aRead = max(min(int(filteredReading[b]), 255), 0); // squash into 8bit unsigned aRead = max(min(int(filteredReading[b]), 255), 0); // squash into 8bit
if(aRead <= POT_SENSITIVITY) aRead = 0; // make sure that 0 and 255 are used if(aRead <= POT_SENSITIVITY) aRead = 0; // make sure that 0 and 255 are used
if(aRead >= 255-POT_SENSITIVITY) aRead = 255; if(aRead >= 255-POT_SENSITIVITY) aRead = 255;
@ -260,7 +260,7 @@ void handleButton()
if (strip.isUpdating() && (now - lastRun < ANALOG_BTN_READ_CYCLE+1)) return; // don't interfere with strip update (unless strip is updating continuously, e.g. very long strips) if (strip.isUpdating() && (now - lastRun < ANALOG_BTN_READ_CYCLE+1)) return; // don't interfere with strip update (unless strip is updating continuously, e.g. very long strips)
lastRun = now; lastRun = now;
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) { for (unsigned b=0; b<WLED_MAX_BUTTONS; b++) {
#ifdef ESP8266 #ifdef ESP8266
if ((btnPin[b]<0 && !(buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED)) || buttonType[b] == BTN_TYPE_NONE) continue; if ((btnPin[b]<0 && !(buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED)) || buttonType[b] == BTN_TYPE_NONE) continue;
#else #else

View File

@ -86,7 +86,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(apBehavior, ap[F("behav")]); CJSON(apBehavior, ap[F("behav")]);
/* /*
JsonArray ap_ip = ap["ip"]; JsonArray ap_ip = ap["ip"];
for (byte i = 0; i < 4; i++) { for (unsigned i = 0; i < 4; i++) {
apIP[i] = ap_ip; apIP[i] = ap_ip;
} }
*/ */
@ -160,44 +160,46 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap());
int s = 0; // bus iterator int s = 0; // bus iterator
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
uint32_t mem = 0; unsigned mem = 0;
bool busesChanged = false;
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
bool useParallel = false; bool useParallel = false;
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
unsigned digitalCount = 0; unsigned digitalCount = 0;
unsigned maxLeds = 0; unsigned maxLedsOnBus = 0;
int oldType = 0; unsigned maxChannels = 0;
int j = 0;
for (JsonObject elm : ins) { for (JsonObject elm : ins) {
unsigned type = elm["type"] | TYPE_WS2812_RGB; unsigned type = elm["type"] | TYPE_WS2812_RGB;
unsigned len = elm["len"] | 30; unsigned len = elm["len"] | DEFAULT_LED_COUNT;
if (IS_DIGITAL(type) && !IS_2PIN(type)) digitalCount++; if (!IS_DIGITAL(type)) continue;
if (len > maxLeds) maxLeds = len; if (!IS_2PIN(type)) {
// we need to have all LEDs of the same type for parallel digitalCount++;
if (j++ < 8 && oldType > 0 && oldType != type) oldType = -1; unsigned channels = Bus::getNumberOfChannels(type);
else if (oldType == 0) oldType = type; if (len > maxLedsOnBus) maxLedsOnBus = len;
if (channels > maxChannels) maxChannels = channels;
} }
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\nDifferent types: %d\n"), maxLeds, digitalCount, (int)(oldType == -1)); }
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
if (/*oldType != -1 && */maxLeds <= 300 && digitalCount > 5) { if (maxLedsOnBus <= 300 && digitalCount > 5) {
DEBUG_PRINTLN(F("Switching to parallel I2S."));
useParallel = true; useParallel = true;
BusManager::useParallelOutput(); BusManager::useParallelOutput();
DEBUG_PRINTF_P(PSTR("Switching to parallel I2S with max. %d LEDs per ouptut.\n"), maxLeds); mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation
} }
#endif #endif
for (JsonObject elm : ins) { for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255}; uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm["pin"]; JsonArray pinArr = elm["pin"];
if (pinArr.size() == 0) continue; if (pinArr.size() == 0) continue;
pins[0] = pinArr[0]; //pins[0] = pinArr[0];
unsigned i = 0; unsigned i = 0;
for (int p : pinArr) { for (int p : pinArr) {
pins[i++] = p; pins[i++] = p;
if (i>4) break; if (i>4) break;
} }
uint16_t length = elm["len"] | 1; uint16_t length = elm["len"] | 1;
uint8_t colorOrder = (int)elm[F("order")]; // contains white channel swap option in upper nibble uint8_t colorOrder = (int)elm[F("order")]; // contains white channel swap option in upper nibble
uint8_t skipFirst = elm[F("skip")]; uint8_t skipFirst = elm[F("skip")];
@ -208,7 +210,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
bool refresh = elm["ref"] | false; bool refresh = elm["ref"] | false;
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM
uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY; uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY;
uint8_t maPerLed = elm[F("ledma")] | 55; uint8_t maPerLed = elm[F("ledma")] | LED_MILLIAMPS_DEFAULT;
uint16_t maMax = elm[F("maxpwr")] | (ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists uint16_t maMax = elm[F("maxpwr")] | (ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current) // To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
if (IS_PWM(ledType) || IS_ONOFF(ledType) || IS_VIRTUAL(ledType)) { // analog and virtual if (IS_PWM(ledType) || IS_ONOFF(ledType) || IS_VIRTUAL(ledType)) { // analog and virtual
@ -219,26 +221,21 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (fromFS) { if (fromFS) {
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
if (useParallel && s < 8) { if (useParallel && s < 8) {
// we are using parallel I2S and memUsage() will include x8 allocation into account // if for some unexplained reason the above pre-calculation was wrong, update
if (s == 0) unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S
mem = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S if (memT > mem) mem = memT; // if we have unequal LED count use the largest
else
if (BusManager::memUsage(bc) > mem)
mem = BusManager::memUsage(bc); // if we have unequal LED count use the largest
} else } else
mem += BusManager::memUsage(bc); // includes global buffer mem += BusManager::memUsage(bc); // includes global buffer
if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip() if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
} else { } else {
if (busConfigs[s] != nullptr) delete busConfigs[s]; if (busConfigs[s] != nullptr) delete busConfigs[s];
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
busesChanged = true; doInitBusses = true; // finalization done in beginStrip()
} }
s++; s++;
} }
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem);
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
doInitBusses = busesChanged;
// finalization done in beginStrip()
} }
if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
@ -275,22 +272,34 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
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
if (((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[s]) < 0)) if ((buttonType[s] == BTN_TYPE_ANALOG) || (buttonType[s] == BTN_TYPE_ANALOG_INVERTED)) {
{ if (digitalPinToAnalogChannel(btnPin[s]) < 0) {
// not an ADC analog pin // not an ADC analog pin
DEBUG_PRINT(F("PIN ALLOC error: GPIO")); DEBUG_PRINT(btnPin[s]); DEBUG_PRINT(F("PIN ALLOC error: GPIO")); DEBUG_PRINT(btnPin[s]);
DEBUG_PRINT(F("for analog button #")); DEBUG_PRINT(s); DEBUG_PRINT(F("for analog button #")); DEBUG_PRINT(s);
DEBUG_PRINTLN(F(" is not an analog pin!")); DEBUG_PRINTLN(F(" is not an analog pin!"));
btnPin[s] = -1; btnPin[s] = -1;
pinManager.deallocatePin(pin,PinOwner::Button); pinManager.deallocatePin(pin,PinOwner::Button);
} else {
analogReadResolution(12); // see #4040
}
}
else if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH))
{
if (digitalPinToTouchChannel(btnPin[s]) < 0) {
// not a touch pin
DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[s], s);
btnPin[s] = -1;
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 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 function to check touch state but need to attach an interrupt to do so
if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) else
{ {
touchAttachInterrupt(btnPin[s], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) touchAttachInterrupt(btnPin[s], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000)
} }
#endif #endif
}
else else
#endif #endif
{ {
@ -553,7 +562,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray if_hue_ip = if_hue["ip"]; JsonArray if_hue_ip = if_hue["ip"];
for (byte i = 0; i < 4; i++) for (unsigned i = 0; i < 4; i++)
CJSON(hueIP[i], if_hue_ip[i]); CJSON(hueIP[i], if_hue_ip[i]);
#endif #endif
@ -781,7 +790,7 @@ void serializeConfig() {
ethernet["type"] = ethernetType; ethernet["type"] = ethernetType;
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
JsonArray pins = ethernet.createNestedArray("pin"); JsonArray pins = ethernet.createNestedArray("pin");
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) pins.add(esp32_nonconfigurable_ethernet_pins[p].pin); for (unsigned p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) pins.add(esp32_nonconfigurable_ethernet_pins[p].pin);
if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power); if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power);
if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc); if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc);
if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio); if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio);
@ -1031,7 +1040,7 @@ void serializeConfig() {
if_hue_recv["col"] = hueApplyColor; if_hue_recv["col"] = hueApplyColor;
JsonArray if_hue_ip = if_hue.createNestedArray("ip"); JsonArray if_hue_ip = if_hue.createNestedArray("ip");
for (byte i = 0; i < 4; i++) { for (unsigned i = 0; i < 4; i++) {
if_hue_ip.add(hueIP[i]); if_hue_ip.add(hueIP[i]);
} }
#endif #endif
@ -1066,7 +1075,7 @@ void serializeConfig() {
JsonArray timers_ins = timers.createNestedArray("ins"); JsonArray timers_ins = timers.createNestedArray("ins");
for (byte i = 0; i < 10; i++) { for (unsigned i = 0; i < 10; i++) {
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255) if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255)
JsonObject timers_ins0 = timers_ins.createNestedObject(); JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0["en"] = (timerWeekday[i] & 0x01); timers_ins0["en"] = (timerWeekday[i] & 0x01);
@ -1098,7 +1107,7 @@ void serializeConfig() {
dmx[F("start-led")] = DMXStartLED; dmx[F("start-led")] = DMXStartLED;
JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap")); JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap"));
for (byte i = 0; i < 15; i++) { for (unsigned i = 0; i < 15; i++) {
dmx_fixmap.add(DMXFixtureMap[i]); dmx_fixmap.add(DMXFixtureMap[i]);
} }

View File

@ -9,7 +9,7 @@
*/ */
uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
if(blend == 0) return color1; if(blend == 0) return color1;
uint16_t blendmax = b16 ? 0xFFFF : 0xFF; unsigned blendmax = b16 ? 0xFFFF : 0xFF;
if(blend == blendmax) return color2; if(blend == blendmax) return color2;
uint8_t shift = b16 ? 16 : 8; uint8_t shift = b16 ? 16 : 8;
@ -52,7 +52,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
uint32_t g = G(c1) + G(c2); uint32_t g = G(c1) + G(c2);
uint32_t b = B(c1) + B(c2); uint32_t b = B(c1) + B(c2);
uint32_t w = W(c1) + W(c2); uint32_t w = W(c1) + W(c2);
uint16_t max = r; unsigned max = r;
if (g > max) max = g; if (g > max) max = g;
if (b > max) max = b; if (b > max) max = b;
if (w > max) max = w; if (w > max) max = w;

View File

@ -1,7 +1,7 @@
//page js //page js
var loc = false, locip, locproto = "http:"; var loc = false, locip, locproto = "http:";
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false/*, syncTglRecv = true*/; var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false/*, syncTglRecv = true*/;
var hasWhite = false, hasRGB = false, hasCCT = false; var hasWhite = false, hasRGB = false, hasCCT = false, has2D = false;
var nlDur = 60, nlTar = 0; var nlDur = 60, nlTar = 0;
var nlMode = false; var nlMode = false;
var segLmax = 0; // size (in pixels) of largest selected segment var segLmax = 0; // size (in pixels) of largest selected segment
@ -1341,7 +1341,7 @@ function updateSelectedFx()
if (ds.id>0) { if (ds.id>0) {
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects) if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
else { else {
if ((segLmax==1 && (!opts[3] || opts[3].indexOf("0")<0)) || (!isM && opts[3] && ((opts[3].indexOf("2")>=0 && opts[3].indexOf("1")<0)))) fx.classList.add('hide'); if ((segLmax==1 && (!opts[3] || opts[3].indexOf("0")<0)) || (!has2D && opts[3] && ((opts[3].indexOf("2")>=0 && opts[3].indexOf("1")<0)))) fx.classList.add('hide');
else fx.classList.remove('hide'); else fx.classList.remove('hide');
} }
} }
@ -1446,7 +1446,7 @@ function readState(s,command=false)
populateSegments(s); populateSegments(s);
var selc=0; var selc=0;
var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected
hasRGB = hasWhite = hasCCT = false; hasRGB = hasWhite = hasCCT = has2D = false;
segLmax = 0; segLmax = 0;
for (let i = 0; i < (s.seg||[]).length; i++) for (let i = 0; i < (s.seg||[]).length; i++)
{ {
@ -1457,20 +1457,23 @@ function readState(s,command=false)
if (s.seg[i].sel) { if (s.seg[i].sel) {
if (sellvl < 2) selc = i; // get first selected segment if (sellvl < 2) selc = i; // get first selected segment
sellvl = 2; sellvl = 2;
var lc = lastinfo.leds.seglc[i]; let w = (s.seg[i].stop - s.seg[i].start);
let h = s.seg[i].stopY ? (s.seg[i].stopY - s.seg[i].startY) : 1;
let lc = lastinfo.leds.seglc[i];
hasRGB |= !!(lc & 0x01); hasRGB |= !!(lc & 0x01);
hasWhite |= !!(lc & 0x02); hasWhite |= !!(lc & 0x02);
hasCCT |= !!(lc & 0x04); hasCCT |= !!(lc & 0x04);
let sLen = (s.seg[i].stop - s.seg[i].start)*(s.seg[i].stopY?(s.seg[i].stopY - s.seg[i].startY):1); has2D |= w > 1 && h > 1;
segLmax = segLmax < sLen ? sLen : segLmax; if (w*h > segLmax) segLmax = w*h;
} }
} }
var i=s.seg[selc]; var i=s.seg[selc];
if (sellvl == 1) { if (sellvl == 1) {
var lc = lastinfo.leds.seglc[selc]; let lc = lastinfo.leds.seglc[selc];
hasRGB = !!(lc & 0x01); hasRGB = !!(lc & 0x01);
hasWhite = !!(lc & 0x02); hasWhite = !!(lc & 0x02);
hasCCT = !!(lc & 0x04); hasCCT = !!(lc & 0x04);
has2D = (i.stop - i.start) > 1 && (i.stopY ? (i.stopY - i.startY) : 1) > 1;
} }
if (!i) { if (!i) {
showToast('No Segments!', true); showToast('No Segments!', true);

View File

@ -22,7 +22,7 @@ void handleDMX()
bool calc_brightness = true; bool calc_brightness = true;
// check if no shutter channel is set // check if no shutter channel is set
for (byte i = 0; i < DMXChannels; i++) for (unsigned i = 0; i < DMXChannels; i++)
{ {
if (DMXFixtureMap[i] == 5) calc_brightness = false; if (DMXFixtureMap[i] == 5) calc_brightness = false;
} }

View File

@ -26,22 +26,21 @@ void handleDDPPacket(e131_packet_t* p) {
} }
} }
uint8_t ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel) unsigned ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed; uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
start += DMXAddress / ddpChannelsPerLed; start += DMXAddress / ddpChannelsPerLed;
uint16_t stop = start + htons(p->dataLen) / ddpChannelsPerLed; unsigned stop = start + htons(p->dataLen) / ddpChannelsPerLed;
uint8_t* data = p->data; uint8_t* data = p->data;
uint16_t c = 0; unsigned c = 0;
if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) { if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
for (uint16_t i = start; i < stop; i++) { for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) {
setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0); setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0);
c += ddpChannelsPerLed;
} }
} }
@ -49,7 +48,7 @@ void handleDDPPacket(e131_packet_t* p) {
ddpSeenPush |= push; ddpSeenPush |= push;
if (!ddpSeenPush || push) { // if we've never seen a push, or this is one, render display if (!ddpSeenPush || push) { // if we've never seen a push, or this is one, render display
e131NewData = true; e131NewData = true;
byte sn = p->sequenceNum & 0xF; int sn = p->sequenceNum & 0xF;
if (sn) e131LastSequenceNumber[0] = sn; if (sn) e131LastSequenceNumber[0] = sn;
} }
} }
@ -57,9 +56,9 @@ void handleDDPPacket(e131_packet_t* p) {
//E1.31 and Art-Net protocol support //E1.31 and Art-Net protocol support
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
uint16_t uni = 0, dmxChannels = 0; unsigned uni = 0, dmxChannels = 0;
uint8_t* e131_data = nullptr; uint8_t* e131_data = nullptr;
uint8_t seq = 0, mde = REALTIME_MODE_E131; unsigned seq = 0, mde = REALTIME_MODE_E131;
if (protocol == P_ARTNET) if (protocol == P_ARTNET)
{ {
@ -105,7 +104,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
// only listen for universes we're handling & allocated memory // only listen for universes we're handling & allocated memory
if (uni < e131Universe || uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return; if (uni < e131Universe || uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return;
uint8_t previousUniverses = uni - e131Universe; unsigned previousUniverses = uni - e131Universe;
if (e131SkipOutOfSequence) if (e131SkipOutOfSequence)
if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){ if (seq < e131LastSequenceNumber[previousUniverses] && seq > 20 && e131LastSequenceNumber[previousUniverses] < 250){
@ -123,12 +122,12 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
// update status info // update status info
realtimeIP = clientIP; realtimeIP = clientIP;
byte wChannel = 0; byte wChannel = 0;
uint16_t totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
uint16_t availDMXLen = 0; unsigned availDMXLen = 0;
uint16_t dataOffset = DMXAddress; unsigned dataOffset = DMXAddress;
// For legacy DMX start address 0 the available DMX length offset is 0 // For legacy DMX start address 0 the available DMX length offset is 0
const uint16_t dmxLenOffset = (DMXAddress == 0) ? 0 : 1; const unsigned dmxLenOffset = (DMXAddress == 0) ? 0 : 1;
// Check if DMX start address fits in available channels // Check if DMX start address fits in available channels
if (dmxChannels >= DMXAddress) { if (dmxChannels >= DMXAddress) {
@ -154,7 +153,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0; wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0;
for (uint16_t i = 0; i < totalLen; i++) for (unsigned i = 0; i < totalLen; i++)
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
break; break;
@ -171,7 +170,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
strip.setBrightness(bri, true); strip.setBrightness(bri, true);
} }
for (uint16_t i = 0; i < totalLen; i++) for (unsigned i = 0; i < totalLen; i++)
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
break; break;
@ -180,7 +179,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
if (uni != e131Universe || availDMXLen < 2) return; if (uni != e131Universe || availDMXLen < 2) return;
// limit max. selectable preset to 250, even though DMX max. val is 255 // limit max. selectable preset to 250, even though DMX max. val is 255
uint8_t dmxValPreset = (e131_data[dataOffset+1] > 250 ? 250 : e131_data[dataOffset+1]); unsigned dmxValPreset = (e131_data[dataOffset+1] > 250 ? 250 : e131_data[dataOffset+1]);
// only apply preset if value changed // only apply preset if value changed
if (dmxValPreset != 0 && dmxValPreset != currentPreset && if (dmxValPreset != 0 && dmxValPreset != currentPreset &&
@ -207,8 +206,8 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
{ {
if (uni != e131Universe) return; if (uni != e131Universe) return;
bool isSegmentMode = DMXMode == DMX_MODE_EFFECT_SEGMENT || DMXMode == DMX_MODE_EFFECT_SEGMENT_W; bool isSegmentMode = DMXMode == DMX_MODE_EFFECT_SEGMENT || DMXMode == DMX_MODE_EFFECT_SEGMENT_W;
uint8_t dmxEffectChannels = (DMXMode == DMX_MODE_EFFECT || DMXMode == DMX_MODE_EFFECT_SEGMENT) ? 15 : 18; unsigned dmxEffectChannels = (DMXMode == DMX_MODE_EFFECT || DMXMode == DMX_MODE_EFFECT_SEGMENT) ? 15 : 18;
for (uint8_t id = 0; id < strip.getSegmentsNum(); id++) { for (unsigned id = 0; id < strip.getSegmentsNum(); id++) {
Segment& seg = strip.getSegment(id); Segment& seg = strip.getSegment(id);
if (isSegmentMode) if (isSegmentMode)
dataOffset = DMXAddress + id * (dmxEffectChannels + DMXSegmentSpacing); dataOffset = DMXAddress + id * (dmxEffectChannels + DMXSegmentSpacing);
@ -271,10 +270,10 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
case DMX_MODE_MULTIPLE_RGBW: case DMX_MODE_MULTIPLE_RGBW:
{ {
bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW); bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW);
const uint16_t dmxChannelsPerLed = is4Chan ? 4 : 3; const unsigned dmxChannelsPerLed = is4Chan ? 4 : 3;
const uint16_t ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE; const unsigned ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE;
uint8_t stripBrightness = bri; uint8_t stripBrightness = bri;
uint16_t previousLeds, dmxOffset, ledsTotal; unsigned previousLeds, dmxOffset, ledsTotal;
if (previousUniverses == 0) { if (previousUniverses == 0) {
if (availDMXLen < 1) return; if (availDMXLen < 1) return;
@ -290,8 +289,8 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
} else { } else {
// All subsequent universes start at the first channel. // All subsequent universes start at the first channel.
dmxOffset = (protocol == P_ARTNET) ? 0 : 1; dmxOffset = (protocol == P_ARTNET) ? 0 : 1;
const uint16_t dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0; const unsigned dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0;
uint16_t ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed; unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed;
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse; previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse;
ledsTotal = previousLeds + (dmxChannels / dmxChannelsPerLed); ledsTotal = previousLeds + (dmxChannels / dmxChannelsPerLed);
} }
@ -316,12 +315,12 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
} }
if (!is4Chan) { if (!is4Chan) {
for (uint16_t i = previousLeds; i < ledsTotal; i++) { for (unsigned i = previousLeds; i < ledsTotal; i++) {
setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0); setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
dmxOffset+=3; dmxOffset+=3;
} }
} else { } else {
for (uint16_t i = previousLeds; i < ledsTotal; i++) { for (unsigned i = previousLeds; i < ledsTotal; i++) {
setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], e131_data[dmxOffset+3]); setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], e131_data[dmxOffset+3]);
dmxOffset+=4; dmxOffset+=4;
} }
@ -341,8 +340,8 @@ void handleArtnetPollReply(IPAddress ipAddress) {
ArtPollReply artnetPollReply; ArtPollReply artnetPollReply;
prepareArtnetPollReply(&artnetPollReply); prepareArtnetPollReply(&artnetPollReply);
uint16_t startUniverse = e131Universe; unsigned startUniverse = e131Universe;
uint16_t endUniverse = e131Universe; unsigned endUniverse = e131Universe;
switch (DMXMode) { switch (DMXMode) {
case DMX_MODE_DISABLED: case DMX_MODE_DISABLED:
@ -362,15 +361,15 @@ void handleArtnetPollReply(IPAddress ipAddress) {
case DMX_MODE_MULTIPLE_RGBW: case DMX_MODE_MULTIPLE_RGBW:
{ {
bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW); bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW);
const uint16_t dmxChannelsPerLed = is4Chan ? 4 : 3; const unsigned dmxChannelsPerLed = is4Chan ? 4 : 3;
const uint16_t dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0; const unsigned dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0;
const uint16_t dmxLenOffset = (DMXAddress == 0) ? 0 : 1; // For legacy DMX start address 0 const unsigned dmxLenOffset = (DMXAddress == 0) ? 0 : 1; // For legacy DMX start address 0
const uint16_t ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed; const unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed;
const uint16_t totalLen = strip.getLengthTotal(); const unsigned totalLen = strip.getLengthTotal();
if (totalLen > ledsInFirstUniverse) { if (totalLen > ledsInFirstUniverse) {
const uint16_t ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE; const unsigned ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE;
const uint16_t remainLED = totalLen - ledsInFirstUniverse; const unsigned remainLED = totalLen - ledsInFirstUniverse;
endUniverse += (remainLED / ledsPerUniverse); endUniverse += (remainLED / ledsPerUniverse);
@ -391,7 +390,7 @@ void handleArtnetPollReply(IPAddress ipAddress) {
} }
if (DMXMode != DMX_MODE_DISABLED) { if (DMXMode != DMX_MODE_DISABLED) {
for (uint16_t i = startUniverse; i <= endUniverse; ++i) { for (unsigned i = startUniverse; i <= endUniverse; ++i) {
sendArtnetPollReply(&artnetPollReply, ipAddress, i); sendArtnetPollReply(&artnetPollReply, ipAddress, i);
} }
} }
@ -417,7 +416,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) {
reply->reply_opcode = ARTNET_OPCODE_OPPOLLREPLY; reply->reply_opcode = ARTNET_OPCODE_OPPOLLREPLY;
IPAddress localIP = Network.localIP(); IPAddress localIP = Network.localIP();
for (uint8_t i = 0; i < 4; i++) { for (unsigned i = 0; i < 4; i++) {
reply->reply_ip[i] = localIP[i]; reply->reply_ip[i] = localIP[i];
} }
@ -493,7 +492,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) {
Network.localMAC(reply->reply_mac); Network.localMAC(reply->reply_mac);
for (uint8_t i = 0; i < 4; i++) { for (unsigned i = 0; i < 4; i++) {
reply->reply_bind_ip[i] = localIP[i]; reply->reply_bind_ip[i] = localIP[i];
} }
@ -517,7 +516,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) {
// Node does not support fail-over // Node does not support fail-over
reply->reply_status_3 = 0x00; reply->reply_status_3 = 0x00;
for (uint8_t i = 0; i < 21; i++) { for (unsigned i = 0; i < 21; i++) {
reply->reply_filler[i] = 0x00; reply->reply_filler[i] = 0x00;
} }
} }

View File

@ -138,7 +138,7 @@ static bool bufferedFindObjectEnd() {
if (!f || !f.size()) return false; if (!f || !f.size()) return false;
uint16_t objDepth = 0; //num of '{' minus num of '}'. return once 0 unsigned objDepth = 0; //num of '{' minus num of '}'. return once 0
//size_t start = f.position(); //size_t start = f.position();
byte buf[FS_BUFSIZE]; byte buf[FS_BUFSIZE];

View File

@ -42,12 +42,12 @@ void handleImprovPacket() {
uint8_t header[6] = {'I','M','P','R','O','V'}; uint8_t header[6] = {'I','M','P','R','O','V'};
bool timeout = false; bool timeout = false;
uint8_t waitTime = 25; unsigned waitTime = 25;
uint16_t packetByte = 0; unsigned packetByte = 0;
uint8_t packetLen = 9; unsigned packetLen = 9;
uint8_t checksum = 0; unsigned checksum = 0;
uint8_t rpcCommandType = 0; unsigned rpcCommandType = 0;
char rpcData[128]; char rpcData[128];
rpcData[0] = 0; rpcData[0] = 0;
@ -92,7 +92,7 @@ void handleImprovPacket() {
switch (rpcCommandType) { switch (rpcCommandType) {
case ImprovRPCType::Command_Wifi: parseWiFiCommand(rpcData); break; case ImprovRPCType::Command_Wifi: parseWiFiCommand(rpcData); break;
case ImprovRPCType::Request_State: { case ImprovRPCType::Request_State: {
uint8_t improvState = 0x02; //authorized unsigned improvState = 0x02; //authorized
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
if (Network.isConnected()) improvState = 0x04; //provisioned if (Network.isConnected()) improvState = 0x04; //provisioned
sendImprovStateResponse(improvState, false); sendImprovStateResponse(improvState, false);
@ -136,8 +136,8 @@ void sendImprovStateResponse(uint8_t state, bool error) {
out[8] = 1; out[8] = 1;
out[9] = state; out[9] = state;
uint8_t checksum = 0; unsigned checksum = 0;
for (uint8_t i = 0; i < 10; i++) checksum += out[i]; for (unsigned i = 0; i < 10; i++) checksum += out[i];
out[10] = checksum; out[10] = checksum;
Serial.write((uint8_t*)out, 11); Serial.write((uint8_t*)out, 11);
Serial.write('\n'); Serial.write('\n');
@ -146,16 +146,16 @@ void sendImprovStateResponse(uint8_t state, bool error) {
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan() // used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) { void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true); if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
uint8_t packetLen = 12; unsigned packetLen = 12;
char out[256] = {'I','M','P','R','O','V'}; char out[256] = {'I','M','P','R','O','V'};
out[6] = IMPROV_VERSION; out[6] = IMPROV_VERSION;
out[7] = ImprovPacketType::RPC_Response; out[7] = ImprovPacketType::RPC_Response;
//out[8] = 2; //Length (set below) //out[8] = 2; //Length (set below)
out[9] = type; out[9] = type;
//out[10] = 0; //Data len (set below) //out[10] = 0; //Data len (set below)
uint16_t pos = 11; unsigned pos = 11;
for (uint8_t s = 0; s < n_strings; s++) { for (unsigned s = 0; s < n_strings; s++) {
size_t len = strlen(strings[s]); size_t len = strlen(strings[s]);
if (pos + len > 254) continue; // simple buffer overflow guard if (pos + len > 254) continue; // simple buffer overflow guard
out[pos++] = len; out[pos++] = len;
@ -167,8 +167,8 @@ void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **str
out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte) out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte)
out[10] = pos -11; // Data len out[10] = pos -11; // Data len
uint8_t checksum = 0; unsigned checksum = 0;
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i]; for (unsigned i = 0; i < packetLen -1; i++) checksum += out[i];
out[packetLen -1] = checksum; out[packetLen -1] = checksum;
Serial.write((uint8_t*)out, packetLen); Serial.write((uint8_t*)out, packetLen);
Serial.write('\n'); Serial.write('\n');
@ -181,7 +181,7 @@ void sendImprovIPRPCResult(ImprovRPCType type) {
{ {
char urlStr[64]; char urlStr[64];
IPAddress localIP = Network.localIP(); IPAddress localIP = Network.localIP();
uint8_t len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); unsigned len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
if (len > 24) return; //sprintf fail? if (len > 24) return; //sprintf fail?
const char *str[1] = {urlStr}; const char *str[1] = {urlStr};
sendImprovRPCResult(type, 1, str); sendImprovRPCResult(type, 1, str);
@ -254,17 +254,17 @@ void handleImprovWifiScan() {}
#endif #endif
void parseWiFiCommand(char* rpcData) { void parseWiFiCommand(char* rpcData) {
uint8_t len = rpcData[0]; unsigned len = rpcData[0];
if (!len || len > 126) return; if (!len || len > 126) return;
uint8_t ssidLen = rpcData[1]; unsigned ssidLen = rpcData[1];
if (ssidLen > len -1 || ssidLen > 32) return; if (ssidLen > len -1 || ssidLen > 32) return;
memset(multiWiFi[0].clientSSID, 0, 32); memset(multiWiFi[0].clientSSID, 0, 32);
memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen); memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen);
memset(multiWiFi[0].clientPass, 0, 64); memset(multiWiFi[0].clientPass, 0, 64);
if (len > ssidLen +1) { if (len > ssidLen +1) {
uint8_t passLen = rpcData[2+ssidLen]; unsigned passLen = rpcData[2+ssidLen];
memset(multiWiFi[0].clientPass, 0, 64); memset(multiWiFi[0].clientPass, 0, 64);
memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen); memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen);
} }

View File

@ -37,14 +37,14 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
//DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data); //DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);
uint16_t start = elem["start"] | seg.start; unsigned start = elem["start"] | seg.start;
if (stop < 0) { if (stop < 0) {
int len = elem["len"]; int len = elem["len"];
stop = (len > 0) ? start + len : seg.stop; stop = (len > 0) ? start + len : seg.stop;
} }
// 2D segments // 2D segments
uint16_t startY = elem["startY"] | seg.startY; unsigned startY = elem["startY"] | seg.startY;
uint16_t stopY = elem["stopY"] | seg.stopY; unsigned stopY = elem["stopY"] | seg.stopY;
//repeat, multiplies segment until all LEDs are used, or max segments reached //repeat, multiplies segment until all LEDs are used, or max segments reached
bool repeat = elem["rpt"] | false; bool repeat = elem["rpt"] | false;
@ -52,7 +52,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
elem.remove("id"); // remove for recursive call elem.remove("id"); // remove for recursive call
elem.remove("rpt"); // remove for recursive call elem.remove("rpt"); // remove for recursive call
elem.remove("n"); // remove for recursive call elem.remove("n"); // remove for recursive call
uint16_t len = stop - start; unsigned len = stop - start;
for (size_t i=id+1; i<strip.getMaxSegments(); i++) { for (size_t i=id+1; i<strip.getMaxSegments(); i++) {
start = start + len; start = start + len;
if (start >= strip.getLengthTotal()) break; if (start >= strip.getLengthTotal()) break;
@ -105,7 +105,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
uint8_t set = elem[F("set")] | seg.set; uint8_t set = elem[F("set")] | seg.set;
seg.set = constrain(set, 0, 3); seg.set = constrain(set, 0, 3);
uint16_t len = 1; unsigned len = 1;
if (stop > start) len = stop - start; if (stop > start) len = stop - start;
int offset = elem[F("of")] | INT32_MAX; int offset = elem[F("of")] | INT32_MAX;
if (offset != INT32_MAX) { if (offset != INT32_MAX) {
@ -667,12 +667,12 @@ void serializeInfo(JsonObject root)
} }
#endif #endif
uint8_t totalLC = 0; unsigned totalLC = 0;
JsonArray lcarr = leds.createNestedArray(F("seglc")); JsonArray lcarr = leds.createNestedArray(F("seglc"));
size_t nSegs = strip.getSegmentsNum(); size_t nSegs = strip.getSegmentsNum();
for (size_t s = 0; s < nSegs; s++) { for (size_t s = 0; s < nSegs; s++) {
if (!strip.getSegment(s).isActive()) continue; if (!strip.getSegment(s).isActive()) continue;
uint8_t lc = strip.getSegment(s).getLightCapabilities(); unsigned lc = strip.getSegment(s).getLightCapabilities();
totalLC |= lc; totalLC |= lc;
lcarr.add(lc); lcarr.add(lc);
} }
@ -855,7 +855,7 @@ void setPaletteColors(JsonArray json, byte* tcp)
TRGBGradientPaletteEntryUnion u; TRGBGradientPaletteEntryUnion u;
// Count entries // Count entries
uint16_t count = 0; unsigned count = 0;
do { do {
u = *(ent + count); u = *(ent + count);
count++; count++;
@ -1174,8 +1174,8 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
} }
#endif #endif
uint16_t used = strip.getLengthTotal(); unsigned used = strip.getLengthTotal();
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS unsigned n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (strip.isMatrix) { if (strip.isMatrix) {
// ignore anything behid matrix (i.e. extra strip) // ignore anything behid matrix (i.e. extra strip)

View File

@ -29,9 +29,9 @@ void setValuesFromSegment(uint8_t s)
void applyValuesToSelectedSegs() void applyValuesToSelectedSegs()
{ {
// copy of first selected segment to tell if value was updated // copy of first selected segment to tell if value was updated
uint8_t firstSel = strip.getFirstSelectedSegId(); unsigned firstSel = strip.getFirstSelectedSegId();
Segment selsegPrev = strip.getSegment(firstSel); Segment selsegPrev = strip.getSegment(firstSel);
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue; if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;
@ -64,7 +64,7 @@ void toggleOnOff()
//scales the brightness with the briMultiplier factor //scales the brightness with the briMultiplier factor
byte scaledBri(byte in) byte scaledBri(byte in)
{ {
uint16_t val = ((uint16_t)in*briMultiplier)/100; unsigned val = ((uint16_t)in*briMultiplier)/100;
if (val > 255) val = 255; if (val > 255) val = 255;
return (byte)val; return (byte)val;
} }
@ -211,7 +211,7 @@ void handleNightlight() {
nightlightDelayMs = (unsigned)(nightlightDelayMins*60000); nightlightDelayMs = (unsigned)(nightlightDelayMins*60000);
nightlightActiveOld = true; nightlightActiveOld = true;
briNlT = bri; briNlT = bri;
for (byte i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color for (unsigned i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color
if (nightlightMode == NL_MODE_SUN) if (nightlightMode == NL_MODE_SUN)
{ {
//save current //save current
@ -236,7 +236,7 @@ void handleNightlight() {
bri = briNlT + ((nightlightTargetBri - briNlT)*nper); bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2" if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2"
{ {
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color for (unsigned i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
} }
colorUpdated(CALL_MODE_NO_NOTIFY); colorUpdated(CALL_MODE_NO_NOTIFY);
} }

View File

@ -377,7 +377,7 @@ void checkTimers()
if (!hour(localTime) && minute(localTime)==1) calculateSunriseAndSunset(); if (!hour(localTime) && minute(localTime)==1) calculateSunriseAndSunset();
DEBUG_PRINTF_P(PSTR("Local time: %02d:%02d\n"), hour(localTime), minute(localTime)); DEBUG_PRINTF_P(PSTR("Local time: %02d:%02d\n"), hour(localTime), minute(localTime));
for (uint8_t i = 0; i < 8; i++) for (unsigned i = 0; i < 8; i++)
{ {
if (timerMacro[i] != 0 if (timerMacro[i] != 0
&& (timerWeekday[i] & 0x01) //timer is enabled && (timerWeekday[i] & 0x01) //timer is enabled

View File

@ -34,7 +34,7 @@ void _overlayAnalogClock()
} }
if (analogClock5MinuteMarks) if (analogClock5MinuteMarks)
{ {
for (byte i = 0; i <= 12; i++) for (unsigned i = 0; i <= 12; i++)
{ {
unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
if (pix > overlayMax) pix -= overlaySize; if (pix > overlayMax) pix -= overlaySize;
@ -91,7 +91,7 @@ void handleOverlayDraw() {
usermods.handleOverlayDraw(); usermods.handleOverlayDraw();
if (analogClockSolidBlack) { if (analogClockSolidBlack) {
const Segment* segments = strip.getSegments(); const Segment* segments = strip.getSegments();
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
const Segment& segment = segments[i]; const Segment& segment = segments[i];
if (!segment.isActive()) continue; if (!segment.isActive()) continue;
if (segment.mode > 0 || segment.colors[0] > 0) { if (segment.mode > 0 || segment.colors[0] > 0) {

View File

@ -295,7 +295,7 @@ byte PinManagerClass::allocateLedc(byte channels)
{ {
if (channels > MAX_LED_CHANNELS || channels == 0) return 255; if (channels > MAX_LED_CHANNELS || channels == 0) return 255;
byte ca = 0; byte ca = 0;
for (byte i = 0; i < MAX_LED_CHANNELS; i++) { for (unsigned i = 0; i < MAX_LED_CHANNELS; i++) {
byte by = i >> 3; byte by = i >> 3;
byte bi = i - 8*by; byte bi = i - 8*by;
if (bitRead(ledcAlloc[by], bi)) { //found occupied pin if (bitRead(ledcAlloc[by], bi)) { //found occupied pin
@ -305,7 +305,7 @@ byte PinManagerClass::allocateLedc(byte channels)
} }
if (ca >= channels) { //enough free channels if (ca >= channels) { //enough free channels
byte in = (i + 1) - ca; byte in = (i + 1) - ca;
for (byte j = 0; j < ca; j++) { for (unsigned j = 0; j < ca; j++) {
byte bChan = in + j; byte bChan = in + j;
byte byChan = bChan >> 3; byte byChan = bChan >> 3;
byte biChan = bChan - 8*byChan; byte biChan = bChan - 8*byChan;
@ -319,7 +319,7 @@ byte PinManagerClass::allocateLedc(byte channels)
void PinManagerClass::deallocateLedc(byte pos, byte channels) void PinManagerClass::deallocateLedc(byte pos, byte channels)
{ {
for (byte j = pos; j < pos + channels; j++) { for (unsigned j = pos; j < pos + channels; j++) {
if (j > MAX_LED_CHANNELS) return; if (j > MAX_LED_CHANNELS) return;
byte by = j >> 3; byte by = j >> 3;
byte bi = j - 8*by; byte bi = j - 8*by;

View File

@ -68,7 +68,7 @@ static bool resetNightMode() {
static void brightnessUp() { static void brightnessUp() {
if (nightModeActive()) return; if (nightModeActive()) return;
// dumb incremental search is efficient enough for so few items // dumb incremental search is efficient enough for so few items
for (uint8_t index = 0; index < numBrightnessSteps; ++index) { for (unsigned index = 0; index < numBrightnessSteps; ++index) {
if (brightnessSteps[index] > bri) { if (brightnessSteps[index] > bri) {
bri = brightnessSteps[index]; bri = brightnessSteps[index];
break; break;

View File

@ -113,7 +113,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
pinManager.deallocatePin(irPin, PinOwner::IR); pinManager.deallocatePin(irPin, PinOwner::IR);
} }
#endif #endif
for (uint8_t 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
@ -123,11 +123,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} }
} }
uint8_t colorOrder, type, skip, awmode, channelSwap, maPerLed; unsigned colorOrder, type, skip, awmode, channelSwap, maPerLed;
uint16_t length, start, maMax; unsigned length, start, maMax;
uint8_t pins[5] = {255, 255, 255, 255, 255}; uint8_t pins[5] = {255, 255, 255, 255, 255};
uint16_t ablMilliampsMax = request->arg(F("MA")).toInt(); unsigned ablMilliampsMax = request->arg(F("MA")).toInt();
BusManager::setMilliampsMax(ablMilliampsMax); BusManager::setMilliampsMax(ablMilliampsMax);
autoSegments = request->hasArg(F("MS")); autoSegments = request->hasArg(F("MS"));
@ -266,12 +266,16 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
buttonType[i] = request->arg(be).toInt(); buttonType[i] = request->arg(be).toInt();
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
// ESP32 only: check that button pin is a valid gpio // ESP32 only: check that button pin is a valid gpio
if (((buttonType[i] == BTN_TYPE_ANALOG) || (buttonType[i] == BTN_TYPE_ANALOG_INVERTED)) && (digitalPinToAnalogChannel(btnPin[i]) < 0)) if ((buttonType[i] == BTN_TYPE_ANALOG) || (buttonType[i] == BTN_TYPE_ANALOG_INVERTED))
{ {
if (digitalPinToAnalogChannel(btnPin[i]) < 0) {
// 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 {
analogReadResolution(12); // see #4040
}
} }
else if ((buttonType[i] == BTN_TYPE_TOUCH || buttonType[i] == BTN_TYPE_TOUCH_SWITCH)) else if ((buttonType[i] == BTN_TYPE_TOUCH || buttonType[i] == BTN_TYPE_TOUCH_SWITCH))
{ {
@ -498,7 +502,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
macroAlexaOff = request->arg(F("A1")).toInt(); macroAlexaOff = request->arg(F("A1")).toInt();
macroCountdown = request->arg(F("MC")).toInt(); macroCountdown = request->arg(F("MC")).toInt();
macroNl = request->arg(F("MN")).toInt(); macroNl = request->arg(F("MN")).toInt();
for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) { for (unsigned i=0; i<WLED_MAX_BUTTONS; i++) {
char mp[4] = "MP"; mp[2] = (i<10?48:55)+i; mp[3] = 0; // short char mp[4] = "MP"; mp[2] = (i<10?48:55)+i; mp[3] = 0; // short
char ml[4] = "ML"; ml[2] = (i<10?48:55)+i; ml[3] = 0; // long char ml[4] = "ML"; ml[2] = (i<10?48:55)+i; ml[3] = 0; // long
char md[4] = "MD"; md[2] = (i<10?48:55)+i; md[3] = 0; // double char md[4] = "MD"; md[2] = (i<10?48:55)+i; md[3] = 0; // double
@ -548,10 +552,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (request->hasArg(F("PIN"))) { if (request->hasArg(F("PIN"))) {
const char *pin = request->arg(F("PIN")).c_str(); const char *pin = request->arg(F("PIN")).c_str();
uint8_t pinLen = strlen(pin); unsigned pinLen = strlen(pin);
if (pinLen == 4 || pinLen == 0) { if (pinLen == 4 || pinLen == 0) {
uint8_t numZeros = 0; unsigned numZeros = 0;
for (uint8_t i = 0; i < pinLen; i++) numZeros += (pin[i] == '0'); for (unsigned i = 0; i < pinLen; i++) numZeros += (pin[i] == '0');
if (numZeros < pinLen || pinLen == 0) { // ignore 0000 input (placeholder) if (numZeros < pinLen || pinLen == 0) { // ignore 0000 input (placeholder)
strlcpy(settingsPIN, pin, 5); strlcpy(settingsPIN, pin, 5);
} }
@ -675,7 +679,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
JsonObject um = pDoc->createNestedObject("um"); JsonObject um = pDoc->createNestedObject("um");
size_t args = request->args(); size_t args = request->args();
uint16_t j=0; unsigned j=0;
for (size_t i=0; i<args; i++) { for (size_t i=0; i<args; i++) {
String name = request->argName(i); String name = request->argName(i);
String value = request->arg(i); String value = request->arg(i);
@ -756,12 +760,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (strip.isMatrix) { if (strip.isMatrix) {
strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt())); strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt()));
strip.panel.reserve(strip.panels); // pre-allocate memory strip.panel.reserve(strip.panels); // pre-allocate memory
for (uint8_t i=0; i<strip.panels; i++) { for (unsigned i=0; i<strip.panels; i++) {
WS2812FX::Panel p; WS2812FX::Panel p;
char pO[8] = { '\0' }; char pO[8] = { '\0' };
snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less
pO[7] = '\0'; pO[7] = '\0';
uint8_t l = strlen(pO); unsigned l = strlen(pO);
// create P0B, P1B, ..., P63B, etc for other PxxX // create P0B, P1B, ..., P63B, etc for other PxxX
pO[l] = 'B'; if (!request->hasArg(pO)) break; pO[l] = 'B'; if (!request->hasArg(pO)) break;
pO[l] = 'B'; p.bottomStart = request->arg(pO).toInt(); pO[l] = 'B'; p.bottomStart = request->arg(pO).toInt();
@ -815,7 +819,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SS=")); pos = req.indexOf(F("SS="));
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); unsigned t = getNumVal(&req, pos);
if (t < strip.getSegmentsNum()) { if (t < strip.getSegmentsNum()) {
selectedSeg = t; selectedSeg = t;
singleSegment = true; singleSegment = true;
@ -825,8 +829,8 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
Segment& selseg = strip.getSegment(selectedSeg); Segment& selseg = strip.getSegment(selectedSeg);
pos = req.indexOf(F("SV=")); //segment selected pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); unsigned t = getNumVal(&req, pos);
if (t == 2) for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).selected = false; // unselect other segments if (t == 2) for (unsigned i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).selected = false; // unselect other segments
selseg.selected = t; selseg.selected = t;
} }
@ -1002,7 +1006,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SC")); pos = req.indexOf(F("SC"));
if (pos > 0) { if (pos > 0) {
byte temp; byte temp;
for (uint8_t i=0; i<4; i++) { for (unsigned i=0; i<4; i++) {
temp = colIn[i]; temp = colIn[i];
colIn[i] = colInSec[i]; colIn[i] = colInSec[i];
colInSec[i] = temp; colInSec[i] = temp;
@ -1043,7 +1047,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged || custom1Changed || custom2Changed || custom3Changed || check1Changed || check2Changed || check3Changed); stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged || custom1Changed || custom2Changed || custom3Changed || check1Changed || check2Changed || check3Changed);
// apply to main and all selected segments to prevent #1618. // apply to main and all selected segments to prevent #1618.
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i); Segment& seg = strip.getSegment(i);
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
if (fxModeChanged) seg.setMode(effectIn, req.indexOf(F("FXD="))>0); // apply defaults if FXD= is specified if (fxModeChanged) seg.setMode(effectIn, req.indexOf(F("FXD="))>0); // apply defaults if FXD= is specified

View File

@ -106,7 +106,7 @@ void notify(byte callMode, bool followUp)
for (size_t i = 0; i < nsegs; i++) { for (size_t i = 0; i < nsegs; i++) {
Segment &selseg = strip.getSegment(i); Segment &selseg = strip.getSegment(i);
if (!selseg.isActive()) continue; if (!selseg.isActive()) continue;
uint16_t ofs = 41 + s*UDP_SEG_SIZE; //start of segment offset byte unsigned ofs = 41 + s*UDP_SEG_SIZE; //start of segment offset byte
udpOut[0 +ofs] = s; udpOut[0 +ofs] = s;
udpOut[1 +ofs] = selseg.start >> 8; udpOut[1 +ofs] = selseg.start >> 8;
udpOut[2 +ofs] = selseg.start & 0xFF; udpOut[2 +ofs] = selseg.start & 0xFF;
@ -239,7 +239,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
if (version > 6) { if (version > 6) {
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color
if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value
uint16_t cct = udpIn[38]; unsigned cct = udpIn[38];
if (udpIn[37] > 0) { //Kelvin if (udpIn[37] > 0) { //Kelvin
cct |= (udpIn[37] << 8); cct |= (udpIn[37] << 8);
} }
@ -253,7 +253,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
bool applyEffects = (receiveNotificationEffects || !someSel); bool applyEffects = (receiveNotificationEffects || !someSel);
if (applyEffects && currentPlaylist >= 0) unloadPlaylist(); if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) { if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) {
uint8_t numSrcSegs = udpIn[39]; unsigned numSrcSegs = udpIn[39];
DEBUG_PRINT(F("UDP segments: ")); DEBUG_PRINTLN(numSrcSegs); DEBUG_PRINT(F("UDP segments: ")); DEBUG_PRINTLN(numSrcSegs);
// are we syncing bounds and slave has more active segments than master? // are we syncing bounds and slave has more active segments than master?
if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) { if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) {
@ -266,8 +266,8 @@ void parseNotifyPacket(uint8_t *udpIn) {
} }
size_t inactiveSegs = 0; size_t inactiveSegs = 0;
for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) { for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte
uint8_t id = udpIn[0 +ofs]; unsigned id = udpIn[0 +ofs];
DEBUG_PRINT(F("UDP segment received: ")); DEBUG_PRINTLN(id); DEBUG_PRINT(F("UDP segment received: ")); DEBUG_PRINTLN(id);
if (id > strip.getSegmentsNum()) break; if (id > strip.getSegmentsNum()) break;
else if (id == strip.getSegmentsNum()) { else if (id == strip.getSegmentsNum()) {
@ -403,7 +403,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
void realtimeLock(uint32_t timeoutMs, byte md) void realtimeLock(uint32_t timeoutMs, byte md)
{ {
if (!realtimeMode && !realtimeOverride) { if (!realtimeMode && !realtimeOverride) {
uint16_t stop, start; unsigned stop, start;
if (useMainSegmentOnly) { if (useMainSegmentOnly) {
Segment& mainseg = strip.getMainSegment(); Segment& mainseg = strip.getMainSegment();
start = mainseg.start; start = mainseg.start;
@ -503,8 +503,8 @@ void handleNotifications()
rgbUdp.read(lbuf, packetSize); rgbUdp.read(lbuf, packetSize);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
uint16_t id = 0; unsigned id = 0;
uint16_t totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
for (size_t i = 0; i < packetSize -2; i += 3) for (size_t i = 0; i < packetSize -2; i += 3)
{ {
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0); setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
@ -521,7 +521,7 @@ void handleNotifications()
if (!isSupp && notifierUdp.remoteIP() == localIP) return; //don't process broadcasts we send ourselves if (!isSupp && notifierUdp.remoteIP() == localIP) return; //don't process broadcasts we send ourselves
uint8_t udpIn[packetSize +1]; uint8_t udpIn[packetSize +1];
uint16_t len; unsigned len;
if (isSupp) len = notifier2Udp.read(udpIn, packetSize); if (isSupp) len = notifier2Udp.read(udpIn, packetSize);
else len = notifierUdp.read(udpIn, packetSize); else len = notifierUdp.read(udpIn, packetSize);
@ -529,7 +529,7 @@ void handleNotifications()
if (isSupp && udpIn[0] == 255 && udpIn[1] == 1 && len >= 40) { if (isSupp && udpIn[0] == 255 && udpIn[1] == 1 && len >= 40) {
if (!nodeListEnabled || notifier2Udp.remoteIP() == localIP) return; if (!nodeListEnabled || notifier2Udp.remoteIP() == localIP) return;
uint8_t unit = udpIn[39]; unsigned unit = udpIn[39];
NodesMap::iterator it = Nodes.find(unit); NodesMap::iterator it = Nodes.find(unit);
if (it == Nodes.end() && Nodes.size() < WLED_MAX_NODES) { // Create a new element when not present if (it == Nodes.end() && Nodes.size() < WLED_MAX_NODES) { // Create a new element when not present
Nodes[unit].age = 0; Nodes[unit].age = 0;
@ -586,8 +586,8 @@ void handleNotifications()
byte packetNum = udpIn[4]; //starts with 1! byte packetNum = udpIn[4]; //starts with 1!
byte numPackets = udpIn[5]; byte numPackets = udpIn[5];
uint16_t id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
uint16_t totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3) for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3)
{ {
if (id < totalLen) if (id < totalLen)
@ -621,7 +621,7 @@ void handleNotifications()
} }
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
uint16_t totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
if (udpIn[0] == 1 && packetSize > 5) //warls if (udpIn[0] == 1 && packetSize > 5) //warls
{ {
for (size_t i = 2; i < packetSize -3; i += 4) for (size_t i = 2; i < packetSize -3; i += 4)
@ -630,7 +630,7 @@ void handleNotifications()
} }
} else if (udpIn[0] == 2 && packetSize > 4) //drgb } else if (udpIn[0] == 2 && packetSize > 4) //drgb
{ {
uint16_t id = 0; unsigned id = 0;
for (size_t i = 2; i < packetSize -2; i += 3) for (size_t i = 2; i < packetSize -2; i += 3)
{ {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
@ -639,7 +639,7 @@ void handleNotifications()
} }
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw } else if (udpIn[0] == 3 && packetSize > 6) //drgbw
{ {
uint16_t id = 0; unsigned id = 0;
for (size_t i = 2; i < packetSize -3; i += 4) for (size_t i = 2; i < packetSize -3; i += 4)
{ {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
@ -648,7 +648,7 @@ void handleNotifications()
} }
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb } else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
{ {
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2; i += 3) for (size_t i = 4; i < packetSize -2; i += 3)
{ {
if (id >= totalLen) break; if (id >= totalLen) break;
@ -657,7 +657,7 @@ void handleNotifications()
} }
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw } else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
{ {
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2; i += 4) for (size_t i = 4; i < packetSize -2; i += 4)
{ {
if (id >= totalLen) break; if (id >= totalLen) break;
@ -689,7 +689,7 @@ void handleNotifications()
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
{ {
uint16_t pix = i + arlsOffset; unsigned pix = i + arlsOffset;
if (pix < strip.getLengthTotal()) { if (pix < strip.getLengthTotal()) {
if (!arlsDisableGammaCorrection && gammaCorrectCol) { if (!arlsDisableGammaCorrection && gammaCorrectCol) {
r = gamma8(r); r = gamma8(r);

View File

@ -4,57 +4,57 @@
*/ */
//Usermod Manager internals //Usermod Manager internals
void UsermodManager::setup() { for (byte i = 0; i < numMods; i++) ums[i]->setup(); } void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); }
void UsermodManager::connected() { for (byte 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 (byte 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 (byte 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 (byte i = 0; i < numMods; i++) ums[i]->appendConfigData(); } void UsermodManager::appendConfigData() { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(); }
bool UsermodManager::handleButton(uint8_t b) { bool UsermodManager::handleButton(uint8_t b) {
bool overrideIO = false; bool overrideIO = false;
for (byte i = 0; i < numMods; i++) { for (unsigned i = 0; i < numMods; i++) {
if (ums[i]->handleButton(b)) overrideIO = true; if (ums[i]->handleButton(b)) overrideIO = true;
} }
return overrideIO; return overrideIO;
} }
bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) { bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) {
for (byte i = 0; i < numMods; i++) { for (unsigned i = 0; i < numMods; i++) {
if (mod_id > 0 && ums[i]->getId() != mod_id) continue; // only get data form requested usermod if provided if (mod_id > 0 && ums[i]->getId() != mod_id) continue; // only get data form requested usermod if provided
if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time) if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time)
} }
return false; return false;
} }
void UsermodManager::addToJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); } void UsermodManager::addToJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); }
void UsermodManager::addToJsonInfo(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); } void UsermodManager::addToJsonInfo(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); }
void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); } void UsermodManager::readFromJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); }
void UsermodManager::addToConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToConfig(obj); } void UsermodManager::addToConfig(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToConfig(obj); }
bool UsermodManager::readFromConfig(JsonObject& obj) { bool UsermodManager::readFromConfig(JsonObject& obj) {
bool allComplete = true; bool allComplete = true;
for (byte i = 0; i < numMods; i++) { for (unsigned i = 0; i < numMods; i++) {
if (!ums[i]->readFromConfig(obj)) allComplete = false; if (!ums[i]->readFromConfig(obj)) allComplete = false;
} }
return allComplete; return allComplete;
} }
#ifndef WLED_DISABLE_MQTT #ifndef WLED_DISABLE_MQTT
void UsermodManager::onMqttConnect(bool sessionPresent) { for (byte i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); } void UsermodManager::onMqttConnect(bool sessionPresent) { for (unsigned i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); }
bool UsermodManager::onMqttMessage(char* topic, char* payload) { bool UsermodManager::onMqttMessage(char* topic, char* payload) {
for (byte i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true; for (unsigned i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true;
return false; return false;
} }
#endif #endif
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW
bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) { bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) {
for (byte i = 0; i < numMods; i++) if (ums[i]->onEspNowMessage(sender, payload, len)) return true; for (unsigned i = 0; i < numMods; i++) if (ums[i]->onEspNowMessage(sender, payload, len)) return true;
return false; return false;
} }
#endif #endif
void UsermodManager::onUpdateBegin(bool init) { for (byte i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin void UsermodManager::onUpdateBegin(bool init) { for (unsigned i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin
void UsermodManager::onStateChange(uint8_t mode) { for (byte i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed void UsermodManager::onStateChange(uint8_t mode) { for (unsigned i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed
/* /*
* Enables usermods to lookup another Usermod. * Enables usermods to lookup another Usermod.
*/ */
Usermod* UsermodManager::lookup(uint16_t mod_id) { Usermod* UsermodManager::lookup(uint16_t mod_id) {
for (byte i = 0; i < numMods; i++) { for (unsigned i = 0; i < numMods; i++) {
if (ums[i]->getId() == mod_id) { if (ums[i]->getId() == mod_id) {
return ums[i]; return ums[i];
} }

View File

@ -156,7 +156,7 @@ bool oappendi(int i)
bool oappend(const char* txt) bool oappend(const char* txt)
{ {
uint16_t len = strlen(txt); unsigned len = strlen(txt);
if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
DEBUG_PRINT(F("oappend() buffer overflow. Cannot append ")); DEBUG_PRINT(F("oappend() buffer overflow. Cannot append "));
@ -175,7 +175,7 @@ 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);
const char *pC = serverDescription; const char *pC = serverDescription;
uint8_t pos = 5; // keep "wled-" unsigned pos = 5; // keep "wled-"
while (*pC && pos < 24) { // while !null and not over length while (*pC && pos < 24) { // while !null and not over length
if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname
hostname[pos] = *pC; hostname[pos] = *pC;
@ -197,7 +197,7 @@ void prepareHostname(char* hostname)
bool isAsterisksOnly(const char* str, byte maxLen) bool isAsterisksOnly(const char* str, byte maxLen)
{ {
for (byte i = 0; i < maxLen; i++) { for (unsigned i = 0; i < maxLen; i++) {
if (str[i] == 0) break; if (str[i] == 0) break;
if (str[i] != '*') return false; if (str[i] != '*') return false;
} }
@ -269,9 +269,9 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
return strlen(dest); return strlen(dest);
} }
uint8_t qComma = 0; unsigned qComma = 0;
bool insideQuotes = false; bool insideQuotes = false;
uint8_t printedChars = 0; unsigned printedChars = 0;
char singleJsonSymbol; char singleJsonSymbol;
size_t len = strlen_P(src); size_t len = strlen_P(src);
@ -308,11 +308,11 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
if (mode < strip.getModeCount()) { if (mode < strip.getModeCount()) {
String lineBuffer = FPSTR(strip.getModeData(mode)); String lineBuffer = FPSTR(strip.getModeData(mode));
if (lineBuffer.length() > 0) { if (lineBuffer.length() > 0) {
int16_t start = lineBuffer.indexOf('@'); unsigned start = lineBuffer.indexOf('@');
int16_t stop = lineBuffer.indexOf(';', start); unsigned stop = lineBuffer.indexOf(';', start);
if (start>0 && stop>0) { if (start>0 && stop>0) {
String names = lineBuffer.substring(start, stop); // include @ String names = lineBuffer.substring(start, stop); // include @
int16_t nameBegin = 1, nameEnd, nameDefault; unsigned nameBegin = 1, nameEnd, nameDefault;
if (slider < 10) { if (slider < 10) {
for (size_t i=0; i<=slider; i++) { for (size_t i=0; i<=slider; i++) {
const char *tmpstr; const char *tmpstr;

View File

@ -175,39 +175,39 @@ void WLED::loop()
DEBUG_PRINTLN(F("Re-init busses.")); DEBUG_PRINTLN(F("Re-init busses."));
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
BusManager::removeAll(); BusManager::removeAll();
unsigned mem = 0;
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
bool useParallel = false; bool useParallel = false;
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
unsigned digitalCount = 0; unsigned digitalCount = 0;
unsigned maxLeds = 0; unsigned maxLedsOnBus = 0;
int oldType = 0; unsigned maxChannels = 0;
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
if (busConfigs[i] == nullptr) break; if (busConfigs[i] == nullptr) break;
if (IS_DIGITAL(busConfigs[i]->type) && !IS_2PIN(busConfigs[i]->type)) digitalCount++; if (!IS_DIGITAL(busConfigs[i]->type)) continue;
if (busConfigs[i]->count > maxLeds) maxLeds = busConfigs[i]->count; if (!IS_2PIN(busConfigs[i]->type)) {
// we need to have all LEDs of the same type for parallel digitalCount++;
if (i < 8 && oldType > 0 && oldType != busConfigs[i]->type) oldType = -1; unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type);
else if (oldType == 0) oldType = busConfigs[i]->type; if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count;
if (channels > maxChannels) maxChannels = channels;
} }
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\nDifferent types: %d\n"), maxLeds, digitalCount, (int)(oldType == -1)); }
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
if (/*oldType != -1 && */maxLeds <= 300 && digitalCount > 5) { if (maxLedsOnBus <= 300 && digitalCount > 5) {
DEBUG_PRINTF_P(PSTR("Switching to parallel I2S."));
useParallel = true; useParallel = true;
BusManager::useParallelOutput(); BusManager::useParallelOutput();
DEBUG_PRINTF_P(PSTR("Switching to parallel I2S with max. %d LEDs per ouptut.\n"), maxLeds); mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation (hse to be used *after* useParallelOutput())
} }
#endif #endif
// create buses/outputs // create buses/outputs
unsigned mem = 0;
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break; if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break;
if (useParallel && i < 8) { if (useParallel && i < 8) {
// we are using parallel I2S and memUsage() will include x8 allocation into account // if for some unexplained reason the above pre-calculation was wrong, update
if (i == 0) unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S
mem = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S if (memT > mem) mem = memT; // if we have unequal LED count use the largest
else
if (BusManager::memUsage(*busConfigs[i]) > mem)
mem = BusManager::memUsage(*busConfigs[i]); // if we have unequal LED count use the largest
} else } else
mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer
if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]);

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2406290 #define VERSION 2407070
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG

View File

@ -24,7 +24,7 @@ bool continuousSendLED = false;
uint32_t lastUpdate = 0; uint32_t lastUpdate = 0;
void updateBaudRate(uint32_t rate){ void updateBaudRate(uint32_t rate){
uint16_t rate100 = rate/100; unsigned rate100 = rate/100;
if (rate100 == currentBaud || rate100 < 96) return; if (rate100 == currentBaud || rate100 < 96) return;
currentBaud = rate100; currentBaud = rate100;
@ -39,9 +39,9 @@ void updateBaudRate(uint32_t rate){
// RGB LED data return as JSON array. Slow, but easy to use on the other end. // RGB LED data return as JSON array. Slow, but easy to use on the other end.
void sendJSON(){ void sendJSON(){
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) { if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) {
uint16_t used = strip.getLengthTotal(); unsigned used = strip.getLengthTotal();
Serial.write('['); Serial.write('[');
for (uint16_t i=0; i<used; i++) { for (unsigned i=0; i<used; i++) {
Serial.print(strip.getPixelColor(i)); Serial.print(strip.getPixelColor(i));
if (i != used-1) Serial.write(','); if (i != used-1) Serial.write(',');
} }
@ -53,11 +53,11 @@ void sendJSON(){
void sendBytes(){ void sendBytes(){
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) { if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) {
Serial.write(0xC9); Serial.write(0xDA); Serial.write(0xC9); Serial.write(0xDA);
uint16_t used = strip.getLengthTotal(); unsigned used = strip.getLengthTotal();
uint16_t len = used*3; unsigned len = used*3;
Serial.write(highByte(len)); Serial.write(highByte(len));
Serial.write(lowByte(len)); Serial.write(lowByte(len));
for (uint16_t i=0; i < used; i++) { for (unsigned i=0; i < used; i++) {
uint32_t c = strip.getPixelColor(i); uint32_t c = strip.getPixelColor(i);
Serial.write(qadd8(W(c), R(c))); //R, add white channel to RGB channels as a simple RGBW -> RGB map Serial.write(qadd8(W(c), R(c))); //R, add white channel to RGB channels as a simple RGBW -> RGB map
Serial.write(qadd8(W(c), G(c))); //G Serial.write(qadd8(W(c), G(c))); //G

View File

@ -168,7 +168,7 @@ void appendGPIOinfo() {
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); } for (unsigned p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); }
if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); } if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); }
if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); } if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); }
if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); } if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); }
@ -629,7 +629,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("A1"),macroAlexaOff); sappend('v',SET_F("A1"),macroAlexaOff);
sappend('v',SET_F("MC"),macroCountdown); sappend('v',SET_F("MC"),macroCountdown);
sappend('v',SET_F("MN"),macroNl); sappend('v',SET_F("MN"),macroNl);
for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) { for (unsigned i=0; i<WLED_MAX_BUTTONS; i++) {
oappend(SET_F("addRow(")); oappend(SET_F("addRow("));
oappend(itoa(i,tm,10)); oappend(","); oappend(itoa(i,tm,10)); oappend(",");
oappend(itoa(macroButton[i],tm,10)); oappend(","); oappend(itoa(macroButton[i],tm,10)); oappend(",");
@ -755,7 +755,7 @@ void getSettingsJS(byte subPage, char* dest)
} }
sappend('v',SET_F("MPC"),strip.panels); sappend('v',SET_F("MPC"),strip.panels);
// panels // panels
for (uint8_t i=0; i<strip.panels; i++) { for (unsigned i=0; i<strip.panels; i++) {
char n[5]; char n[5];
oappend(SET_F("addPanel(")); oappend(SET_F("addPanel("));
oappend(itoa(i,n,10)); oappend(itoa(i,n,10));
@ -763,7 +763,7 @@ void getSettingsJS(byte subPage, char* dest)
char pO[8] = { '\0' }; char pO[8] = { '\0' };
snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less snprintf_P(pO, 7, PSTR("P%d"), i); // MAX_PANELS is 64 so pO will always only be 4 characters or less
pO[7] = '\0'; pO[7] = '\0';
uint8_t l = strlen(pO); unsigned l = strlen(pO);
// create P0B, P1B, ..., P63B, etc for other PxxX // create P0B, P1B, ..., P63B, etc for other PxxX
pO[l] = 'B'; sappend('v',pO,strip.panel[i].bottomStart); pO[l] = 'B'; sappend('v',pO,strip.panel[i].bottomStart);
pO[l] = 'R'; sappend('v',pO,strip.panel[i].rightStart); pO[l] = 'R'; sappend('v',pO,strip.panel[i].rightStart);