diff --git a/platformio.ini b/platformio.ini index 14235a4a..107ab6fe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -90,6 +90,7 @@ default_envs = esp01_1MB_S esp32_16MB_M_eth athom_music_esp32_4MB_M + adafruit_matrixportal_esp32s3 ; Go to MoonModules environments for environments @@ -336,11 +337,15 @@ build_flagsV4 = -g -D CONFIG_ASYNC_TCP_USE_WDT=0 -D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 + -D NO_GFX ; Disable the use of Adafruit_GFX by the HUB75 driver + ;;; V4.4.x libraries (without LOROL_LITTLEFS; with newer NeoPixelBus) lib_depsV4 = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ;; WLEDMM this must be first in the list, otherwise Aircoookie/ESPAsyncWebServer pulls in an older version of AsyncTCP !! makuna/NeoPixelBus @ 2.7.5 ${env.lib_deps} + https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git @ 3.0.10 + ;; WLEDMM end @@ -1504,11 +1509,12 @@ build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} ; -D WLED_DEBUG ; -D SR_DEBUG ; -D MIC_LOGGER + -D WLED_ENABLE_HUB75MATRIX + lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation - ; RAM: [=== ] 25.1% (used 82176 bytes from 327680 bytes) - ; Flash: [========= ] 93.8% (used 1474893 bytes from 1572864 bytes) - + ; RAM: [=== ] 27.7% (used 90664 bytes from 327680 bytes) + ; Flash: [==========] 95.1% (used 1495497 bytes from 1572864 bytes) ; compiled with ESP-IDF 4.4.1 [env:esp32_4MB_V4_M] extends = esp32_4MB_V4_M_base @@ -1525,6 +1531,7 @@ lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation build_unflags = ${esp32_4MB_V4_M_base.build_unflags} -D USERMOD_ANIMARTRIX ;; Tips our memory usage over the limit + -D WLED_ENABLE_HUB75MATRIX ;; RAM: [=== ] 25.9% (used 84708 bytes from 327680 bytes) ;; Flash: [==========] 98.5% (used 1549033 bytes from 1572864 bytes) @@ -2276,3 +2283,26 @@ lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} ; RAM: [=== ] 25.4% (used 83144 bytes from 327680 bytes) ; Flash: [==========] 96.4% (used 1516029 bytes from 1572864 bytes) ; + + +[env:adafruit_matrixportal_esp32s3] +platform = espressif32 ; latest +board = adafruit_matrixportal_esp32s3 +extends = esp32_4MB_V4_S_base +build_unflags = ${env:esp32S3_8MB_M.build_unflags} ;; use the same as "normal" S3 buildenv +build_flags = ${common.build_flags} ${esp32s3.build_flags} -Wno-misleading-indentation -Wno-format-truncation + ${common_mm.build_flags_S} + -D WLED_RELEASE_NAME=matrixportal_esp32s3 + -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=1 ;; for Hardware-CDC USB mode + -D WLED_DISABLE_ADALIGHT ;; disables serial protocols - recommended for Hardware-CDC USB (Serial RX will receive junk commands when RX pin is unconnected, unless its pulled down by resistor) + ${common_mm.animartrix_build_flags} + ${common_mm.build_disable_sync_interfaces} + -D LOLIN_WIFI_FIX ;; try this in case Wifi does not work + -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D WLED_USE_PSRAM -DBOARD_HAS_PSRAM ; tells WLED that PSRAM shall be used + -D WLED_ENABLE_HUB75MATRIX -D NO_GFX ;-D SPIRAM_FRAMEBUFFER + -D DEFAULT_LED_TYPE=101 +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} + ${common_mm.animartrix_lib_deps} +lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation +monitor_filters = esp32_exception_decoder diff --git a/requirements.txt b/requirements.txt index 8b55606d..cca736f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ marshmallow==3.19.0 # via platformio packaging==23.1 # via marshmallow -platformio==6.1.6 +platformio==6.1.14 # via -r requirements.in pyelftools==0.29 # via platformio diff --git a/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h index b93d3dff..a33b9823 100644 --- a/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h +++ b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h @@ -96,10 +96,10 @@ class ANIMartRIXMod:public ANIMartRIX { } float speedFactor = 1.0; if (SEGMENT.speed < 128) { - speedFactor = (float) map(SEGMENT.speed, 0, 127, 1, 10) / 10.0f; + speedFactor = (float) map(SEGMENT.speed, 0, 127, 1, 100) / 100.0f; } else{ - speedFactor = map(SEGMENT.speed, 128, 255, 10, 100) / 10; + speedFactor = (float) map(SEGMENT.speed, 128, 255, 10, 100) / 10.0f; } setSpeedFactor(speedFactor); } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 14e0888a..3801c534 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -458,6 +458,232 @@ void BusNetwork::cleanup() { _data = nullptr; } +// *************************************************************************** + +#ifdef WLED_ENABLE_HUB75MATRIX + +BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { + + mxconfig.double_buff = false; // <------------- Turn on double buffer + + + fourScanPanel = nullptr; + + switch(bc.type) { + case 101: + mxconfig.mx_width = 32; + mxconfig.mx_height = 32; + break; + case 102: + mxconfig.mx_width = 64; + mxconfig.mx_height = 32; + break; + case 103: + mxconfig.mx_width = 64; + mxconfig.mx_height = 64; + break; + case 105: + mxconfig.mx_width = 32 * 2; + mxconfig.mx_height = 32 / 2; + break; + case 106: + mxconfig.mx_width = 64 * 2; + mxconfig.mx_height = 64 / 2; + break; + } + + mxconfig.chain_length = max((u_int8_t) 1, min(bc.pins[0], (u_int8_t) 4)); // prevent bad data preventing boot due to low memory + + if(mxconfig.mx_width >= 64 && (bc.pins[0] > 1)) { + USER_PRINT("WARNING, only single panel can be used of 64 pixel boards due to memory") + mxconfig.chain_length = 1; + } + + // mxconfig.driver = HUB75_I2S_CFG::SHIFTREG; + +#if defined(ARDUINO_ADAFRUIT_MATRIXPORTAL_ESP32S3) // MatrixPortal ESP32-S3 + + // https://www.adafruit.com/product/5778 + + USER_PRINTLN("MatrixPanel_I2S_DMA - Matrix Portal S3 config"); + + mxconfig.gpio.r1 = 42; + mxconfig.gpio.g1 = 41; + mxconfig.gpio.b1 = 40; + mxconfig.gpio.r2 = 38; + mxconfig.gpio.g2 = 39; + mxconfig.gpio.b2 = 37; + + mxconfig.gpio.lat = 47; + mxconfig.gpio.oe = 14; + mxconfig.gpio.clk = 2; + + mxconfig.gpio.a = 45; + mxconfig.gpio.b = 36; + mxconfig.gpio.c = 48; + mxconfig.gpio.d = 35; + mxconfig.gpio.e = 21; + +#elif defined(ESP32_FORUM_PINOUT) // Common format for boards designed for SmartMatrix + + USER_PRINTLN("MatrixPanel_I2S_DMA - ESP32_FORUM_PINOUT"); + +/* + ESP32 with SmartMatrix's default pinout - ESP32_FORUM_PINOUT + + https://github.com/pixelmatix/SmartMatrix/blob/teensylc/src/MatrixHardware_ESP32_V0.h + + Can use a board like https://github.com/rorosaurus/esp32-hub75-driver +*/ + + mxconfig.gpio.r1 = 2; + mxconfig.gpio.g1 = 15; + mxconfig.gpio.b1 = 4; + mxconfig.gpio.r2 = 16; + mxconfig.gpio.g2 = 27; + mxconfig.gpio.b2 = 17; + + mxconfig.gpio.lat = 26; + mxconfig.gpio.oe = 25; + mxconfig.gpio.clk = 22; + + mxconfig.gpio.a = 5; + mxconfig.gpio.b = 18; + mxconfig.gpio.c = 19; + mxconfig.gpio.d = 21; + mxconfig.gpio.e = 12; + +#else + USER_PRINTLN("MatrixPanel_I2S_DMA - Default pins"); + /* + https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA?tab=readme-ov-file + + Boards + + https://esp32trinity.com/ + https://www.electrodragon.com/product/rgb-matrix-panel-drive-interface-board-for-esp32-dma/ + + */ + mxconfig.gpio.r1 = 25; + mxconfig.gpio.g1 = 26; + mxconfig.gpio.b1 = 27; + mxconfig.gpio.r2 = 14; + mxconfig.gpio.g2 = 12; + mxconfig.gpio.b2 = 13; + + mxconfig.gpio.lat = 4; + mxconfig.gpio.oe = 15; + mxconfig.gpio.clk = 16; + + mxconfig.gpio.a = 23; + mxconfig.gpio.b = 19; + mxconfig.gpio.c = 5; + mxconfig.gpio.d = 17; + mxconfig.gpio.e = 18; + +#endif + + + USER_PRINTF("MatrixPanel_I2S_DMA config - %ux%u length: %u\n", mxconfig.mx_width, mxconfig.mx_height, mxconfig.chain_length); + + // OK, now we can create our matrix object + display = new MatrixPanel_I2S_DMA(mxconfig); + + this->_len = (display->width() * display->height()); + + pinManager.allocatePin(mxconfig.gpio.r1, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.g1, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.b1, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.r2, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.g2, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.b2, true, PinOwner::HUB75); + + pinManager.allocatePin(mxconfig.gpio.lat, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.oe, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.clk, true, PinOwner::HUB75); + + pinManager.allocatePin(mxconfig.gpio.a, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.b, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.c, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.d, true, PinOwner::HUB75); + pinManager.allocatePin(mxconfig.gpio.e, true, PinOwner::HUB75); + + // display->setLatBlanking(4); + + USER_PRINTLN("MatrixPanel_I2S_DMA created"); + // let's adjust default brightness + display->setBrightness8(25); // range is 0-255, 0 - 0%, 255 - 100% + + // Allocate memory and start DMA display + if( not display->begin() ) { + USER_PRINTLN("****** MatrixPanel_I2S_DMA !KABOOM! I2S memory allocation failed ***********"); + return; + } + else { + _valid = true; + } + + switch(bc.type) { + case 105: + USER_PRINTLN("MatrixPanel_I2S_DMA FOUR_SCAN_32PX_HIGH"); + fourScanPanel = new VirtualMatrixPanel((*display), 1, 1, 32, 32); + fourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_32PX_HIGH); + fourScanPanel->setRotation(0); + break; + case 106: + USER_PRINTLN("MatrixPanel_I2S_DMA FOUR_SCAN_64PX_HIGH"); + fourScanPanel = new VirtualMatrixPanel((*display), 1, 1, 64, 64); + fourScanPanel->setPhysicalPanelScanRate(FOUR_SCAN_64PX_HIGH); + fourScanPanel->setRotation(0); + break; + } + + + USER_PRINTLN("MatrixPanel_I2S_DMA started"); +} + +void BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { + r = R(c); + g = G(c); + b = B(c); + if(fourScanPanel != nullptr) { + x = pix % fourScanPanel->width(); + y = floor(pix / fourScanPanel->width()); + fourScanPanel->drawPixelRGB888(x, y, r, g, b); + } + else { + x = pix % display->width(); + y = floor(pix / display->width()); + display->drawPixelRGB888(x, y, r, g, b); + } +} + +void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { + this->display->setBrightness(b); +} + +void BusHub75Matrix::deallocatePins() { + + pinManager.deallocatePin(mxconfig.gpio.r1, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.g1, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.b1, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.r2, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.g2, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.b2, PinOwner::HUB75); + + pinManager.deallocatePin(mxconfig.gpio.lat, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.oe, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.clk, PinOwner::HUB75); + + pinManager.deallocatePin(mxconfig.gpio.a, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.b, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.c, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.d, PinOwner::HUB75); + pinManager.deallocatePin(mxconfig.gpio.e, PinOwner::HUB75); + +} +#endif +// *************************************************************************** //utility to get the approx. memory usage of a given BusConfig uint32_t BusManager::memUsage(BusConfig &bc) { @@ -483,8 +709,14 @@ uint32_t BusManager::memUsage(BusConfig &bc) { int BusManager::add(BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; + USER_PRINTF("BusManager::add(bc.type=%u)\n", bc.type); if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) { busses[numBusses] = new BusNetwork(bc); +#ifdef WLED_ENABLE_HUB75MATRIX + } else if (bc.type >= TYPE_HUB75MATRIX && bc.type <= (TYPE_HUB75MATRIX + 10)) { + USER_PRINTLN("BusManager::add - Adding BusHub75Matrix"); + busses[numBusses] = new BusHub75Matrix(bc); +#endif } else if (IS_DIGITAL(bc.type)) { busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); } else if (bc.type == TYPE_ONOFF) { diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 2f860ae1..f089b529 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -1,6 +1,10 @@ #ifndef BusManager_h #define BusManager_h +#ifdef WLED_ENABLE_HUB75MATRIX +#include +#include +#endif /* * Class for addressing various light types */ @@ -38,6 +42,7 @@ struct BusConfig { if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address else if (type > 47) nPins = 2; else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type); + else if (type >= TYPE_HUB75MATRIX && type <= (TYPE_HUB75MATRIX + 10)) nPins = 0; for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i]; } @@ -122,6 +127,7 @@ class Bus { inline bool isOk() { return _valid; } inline bool isOffRefreshRequired() { return _needsRefresh; } bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; } + virtual uint16_t getMaxPixels() { return MAX_LEDS_PER_BUS; }; virtual bool hasRGB() { if ((_type >= TYPE_WS2812_1CH && _type <= TYPE_WS2812_WWA) || _type == TYPE_ANALOG_1CH || _type == TYPE_ANALOG_2CH || _type == TYPE_ONOFF) return false; @@ -291,6 +297,7 @@ class BusNetwork : public Bus { public: BusNetwork(BusConfig &bc); + uint16_t getMaxPixels() override { return 4096; }; bool hasRGB() { return true; } bool hasWhite() { return _rgbw; } @@ -326,6 +333,54 @@ class BusNetwork : public Bus { byte *_data; }; +#ifdef WLED_ENABLE_HUB75MATRIX +class BusHub75Matrix : public Bus { + public: + BusHub75Matrix(BusConfig &bc); + + uint16_t getMaxPixels() override { return 4096; }; + + bool hasRGB() { return true; } + bool hasWhite() { return false; } + + void setPixelColor(uint16_t pix, uint32_t c); + + void show() { + if(mxconfig.double_buff) { + display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) + display->clearScreen(); // Now clear the back-buffer + } + } + + void setBrightness(uint8_t b, bool immediate); + + uint8_t getPins(uint8_t* pinArray) { + pinArray[0] = mxconfig.chain_length; + return 1; + } // Fake value due to keep finaliseInit happy + + void deallocatePins(); + + void cleanup() { + deallocatePins(); + fourScanPanel = nullptr; + // delete fourScanPanel; + delete display; + _valid = false; + } + + ~BusHub75Matrix() { + cleanup(); + } + + private: + MatrixPanel_I2S_DMA *display = nullptr; + VirtualMatrixPanel *fourScanPanel = nullptr; + HUB75_I2S_CFG mxconfig; + uint8_t r, g, b, x, y; + +}; +#endif class BusManager { public: diff --git a/wled00/const.h b/wled00/const.h index ae97beef..578e1ab0 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -243,6 +243,9 @@ #define TYPE_LPD8806 52 #define TYPE_P9813 53 #define TYPE_LPD6803 54 + +#define TYPE_HUB75MATRIX 100 // 100 - 110 + //Network types (master broadcast) (80-95) #define TYPE_NET_DDP_RGB 80 //network DDP RGB bus (master broadcast bus) #define TYPE_NET_E131_RGB 81 //network E131 RGB bus (master broadcast bus, unused) diff --git a/wled00/data/index.js b/wled00/data/index.js index c8159d9e..3ea998e3 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -3210,7 +3210,8 @@ function genPresets() var playlistSep = JSON.parse("{}"); var playlistDur = JSON.parse("{}"); var playlistTrans = JSON.parse("{}"); - function addToPlaylist(m, id) { + var playlistQL = JSON.parse("{}"); + function addToPlaylist(m, id, ql = undefined) { if (!playlistPS[m]) playlistPS[m] = ""; if (!playlistDur[m]) playlistDur[m] = ""; if (!playlistTrans[m]) playlistTrans[m] = ""; @@ -3219,7 +3220,9 @@ function genPresets() playlistDur[m] += playlistSep[m] + "100"; playlistTrans[m] += playlistSep[m] + "7"; playlistSep[m] = ","; + if(ql) playlistQL[m] = `${ql}`; } + var seq=230; //Playlist start here for (let ef of effects) { if (ef.name.indexOf("RSVD") < 0) { if (Array.isArray(fxdata) && fxdata.length>ef.id) { @@ -3257,18 +3260,26 @@ function genPresets() } result += `${sep}"${ef.id}":{"n":"${ef.name}","mainseg":0,"seg":[{"id":0,"fx":${ef.id}${defaultString}}]}`; sep = "\n,"; - addToPlaylist(m, ef.id); - addToPlaylist("All", ef.id); - if (m.includes("1")) addToPlaylist("All1", ef.id); - if (m.includes("2")) addToPlaylist("All2", ef.id); + if(m.length <= 3) { + addToPlaylist(m, ef.id, m); + } + else { + addToPlaylist(m, ef.id); + } + addToPlaylist("All", ef.id, "ALL"); + if(ef.name.startsWith("Y💡")) addToPlaylist("AnimARTrix", ef.id, "AM"); + if (m.includes("1")) addToPlaylist("All 1D", ef.id, "1D"); + if (m.includes("2")) addToPlaylist("All 2D", ef.id, "2D"); + + seq = Math.max(seq, (parseInt(ef.id) + 1)); } //fxdata is array } //not RSVD } //all effects - var seq=230; //Playlist start here // console.log(playlistPS, playlistDur, playlistTrans); for (const m in playlistPS) { - let playListString = `\n,"${seq}":{"n":"${m}D Playlist","ql":"${seq}","on":true,"playlist":{"ps":[${playlistPS[m]}],"dur":[${playlistDur[m]}],"transition":[${playlistTrans[m]}],"repeat":0,"end":0,"r":1}}`; + if(!playlistQL[m]) playlistQL[m] = seq; + let playListString = `\n,"${seq}":{"n":"${m} Playlist","ql":"${playlistQL[m]}","on":true,"playlist":{"ps":[${playlistPS[m]}],"dur":[${playlistDur[m]}],"transition":[${playlistTrans[m]}],"repeat":0,"end":0,"r":1}}`; // console.log(playListString); result += playListString; seq++; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 42f629fa..e1979fdc 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -16,6 +16,19 @@ function B(){window.open("/settings","_self");} function gId(n){return d.getElementById(n);} function hideNoIR(){gId("irOnOff2").style.display="none";} //WLEDMM + function hideHub75() { + var s = d.getElementsByTagName("select"); + for (i=0; i 0; j--) { + var t = parseInt(selectobject.options[j].value); + if(t >= 100 && t <= 110) selectobject.remove(j); + } + } + } + } function off(n){d.getElementsByName(n)[0].value = -1;} // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript function loadJS(FILE_URL, async = true) { @@ -47,10 +60,14 @@ x.style.animation = 'none'; timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900); } - function bLimits(b,v,p,m,l) { - maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l; + function bLimits(b,v,m,l) { + maxB = b; maxV = v; maxM = m; maxL = l; } - function pinsOK() { + function setPixelLimit(i, max) { + var lc = d.getElementsByName("LC"+i)[0]; + lc.max = max; + } + function pinsOK() { var LCs = d.getElementsByTagName("input"); for (i=0; i=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:"; + gId("p0d"+n).innerHTML = (t >= 100 && t < 110) ? "Chain Length:" : (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:"; gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : ""; var LK = d.getElementsByName("L1"+n)[0]; // clock pin @@ -174,7 +191,13 @@ for (p=1; p<5; p++) { var LK = d.getElementsByName("L"+p+n)[0]; // secondary pins if (!LK) continue; - if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h + if(t >= 100 && t < 110) { + // hide pin field + LK.style.display = "none"; + LK.required = false; + LK.value=""; + } + else if (((t>=80 && t<96) && p<4) || (t>49 && p==1) || (t>41 && t < 50 && (p+40 < t))) // TYPE_xxxx values from const.h { // display pin field LK.style.display = "inline"; @@ -192,15 +215,15 @@ } gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814 gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h - gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide color order for PWM + gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)||(t >= 100 && t < 110)) ? "none":"inline"; // hide color order for PWM gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown if (!(t > 28 && t < 32)) d.getElementsByName("WO"+n)[0].value = 0; // reset swapping - gId("dig"+n+"c").style.display = (t >= 40 && t < 48) ? "none":"inline"; // hide count for analog - gId("dig"+n+"r").style.display = (t >= 80 && t < 96) ? "none":"inline"; // hide reversed for virtual - gId("dig"+n+"s").style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog + gId("dig"+n+"c").style.display = ((t >= 40 && t < 48)||(t >= 100 && t < 110)) ? "none":"inline"; // hide count for analog and HUB75 + gId("dig"+n+"r").style.display = (t >= 80) ? "none":"inline"; // hide reversed for virtual + gId("dig"+n+"s").style.display = ((t >= 80) || (t >= 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog gId("dig"+n+"f").style.display = ((t >= 16 && t < 32) || (t >= 50 && t < 64)) ? "inline":"none"; // hide refresh gId("dig"+n+"a").style.display = (isRGBW && t != 40) ? "inline":"none"; // auto calculate white - gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed + gId("dig"+n+"l").style.display = ((t > 48 && t < 64) && !(t >= 100 && t < 110)) ? "inline":"none"; // bus clock speed gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description } @@ -357,6 +380,11 @@ ${i+1}: + + + + +
Color Order: