Skip to content

Commit 1dadf47

Browse files
committed
Support for RGB2040 curtains , Firefox number width
Front-end ======== - MultiInput: more space for numbers (Firefox compatibility) - Monitor: support nrOfChannels (RGB2040) Back-end ======== - Nodes: DriverNode: use header.lightPreset and add RGB2040 - Physical layer: header: add nrOfChannels and lightPreset - Virtual layer: set/getLight: check for lightPresets (RGB2040), fade*: use nrOfChannels
1 parent 7fdc3ac commit 1dadf47

File tree

11 files changed

+12806
-12777
lines changed

11 files changed

+12806
-12777
lines changed

interface/src/lib/components/moonbase/MultiInput.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
{:else if property.type == 'number'}
185185
<input
186186
type="number"
187-
style="width: {String(property.max || 255).length + 4}ch"
187+
style="width: {String(property.max || 255).length + 5}ch"
188188
min={property.min ? property.min : 0}
189189
max={property.max ? property.max : 255}
190190
class="input invalid:border-error invalid:border-2"

interface/src/routes/moonbase/monitor/Monitor.svelte

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
let offsetRGB: number;
5555
let offsetWhite: number;
5656
let isPositions: boolean = false;
57+
let lightPreset: number = 2;
58+
let nrOfChannels: number = 0;
5759
// let offsetRed:number;
5860
// let offsetGreen:number;
5961
// let offsetBlue:number;
@@ -70,10 +72,12 @@
7072
// offsetBlue = (header[6] >> 6) & 0x3; // bits 6-7
7173
// offsetWhite = header[13];
7274
73-
nrOfLights = view.getUint16(12, true); // header[12] + 256 * header[13];
74-
channelsPerLight = view.getUint8(19); //header[19];
75-
offsetRGB = view.getUint8(20); //header[20];
76-
offsetWhite = view.getUint8(21); //header[21];
75+
nrOfLights = view.getUint16(12, true);
76+
channelsPerLight = view.getUint8(19);
77+
offsetRGB = view.getUint8(20);
78+
offsetWhite = view.getUint8(21);
79+
nrOfChannels = view.getUint16(32, true);
80+
lightPreset = view.getUint8(34);
7781
7882
//rebuild scene
7983
createScene(el);
@@ -95,17 +99,18 @@
9599
depth,
96100
nrOfLights,
97101
channelsPerLight,
98-
offsetRGB
102+
offsetRGB,
103+
nrOfChannels
99104
);
100105
};
101106
102107
const handlePositions = (positions: Uint8Array) => {
103108
console.log('Monitor.handlePositions', positions);
104109
105-
for (let index = 0; index < nrOfLights * 3; index += 3) {
106-
let x = positions[index];
107-
let y = positions[index + 1];
108-
let z = positions[index + 2];
110+
for (let indexP = 0; indexP < nrOfLights; indexP++) {
111+
let x = positions[indexP * 3];
112+
let y = positions[indexP * 3 + 1];
113+
let z = positions[indexP * 3 + 2];
109114
110115
//set to -1,1 coordinate system of webGL
111116
//width -1 etc as 0,0 should be top left, not bottom right
@@ -124,17 +129,20 @@
124129
done = true;
125130
}
126131
clearColors();
132+
let rgb2040 = lightPreset == 13;
127133
//max size supported is 255x255x255 (index < width * height * depth) ... todo: only any of the component < 255
128-
for (let index = 0; index < nrOfLights * channelsPerLight; index += channelsPerLight) {
129-
// && index < width * height * depth
130-
// colorLed(index/3, data[index]/255, data[index+1]/255, data[index+2]/255);
131-
const r = channels[index + offsetRGB + 0] / 255;
132-
const g = channels[index + offsetRGB + 1] / 255;
133-
const b = channels[index + offsetRGB + 2] / 255;
134-
let w = 0;
135-
if (offsetWhite != 255) w = channels[index + offsetRGB + 3] / 255; //add white channel if present
136-
const a = 1.0; // Full opacity
137-
colors.push(r + w, g + w, b + w, a);
134+
for (let index = 0; index < nrOfChannels; index += channelsPerLight) {
135+
if (!rgb2040 || Math.floor(index / 60) % 2 == 0) {
136+
// RGB2040 Skip the empty channels
137+
// && index < width * height * depth
138+
const r = channels[index + offsetRGB + 0] / 255;
139+
const g = channels[index + offsetRGB + 1] / 255;
140+
const b = channels[index + offsetRGB + 2] / 255;
141+
let w = 0;
142+
if (offsetWhite != 255) w = channels[index + offsetRGB + 3] / 255; //add white channel if present
143+
const a = 1.0; // Full opacity
144+
colors.push(r + w, g + w, b + w, a);
145+
}
138146
}
139147
140148
updateScene(vertices, colors);

lib/framework/WWWData.h

Lines changed: 12735 additions & 12732 deletions
Large diffs are not rendered by default.

src/MoonBase/Nodes.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ I2SClocklessLedDriver ledsDriver;
345345
#endif
346346

347347
void DriverNode::setup() {
348-
addControl(lightPreset, "lightPreset", "select");
348+
addControl(layerP.lights.header.lightPreset, "lightPreset", "select");
349349
addControlValue("RGB");
350350
addControlValue("RBG");
351351
addControlValue("GRB"); // default WS2812
@@ -359,6 +359,7 @@ void DriverNode::setup() {
359359
addControlValue("MHBeeEyes150W-15 🐺"); // 15 channels moving head, see https://moonmodules.org/MoonLight/moonlight/drivers/#art-net
360360
addControlValue("MHBeTopper19x15W-32 🐺"); // 32 channels moving head
361361
addControlValue("MH19x15W-24"); // 24 channels moving heads
362+
addControlValue("RGB2040"); // curtain 2040
362363
}
363364

364365
void DriverNode::loop() {
@@ -407,7 +408,7 @@ void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
407408

408409
header->resetOffsets();
409410

410-
switch (lightPreset) {
411+
switch (header->lightPreset) {
411412
case 0:
412413
header->channelsPerLight = 3;
413414
header->offsetRed = 0;
@@ -511,9 +512,15 @@ void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
511512
layer->layerP->lights.header.offsetRGB2 = 12;
512513
layer->layerP->lights.header.offsetZoom = 17;
513514
break;
515+
case 13: // curtain RGB2040
516+
header->channelsPerLight = 3;
517+
header->offsetRed = 0;
518+
header->offsetGreen = 1;
519+
header->offsetBlue = 2;
520+
break;
514521
}
515522

516-
EXT_LOGI(ML_TAG, "setLightPreset %d (cPL:%d, o:%d,%d,%d,%d)", lightPreset, header->channelsPerLight, header->offsetRed, header->offsetGreen, header->offsetBlue, header->offsetWhite);
523+
EXT_LOGI(ML_TAG, "setLightPreset %d (cPL:%d, o:%d,%d,%d,%d)", header->lightPreset, header->channelsPerLight, header->offsetRed, header->offsetGreen, header->offsetBlue, header->offsetWhite);
517524

518525
// FASTLED_ASSERT(true, "oki");
519526

src/MoonBase/Nodes.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,6 @@ class DriverNode : public Node {
285285
bool initDone = false;
286286
#endif
287287

288-
protected:
289-
uint8_t lightPreset = 2; // GRB
290-
291288
public:
292289
void setup() override;
293290

src/MoonLight/Layers/PhysicalLayer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ void PhysicalLayer::nextPin(uint8_t ledPinDIO) {
184184
}
185185
// ledsPerPin[i] is the first empty slot
186186
if (i < MAXLEDPINS) {
187-
ledsPerPin[i] = lights.header.nrOfLights - prevNrOfLights;
187+
ledsPerPin[i] = (lights.header.nrOfLights - prevNrOfLights) * ((lights.header.lightPreset == 13) ? 2 : 1); // RGB2040 has empty channels
188188
if (ledPinDIO != UINT8_MAX)
189189
ledPinsAssigned[i] = ledPinDIO; // override order
190190
else
@@ -198,7 +198,8 @@ void PhysicalLayer::nextPin(uint8_t ledPinDIO) {
198198
void PhysicalLayer::onLayoutPost() {
199199
if (pass == 1) {
200200
lights.header.size += Coord3D{1, 1, 1};
201-
EXT_LOGD(ML_TAG, "pass %d mp:%d #:%d s:%d,%d,%d", pass, monitorPass, lights.header.nrOfLights, lights.header.size.x, lights.header.size.y, lights.header.size.z);
201+
lights.header.nrOfChannels = lights.header.nrOfLights * lights.header.channelsPerLight * ((lights.header.lightPreset == 13) ? 2 : 1); // RGB2040 has empty channels
202+
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);
202203
// send the positions to the UI _socket_emit
203204
EXT_LOGD(ML_TAG, "positions stored (%d -> %d)", lights.header.isPositions, lights.header.nrOfLights ? 2 : 3);
204205
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)

src/MoonLight/Layers/PhysicalLayer.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ struct LightsHeader {
5454
uint8_t offsetRGB2 = UINT8_MAX;
5555
uint8_t offsetRGB3 = UINT8_MAX;
5656
uint8_t offsetBrightness2 = UINT8_MAX; // 31
57-
// 19 + 9? bytes until here
58-
// uint8_t ledFactor = 1; //factor to multiply the positions with
59-
// uint8_t ledSize = 4; //mm size of each light, used in monitor ...
60-
// 32 bytes total
61-
uint8_t fill[8]; //->37 needed so pack up until 40
57+
uint16_t nrOfChannels; // 32, so we can deal with exceptional cases e.g. RGB2040 make sure it starts at even position!!! for alignment!!!
58+
uint8_t lightPreset; // 34, so we can deal with exceptional cases e.g. RGB2040
59+
// =============
60+
// 35 bytes total
61+
uint8_t fill[5]; //->37 max (prime number)!!! needed so pack up until 40
6262
// support for more channels, like white, pan, tilt etc.
6363

6464
void resetOffsets() {
@@ -78,6 +78,8 @@ struct LightsHeader {
7878
offsetRGB2 = UINT8_MAX;
7979
offsetRGB3 = UINT8_MAX;
8080
offsetBrightness2 = UINT8_MAX;
81+
// lightPreset = 2; // don't reset as managed by Drivers
82+
nrOfChannels = 0;
8183
memset(fill, 0, sizeof(fill)); // set to 0
8284
}
8385

@@ -129,7 +131,7 @@ class PhysicalLayer {
129131
void nextPin(uint8_t ledPin = UINT8_MAX); // if more pins are defined, the next lights will be assigned to the next pin
130132
void onLayoutPost();
131133

132-
//from board presets
134+
// from board presets
133135
uint8_t ledPins[MAXLEDPINS];
134136
uint8_t ledPinsAssigned[MAXLEDPINS];
135137
uint16_t ledsPerPin[MAXLEDPINS];

src/MoonLight/Layers/VirtualLayer.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ void fastled_fadeToBlackBy(CRGB* leds, uint16_t num_leds, uint8_t fadeBy) { fade
2121
void fastled_fill_solid(struct CRGB* targetArray, int numToFill, const CRGB& color) { fill_solid(targetArray, numToFill, color); }
2222
void fastled_fill_rainbow(struct CRGB* targetArray, int numToFill, uint8_t initialhue, uint8_t deltahue) { fill_rainbow(targetArray, numToFill, initialhue, deltahue); }
2323

24-
VirtualLayer::VirtualLayer() {
25-
EXT_LOGV(ML_TAG, "constructor");
26-
}
24+
VirtualLayer::VirtualLayer() { EXT_LOGV(ML_TAG, "constructor"); }
2725

2826
VirtualLayer::~VirtualLayer() {
2927
EXT_LOGV(ML_TAG, "destructor");
@@ -138,12 +136,19 @@ void VirtualLayer::setLight(const uint16_t indexV, const uint8_t* channels, uint
138136
}
139137
case m_oneLight: {
140138
uint16_t indexP = mappingTable[indexV].indexP;
139+
if (layerP->lights.header.lightPreset == 13) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
140+
indexP = (indexP / 20 * 40 + indexP % 20);
141+
}
141142
memcpy(&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
143+
142144
break;
143145
}
144146
case m_moreLights:
145147
if (mappingTable[indexV].indexes < mappingTableIndexes.size())
146148
for (uint16_t indexP : mappingTableIndexes[mappingTable[indexV].indexes]) {
149+
if (layerP->lights.header.lightPreset == 13) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
150+
indexP = (indexP / 20 * 40 + indexP % 20);
151+
}
147152
memcpy(&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset], channels, length);
148153
}
149154
else
@@ -161,7 +166,11 @@ T VirtualLayer::getLight(const uint16_t indexV, uint8_t offset) const {
161166
if (indexV < mappingTableSize) {
162167
switch (mappingTable[indexV].mapType) {
163168
case m_oneLight: {
164-
T* result = (T*)&layerP->lights.channels[mappingTable[indexV].indexP * layerP->lights.header.channelsPerLight + offset];
169+
uint16_t indexP = mappingTable[indexV].indexP;
170+
if (layerP->lights.header.lightPreset == 13) { // RGB2040 has empty channels: Skip the 20..39 range, so adjust group mapping
171+
indexP = (indexP / 20 * 40 + indexP % 20);
172+
}
173+
T* result = (T*)&layerP->lights.channels[indexP * layerP->lights.header.channelsPerLight + offset];
165174
return *result; // return the color as CRGB
166175
break;
167176
}
@@ -208,7 +217,7 @@ void VirtualLayer::fadeToBlackMin() {
208217
// }
209218
// } else
210219
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // CRGB lights
211-
fastled_fadeToBlackBy((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfLights, fadeBy);
220+
fastled_fadeToBlackBy((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels, fadeBy);
212221
} else { // multichannel lights
213222
for (uint16_t index = 0; index < nrOfLights; index++) {
214223
CRGB color = getRGB(index); // direct access to the channels
@@ -250,7 +259,7 @@ void VirtualLayer::fill_solid(const CRGB& color) {
250259
// }
251260
// } else
252261
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // faster, else manual
253-
fastled_fill_solid((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfLights, color);
262+
fastled_fill_solid((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels, color);
254263
} else {
255264
for (uint16_t index = 0; index < nrOfLights; index++) setRGB(index, color);
256265
}
@@ -270,7 +279,7 @@ void VirtualLayer::fill_rainbow(const uint8_t initialhue, const uint8_t deltahue
270279
// }
271280
// } else
272281
if (layerP->lights.header.channelsPerLight == 3 && layerP->layers.size() == 1) { // faster, else manual
273-
fastled_fill_rainbow((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfLights, initialhue, deltahue);
282+
fastled_fill_rainbow((CRGB*)layerP->lights.channels, layerP->lights.header.nrOfChannels, initialhue, deltahue); // RGB2040 has empty channels
274283
} else {
275284
CHSV hsv;
276285
hsv.hue = initialhue;

src/MoonLight/Modules/ModuleLightsControl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ class ModuleLightsControl : public Module {
344344
} else if (layerP.lights.header.isPositions == 0 && layerP.lights.header.nrOfLights) { // send to UI
345345
EVERY_N_MILLIS(layerP.lights.header.nrOfLights / 12) {
346346
read([&](ModuleState& _state) {
347-
if (_socket->getConnectedClients() && _state.data["monitorOn"]) _socket->emitEvent("monitor", (char*)layerP.lights.channels, MIN(layerP.lights.header.nrOfLights * layerP.lights.header.channelsPerLight, layerP.lights.maxChannels));
347+
if (_socket->getConnectedClients() && _state.data["monitorOn"]) _socket->emitEvent("monitor", (char*)layerP.lights.channels, MIN(layerP.lights.header.nrOfChannels, layerP.lights.maxChannels));
348348
});
349349
}
350350
}

src/MoonLight/Modules/ModuleMoonLightInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class ModuleMoonLightInfo : public Module {
2626

2727
addControl(controls, "nrOfLights", "number", 0, 65535, true);
2828
addControl(controls, "channelsPerLight", "number", 0, 65535, true);
29+
addControl(controls, "nrOfChannels", "number", 0, 65535, true);
2930
addControl(controls, "maxChannels", "number", 0, 65535, true);
3031
addControl(controls, "size", "coord3D", 0, UINT16_MAX, true);
3132
addControl(controls, "nodes#", "number", 0, 65535, true);
@@ -54,6 +55,7 @@ class ModuleMoonLightInfo : public Module {
5455
// this should be updated each time the UI queries for it ... (now only at boot)
5556
data["nrOfLights"] = layerP.lights.header.nrOfLights;
5657
data["channelsPerLight"] = layerP.lights.header.channelsPerLight;
58+
data["nrOfChannels"] = layerP.lights.header.nrOfChannels;
5759
data["maxChannels"] = layerP.lights.maxChannels;
5860
data["size"]["x"] = layerP.lights.header.size.x;
5961
data["size"]["y"] = layerP.lights.header.size.y;

0 commit comments

Comments
 (0)