Introduce network type (previous virtual)

- phase shifting correction (limit to PWM CCT)
This commit is contained in:
Blaz Kristan 2024-08-27 14:11:56 +02:00
parent 820df0c596
commit b2e00eb868
2 changed files with 47 additions and 32 deletions

View File

@ -427,6 +427,9 @@ BusPwm::BusPwm(BusConfig &bc)
#else
ledcSetup(_ledcStart + i, _frequency, _depth);
ledcAttachPin(_pins[i], _ledcStart + i);
// LEDC timer reset credit @dedehai
uint8_t group = ((_ledcStart + i) / 8), channel = ((_ledcStart + i) % 8); // _ledcStart + i is always less than MAX_LED_CHANNELS/LEDC_CHANNELS
ledc_timer_rst((ledc_mode_t)group, (ledc_channel_t)channel); // reset timer so all timers are almost in sync (for phase shift)
#endif
}
_hasRgb = hasRGB(bc.type);
@ -496,29 +499,30 @@ uint32_t BusPwm::getPixelColor(uint16_t pix) const {
void BusPwm::show() {
if (!_valid) return;
unsigned numPins = getPins();
unsigned maxBri = (1<<_depth) - 1;
const unsigned numPins = getPins();
const unsigned maxBri = (1<<_depth);
// use CIE brightness formula
unsigned pwmBri = (unsigned)_bri * 100;
if(pwmBri < 2040) pwmBri = ((pwmBri << _depth) + 115043) / 230087; //adding '0.5' before division for correct rounding
if (pwmBri < 2040)
pwmBri = ((pwmBri << _depth) + 115043) / 230087; //adding '0.5' before division for correct rounding
else {
pwmBri += 4080;
float temp = (float)pwmBri / 29580;
temp = temp * temp * temp * (1<<_depth) - 1;
temp = temp * temp * temp * maxBri;
pwmBri = (unsigned)temp;
}
// determine phase shift POC (credit @dedehai)
[[maybe_unused]] uint32_t phaseOffset = maxBri / numPins;
for (unsigned i = 0; i < numPins; i++) {
unsigned scaled = (_data[i] * pwmBri) / 255;
if (_reversed) scaled = maxBri - scaled;
#ifdef ESP8266
analogWrite(_pins[i], scaled);
#else
if (_needsRefresh) { // hacked to determine if phase shifted PWM is requested
// CCT blending has to be 0 for phse shift to work (WW & CW must not overlap)
if (_type == TYPE_ANALOG_2CH && _needsRefresh && Bus::getCCTBlend() == 0) { // hacked to determine if phase shifted PWM is requested
if (scaled >= maxBri/2) scaled = maxBri/2 - 1; // safety check & add dead time of 1 pulse
uint8_t group = ((_ledcStart + i) / 8), channel = ((_ledcStart + i) % 8); // _ledcStart + i is always less than MAX_LED_CHANNELS/LEDC_CHANNELS
ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, scaled, phaseOffset*i);
ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
ledc_set_duty_and_update((ledc_mode_t)group, (ledc_channel_t)channel, scaled, (maxBri / numPins)*i);
} else
ledcWrite(_ledcStart + i, scaled);
#endif
@ -719,8 +723,8 @@ String BusManager::getLEDTypesJSONString(void) {
{TYPE_WS2805, "D", PSTR("WS2805 RGBCW")},
{TYPE_SM16825, "D", PSTR("SM16825 RGBCW")},
{TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")},
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")},
//{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")},
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented
//{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented
{TYPE_WS2801, "2P", PSTR("WS2801")},
{TYPE_APA102, "2P", PSTR("APA102")},
{TYPE_LPD8806, "2P", PSTR("LPD8806")},
@ -732,11 +736,15 @@ String BusManager::getLEDTypesJSONString(void) {
{TYPE_ANALOG_3CH, "AAA", PSTR("PWM RGB")},
{TYPE_ANALOG_4CH, "AAAA", PSTR("PWM RGBW")},
{TYPE_ANALOG_5CH, "AAAAA", PSTR("PWM RGB+CCT")},
//{TYPE_ANALOG_6CH, "AAAAAA", PSTR("PWM RGB+DCCT")},
{TYPE_NET_DDP_RGB, "V", PSTR("DDP RGB (network)")},
{TYPE_NET_ARTNET_RGB, "V", PSTR("Art-Net RGB (network)")},
{TYPE_NET_DDP_RGBW, "V", PSTR("DDP RGBW (network)")},
{TYPE_NET_ARTNET_RGBW, "V", PSTR("Art-Net RGBW (network)")}
//{TYPE_ANALOG_6CH, "AAAAAA", PSTR("PWM RGB+DCCT")}, // unimplementable ATM
{TYPE_NET_DDP_RGB, "N", PSTR("DDP RGB (network)")},
{TYPE_NET_ARTNET_RGB, "N", PSTR("Art-Net RGB (network)")},
{TYPE_NET_DDP_RGBW, "N", PSTR("DDP RGBW (network)")},
{TYPE_NET_ARTNET_RGBW, "N", PSTR("Art-Net RGBW (network)")},
// hypothetical extensions
//{TYPE_VIRTUAL_I2C_W, "V", PSTR("I2C White (virtual)")}, // allows setting I2C address in _pin[0]
//{TYPE_VIRTUAL_I2C_CCT, "V", PSTR("I2C CCT (virtual)")}, // allows setting I2C address in _pin[0]
//{TYPE_VIRTUAL_I2C_RGB, "V", PSTR("I2C RGB (virtual)")}, // allows setting I2C address in _pin[0]
};
String json = "[";
for (const auto &type : types) {

View File

@ -24,7 +24,8 @@
function isAna(t) { return gT(t).t === "" || isPWM(t); } // is analog type
function isDig(t) { return gT(t).t === "D" || isD2P(t); } // is digital type
function isD2P(t) { return gT(t).t === "2P"; } // is digital 2 pin type
function isVir(t) { return gT(t).t === "V"; } // is virtual type
function isNet(t) { return gT(t).t === "N"; } // is network type
function isVir(t) { return gT(t).t === "V" || isNet(t); } // is virtual type
function hasRGB(t) { return !!(gT(t).c & 0x01); } // has RGB
function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel
function hasCCT(t) { return !!(gT(t).c & 0x04); } // is white CCT enabled
@ -202,12 +203,10 @@
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
let dbl = 0;
let ch = 3;
let ch = 3*hasRGB(t) + hasW(t) + hasCCT(t);
let mul = 1;
if (isDig(t)) {
if (is16b(t)) len *= 2; // 16 bit LEDs
if (t > 28 && t < 40) ch = 4; //RGBW
if (t == 28) ch = 5; //GRBCW
if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
mul = 5;
}
@ -216,7 +215,6 @@
}
if (d.Sf.LD.checked) dbl = len * ch; // double buffering
}
if (isVir(t) && t == 88) ch = 4;
return len * ch * mul + dbl;
}
@ -232,27 +230,36 @@
let p1d = "";
let off = "Off Refresh";
switch (gT(t).t.charAt(0)) {
case '2':
case '2': // 2 pin digital
p1d = "Clock "+p0d;
case 'D':
// fallthrough
case 'D': // digital
p0d = "Data "+p0d;
break;
case 'A':
if (gT(t).t.length > 1) {
p0d = "GPIOs:";
off = "Phase shift";
} else gId(`dig${n}f`).style.display = "none";
case 'A': // PWM analog
switch (gT(t).t.length) { // type length determines number of GPIO used
case 1: break;
case 2: off = "Phase shift";
if (d.Sf["CB"].value != 0) gId(`rf${n}`).checked = 0; // disable phase shifting
gId(`rf${n}`).disabled = (d.Sf["CB"].value != 0); // prevent changes
// fallthrough
default: p0d = "GPIOs:"; break;
}
// PWM CCT allows phase shifting
gId(`dig${n}f`).style.display = (gT(t).t.length != 2) ? "none" : "inline";
break;
case 'V':
case 'N': // network
p0d = "IP address:";
break;
case 'V': // virtual/non-GPIO based
p0d = "Config:"
break;
}
gId("p0d"+n).innerText = p0d;
gId("p1d"+n).innerText = p1d;
gId("off"+n).innerText = off;
// secondary pins show/hide (type string length is equivalent to number of pins used; except for virtual and on/off)
let pins = gT(t).t.length + 3*isVir(t); // fixes virtual pins to 4
if (pins == 0) pins = 1; // fixes on/off pin
// secondary pins show/hide (type string length is equivalent to number of pins used; except for network and on/off)
let pins = Math.min(gT(t).t.length,1) + 3*isNet(t); // fixes network pins to 4
for (let p=1; p<5; p++) {
var LK = d.Sf["L"+p+n];
if (!LK) continue;
@ -909,7 +916,7 @@ Swap: <select id="xw${s}" name="XW${s}">
<br>
Calculate CCT from RGB: <input type="checkbox" name="CR"><br>
CCT IC used (Athom 15W): <input type="checkbox" name="IC"><br>
CCT additive blending: <input type="number" class="s" min="0" max="100" name="CB" required> %
CCT additive blending: <input type="number" class="s" min="0" max="100" name="CB" onchange="UI()" required> %
</div>
<h3>Advanced</h3>
Palette blending: