Skip to content

Commit 601fb8a

Browse files
committed
channelsE and channelsP (swap for double buffering)
Effects and modifiers use channelsE (virtual layer, Art-Net In) Drivers use channelsD (FastLED, parallel, Art-Net out) main swaps between them
1 parent b15d69f commit 601fb8a

File tree

15 files changed

+58
-55
lines changed

15 files changed

+58
-55
lines changed

docs/develop/architecture.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,15 @@ Synchronization Flow
162162
void effectTask(void* param) {
163163
while (true) {
164164
if (layerP.lights.useDoubleBuffer) {
165-
layerP.lights.channels = layerP.lights.channelsBack;
165+
layerP.lights.channelsE = layerP.lights.channelsD;
166+
166167
layerP.loop(); // getRGB and setRGB both use channelsBack
167168

168169
// Atomic swap channels
169170
xSemaphoreTake(swapMutex, portMAX_DELAY);
170-
uint8_t* temp = layerP.lights.channelsBack;
171-
layerP.lights.channelsBack = layerP.lights.channels;
172-
layerP.lights.channels = temp;
171+
uint8_t* temp = layerP.lights.channelsD;
172+
layerP.lights.channelsD = layerP.lights.channelsE;
173+
layerP.lights.channelsE = temp;
173174
newFrameReady = true;
174175
xSemaphoreGive(swapMutex);
175176

@@ -366,11 +367,11 @@ Double buffering is **automatically enabled** when PSRAM is detected:
366367
// In PhysicalLayer::setup()
367368
if (psramFound()) {
368369
lights.useDoubleBuffer = true;
369-
lights.channels = allocMB<uint8_t>(maxChannels);
370-
lights.channelsBack = allocMB<uint8_t>(maxChannels);
370+
lights.channelsE = allocMB<uint8_t>(maxChannels);
371+
lights.channelsD = allocMB<uint8_t>(maxChannels);
371372
} else {
372373
lights.useDoubleBuffer = false;
373-
lights.channels = allocMB<uint8_t>(maxChannels);
374+
lights.channelsE = allocMB<uint8_t>(maxChannels);
374375
}
375376
```
376377

docs/develop/layers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* A Virtual Layer mapping gets updated if a layout, mapping or dimensions change 🚧
3636
* An effect uses a virtual layer. One Virtual layer can have multiple effects. ✅
3737
* Physical layer
38-
* Lights.header and Lights.channels. CRGB leds[] is using lights.channels (acting like leds[] in FASTLED) ✅
38+
* Lights.header and lights.channelsE/D. CRGB leds[] is using lights.channelsE/D (acting like leds[] in FASTLED) ✅
3939
* A Physical layer has one or more virtual layers and a virtual layer has one or more effects using it. ✅
4040
* Presets/playlist: change (part of) the nodes model
4141

src/MoonBase/Nodes.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ void LiveScriptNode::setup() {
183183
// addExternal( "uint8_t dmaBuffer", &layerP.ledsDriver.dmaBuffer);
184184

185185
addExternal("void fadeToBlackBy(uint8_t)", (void*)_fadeToBlackBy);
186-
addExternal("CRGB* leds", (void*)(CRGB*)layerP.lights.channels);
186+
addExternal("CRGB* leds", (void*)(CRGB*)layerP.lights.channelsE);
187187
addExternal("void setRGB(uint16_t,CRGB)", (void*)_setRGB);
188188
addExternal("void setRGBPal(uint16_t,uint8_t,uint8_t)", (void*)_setRGBPal);
189189
addExternal("void setPan(uint16_t,uint8_t)", (void*)_setPan);
@@ -370,7 +370,7 @@ void DriverNode::loop() {
370370

371371
if (brightness != brightnessSaved || layerP.maxPower != maxPowerSaved) {
372372
// Use FastLED for setMaxPowerInMilliWatts stuff
373-
uint8_t correctedBrightness = calculate_max_brightness_for_power_mW((CRGB*)&layerP.lights.channels, layerP.lights.header.nrOfLights, brightness, layerP.maxPower * 1000);
373+
uint8_t correctedBrightness = calculate_max_brightness_for_power_mW((CRGB*)&layerP.lights.channelsD, layerP.lights.header.nrOfLights, brightness, layerP.maxPower * 1000);
374374
// EXT_LOGD(ML_TAG, "setBrightness b:%d + p:%d -> cb:%d", brightness, layerP.maxPower, correctedBrightness);
375375
ledsDriver.setBrightness(correctedBrightness);
376376
brightnessSaved = brightness;

src/MoonLight/Layers/PhysicalLayer.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ PhysicalLayer::PhysicalLayer() {
3333

3434
// heap-optimization: request heap optimization review
3535
// on boards without PSRAM, heap is only 60 KB (30KB max alloc) available, need to find out how to increase the heap
36-
// goal is to have lights.channels as large as possible, preferable 12288 at least for boards without PSRAM
36+
// goal is to have lights.channelsE/D as large as possible, preferable 12288 at least for boards without PSRAM
3737

3838
void PhysicalLayer::setup() {
39-
// allocate lights.channels
39+
// allocate lights.channelsE/D
4040

4141
if (psramFound()) {
4242
lights.maxChannels = MIN(ESP.getPsramSize() / 4, 61440 * 3); // fill halve with channels, max 120 pins * 512 LEDs, still addressable with uint16_t
@@ -46,17 +46,19 @@ void PhysicalLayer::setup() {
4646
lights.useDoubleBuffer = false; // Single buffer mode
4747
}
4848

49-
lights.channels = allocMB<uint8_t>(lights.maxChannels);
49+
lights.channelsE = allocMB<uint8_t>(lights.maxChannels);
5050

51-
if (lights.channels) {
52-
EXT_LOGD(ML_TAG, "allocated %d bytes in %s", lights.maxChannels, isInPSRAM(lights.channels) ? "PSRAM" : "RAM");
51+
if (lights.channelsE) {
52+
EXT_LOGD(ML_TAG, "allocated %d bytes in %s", lights.maxChannels, isInPSRAM(lights.channelsE) ? "PSRAM" : "RAM");
5353
// Allocate back buffer only if PSRAM available
5454
if (lights.useDoubleBuffer) {
55-
lights.channelsBack = allocMB<uint8_t>(lights.maxChannels);
56-
if (!lights.channelsBack) {
55+
lights.channelsD = allocMB<uint8_t>(lights.maxChannels);
56+
if (!lights.channelsD) {
5757
EXT_LOGW(ML_TAG, "Failed to allocate back buffer, disabling double buffering");
5858
lights.useDoubleBuffer = false;
5959
}
60+
} else {
61+
lights.channelsD = lights.channelsE; // share the same array
6062
}
6163
} else {
6264
EXT_LOGE(ML_TAG, "failed to allocated %d bytes of RAM or PSRAM", lights.maxChannels);
@@ -141,7 +143,7 @@ void PhysicalLayer::onLayoutPre() {
141143
lights.header.isPositions = 1; // in progress...
142144
delay(100); // wait to stop effects
143145
// set all channels to 0 (e.g for multichannel to not activate unused channels, e.g. fancy modes on MHs)
144-
memset(lights.channels, 0, lights.maxChannels); // set all the channels to 0
146+
memset(lights.channelsE, 0, lights.maxChannels); // set all the channels to 0, positions in channelsE
145147
// dealloc pins
146148
if (!monitorPass) {
147149
memset(ledsPerPin, 0xFF, sizeof(ledsPerPin)); // UINT16_MAX is 2 * 0xFF
@@ -171,7 +173,7 @@ void PhysicalLayer::addLight(Coord3D position) {
171173
if (pass == 1) {
172174
// EXT_LOGD(ML_TAG, "%d,%d,%d", position.x, position.y, position.z);
173175
if (lights.header.nrOfLights < lights.maxChannels / 3) {
174-
packCoord3DInto3Bytes(&lights.channels[lights.header.nrOfLights * 3], position);
176+
packCoord3DInto3Bytes(&lights.channelsE[lights.header.nrOfLights * 3], position); // positions in channelsE
175177
}
176178

177179
lights.header.size = lights.header.size.maximum(position);

src/MoonLight/Layers/PhysicalLayer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ struct LightsHeader {
8888

8989
struct Lights {
9090
LightsHeader header;
91-
uint8_t* channels = nullptr; // pka leds, created in constructor
92-
uint8_t* channelsBack = nullptr; // Back buffer (being written by effects)
91+
uint8_t* channelsE = nullptr; // channels used by effects and modifiers (double buffering)
92+
uint8_t* channelsD = nullptr; // channels used by drivers (double buffering)
9393
size_t maxChannels = 0;
9494
bool useDoubleBuffer = false; // Only when PSRAM available
9595

src/MoonLight/Layers/VirtualLayer.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void VirtualLayer::setLight(const uint16_t indexV, const uint8_t* channels, uint
139139
if (layerP->lights.header.lightPreset == lightPreset_RGB2040) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
140140
indexP += (indexP / 20) * 20;
141141
}
142-
memcpy(&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
142+
memcpy(&layerP->lights.channelsE[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
143143

144144
break;
145145
}
@@ -149,15 +149,15 @@ void VirtualLayer::setLight(const uint16_t indexV, const uint8_t* channels, uint
149149
if (layerP->lights.header.lightPreset == lightPreset_RGB2040) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
150150
indexP += (indexP / 20) * 20;
151151
}
152-
memcpy(&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
152+
memcpy(&layerP->lights.channelsE[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
153153
}
154154
else
155155
EXT_LOGW(ML_TAG, "dev setLightColor i:%d m:%d s:%d", indexV, mappingTable[indexV].indexes, mappingTableIndexes.size());
156156
break;
157157
default:;
158158
}
159159
} else if (indexV * layerP->lights.header.channelsPerLight + offset + length < layerP->lights.maxChannels) { // no mapping
160-
memcpy(&layerP->lights.channels[indexV * layerP->lights.header.channelsPerLight + offset], channels, length);
160+
memcpy(&layerP->lights.channelsE[indexV * layerP->lights.header.channelsPerLight + offset], channels, length);
161161
}
162162
}
163163

@@ -170,7 +170,7 @@ T VirtualLayer::getLight(const uint16_t indexV, uint8_t offset) const {
170170
if (layerP->lights.header.lightPreset == lightPreset_RGB2040) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
171171
indexP += (indexP / 20) * 20;
172172
}
173-
T* result = (T*)&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset];
173+
T* result = (T*)&layerP->lights.channelsE[indexP * layerP->lights.header.channelsPerLight + offset];
174174
return *result; // return the color as CRGB
175175
break;
176176
}
@@ -179,7 +179,7 @@ T VirtualLayer::getLight(const uint16_t indexV, uint8_t offset) const {
179179
if (layerP->lights.header.lightPreset == lightPreset_RGB2040) { // RGB2040 has empty channels
180180
indexP += (indexP / 20) * 20;
181181
}
182-
T* result = (T*)&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset];
182+
T* result = (T*)&layerP->lights.channelsE[indexP * layerP->lights.header.channelsPerLight + offset];
183183
return *result; // return the color as CRGB
184184
break;
185185
}
@@ -195,7 +195,7 @@ T VirtualLayer::getLight(const uint16_t indexV, uint8_t offset) const {
195195
break;
196196
}
197197
} else if (indexV * layerP->lights.header.channelsPerLight + offset + 3 < layerP->lights.maxChannels) { // no mapping
198-
T* result = (T*)&layerP->lights.channels[indexV * layerP->lights.header.channelsPerLight + offset];
198+
T* result = (T*)&layerP->lights.channelsE[indexV * layerP->lights.header.channelsPerLight + offset];
199199
return *result; // return the color as CRGB
200200
} else {
201201
// some operations will go out of bounds e.g. VUMeter, uncomment below lines if you wanna test on a specific effect
@@ -221,7 +221,7 @@ void VirtualLayer::fadeToBlackMin() {
221221
// }
222222
// } else
223223
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // CRGB lights
224-
fastled_fadeToBlackBy((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels / sizeof(CRGB), fadeBy);
224+
fastled_fadeToBlackBy((CRGB*)layerP->lights.channelsE, layerP->lights.header.nrOfChannels / sizeof(CRGB), fadeBy);
225225
} else { // multichannel lights
226226
for (uint16_t index = 0; index < nrOfLights; index++) {
227227
CRGB color = getRGB(index); // direct access to the channels
@@ -263,7 +263,7 @@ void VirtualLayer::fill_solid(const CRGB& color) {
263263
// }
264264
// } else
265265
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // faster, else manual
266-
fastled_fill_solid((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels / sizeof(CRGB), color);
266+
fastled_fill_solid((CRGB*)layerP->lights.channelsE, layerP->lights.header.nrOfChannels / sizeof(CRGB), color);
267267
} else {
268268
for (uint16_t index = 0; index < nrOfLights; index++) setRGB(index, color);
269269
}
@@ -283,7 +283,7 @@ void VirtualLayer::fill_rainbow(const uint8_t initialhue, const uint8_t deltahue
283283
// }
284284
// } else
285285
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // faster, else manual
286-
fastled_fill_rainbow((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels / sizeof(CRGB), initialhue, deltahue);
286+
fastled_fill_rainbow((CRGB*)layerP->lights.channelsE, layerP->lights.header.nrOfChannels / sizeof(CRGB), initialhue, deltahue);
287287
} else {
288288
CHSV hsv;
289289
hsv.hue = initialhue;
@@ -354,7 +354,7 @@ void VirtualLayer::addLight(Coord3D position) {
354354
}
355355
} else {
356356
// set unmapped lights to 0, e.g. needed by checkerboard modifier
357-
memset(&layerP->lights.channels[layerP->indexP * layerP->lights.header.channelsPerLight], 0, layerP->lights.header.channelsPerLight);
357+
memset(&layerP->lights.channelsE[layerP->indexP * layerP->lights.header.channelsPerLight], 0, layerP->lights.header.channelsPerLight);
358358
}
359359
}
360360

src/MoonLight/Layers/VirtualLayer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class VirtualLayer {
6363
// heap-optimization: request heap optimization review
6464
// on boards without PSRAM, heap is only 60 KB (30KB max alloc) available, need to find out how to increase the heap
6565
// for virtual mapping mappingTable and mappingTableIndexes is used
66-
// mappingTable is per default same size as the number of LEDs/lights (stored in lights.channels), see Physical layer, goal is also here to support 12288 LEDs on non PSRAM boards at least for non PSRAM board
66+
// mappingTable is per default same size as the number of LEDs/lights (stored in lights.channelsE/D), see Physical layer, goal is also here to support 12288 LEDs on non PSRAM boards at least for non PSRAM board
6767
// mappingTableIndexes is used of the mapping of effects to lights.channel is not 1:1 but 1:M
6868

6969
// they will be reused to avoid fragmentation

src/MoonLight/Modules/ModuleChannels.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ class ModuleChannels : public Module {
7474
// EXT_LOGD(ML_TAG, "%s[%d]%s[%d].%s = %s -> %s", updatedItem.parent[0].c_str(), updatedItem.index[0], updatedItem.parent[1].c_str(), updatedItem.index[1], updatedItem.name.c_str(), updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
7575
// copy the file to the hidden folder...
7676
if (updatedItem.oldValue != "" && !updatedItem.value["action"].isNull() && updatedItem.value["action"] != "") {
77-
if (!layerP.lights.channels) return; // to avoid crash during init
77+
if (!layerP.lights.channelsE) return; // to avoid crash during init
7878
EXT_LOGD(ML_TAG, "handle %s[%d]%s[%d].%s = %s -> %s", updatedItem.parent[0].c_str(), updatedItem.index[0], updatedItem.parent[1].c_str(), updatedItem.index[1], updatedItem.name.c_str(), updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
7979
uint16_t select = updatedItem.value["select"];
8080
uint8_t value = updatedItem.value["action"] == "mouseenter" ? 255 : 0;
8181
if (view == 0) { // physical layer
8282
if (group)
83-
for (uint8_t i = 0; i < layerP.lights.header.channelsPerLight; i++) layerP.lights.channels[select * layerP.lights.header.channelsPerLight + i] = value;
83+
for (uint8_t i = 0; i < layerP.lights.header.channelsPerLight; i++) layerP.lights.channelsE[select * layerP.lights.header.channelsPerLight + i] = value;
8484
else
85-
layerP.lights.channels[select] = value;
85+
layerP.lights.channelsE[select] = value;
8686
} else {
8787
if (group)
8888
for (uint8_t i = 0; i < layerP.lights.header.channelsPerLight; i++) layerP.layers[view - 1]->setLight(select, &value, i, 1);

src/MoonLight/Modules/ModuleLightsControl.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ModuleLightsControl : public Module {
4141

4242
EXT_LOGI(ML_TAG, "Lights:%d(Header:%d) L-H:%d Node:%d PL:%d(PL-L:%d) VL:%d PM:%d C3D:%d", sizeof(Lights), sizeof(LightsHeader), sizeof(Lights) - sizeof(LightsHeader), sizeof(Node), sizeof(PhysicalLayer), sizeof(PhysicalLayer) - sizeof(Lights), sizeof(VirtualLayer), sizeof(PhysMap), sizeof(Coord3D));
4343

44-
EXT_LOGI(ML_TAG, "isInPSRAM: mt:%d mti:%d ch:%d", isInPSRAM(layerP.layers[0]->mappingTable), isInPSRAM(layerP.layers[0]->mappingTableIndexes.data()), isInPSRAM(layerP.lights.channels));
44+
EXT_LOGI(ML_TAG, "isInPSRAM: mt:%d mti:%d ch:%d", isInPSRAM(layerP.layers[0]->mappingTable), isInPSRAM(layerP.layers[0]->mappingTableIndexes.data()), isInPSRAM(layerP.lights.channelsE));
4545

4646
setPresetsFromFolder(); // set the right values during boot
4747

@@ -356,9 +356,9 @@ class ModuleLightsControl : public Module {
356356
read([&](ModuleState& _state) {
357357
if (_socket->getConnectedClients() && _state.data["monitorOn"]) {
358358
_socket->emitEvent("monitor", (char*)&layerP.lights.header, 37); // sizeof(LightsHeader)); //sizeof(LightsHeader), nearest prime nr above 32 to avoid monitor data to be seen as header
359-
_socket->emitEvent("monitor", (char*)layerP.lights.channels, MIN(layerP.lights.header.nrOfLights * 3, layerP.lights.maxChannels)); //*3 is for 3 bytes position
359+
_socket->emitEvent("monitor", (char*)layerP.lights.channelsE, MIN(layerP.lights.header.nrOfLights * 3, layerP.lights.maxChannels)); //*3 is for 3 bytes position
360360
}
361-
memset(layerP.lights.channels, 0, layerP.lights.maxChannels); // set all the channels to 0 //cleaning the positions
361+
memset(layerP.lights.channelsE, 0, layerP.lights.maxChannels); // set all the channels to 0 //cleaning the positions
362362
EXT_LOGD(ML_TAG, "positions sent to monitor (2 -> 3, #L:%d maxC:%d)", layerP.lights.header.nrOfLights, layerP.lights.maxChannels);
363363
layerP.lights.header.isPositions = 3;
364364
});
@@ -372,7 +372,7 @@ class ModuleLightsControl : public Module {
372372
extern SemaphoreHandle_t swapMutex;
373373

374374
xSemaphoreTake(swapMutex, portMAX_DELAY);
375-
_socket->emitEvent("monitor", (char*)layerP.lights.channels, MIN(layerP.lights.header.nrOfChannels, layerP.lights.maxChannels));
375+
_socket->emitEvent("monitor", (char*)layerP.lights.channelsE, MIN(layerP.lights.header.nrOfChannels, layerP.lights.maxChannels));
376376
xSemaphoreGive(swapMutex);
377377
}
378378
});

src/MoonLight/Nodes/Drivers/D_ArtnetIn.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class ArtNetInDriver : public Node {
130130
int ledIndex = startPixel + i;
131131
if (ledIndex < layerP.lights.header.nrOfLights) {
132132
if (layer == 0) { // Physical layer
133-
memcpy(&layerP.lights.channels[ledIndex * layerP.lights.header.channelsPerLight], &dmxData[i * layerP.lights.header.channelsPerLight], layerP.lights.header.channelsPerLight);
133+
memcpy(&layerP.lights.channelsE[ledIndex * layerP.lights.header.channelsPerLight], &dmxData[i * layerP.lights.header.channelsPerLight], layerP.lights.header.channelsPerLight);
134134
} else { // Virtual layer
135135
layerP.layers[layer - 1]->setLight(ledIndex, &dmxData[i * layerP.lights.header.channelsPerLight], 0, layerP.lights.header.channelsPerLight);
136136
}
@@ -160,7 +160,7 @@ class ArtNetInDriver : public Node {
160160
int ledIndex = startPixel + i;
161161
if (ledIndex < layerP.lights.header.nrOfLights) {
162162
if (layer == 0) { // Physical layer
163-
memcpy(&layerP.lights.channels[ledIndex * layerP.lights.header.channelsPerLight], &pixelData[i * layerP.lights.header.channelsPerLight], layerP.lights.header.channelsPerLight);
163+
memcpy(&layerP.lights.channelsE[ledIndex * layerP.lights.header.channelsPerLight], &pixelData[i * layerP.lights.header.channelsPerLight], layerP.lights.header.channelsPerLight);
164164
} else { // Virtual layer
165165
layerP.layers[layer - 1]->setLight(ledIndex, &pixelData[i * layerP.lights.header.channelsPerLight], 0, layerP.lights.header.channelsPerLight);
166166
}

0 commit comments

Comments
 (0)