Refactor setUpMatrix, deserializeMap for ledmaps

This commit is contained in:
Ewoud
2023-03-07 13:56:18 +01:00
parent 92c97e33b1
commit 10c5d8f20f
4 changed files with 71 additions and 106 deletions

View File

@@ -859,7 +859,7 @@ class WS2812FX { // 96 bytes
#endif #endif
void void
setUpMatrix(bool reset = true), //WLEDMM: add reset option to switch on/off reset of customMappingTable setUpMatrix(),
setPixelColorXY(int x, int y, uint32_t c); setPixelColorXY(int x, int y, uint32_t c);
// outsmart the compiler :) by correctly overloading // outsmart the compiler :) by correctly overloading

View File

@@ -34,15 +34,12 @@
// note: matrix may be comprised of multiple panels each with different orientation // note: matrix may be comprised of multiple panels each with different orientation
// but ledmap takes care of that. ledmap is constructed upon initialization // but ledmap takes care of that. ledmap is constructed upon initialization
// so matrix should disable regular ledmap processing // so matrix should disable regular ledmap processing
void WS2812FX::setUpMatrix(bool reset) { void WS2812FX::setUpMatrix() {
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
// erase old ledmap, just in case. // erase old ledmap, just in case.
if (reset) { //WLEDMM: add reset option to switch on/off reset of customMappingTable if (customMappingTable != nullptr) delete[] customMappingTable;
if (customMappingTable != nullptr) delete[] customMappingTable; customMappingTable = nullptr;
customMappingTable = nullptr; customMappingSize = 0;
customMappingSize = 0;
loadedLedmap = 0;
}
// isMatrix is set in cfg.cpp or set.cpp // isMatrix is set in cfg.cpp or set.cpp
if (isMatrix) { if (isMatrix) {
@@ -59,30 +56,26 @@ void WS2812FX::setUpMatrix(bool reset) {
} }
} }
if (reset) { //WLEDMM: add reset option to switch on/off reset of customMappingTable // safety check
// safety check if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth <= 1 || Segment::maxHeight <= 1) {
if (Segment::maxWidth * Segment::maxHeight > MAX_LEDS || Segment::maxWidth <= 1 || Segment::maxHeight <= 1) { DEBUG_PRINTF("2D Bounds error. %d x %d\n", Segment::maxWidth, Segment::maxHeight);
DEBUG_PRINTF("2D Bounds error. %d x %d\n", Segment::maxWidth, Segment::maxHeight); isMatrix = false;
isMatrix = false; Segment::maxWidth = _length;
Segment::maxWidth = _length; Segment::maxHeight = 1;
Segment::maxHeight = 1; panels = 0;
panels = 0; panel.clear(); // release memory allocated by panels
panel.clear(); // release memory allocated by panels resetSegments(true); //WLEDMM bounds only
resetSegments(true); //WLEDMM bounds only return;
return;
}
customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
} }
customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
if (customMappingTable != nullptr) { if (customMappingTable != nullptr) {
uint16_t customMappingSizeLedmap = customMappingSize;
customMappingSize = Segment::maxWidth * Segment::maxHeight; customMappingSize = Segment::maxWidth * Segment::maxHeight;
uint16_t *customMappingTableCombi = nullptr; //WLEDMM: Idea @Troy#2642 // fill with empty in case we don't fill the entire matrix
if (customMappingSizeLedmap > 0) { //WLEDMM: @Troy#2642 : include ledmap = 0 as default ledmap for (size_t i = 0; i< customMappingSize; i++) {
customMappingTableCombi = new uint16_t[customMappingSize]; customMappingTable[i] = (uint16_t)-1;
for (int i=0; i<customMappingSize;i++) customMappingTableCombi[i] = (uint16_t)0xFFFFU; //WLEDMM: init with no show
} }
// we will try to load a "gap" array (a JSON file) // we will try to load a "gap" array (a JSON file)
@@ -130,31 +123,17 @@ void WS2812FX::setUpMatrix(bool reset) {
x = (p.vertical?p.bottomStart:p.rightStart) ? h-i-1 : i; x = (p.vertical?p.bottomStart:p.rightStart) ? h-i-1 : i;
x = p.serpentine && j%2 ? h-x-1 : x; x = p.serpentine && j%2 ? h-x-1 : x;
size_t index = (p.yOffset + (p.vertical?x:y)) * Segment::maxWidth + p.xOffset + (p.vertical?y:x); size_t index = (p.yOffset + (p.vertical?x:y)) * Segment::maxWidth + p.xOffset + (p.vertical?y:x);
if (customMappingSizeLedmap > 0) { //WLEDMM: @Troy#2642 : include ledmap = 0 as default ledmap if (!gapTable || (gapTable && gapTable[index] > 0)) customMappingTable[index] = pix; // a useful pixel (otherwise -1 is retained)
if (index < customMappingSizeLedmap && customMappingTable[index] < customMappingSize) if (!gapTable || (gapTable && gapTable[index] >= 0)) pix++; // not a missing pixel
customMappingTableCombi[customMappingTable[index]] = pix; //WLEDMM: allow for 2 transitions if reset = false (ledmap and logical to physical)
pix++;
}
else {
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
}
} }
} }
} }
if (customMappingSizeLedmap > 0) { //WLEDMM: @Troy#2642 : include ledmap = 0 as default ledmap
for (size_t i = 0; i < customMappingSize; i++) {
customMappingTable[i] = customMappingTableCombi[i];
}
delete[] customMappingTableCombi;
}
// delete gap array as we no longer need it // delete gap array as we no longer need it
if (gapTable) delete[] gapTable; if (gapTable) delete[] gapTable;
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
DEBUG_PRINTF("Matrix ledmap: %d\n", loadedLedmap); DEBUG_PRINTF("Matrix ledmap: \n");
for (uint16_t i=0; i<customMappingSize; i++) { for (uint16_t i=0; i<customMappingSize; i++) {
if (!(i%Segment::maxWidth)) DEBUG_PRINTLN(); if (!(i%Segment::maxWidth)) DEBUG_PRINTLN();
DEBUG_PRINTF("%4d,", customMappingTable[i]); DEBUG_PRINTF("%4d,", customMappingTable[i]);
@@ -168,7 +147,7 @@ void WS2812FX::setUpMatrix(bool reset) {
panel.clear(); panel.clear();
Segment::maxWidth = _length; Segment::maxWidth = _length;
Segment::maxHeight = 1; Segment::maxHeight = 1;
//WLEDMM: no resetSegments here, only do it in set.cpp/handleSettingsSet //WLEDMM: no resetSegments here, only do it in set.cpp/handleSettingsSet - as we want t0 maintain the segment settings after setup has changed
} }
} }
#else #else

