commit
9249c74b7b
@ -375,6 +375,7 @@ public:
|
||||
* onStateChanged() is used to detect WLED state change
|
||||
*/
|
||||
void onStateChange(uint8_t mode) {
|
||||
if (!initDone) return;
|
||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||
if (PIRtriggered && offTimerStart) {
|
||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||
|
14
wled00/FX.h
14
wled00/FX.h
@ -460,7 +460,7 @@ typedef struct Segment {
|
||||
_dataLen(0),
|
||||
_t(nullptr)
|
||||
{
|
||||
refreshLightCapabilities();
|
||||
//refreshLightCapabilities();
|
||||
}
|
||||
|
||||
Segment(uint16_t sStartX, uint16_t sStopX, uint16_t sStartY, uint16_t sStopY) : Segment(sStartX, sStopX) {
|
||||
@ -659,7 +659,6 @@ class WS2812FX { // 96 bytes
|
||||
isMatrix(false),
|
||||
#ifndef WLED_DISABLE_2D
|
||||
panels(1),
|
||||
matrix{0,0,0,0},
|
||||
#endif
|
||||
// semi-private (just obscured) used in effect functions through macros
|
||||
_currentPalette(CRGBPalette16(CRGB::Black)),
|
||||
@ -727,8 +726,7 @@ class WS2812FX { // 96 bytes
|
||||
fixInvalidSegments(),
|
||||
setPixelColor(int n, uint32_t c),
|
||||
show(void),
|
||||
setTargetFps(uint8_t fps),
|
||||
deserializeMap(uint8_t n=0);
|
||||
setTargetFps(uint8_t fps);
|
||||
|
||||
void fill(uint32_t c) { for (int i = 0; i < _length; i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
void addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp
|
||||
@ -748,6 +746,7 @@ class WS2812FX { // 96 bytes
|
||||
hasCCTBus(void),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void),
|
||||
deserializeMap(uint8_t n=0),
|
||||
useLedsArray = false;
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; }
|
||||
@ -813,13 +812,6 @@ class WS2812FX { // 96 bytes
|
||||
uint8_t
|
||||
panels;
|
||||
|
||||
struct {
|
||||
bool bottomStart : 1;
|
||||
bool rightStart : 1;
|
||||
bool vertical : 1;
|
||||
bool serpentine : 1;
|
||||
} matrix;
|
||||
|
||||
typedef struct panel_t {
|
||||
uint16_t xOffset; // x offset relative to the top left of matrix in LEDs
|
||||
uint16_t yOffset; // y offset relative to the top left of matrix in LEDs
|
||||
|
@ -78,21 +78,60 @@ void WS2812FX::setUpMatrix() {
|
||||
customMappingTable[i] = (uint16_t)-1;
|
||||
}
|
||||
|
||||
// we will try to load a "gap" array (a JSON file)
|
||||
// the array has to have the same amount of values as mapping array (or larger)
|
||||
// "gap" array is used while building ledmap (mapping array)
|
||||
// and discarded afterwards as it has no meaning after the process
|
||||
// content of the file is just raw JSON array in the form of [val1,val2,val3,...]
|
||||
// there are no other "key":"value" pairs in it
|
||||
// allowed values are: -1 (missing pixel/no LED attached), 0 (inactive/unused pixel), 1 (active/used pixel)
|
||||
char fileName[32]; strcpy_P(fileName, PSTR("/2d-gaps.json")); // reduce flash footprint
|
||||
bool isFile = WLED_FS.exists(fileName);
|
||||
size_t gapSize = 0;
|
||||
int8_t *gapTable = nullptr;
|
||||
|
||||
if (isFile && requestJSONBufferLock(20)) {
|
||||
DEBUG_PRINT(F("Reading LED gap from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
// read the array into global JSON buffer
|
||||
if (readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
// the array is similar to ledmap, except it has only 3 values:
|
||||
// -1 ... missing pixel (do not increase pixel count)
|
||||
// 0 ... inactive pixel (it does count, but should be mapped out (-1))
|
||||
// 1 ... active pixel (it will count and will be mapped)
|
||||
JsonArray map = doc.as<JsonArray>();
|
||||
gapSize = map.size();
|
||||
if (!map.isNull() && gapSize >= customMappingSize) { // not an empty map
|
||||
gapTable = new int8_t[gapSize];
|
||||
if (gapTable) for (size_t i = 0; i < gapSize; i++) {
|
||||
gapTable[i] = constrain(map[i], -1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN(F("Gaps loaded."));
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
|
||||
uint16_t x, y, pix=0; //pixel
|
||||
for (size_t pan = 0; pan < panel.size(); pan++) {
|
||||
Panel &p = panel[pan];
|
||||
uint16_t h = p.vertical ? p.height : p.width;
|
||||
uint16_t v = p.vertical ? p.width : p.height;
|
||||
for (size_t j = 0; j < v; j++){
|
||||
for(size_t i = 0; i < h; i++, pix++) {
|
||||
for(size_t i = 0; i < h; i++) {
|
||||
y = (p.vertical?p.rightStart:p.bottomStart) ? v-j-1 : j;
|
||||
x = (p.vertical?p.bottomStart:p.rightStart) ? h-i-1 : i;
|
||||
x = p.serpentine && j%2 ? h-x-1 : x;
|
||||
customMappingTable[(p.yOffset + (p.vertical?x:y)) * Segment::maxWidth + p.xOffset + (p.vertical?y:x)] = pix;
|
||||
size_t index = (p.yOffset + (p.vertical?x:y)) * Segment::maxWidth + p.xOffset + (p.vertical?y:x);
|
||||
if (!gapTable || (gapTable && gapTable[index] > 0)) customMappingTable[index] = pix; // a useful pixel (otherwise -1 is retained)
|
||||
if (!gapTable || (gapTable && gapTable[index] >= 0)) pix++; // not a missing pixel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete gap array as we no longer need it
|
||||
if (gapTable) delete[] gapTable;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINT(F("Matrix ledmap:"));
|
||||
for (uint16_t i=0; i<customMappingSize; i++) {
|
||||
@ -108,8 +147,8 @@ void WS2812FX::setUpMatrix() {
|
||||
panel.clear();
|
||||
Segment::maxWidth = _length;
|
||||
Segment::maxHeight = 1;
|
||||
resetSegments();
|
||||
}
|
||||
resetSegments();
|
||||
}
|
||||
#else
|
||||
isMatrix = false; // no matter what config says
|
||||
|
@ -750,15 +750,33 @@ uint8_t Segment::differs(Segment& b) const {
|
||||
|
||||
void Segment::refreshLightCapabilities() {
|
||||
uint8_t capabilities = 0;
|
||||
uint16_t segStartIdx = 0xFFFFU;
|
||||
uint16_t segStopIdx = 0;
|
||||
|
||||
if (start < Segment::maxWidth * Segment::maxHeight) {
|
||||
// we are withing 2D matrix (includes 1D segments)
|
||||
for (int y = startY; y < stopY; y++) for (int x = start; x < stop; x++) {
|
||||
uint16_t index = x + Segment::maxWidth * y;
|
||||
if (index < strip.customMappingSize) index = strip.customMappingTable[index]; // convert logical address to physical
|
||||
if (index < 0xFFFFU) {
|
||||
if (segStartIdx > index) segStartIdx = index;
|
||||
if (segStopIdx < index) segStopIdx = index;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we are on the strip located after the matrix
|
||||
segStartIdx = start;
|
||||
segStopIdx = stop;
|
||||
}
|
||||
|
||||
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (!bus->isOk()) continue;
|
||||
if (bus->getStart() >= stop) continue;
|
||||
if (bus->getStart() + bus->getLength() <= start) continue;
|
||||
if (bus->getStart() >= segStopIdx) continue;
|
||||
if (bus->getStart() + bus->getLength() <= segStartIdx) continue;
|
||||
|
||||
uint8_t type = bus->getType();
|
||||
//uint8_t type = bus->getType();
|
||||
if (bus->hasRGB() || (cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB;
|
||||
if (!cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
|
||||
if (correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
|
||||
@ -1012,10 +1030,11 @@ void WS2812FX::finalizeInit(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!isMatrix) { // if 2D then max values defined in setUpMatrix() using panel set-up
|
||||
if (isMatrix) setUpMatrix();
|
||||
else {
|
||||
Segment::maxWidth = _length;
|
||||
Segment::maxHeight = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//initialize leds array. TBD: realloc if nr of leds change
|
||||
if (Segment::_globalLeds) {
|
||||
@ -1024,17 +1043,20 @@ void WS2812FX::finalizeInit(void)
|
||||
Segment::_globalLeds = nullptr;
|
||||
}
|
||||
if (useLedsArray) {
|
||||
size_t arrSize = sizeof(CRGB) * MAX(_length, Segment::maxWidth*Segment::maxHeight);
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound())
|
||||
Segment::_globalLeds = (CRGB*) ps_malloc(sizeof(CRGB) * _length);
|
||||
Segment::_globalLeds = (CRGB*) ps_malloc(arrSize);
|
||||
else
|
||||
#endif
|
||||
Segment::_globalLeds = (CRGB*) malloc(sizeof(CRGB) * _length);
|
||||
memset(Segment::_globalLeds, 0, sizeof(CRGB) * _length);
|
||||
Segment::_globalLeds = (CRGB*) malloc(arrSize);
|
||||
memset(Segment::_globalLeds, 0, arrSize);
|
||||
}
|
||||
|
||||
//segments are created in makeAutoSegments();
|
||||
DEBUG_PRINTLN(F("Loading custom palettes"));
|
||||
loadCustomPalettes(); // (re)load all custom palettes
|
||||
DEBUG_PRINTLN(F("Loading custom ledmaps"));
|
||||
deserializeMap(); // (re)load default ledmap
|
||||
}
|
||||
|
||||
@ -1409,9 +1431,9 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
}
|
||||
// do we have LEDs after the matrix? (ignore buses)
|
||||
if (autoSegments && _length > Segment::maxWidth*Segment::maxHeight /*&& getActiveSegmentsNum() == 2*/) {
|
||||
if (_segments.size() == getLastActiveSegmentId()+1)
|
||||
if (_segments.size() == getLastActiveSegmentId()+1U) {
|
||||
_segments.push_back(Segment(Segment::maxWidth*Segment::maxHeight, _length));
|
||||
else {
|
||||
} else {
|
||||
size_t i = getLastActiveSegmentId() + 1;
|
||||
_segments[i].start = Segment::maxWidth*Segment::maxHeight;
|
||||
_segments[i].stop = _length;
|
||||
@ -1468,14 +1490,30 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
void WS2812FX::fixInvalidSegments() {
|
||||
//make sure no segment is longer than total (sanity check)
|
||||
for (size_t i = getSegmentsNum()-1; i > 0; i--) {
|
||||
if (_segments[i].start >= _length) { _segments.erase(_segments.begin()+i); continue; }
|
||||
if (_segments[i].stop > _length) _segments[i].stop = _length;
|
||||
// this is always called as the last step after finalizeInit(), update covered bus types
|
||||
_segments[i].refreshLightCapabilities();
|
||||
if (isMatrix) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (_segments[i].start >= Segment::maxWidth * Segment::maxHeight) {
|
||||
// 1D segment at the end of matrix
|
||||
if (_segments[i].start >= _length || _segments[i].startY > 0 || _segments[i].stopY > 1) { _segments.erase(_segments.begin()+i); continue; }
|
||||
if (_segments[i].stop > _length) _segments[i].stop = _length;
|
||||
continue;
|
||||
}
|
||||
if (_segments[i].start >= Segment::maxWidth || _segments[i].startY >= Segment::maxHeight) { _segments.erase(_segments.begin()+i); continue; }
|
||||
if (_segments[i].stop > Segment::maxWidth) _segments[i].stop = Segment::maxWidth;
|
||||
if (_segments[i].stopY > Segment::maxHeight) _segments[i].stopY = Segment::maxHeight;
|
||||
#endif
|
||||
} else {
|
||||
if (_segments[i].start >= _length) { _segments.erase(_segments.begin()+i); continue; }
|
||||
if (_segments[i].stop > _length) _segments[i].stop = _length;
|
||||
}
|
||||
}
|
||||
// this is always called as the last step after finalizeInit(), update covered bus types
|
||||
for (segment &seg : _segments)
|
||||
seg.refreshLightCapabilities();
|
||||
}
|
||||
|
||||
//true if all segments align with a bus, or if a segment covers the total length
|
||||
//irrelevant in 2D set-up
|
||||
bool WS2812FX::checkSegmentAlignment() {
|
||||
bool aligned = false;
|
||||
for (segment &seg : _segments) {
|
||||
@ -1575,8 +1613,8 @@ void WS2812FX::loadCustomPalettes() {
|
||||
}
|
||||
|
||||
//load custom mapping table from JSON file (called from finalizeInit() or deserializeState())
|
||||
void WS2812FX::deserializeMap(uint8_t n) {
|
||||
if (isMatrix) return; // 2D support creates its own ledmap
|
||||
bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
// 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one.
|
||||
|
||||
char fileName[32];
|
||||
strcpy_P(fileName, PSTR("/ledmap"));
|
||||
@ -1586,24 +1624,24 @@ void WS2812FX::deserializeMap(uint8_t n) {
|
||||
|
||||
if (!isFile) {
|
||||
// erase custom mapping if selecting nonexistent ledmap.json (n==0)
|
||||
if (!n && customMappingTable != nullptr) {
|
||||
if (!isMatrix && !n && customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!requestJSONBufferLock(7)) return;
|
||||
|
||||
DEBUG_PRINT(F("Reading LED map from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
if (!requestJSONBufferLock(7)) return false;
|
||||
|
||||
if (!readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
releaseJSONBufferLock();
|
||||
return; //if file does not exist just exit
|
||||
return false; //if file does not exist just exit
|
||||
}
|
||||
|
||||
DEBUG_PRINT(F("Reading LED map from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
|
||||
// erase old custom ledmap
|
||||
if (customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
@ -1621,6 +1659,7 @@ void WS2812FX::deserializeMap(uint8_t n) {
|
||||
}
|
||||
|
||||
releaseJSONBufferLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,16 +140,16 @@ class Bus {
|
||||
static void setCCT(uint16_t cct) {
|
||||
_cct = cct;
|
||||
}
|
||||
static void setCCTBlend(uint8_t b) {
|
||||
if (b > 100) b = 100;
|
||||
_cctBlend = (b * 127) / 100;
|
||||
//compile-time limiter for hardware that can't power both white channels at max
|
||||
#ifdef WLED_MAX_CCT_BLEND
|
||||
if (_cctBlend > WLED_MAX_CCT_BLEND) _cctBlend = WLED_MAX_CCT_BLEND;
|
||||
#endif
|
||||
}
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; }
|
||||
static void setCCTBlend(uint8_t b) {
|
||||
if (b > 100) b = 100;
|
||||
_cctBlend = (b * 127) / 100;
|
||||
//compile-time limiter for hardware that can't power both white channels at max
|
||||
#ifdef WLED_MAX_CCT_BLEND
|
||||
if (_cctBlend > WLED_MAX_CCT_BLEND) _cctBlend = WLED_MAX_CCT_BLEND;
|
||||
#endif
|
||||
}
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; }
|
||||
inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
|
||||
inline static uint8_t getGlobalAWMode() { return _gAWM; }
|
||||
|
||||
|
@ -97,12 +97,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
JsonObject matrix = hw_led[F("matrix")];
|
||||
if (!matrix.isNull()) {
|
||||
strip.isMatrix = true;
|
||||
CJSON(strip.panels, matrix[F("mpc")]);
|
||||
CJSON(strip.matrix.bottomStart, matrix[F("pb")]);
|
||||
CJSON(strip.matrix.rightStart, matrix[F("pr")]);
|
||||
CJSON(strip.matrix.vertical, matrix[F("pv")]);
|
||||
CJSON(strip.matrix.serpentine, matrix["ps"]);
|
||||
|
||||
CJSON(strip.panels, matrix[F("mpc")]);
|
||||
strip.panel.clear();
|
||||
JsonArray panels = matrix[F("panels")];
|
||||
uint8_t s = 0;
|
||||
@ -130,8 +125,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
p.options = 0;
|
||||
strip.panel.push_back(p);
|
||||
}
|
||||
|
||||
strip.setUpMatrix();
|
||||
// cannot call strip.setUpMatrix() here due to already locked JSON buffer
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -333,12 +327,20 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(strip.paletteBlend, light[F("pal-mode")]);
|
||||
CJSON(autoSegments, light[F("aseg")]);
|
||||
|
||||
CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.8
|
||||
float light_gc_bri = light["gc"]["bri"];
|
||||
float light_gc_col = light["gc"]["col"]; // 2.8
|
||||
if (light_gc_bri > 1.5) gammaCorrectBri = true;
|
||||
else if (light_gc_bri > 0.5) gammaCorrectBri = false;
|
||||
if (light_gc_col > 1.5) gammaCorrectCol = true;
|
||||
else if (light_gc_col > 0.5) gammaCorrectCol = false;
|
||||
float light_gc_col = light["gc"]["col"];
|
||||
if (light_gc_bri > 1.0f) gammaCorrectBri = true;
|
||||
else gammaCorrectBri = false;
|
||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||
else gammaCorrectCol = false;
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
||||
} else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
gammaCorrectCol = false;
|
||||
}
|
||||
|
||||
JsonObject light_tr = light["tr"];
|
||||
CJSON(fadeTransition, light_tr["mode"]);
|
||||
@ -708,11 +710,6 @@ void serializeConfig() {
|
||||
if (strip.isMatrix) {
|
||||
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
|
||||
matrix[F("mpc")] = strip.panels;
|
||||
matrix[F("pb")] = strip.matrix.bottomStart;
|
||||
matrix[F("pr")] = strip.matrix.rightStart;
|
||||
matrix[F("pv")] = strip.matrix.vertical;
|
||||
matrix["ps"] = strip.matrix.serpentine;
|
||||
|
||||
JsonArray panels = matrix.createNestedArray(F("panels"));
|
||||
for (uint8_t i=0; i<strip.panel.size(); i++) {
|
||||
JsonObject pnl = panels.createNestedObject();
|
||||
@ -810,8 +807,9 @@ void serializeConfig() {
|
||||
light[F("aseg")] = autoSegments;
|
||||
|
||||
JsonObject light_gc = light.createNestedObject("gc");
|
||||
light_gc["bri"] = (gammaCorrectBri) ? 2.8 : 1.0;
|
||||
light_gc["col"] = (gammaCorrectCol) ? 2.8 : 1.0;
|
||||
light_gc["bri"] = (gammaCorrectBri) ? gammaCorrectVal : 1.0f; // keep compatibility
|
||||
light_gc["col"] = (gammaCorrectCol) ? gammaCorrectVal : 1.0f; // keep compatibility
|
||||
light_gc["val"] = gammaCorrectVal;
|
||||
|
||||
JsonObject light_tr = light.createNestedObject("tr");
|
||||
light_tr["mode"] = fadeTransition;
|
||||
|
@ -79,6 +79,17 @@
|
||||
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
|
||||
#endif
|
||||
|
||||
#if defined(WLED_MAX_LEDMAPS) && (WLED_MAX_LEDMAPS > 32 || WLED_MAX_LEDMAPS < 10)
|
||||
#undef WLED_MAX_LEDMAPS
|
||||
#endif
|
||||
#ifndef WLED_MAX_LEDMAPS
|
||||
#ifdef ESP8266
|
||||
#define WLED_MAX_LEDMAPS 10
|
||||
#else
|
||||
#define WLED_MAX_LEDMAPS 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Usermod IDs
|
||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||
|
@ -808,9 +808,9 @@ function populateSegments(s)
|
||||
if (!isM && !noNewSegs && (cfg.comp.seglen?parseInt(gId(`seg${lSeg}s`).value):0)+parseInt(gId(`seg${lSeg}e`).value)<ledCount) gId(`segr${lSeg}`).style.display = "inline";
|
||||
gId('segutil2').style.display = (segCount > 1) ? "block":"none"; // rsbtn parent
|
||||
|
||||
if (!isM && Array.isArray(li.maps) && li.maps.length>1) {
|
||||
if (Array.isArray(li.maps) && li.maps.length>1) {
|
||||
let cont = `Ledmap: <select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})"><option value="" selected>Unchanged</option>`;
|
||||
for (const k of (li.maps||[])) cont += `<option value="${k}">${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
||||
for (const k of (li.maps||[])) cont += `<option value="${k.id}">${k.id==0?'Default':(k.n?k.n:'ledmap'+k.id+'.json')}</option>`;
|
||||
cont += "</select></div>";
|
||||
gId("ledmap").innerHTML = cont;
|
||||
gId("ledmap").classList.remove('hide');
|
||||
@ -1875,9 +1875,9 @@ ${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||
<input type="checkbox" id="p${i}sbchk">
|
||||
<span class="checkmark"></span>
|
||||
</label>`;
|
||||
if (!isM && Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) {
|
||||
if (Array.isArray(lastinfo.maps) && lastinfo.maps.length>1) {
|
||||
content += `<div class="lbl-l">Ledmap: <div class="sel-p"><select class="sel-p" id="p${i}lmp"><option value="">Unchanged</option>`;
|
||||
for (const k of (lastinfo.maps||[])) content += `<option value="${k}"${(i>0 && pJson[i].ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`;
|
||||
for (const k of (lastinfo.maps||[])) content += `<option value="${k.id}"${(i>0 && pJson[i].ledmap==k.id)?" selected":""}>${k.id==0?'Default':(k.n?k.n:'ledmap'+k.id+'.json')}</option>`;
|
||||
content += "</select></div></div>";
|
||||
}
|
||||
}
|
||||
@ -2072,7 +2072,7 @@ function setSeg(s)
|
||||
obj.seg.grp = grp;
|
||||
obj.seg.spc = spc;
|
||||
obj.seg.of = ofs;
|
||||
if (isM) obj.seg.tp = gId(`seg${s}tp`).checked;
|
||||
if (isM && gId(`seg${s}tp`)) obj.seg.tp = gId(`seg${s}tp`).checked;
|
||||
}
|
||||
resetUtil(); // close add segment dialog just in case
|
||||
requestJson(obj);
|
||||
|
@ -9,6 +9,7 @@
|
||||
var d=document;
|
||||
var loc = false, locip;
|
||||
var maxPanels=64;
|
||||
var ctx = null; // WLEDMM
|
||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||
function B(){window.open("/settings","_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
@ -52,6 +53,30 @@
|
||||
return;
|
||||
}
|
||||
gId("mpdiv").style.display = "block";
|
||||
draw();
|
||||
}
|
||||
|
||||
var timeout;
|
||||
function showToast(text, error = false)
|
||||
{
|
||||
var x = gId("toast");
|
||||
x.innerHTML = text;
|
||||
x.className = error ? "error":"show";
|
||||
clearTimeout(timeout);
|
||||
x.style.animation = 'none';
|
||||
timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900);
|
||||
}
|
||||
|
||||
function uploadFile(name) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
||||
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
||||
req.open("POST", "/upload");
|
||||
var formData = new FormData();
|
||||
formData.append("data", d.Sf.data.files[0], name);
|
||||
req.send(formData);
|
||||
d.Sf.data.value = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
function addPanels() {
|
||||
@ -67,21 +92,21 @@
|
||||
var pw = parseInt(d.Sf.PW.value);
|
||||
var ph = parseInt(d.Sf.PH.value);
|
||||
let b = `<div id="pnl${i}"><hr class="sml">Panel ${i}<br>
|
||||
1<sup>st</sup> LED: <select name="P${i}B">
|
||||
1<sup>st</sup> LED: <select name="P${i}B" oninput="UI()">
|
||||
<option value="0">Top</option>
|
||||
<option value="1">Bottom</option>
|
||||
</select><select name="P${i}R">
|
||||
</select><select name="P${i}R" oninput="UI()">
|
||||
<option value="0">Left</option>
|
||||
<option value="1">Right</option>
|
||||
</select><br>
|
||||
Orientation: <select name="P${i}V">
|
||||
Orientation: <select name="P${i}V" oninput="UI()">
|
||||
<option value="0">Horizontal</option>
|
||||
<option value="1">Vertical</option>
|
||||
</select><br>
|
||||
Serpentine: <input type="checkbox" name="P${i}S"><br>
|
||||
Dimensions (WxH): <input id="P${i}W" name="P${i}W" type="number" min="1" max="128" value="${pw}"> x <input id="P${i}H" name="P${i}H" type="number" min="1" max="128" value="${ph}"><br>
|
||||
Offset X:<input id="P${i}X" name="P${i}X" type="number" min="0" max="256" value="0">
|
||||
Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0"><br><i>(offset from top-left corner in # LEDs)</i>
|
||||
Serpentine: <input type="checkbox" name="P${i}S" oninput="UI()"><br>
|
||||
Dimensions (WxH): <input name="P${i}W" type="number" min="1" max="255" value="${pw}" oninput="UI()"> x <input name="P${i}H" type="number" min="1" max="255" value="${ph}" oninput="UI()"><br>
|
||||
Offset X:<input name="P${i}X" type="number" min="0" max="255" value="0" oninput="UI()">
|
||||
Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()"><br><i>(offset from top-left corner in # LEDs)</i>
|
||||
</div>`;
|
||||
p.insertAdjacentHTML("beforeend", b);
|
||||
}
|
||||
@ -107,17 +132,17 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0"><br
|
||||
function gen() {
|
||||
resetPanels();
|
||||
|
||||
var pansH = parseInt(d.Sf.MPH.value);
|
||||
var pansV = parseInt(d.Sf.MPV.value);
|
||||
var pansH = parseInt(Sf.MPH.value);
|
||||
var pansV = parseInt(Sf.MPV.value);
|
||||
var c = pansH*pansV;
|
||||
d.Sf.MPC.value = c; // number of panels
|
||||
Sf.MPC.value = c; // number of panels
|
||||
|
||||
var ps = d.Sf.PS.checked;
|
||||
var pv = d.Sf.PV.value==="1";
|
||||
var pb = d.Sf.PB.value==="1";
|
||||
var pr = d.Sf.PR.value==="1";
|
||||
var pw = parseInt(d.Sf.PW.value);
|
||||
var ph = parseInt(d.Sf.PH.value);
|
||||
var ps = Sf.PS.checked;
|
||||
var pv = Sf.PV.value==="1";
|
||||
var pb = Sf.PB.value==="1";
|
||||
var pr = Sf.PR.value==="1";
|
||||
var pw = parseInt(Sf.PW.value);
|
||||
var ph = parseInt(Sf.PH.value);
|
||||
|
||||
var h = pv ? pansV : pansH;
|
||||
var v = pv ? pansH : pansV;
|
||||
@ -127,13 +152,141 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0"><br
|
||||
var y = (pv?pr:pb) ? v-j-1: j;
|
||||
var x = (pv?pb:pr) ? h-i-1 : i;
|
||||
x = ps && j%2 ? h-x-1 : x;
|
||||
gId("P"+p+"X").value = (pv?y:x) * pw;
|
||||
gId("P"+p+"Y").value = (pv?x:y) * ph
|
||||
gId("P"+p+"W").value = pw;
|
||||
gId("P"+p+"H").value = ph;
|
||||
Sf[`P${p}X`].value = (pv?y:x) * pw;
|
||||
Sf[`P${p}Y`].value = (pv?x:y) * ph
|
||||
Sf[`P${p}W`].value = pw;
|
||||
Sf[`P${p}H`].value = ph;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function expand(o,i)
|
||||
{
|
||||
i.style.display = i.style.display!=="none" ? "none" : "";
|
||||
o.style.rotate = i.style.display==="none" ? "none" : "90deg";
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
||||
if (!ctx) {
|
||||
//WLEDMM: add canvas, initialize and set UI
|
||||
var canvas = gId("canvas");
|
||||
canvas.width = window.innerWidth > 640?640:400; //Mobile gets 400, pc 640
|
||||
canvas.height = canvas.width;
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
// window.requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
//calc max height and width
|
||||
var maxWidth = 0;
|
||||
var maxHeight = 0;
|
||||
for (let p=0; p<gId("panels").children.length; p++) {
|
||||
var px = parseInt(Sf[`P${p}X`].value); //first led x
|
||||
var py = parseInt(Sf[`P${p}Y`].value); //first led y
|
||||
var pw = parseInt(Sf[`P${p}W`].value); //width
|
||||
var ph = parseInt(Sf[`P${p}H`].value); //height
|
||||
maxWidth = Math.max(maxWidth, px + pw);
|
||||
maxHeight = Math.max(maxHeight, py + ph);
|
||||
}
|
||||
|
||||
ctx.canvas.height = ctx.canvas.width / maxWidth * maxHeight;
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
var space=0; // space between panels + margin
|
||||
var ppL = (ctx.canvas.width - space * 2) / maxWidth; //pixels per led
|
||||
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeStyle="yellow";
|
||||
ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height); // add space between panels
|
||||
|
||||
for (let p=0; p<gId("panels").children.length; p++) {
|
||||
var px = parseInt(Sf[`P${p}X`].value); //first led x
|
||||
var py = parseInt(Sf[`P${p}Y`].value); //first led y
|
||||
var pw = parseInt(Sf[`P${p}W`].value); //width
|
||||
var ph = parseInt(Sf[`P${p}H`].value); //height
|
||||
|
||||
var pb = Sf[`P${p}B`].value == "1"; //bottom
|
||||
var pr = Sf[`P${p}R`].value == "1"; //right
|
||||
var pv = Sf[`P${p}V`].value == "1"; //vertical
|
||||
var ps = Sf[`P${p}S`].checked; //serpentine
|
||||
|
||||
var topLeftX = px*ppL + space; //left margin
|
||||
var topLeftY = py*ppL + space; //top margin
|
||||
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle="white";
|
||||
ctx.strokeRect(topLeftX, topLeftY, pw*ppL, ph*ppL); // add space between panels
|
||||
|
||||
var lnX;
|
||||
var lnY;
|
||||
|
||||
//find start led
|
||||
if (pb) //bottom
|
||||
lnY = topLeftY + ph*ppL - ppL/2;
|
||||
else //top
|
||||
lnY = topLeftY + ppL/2;
|
||||
if (pr) //right
|
||||
lnX = topLeftX + pw*ppL - ppL/2;
|
||||
else //left
|
||||
lnX = topLeftX + ppL/2;
|
||||
|
||||
//first led
|
||||
ctx.fillStyle = "green";
|
||||
ctx.beginPath();
|
||||
ctx.arc(lnX, lnY, ppL*0.5, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
//start line
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(lnX, lnY);
|
||||
|
||||
var longLineLength = (pv?ph:pw)*ppL - ppL;
|
||||
for (let ln=0; ln<(pv?pw:ph); ln++) { //loop over panelwidth (or height of vertical?)
|
||||
|
||||
var serpLine = ps && ln%2!=0; //serp: turn around if even line
|
||||
|
||||
if (pv) //if vertical
|
||||
lnY += (pb?-1:1) * longLineLength * (serpLine?-1:1); //if vertical change the Y
|
||||
else
|
||||
lnX += (pr?-1:1) * longLineLength * (serpLine?-1:1); //if horizontal change the X
|
||||
|
||||
ctx.lineTo(lnX, lnY); //draw the long line
|
||||
|
||||
if (ln<(pv?pw:ph)-1) { //not the last
|
||||
//find the small line end point
|
||||
if (pv) //vertical
|
||||
lnX += (pr?-1:1) * ppL;
|
||||
else //horizontal
|
||||
lnY += (pb?-1:1) * ppL;
|
||||
|
||||
//if serpentine go next else go down
|
||||
if (ps) { //serpentine
|
||||
ctx.lineTo(lnX, lnY); //draw the serpentine line
|
||||
} else {
|
||||
//find the other end of the long line
|
||||
if (pv) //vertical
|
||||
lnY += (pb?1:-1) * longLineLength * (serpLine?-1:1); //min as we go back
|
||||
else //horizontal
|
||||
lnX += (pr?1:-1) * longLineLength * (serpLine?-1:1);
|
||||
ctx.moveTo(lnX, lnY); //move to the start point of the next long line
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
|
||||
//last led
|
||||
ctx.fillStyle = "red";
|
||||
ctx.beginPath();
|
||||
ctx.arc(lnX, lnY, ppL*0.5, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
ctx.font = '40px Arial';
|
||||
ctx.fillStyle = "orange";
|
||||
ctx.fillText(p, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10);
|
||||
}
|
||||
gId("MD").innerHTML = "Matrix Dimensions (W*H=LC): " + maxWidth + " x " + maxHeight + " = " + maxWidth * maxHeight;
|
||||
}
|
||||
</script>
|
||||
<style>@import url("style.css");</style>
|
||||
</head>
|
||||
@ -151,36 +304,45 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0"><br
|
||||
</select><br>
|
||||
<div id="mpdiv" style="display:none;">
|
||||
<hr class="sml">
|
||||
<h3>Matrix Generator</h3>
|
||||
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="128" value="8"> x <input name="PH" type="number" min="1" max="128" value="8"><br>
|
||||
Horizontal panels: <input name="MPH" type="number" min="1" max="8" value="1">
|
||||
Vertical panels: <input name="MPV" type="number" min="1" max="8" value="1"><br>
|
||||
1<sup>st</sup> panel: <select name="PB">
|
||||
<option value="0">Top</option>
|
||||
<option value="1">Bottom</option>
|
||||
</select><select name="PR">
|
||||
<option value="0">Left</option>
|
||||
<option value="1">Right</option>
|
||||
</select><br>
|
||||
Orientation: <select name="PV">
|
||||
<option value="0">Horizontal</option>
|
||||
<option value="1">Vertical</option>
|
||||
</select><br>
|
||||
Serpentine: <input type="checkbox" name="PS"><br>
|
||||
<i style="color:#fa0;">Can populate LED panel layout with pre-arranged matrix.<br>These values do not affect final layout.</i><br>
|
||||
<button type="button" onclick="gen()">Populate</button>
|
||||
<h3>Matrix Generator <button type="button" id="expGen" onclick="expand(this,gId('mxGen'));">></button></h3>
|
||||
<div id="mxGen" style="display:none;">
|
||||
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="128" value="8"> x <input name="PH" type="number" min="1" max="128" value="8"><br>
|
||||
Horizontal panels: <input name="MPH" type="number" min="1" max="8" value="1">
|
||||
Vertical panels: <input name="MPV" type="number" min="1" max="8" value="1"><br>
|
||||
1<sup>st</sup> panel: <select name="PB">
|
||||
<option value="0">Top</option>
|
||||
<option value="1">Bottom</option>
|
||||
</select><select name="PR">
|
||||
<option value="0">Left</option>
|
||||
<option value="1">Right</option>
|
||||
</select><br>
|
||||
Orientation: <select name="PV">
|
||||
<option value="0">Horizontal</option>
|
||||
<option value="1">Vertical</option>
|
||||
</select><br>
|
||||
Serpentine: <input type="checkbox" name="PS"><br>
|
||||
<i style="color:#fa0;">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
||||
WARNING: You may need to update each panel parameters after they are generated.</i><br>
|
||||
<button type="button" onclick="gen();expand(gId('expGen'),gId('mxGen'));">Populate</button>
|
||||
</div>
|
||||
<hr class="sml">
|
||||
<h3>Panel set-up</h3>
|
||||
Number of panels: <input name="MPC" type="number" min="1" max="64" value="1" oninput="addPanels()"><br>
|
||||
Number of panels: <input name="MPC" type="number" min="1" max="64" value="1" oninput="addPanels();UI();"><br>
|
||||
<i>A matrix is made of 1 or more physical LED panels.<br>
|
||||
<!--Panels should be arranged from top-left to bottom-right order, starting with lower panel number on the left (or top if transposed).<br>-->
|
||||
Each panel can be of different size and/or have different LED orientation and/or starting point and/or layout.</i><br>
|
||||
<h3>LED panel layout</h3>
|
||||
<div id="panels">
|
||||
</div>
|
||||
<hr class="sml">
|
||||
<div id="MD"></div>
|
||||
<canvas id="canvas"></canvas>
|
||||
<div id="json" >Gap file: <input type="file" name="data" accept=".json"><button type="button" class="sml" onclick="uploadFile('/2d-gaps.json')">Upload</button></div>
|
||||
<i>Note: Gap file is a <b>.json</b> file containing an array with number of elements equal to the matrix size.<br>
|
||||
A value of -1 means that pixel at that position is missing, a value of 0 means never paint that pixel, and 1 means regular pixel.</i>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
<div id="toast"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -642,7 +642,8 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses defaults)
|
||||
<br><br>
|
||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br>
|
||||
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
|
||||
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
|
1498
wled00/html_other.h
1498
wled00/html_other.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2241
wled00/html_simple.h
2241
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
1907
wled00/html_ui.h
1907
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -643,8 +643,14 @@ void serializeInfo(JsonObject root)
|
||||
root[F("cpalcount")] = strip.customPalettes.size(); //number of custom palettes
|
||||
|
||||
JsonArray ledmaps = root.createNestedArray(F("maps"));
|
||||
for (size_t i=0; i<10; i++) {
|
||||
if ((ledMaps>>i) & 0x0001) ledmaps.add(i);
|
||||
for (size_t i=0; i<WLED_MAX_LEDMAPS; i++) {
|
||||
if ((ledMaps>>i) & 0x00000001U) {
|
||||
JsonObject ledmaps0 = ledmaps.createNestedObject();
|
||||
ledmaps0["id"] = i;
|
||||
#ifndef ESP8266
|
||||
if (i && ledmapNames[i-1]) ledmaps0["n"] = ledmapNames[i-1];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject wifi_info = root.createNestedObject("wifi");
|
||||
|
@ -208,6 +208,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (t <= 250) bootPreset = t;
|
||||
gammaCorrectBri = request->hasArg(F("GB"));
|
||||
gammaCorrectCol = request->hasArg(F("GC"));
|
||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||
calcGammaTable(gammaCorrectVal);
|
||||
else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
gammaCorrectCol = false;
|
||||
}
|
||||
|
||||
fadeTransition = request->hasArg(F("TF"));
|
||||
t = request->arg(F("TD")).toInt();
|
||||
@ -240,6 +248,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
simplifiedUI = request->hasArg(F("SU"));
|
||||
#endif
|
||||
DEBUG_PRINTLN(F("Enumerating ledmaps"));
|
||||
enumerateLedmaps();
|
||||
DEBUG_PRINTLN(F("Loading custom palettes"));
|
||||
strip.loadCustomPalettes(); // (re)load all custom palettes
|
||||
}
|
||||
|
||||
//SYNC
|
||||
@ -409,15 +421,15 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
k[0] = 'W'; //weekdays
|
||||
timerWeekday[i] = request->arg(k).toInt();
|
||||
if (i<8) {
|
||||
k[0] = 'M'; //start month
|
||||
timerMonth[i] = request->arg(k).toInt() & 0x0F;
|
||||
timerMonth[i] <<= 4;
|
||||
k[0] = 'P'; //end month
|
||||
timerMonth[i] += (request->arg(k).toInt() & 0x0F);
|
||||
k[0] = 'D'; //start day
|
||||
timerDay[i] = request->arg(k).toInt();
|
||||
k[0] = 'E'; //end day
|
||||
timerDayEnd[i] = request->arg(k).toInt();
|
||||
k[0] = 'M'; //start month
|
||||
timerMonth[i] = request->arg(k).toInt() & 0x0F;
|
||||
timerMonth[i] <<= 4;
|
||||
k[0] = 'P'; //end month
|
||||
timerMonth[i] += (request->arg(k).toInt() & 0x0F);
|
||||
k[0] = 'D'; //start day
|
||||
timerDay[i] = request->arg(k).toInt();
|
||||
k[0] = 'E'; //end day
|
||||
timerDayEnd[i] = request->arg(k).toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -645,15 +657,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (subPage == 10)
|
||||
{
|
||||
strip.isMatrix = request->arg(F("SOMP")).toInt();
|
||||
// strip.panelH = MAX(1,MIN(128,request->arg(F("PH")).toInt()));
|
||||
// strip.panelW = MAX(1,MIN(128,request->arg(F("PW")).toInt()));
|
||||
strip.panel.clear(); // release memory if allocated
|
||||
if (strip.isMatrix) {
|
||||
strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt()));
|
||||
strip.matrix.bottomStart = request->arg(F("PB")).toInt();
|
||||
strip.matrix.rightStart = request->arg(F("PR")).toInt();
|
||||
strip.matrix.vertical = request->arg(F("PV")).toInt();
|
||||
strip.matrix.serpentine = request->hasArg(F("PS"));
|
||||
strip.panel.reserve(strip.panels); // pre-allocate memory
|
||||
for (uint8_t i=0; i<strip.panels; i++) {
|
||||
WS2812FX::Panel p;
|
||||
@ -673,11 +679,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
pO[l] = 'H'; p.height = request->arg(pO).toInt();
|
||||
strip.panel.push_back(p);
|
||||
}
|
||||
strip.setUpMatrix(); // will check limits
|
||||
strip.makeAutoSegments(true);
|
||||
strip.deserializeMap();
|
||||
} else {
|
||||
Segment::maxWidth = strip.getLengthTotal();
|
||||
Segment::maxHeight = 1;
|
||||
}
|
||||
strip.setUpMatrix(); // will check limits
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -800,7 +808,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
|
||||
//apply preset
|
||||
if (updateVal(req.c_str(), "PL=", &presetCycCurr, presetCycMin, presetCycMax)) {
|
||||
unloadPlaylist();
|
||||
unloadPlaylist();
|
||||
applyPreset(presetCycCurr);
|
||||
}
|
||||
|
||||
|
@ -503,12 +503,49 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
}
|
||||
|
||||
|
||||
// enumerate all ledmapX.json files on FS and extract ledmap names if existing
|
||||
void enumerateLedmaps() {
|
||||
ledMaps = 1;
|
||||
for (size_t i=1; i<10; i++) {
|
||||
char fileName[16];
|
||||
for (size_t i=1; i<WLED_MAX_LEDMAPS; i++) {
|
||||
char fileName[33];
|
||||
sprintf_P(fileName, PSTR("/ledmap%d.json"), i);
|
||||
bool isFile = WLED_FS.exists(fileName);
|
||||
if (isFile) ledMaps |= 1 << i;
|
||||
|
||||
#ifndef ESP8266
|
||||
if (ledmapNames[i-1]) { //clear old name
|
||||
delete[] ledmapNames[i-1];
|
||||
ledmapNames[i-1] = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isFile) {
|
||||
ledMaps |= 1 << i;
|
||||
|
||||
#ifndef ESP8266
|
||||
if (requestJSONBufferLock(21)) {
|
||||
if (readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
size_t len = 0;
|
||||
if (!doc["n"].isNull()) {
|
||||
// name field exists
|
||||
const char *name = doc["n"].as<const char*>();
|
||||
if (name != nullptr) len = strlen(name);
|
||||
if (len > 0 && len < 33) {
|
||||
ledmapNames[i-1] = new char[len+1];
|
||||
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33);
|
||||
}
|
||||
}
|
||||
if (!ledmapNames[i-1]) {
|
||||
char tmp[33];
|
||||
snprintf_P(tmp, 32, PSTR("ledmap%d.json"), i);
|
||||
len = strlen(tmp);
|
||||
ledmapNames[i-1] = new char[len+1];
|
||||
if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33);
|
||||
}
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -171,15 +171,14 @@ void WLED::loop()
|
||||
}
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit();
|
||||
loadLedmap = 0;
|
||||
strip.finalizeInit(); // also loads default ledmap if present
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
if (loadLedmap >= 0) {
|
||||
strip.deserializeMap(loadLedmap);
|
||||
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
||||
loadLedmap = -1;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2302120
|
||||
#define VERSION 2302150
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -319,6 +319,7 @@ WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB co
|
||||
WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct
|
||||
WLED_GLOBAL bool gammaCorrectCol _INIT(true ); // use gamma correction on colors
|
||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
|
||||
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
|
||||
|
||||
WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color.
|
||||
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color
|
||||
@ -677,7 +678,14 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
||||
#ifndef ESP8266
|
||||
WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr}));
|
||||
#endif
|
||||
#if WLED_MAX_LEDMAPS>16
|
||||
WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
||||
#else
|
||||
WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps
|
||||
#endif
|
||||
|
||||
// Usermod manager
|
||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
|
@ -364,7 +364,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
if (subPage == 2)
|
||||
{
|
||||
char nS[8];
|
||||
char nS[32];
|
||||
|
||||
appendGPIOinfo();
|
||||
|
||||
@ -445,6 +445,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
|
||||
sappend('c',SET_F("GB"),gammaCorrectBri);
|
||||
sappend('c',SET_F("GC"),gammaCorrectCol);
|
||||
dtostrf(gammaCorrectVal,3,1,nS); sappends('s',SET_F("GV"),nS);
|
||||
sappend('c',SET_F("TF"),fadeTransition);
|
||||
sappend('v',SET_F("TD"),transitionDelayDefault);
|
||||
sappend('c',SET_F("PF"),strip.paletteFade);
|
||||
@ -738,10 +739,6 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',SET_F("PH"),strip.panel[0].height);
|
||||
}
|
||||
sappend('v',SET_F("MPC"),strip.panels);
|
||||
sappend('v',SET_F("PB"),strip.matrix.bottomStart);
|
||||
sappend('v',SET_F("PR"),strip.matrix.rightStart);
|
||||
sappend('v',SET_F("PV"),strip.matrix.vertical);
|
||||
sappend('c',SET_F("PS"),strip.matrix.serpentine);
|
||||
// panels
|
||||
for (uint8_t i=0; i<strip.panels; i++) {
|
||||
char n[5];
|
||||
|
Loading…
Reference in New Issue
Block a user