Skip to content

Commit 3cef785

Browse files
committed
isPosition guarded by mutex, monitor using channelsD
1 parent 34afb73 commit 3cef785

File tree

3 files changed

+38
-12
lines changed

3 files changed

+38
-12
lines changed

src/MoonLight/Layers/PhysicalLayer.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ void PhysicalLayer::loopDrivers() {
111111
if (prevSize != lights.header.size) node->onSizeChanged(prevSize);
112112
if (node->on) node->loop();
113113
}
114-
114+
115115
prevSize = lights.header.size;
116116
}
117117

@@ -131,9 +131,14 @@ void PhysicalLayer::onLayoutPre() {
131131
if (pass == 1) {
132132
lights.header.nrOfLights = 0; // for pass1 and pass2 as in pass2 virtual layer needs it
133133
lights.header.size = {0, 0, 0};
134+
extern SemaphoreHandle_t swapMutex;
135+
xSemaphoreTake(swapMutex, portMAX_DELAY);
134136
EXT_LOGD(ML_TAG, "positions in progress (%d -> 1)", lights.header.isPositions);
135137
lights.header.isPositions = 1; // in progress...
136-
delay(100); // wait to stop effects
138+
xSemaphoreGive(swapMutex);
139+
140+
delay(100); // wait to stop effects
141+
137142
// set all channels to 0 (e.g for multichannel to not activate unused channels, e.g. fancy modes on MHs)
138143
memset(lights.channelsE, 0, lights.maxChannels); // set all the channels to 0, positions in channelsE
139144
// dealloc pins
@@ -206,8 +211,11 @@ void PhysicalLayer::onLayoutPost() {
206211
lights.header.nrOfChannels = lights.header.nrOfLights * lights.header.channelsPerLight * ((lights.header.lightPreset == lightPreset_RGB2040) ? 2 : 1); // RGB2040 has empty channels
207212
EXT_LOGD(ML_TAG, "pass %d mp:%d #:%d / %d s:%d,%d,%d", pass, monitorPass, lights.header.nrOfLights, lights.header.nrOfChannels, lights.header.size.x, lights.header.size.y, lights.header.size.z);
208213
// send the positions to the UI _socket_emit
214+
extern SemaphoreHandle_t swapMutex;
215+
xSemaphoreTake(swapMutex, portMAX_DELAY);
209216
EXT_LOGD(ML_TAG, "positions stored (%d -> %d)", lights.header.isPositions, lights.header.nrOfLights ? 2 : 3);
210217
lights.header.isPositions = lights.header.nrOfLights ? 2 : 3; // filled with positions, set back to 3 in ModuleEffects, or direct to 3 if no lights (effects will move it to 0)
218+
xSemaphoreGive(swapMutex);
211219

212220
// initLightsToBlend();
213221

src/MoonLight/Modules/ModuleLightsControl.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,18 +352,27 @@ class ModuleLightsControl : public Module {
352352
}
353353

354354
#if FT_ENABLED(FT_MONITOR)
355-
extern SemaphoreHandle_t monitorMutex; // defined in main
356-
if (layerP.lights.header.isPositions == 2) { // send to UI
355+
extern SemaphoreHandle_t monitorMutex; // defined in main
356+
extern SemaphoreHandle_t swapMutex;
357+
358+
// Check and transition under lock
359+
xSemaphoreTake(swapMutex, portMAX_DELAY);
360+
uint8_t isPositions = layerP.lights.header.isPositions;
361+
xSemaphoreGive(swapMutex);
362+
363+
if (isPositions == 2) { // send to UI
357364
read([&](ModuleState& _state) {
358365
if (_socket->getConnectedClients() && _state.data["monitorOn"]) {
359366
_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
360367
_socket->emitEvent("monitor", (char*)layerP.lights.channelsE, MIN(layerP.lights.header.nrOfLights * 3, layerP.lights.maxChannels)); //*3 is for 3 bytes position
361368
}
362369
memset(layerP.lights.channelsE, 0, layerP.lights.maxChannels); // set all the channels to 0 //cleaning the positions
363-
EXT_LOGD(ML_TAG, "positions sent to monitor (2 -> 3, #L:%d maxC:%d)", layerP.lights.header.nrOfLights, layerP.lights.maxChannels);
370+
xSemaphoreTake(swapMutex, portMAX_DELAY);
371+
EXT_LOGD(ML_TAG, "positions sent to monitor (2 -> 3)");
364372
layerP.lights.header.isPositions = 3;
373+
xSemaphoreGive(swapMutex);
365374
});
366-
} else if (layerP.lights.header.isPositions == 0 && layerP.lights.header.nrOfLights) { // send to UI
375+
} else if (isPositions == 0 && layerP.lights.header.nrOfLights) { // send to UI
367376
static unsigned long monitorMillis = 0;
368377
if (millis() - monitorMillis >= layerP.lights.header.nrOfLights / 12) {
369378
monitorMillis = millis();
@@ -372,7 +381,7 @@ class ModuleLightsControl : public Module {
372381
if (_socket->getConnectedClients() && _state.data["monitorOn"]) {
373382
// protect emit by monitorMutex, see main.cpp
374383
xSemaphoreTake(monitorMutex, portMAX_DELAY);
375-
_socket->emitEvent("monitor", (char*)layerP.lights.channelsE, MIN(layerP.lights.header.nrOfChannels, layerP.lights.maxChannels));
384+
_socket->emitEvent("monitor", (char*)layerP.lights.channelsD, MIN(layerP.lights.header.nrOfChannels, layerP.lights.maxChannels)); // use channelsD as it won't be overwritten by effects during loop
376385
xSemaphoreGive(monitorMutex);
377386
}
378387
});

src/main.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,12 @@ void effectTask(void* pvParameters) {
128128
static unsigned long last20ms = 0;
129129

130130
while (true) {
131-
if (layerP.lights.header.isPositions == 0) { // driver task can change this
131+
// Check state under lock
132+
xSemaphoreTake(swapMutex, portMAX_DELAY);
133+
uint8_t isPositions = layerP.lights.header.isPositions;
134+
xSemaphoreGive(swapMutex);
135+
136+
if (isPositions == 0) { // driver task can change this
132137
if (layerP.lights.useDoubleBuffer) {
133138
xSemaphoreTake(swapMutex, portMAX_DELAY);
134139
bool canProduce = !newFrameReady;
@@ -138,21 +143,21 @@ void effectTask(void* pvParameters) {
138143
// Copy previous frame (channelsD) to working buffer (channelsE)
139144
memcpy(layerP.lights.channelsE, layerP.lights.channelsD, layerP.lights.header.nrOfChannels);
140145

141-
xSemaphoreTake(monitorMutex, portMAX_DELAY); // don't change channelsE while the monitor display data is sent
142146
layerP.loop();
143147

144148
if (millis() - last20ms >= 20) {
145149
last20ms = millis();
146150
layerP.loop20ms();
147151
}
148-
xSemaphoreGive(monitorMutex);
149152

150153
// Atomic swap channels
151154
xSemaphoreTake(swapMutex, portMAX_DELAY);
155+
xSemaphoreTake(monitorMutex, portMAX_DELAY);
152156
uint8_t* temp = layerP.lights.channelsD;
153157
layerP.lights.channelsD = layerP.lights.channelsE;
154158
layerP.lights.channelsE = temp;
155159
newFrameReady = true;
160+
xSemaphoreGive(monitorMutex);
156161
xSemaphoreGive(swapMutex);
157162
}
158163

@@ -180,12 +185,16 @@ void driverTask(void* pvParameters) {
180185
// layerP.setup() done in effectTask
181186

182187
while (true) {
188+
// Check and transition state under lock
189+
xSemaphoreTake(swapMutex, portMAX_DELAY);
183190
if (layerP.lights.header.isPositions == 3) {
184191
EXT_LOGD(ML_TAG, "positions done (3 -> 0)");
185-
layerP.lights.header.isPositions = 0; // now driver can show again
192+
layerP.lights.header.isPositions = 0;
186193
}
194+
uint8_t isPositions = layerP.lights.header.isPositions;
195+
xSemaphoreGive(swapMutex);
187196

188-
if (layerP.lights.header.isPositions == 0) {
197+
if (isPositions == 0) {
189198
xSemaphoreTake(swapMutex, portMAX_DELAY);
190199
if (layerP.lights.useDoubleBuffer) {
191200
if (newFrameReady) {

0 commit comments

Comments
 (0)