View File

@@ -575,12 +575,12 @@ class JMapC {
char previousSegmentName[50] = ""; char previousSegmentName[50] = "";
~JMapC() { ~JMapC() {
Serial.println("~JMapC"); USER_PRINTLN("~JMapC");
deletejVectorMap(); deletejVectorMap();
} }
void deletejVectorMap() { void deletejVectorMap() {
if (jVectorMap.size() > 0) { if (jVectorMap.size() > 0) {
Serial.println("delete jVectorMap"); USER_PRINTLN("delete jVectorMap");
for (size_t i=0; i<jVectorMap.size(); i++) for (size_t i=0; i<jVectorMap.size(); i++)
delete jVectorMap[i].array; delete jVectorMap[i].array;
jVectorMap.clear(); jVectorMap.clear();
@@ -624,7 +624,7 @@ class JMapC {
else if (SEGMENT.name != nullptr && strcmp(SEGMENT.name, previousSegmentName) != 0) { else if (SEGMENT.name != nullptr && strcmp(SEGMENT.name, previousSegmentName) != 0) {
uint32_t dataSize = 0; uint32_t dataSize = 0;
deletejVectorMap(); deletejVectorMap();
Serial.print("New "); Serial.println(SEGMENT.name); USER_PRINT("New "); USER_PRINTLN(SEGMENT.name);
char jMapFileName[50]; char jMapFileName[50];
strcpy(jMapFileName, "/"); strcpy(jMapFileName, "/");
strcat(jMapFileName, SEGMENT.name); strcat(jMapFileName, SEGMENT.name);
@@ -639,11 +639,11 @@ class JMapC {
jMapFile.find("["); jMapFile.find("[");
do { do {
DeserializationError err = deserializeJson(docChunk, jMapFile); DeserializationError err = deserializeJson(docChunk, jMapFile);
// serializeJson(docChunk, Serial); Serial.println(); // serializeJson(docChunk, Serial); USER_PRINTLN();
// Serial.printf("docChunk %u / %u%% (%u %u %u) %u\n", (unsigned int)docChunk.memoryUsage(), 100 * docChunk.memoryUsage() / docChunk.capacity(), (unsigned int)docChunk.size(), docChunk.overflowed(), (unsigned int)docChunk.nesting(), jMapFile.size()); // USER_PRINTf("docChunk %u / %u%% (%u %u %u) %u\n", (unsigned int)docChunk.memoryUsage(), 100 * docChunk.memoryUsage() / docChunk.capacity(), (unsigned int)docChunk.size(), docChunk.overflowed(), (unsigned int)docChunk.nesting(), jMapFile.size());
if (err) if (err)
{ {
Serial.printf("deserializeJson() of parseTree failed with code %s\n", err.c_str()); USER_PRINTf("deserializeJson() of parseTree failed with code %s\n", err.c_str());
delete[] SEGMENT.name; SEGMENT.name = nullptr; //need to clear the name as otherwise continuously loaded delete[] SEGMENT.name; SEGMENT.name = nullptr; //need to clear the name as otherwise continuously loaded
return; return;
} }
@@ -684,10 +684,10 @@ class JMapC {
scale = MIN(SEGMENT.virtualWidth() / maxWidth, SEGMENT.virtualHeight() / maxHeight); scale = MIN(SEGMENT.virtualWidth() / maxWidth, SEGMENT.virtualHeight() / maxHeight);
dataSize += sizeof(jVectorMap); dataSize += sizeof(jVectorMap);
Serial.print("dataSize "); USER_PRINT("dataSize ");
Serial.print(dataSize); USER_PRINT(dataSize);
Serial.print(" scale "); USER_PRINT(" scale ");
Serial.println(scale); USER_PRINTLN(scale);
strcpy(previousSegmentName, SEGMENT.name); strcpy(previousSegmentName, SEGMENT.name);
} }
} //updatejMapDoc } //updatejMapDoc
@@ -696,7 +696,7 @@ class JMapC {
//WLEDMM jMap //WLEDMM jMap
void Segment::createjMap() { void Segment::createjMap() {
if (!jMap) { if (!jMap) {
Serial.println("createjMap"); USER_PRINTLN("createjMap");
jMap = new JMapC(); jMap = new JMapC();
} }
} }
@@ -705,7 +705,7 @@ void Segment::createjMap() {
void Segment::deletejMap() { void Segment::deletejMap() {
//Should be called from ~Segment but causes crash (and ~Segment is called quite often...) //Should be called from ~Segment but causes crash (and ~Segment is called quite often...)
if (jMap) { if (jMap) {
Serial.println("deletejMap"); USER_PRINTLN("deletejMap");
delete (JMapC *)jMap; jMap = nullptr; delete (JMapC *)jMap; jMap = nullptr;
} }
} }
@@ -2024,7 +2024,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
bool isFile = false;; bool isFile = false;;
if (n<10) { if (n<10) {
strcpy_P(fileName, PSTR("/ledmap")); strcpy_P(fileName, PSTR("/ledmap"));
if (n) sprintf(fileName +7, "%d", n); if (n) sprintf(fileName +7, "%d", n); //WLEDMM: trick to not include 0 in ledmap.json
strcat(fileName, ".json"); strcat(fileName, ".json");
isFile = WLED_FS.exists(fileName); isFile = WLED_FS.exists(fileName);
} else { //WLEDM add segment name as ledmap.name } else { //WLEDM add segment name as ledmap.name
@@ -2040,18 +2040,13 @@ bool WS2812FX::deserializeMap(uint8_t n) {
} }
if (!isFile) { if (!isFile) {
// erase custom mapping if selecting nonexistent ledmap.json (n==0) //WLEDM always erase if nonexistant //WLEDMM: disable temporary!!!
if (customMappingTable != nullptr) { // erase custom mapping if selecting nonexistent ledmap.json (n==0)
//WLEDMM: if isMatrix then not erase but back to matrix default // if (!isMatrix && !n && customMappingTable != nullptr) {
if (isMatrix) // customMappingSize = 0;
setUpMatrix(true); // delete[] customMappingTable;
else { // customMappingTable = nullptr;
customMappingSize = 0; // }
delete[] customMappingTable;
customMappingTable = nullptr;
loadedLedmap = 0;
}
}
return false; return false;
} }
@@ -2075,45 +2070,40 @@ bool WS2812FX::deserializeMap(uint8_t n) {
JsonArray map = doc[F("map")]; JsonArray map = doc[F("map")];
if (!map.isNull() && map.size()) { // not an empty map if (!map.isNull() && map.size()) { // not an empty map
//WLEDMM: if isMatrix then customMap size is whole matrix if (doc[F("physical")]) {
#ifndef WLED_DISABLE_2D //WLEDMM: support ledmap file properties width and height
if (doc[F("width")]>0 && doc[F("height")]>0) {
panels = 1;
panel.clear();
panel.reserve(1U); // pre-allocate memory for panels
Panel p;
p.bottomStart = p.rightStart = p.vertical = p.serpentine = false;
p.xOffset = p.yOffset = 0;
p.width = doc[F("width")];
p.height = doc[F("height")];
strip.panel.push_back(p);
//WLEDMM: support ledmap file properties width and height Segment::maxWidth = p.width;
if (doc[F("width")]>0 && doc[F("height")]>0) { Segment::maxHeight = p.height;
panels = 1;
panel.clear();
panel.reserve(1U); // pre-allocate memory for panels
Panel p;
p.bottomStart = p.rightStart = p.vertical = p.serpentine = false;
p.xOffset = p.yOffset = 0;
p.width = doc[F("width")];
p.height = doc[F("height")];
strip.panel.push_back(p);
Segment::maxWidth = p.width; makeAutoSegments();
Segment::maxHeight = p.height; }
makeAutoSegments();
} }
if (isMatrix) customMappingSize = map.size();
customMappingSize = Segment::maxWidth * Segment::maxHeight; //as whole matrix will be stored in setUpMatrix
else
#endif
customMappingSize = map.size();
customMappingTable = new uint16_t[customMappingSize]; customMappingTable = new uint16_t[customMappingSize];
if (!doc[F("physical")]) { // if (!doc[F("physical")]) {
for (uint16_t i=0; i<MIN(customMappingSize, map.size()); i++) for (uint16_t i=0; i<MIN(customMappingSize, map.size()); i++)
customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]); customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
} // }
else { // else {
for (int i=0; i<customMappingSize;i++) customMappingTable[i] = (uint16_t)0xFFFFU; //WLEDMM: init with no show // for (int i=0; i<customMappingSize;i++) customMappingTable[i] = (uint16_t)0xFFFFU; //WLEDMM: init with no show
//assign all >=0 mappings to customMappingTable // //assign all >=0 mappings to customMappingTable
for (uint16_t i=0; i<map.size(); i++) // for (uint16_t i=0; i<map.size(); i++)
if (map[i]>=0) // if (map[i]>=0)
customMappingTable[map[i].as<uint16_t>()] = i; // customMappingTable[map[i].as<uint16_t>()] = i;
} // }
loadedLedmap = n; loadedLedmap = n;
@@ -2126,11 +2116,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
} }
DEBUG_PRINTLN(); DEBUG_PRINTLN();
#endif #endif
setUpMatrix(false); //WLEDMM: apply logical to physical mapping after the ledmap
} }
else
setUpMatrix(true); //WLEDMM: if no map then back to matrix default
releaseJSONBufferLock(); releaseJSONBufferLock();
return true; return true;

View File

@@ -649,7 +649,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
seg0["stop"] = 0; seg0["stop"] = 0;
} }
} }
root[F("ledmap")] = loadedLedmap; //WLEDMM ledmaps will be stored in json root[F("ledmap")] = loadedLedmap; //WLEDMM ledmaps will be stored in json so dropdown can display it
} }
// begin WLEDMM // begin WLEDMM