Merge branch 'MoonModules:mdev' into Strip_Level_Color_Adjust

This commit is contained in:
Troy
2024-06-06 11:57:03 -04:00
committed by GitHub
21 changed files with 595 additions and 218 deletions

View File

@@ -22,6 +22,88 @@ def _create_dirs(dirs=["firmware", "map"]):
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
os.mkdir("{}{}".format(OUTPUT_DIR, d))
# trick for py2/3 compatibility
if 'basestring' not in globals():
basestring = str
# WLEDMM : custom print function
def print_my_item(items, flag = False):
if flag: print(" -D", end='')
else: print(" ", end='')
if isinstance(items, basestring):
# print a single string
print(items, end='')
else:
# print a list
first = True
for item in items:
if not first: print("=", end='')
print(item, end='')
first = False
# WLEDMM : dump out buildflags : usermods, disable, enable, use_..
def wledmm_print_build_info(env):
all_flags = env["CPPDEFINES"]
first = True
found = False
for item in all_flags:
if 'WLED_RELEASE_NAME' in item[0] or 'WLED_VERSION' in item[0] or 'ARDUINO_USB_CDC_ON_BOOT' in item[0]:
if first: print("\nUsermods and Features:")
print_my_item(item)
first = False
found = True
if found: print("")
found = False
for item in all_flags:
if 'USERMOD_' in item or 'UM_' in item:
if first: print("\nUsermods and Features:")
print_my_item(item)
first = False
found = True
if found: print("")
found = False
for item in all_flags:
if 'WLED_DISABLE' in item or 'WIFI_FIX' in item:
if first: print("\nUsermods and Features:")
print_my_item(item)
first = False
found = True
if found: print("")
found = False
for item in all_flags:
if 'WLED_' in item or 'WLED_' in item[0] or 'MAX_LED' in item[0]:
if not 'WLED_RELEASE_NAME' in item[0] and not 'WLED_VERSION' in item[0] and not 'WLED_WATCHDOG_TIMEOUT' in item[0] and not 'WLED_DISABLE' in item and not 'WLED_USE_MY_CONFIG' in item and not 'ARDUINO_PARTITION' in item:
if first: print("\nUsermods and Features:")
print_my_item(item)
first = False
found = True
if found: print("")
first = True
found = False
for item in all_flags:
if 'WLEDMM_' in item[0] or 'WLEDMM_' in item or 'TROYHACKS' in item:
if first: print("\nWLEDMM Features:")
print_my_item(item)
first = False
found = True
if found: print("\n")
def wledmm_print_all_defines(env):
all_flags = env["CPPDEFINES"]
found = False
for item in all_flags:
if not found: print("\nBuild Flags:")
print_my_item(item, True)
found = True
if found: print("\n")
def bin_rename_copy(source, target, env):
_create_dirs()
variant = env["PIOENV"]
@@ -56,6 +138,9 @@ def bin_rename_copy(source, target, env):
print(f"Found linker mapfile {source_map}")
shutil.copy(source_map, map_file)
# wledmm_print_all_defines(env)
# wledmm_print_build_info(env)
def bin_gzip(source, target, env):
_create_dirs()
variant = env["PIOENV"]

View File

@@ -305,6 +305,8 @@ build_flags = -g
-D CONFIG_ASYNC_TCP_TASK_STACK_SIZE=9472 ;; WLEDMM increase stack by 1.25Kb, as audioreactive needs bigger SETTINGS_STACK_BUF_SIZE
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
-D LOROL_LITTLEFS
; -D WLEDMM_TWOPATH ;; use I2S1 as the second bus --> ~15% faster on "V3" builds - may flicker a bit more
; -D WLEDMM_SLOWPATH ;; don't use I2S for LED bus
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv ;; WLED standard for 4MB flash: 1.4MB firmware, 1MB filesystem
@@ -322,6 +324,7 @@ lib_deps =
; WLEDMM specific: use patched version of lorol LittleFS
https://github.com/softhack007/LITTLEFS-threadsafe.git#master
makuna/NeoPixelBus @ 2.7.5
;; makuna/NeoPixelBus @ 2.7.9 ;; experimental
${env.lib_deps}
;; Compatibility with upstream --> you should prefer using ${common_mm.build_flags_S} and ${common_mm.lib_deps_S}
@@ -348,6 +351,8 @@ build_flagsV4 = -g
-DCONFIG_LITTLEFS_FOR_IDF_3_2 -DLFS_THREADSAFE
-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
; -D WLEDMM_TWOPATH ;; use I2S1 as the second bus --> slightly faster on some setups
; -D WLEDMM_SLOWPATH ;; don't use I2S for LED bus
; -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
@@ -355,6 +360,7 @@ build_flagsV4 = -g
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
;; makuna/NeoPixelBus @ 2.7.9 ;; experimental
${common_mm.HUB75_lib_deps}
${env.lib_deps}
@@ -376,10 +382,13 @@ build_flags = -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 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
; -D WLEDMM_TWOPATH ;; use I2S1 as the second bus --> slightly faster on some setups
; -D WLEDMM_SLOWPATH ;; don't use I2S for LED bus
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
makuna/NeoPixelBus @ 2.7.5
;; makuna/NeoPixelBus @ 2.7.9 ;; experimental
${env.lib_deps}
[esp32s2]
@@ -406,7 +415,8 @@ build_flags = -g
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
makuna/NeoPixelBus @ 2.7.5
;; makuna/NeoPixelBus @ 2.7.5 ;; standard
makuna/NeoPixelBus @ 2.7.9 ;; experimental - reduces LED glitches on -S2
${env.lib_deps}
[esp32c3]
@@ -428,6 +438,7 @@ build_flags = -g
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
makuna/NeoPixelBus @ 2.7.5
;; makuna/NeoPixelBus @ 2.7.9 ;; experimental
${env.lib_deps}
[esp32s3]
@@ -449,6 +460,7 @@ build_flags = -g
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
makuna/NeoPixelBus @ 2.7.5
;; makuna/NeoPixelBus @ 2.7.9 ;; experimental
${env.lib_deps}
@@ -2464,16 +2476,23 @@ lib_ignore =
[env:adafruit_matrixportal_esp32s3]
; ESP32-S3 processor, 8 MB flash, 2 MB of PSRAM, dedicated driver pins for HUB75
extends = esp32_4MB_V4_M_base
platform = ${esp32.platformV4_xp} ;; 6.5.0 = first platform release supporting matrixportal
platform_packages = ${esp32.platformV4_packages_xp} ;; arduino-esp32 2.0.14 needed - previous versions were missing files for matrixportal
board = adafruit_matrixportal_esp32s3
board_build.partitions = ${esp32.large_partitions}
board_build.f_flash = 80000000L
board_build.flash_mode = qio
build_unflags = ${env:esp32S3_8MB_M.build_unflags} ;; use the same as "normal" S3 buildenv
-D ARDUINO_USB_CDC_ON_BOOT=1 ;; fix warning: "ARDUINO_USB_CDC_ON_BOOT" redefined; comment out for Serial debug
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
; Serial debug enabled -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 ARDUINO_USB_CDC_ON_BOOT=0
-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}

View File

@@ -543,6 +543,8 @@ void show_psram_info_part2(void)
void showRealSpeed() {
//Serial.begin(115200);
if (!Serial) return; // Avoid writing to unconnected USB-CDC
Serial.flush();
Serial.println(F("\n"));
for(int aa=0; aa<65; aa++) Serial.print("="); Serial.println();

View File

@@ -1,5 +1,24 @@
#pragma once
/*
@title MoonModules WLED - audioreactive usermod
@file audio_reactive.h
@repo https://github.com/MoonModules/WLED, submit changes to this file as PRs to MoonModules/WLED
@Authors https://github.com/MoonModules/WLED/commits/mdev/
@Copyright © 2024 Github MoonModules Commit Authors (contact moonmodules@icloud.com for details)
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
This file is part of the MoonModules WLED fork also known as "WLED-MM".
WLED-MM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
WLED-MM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with WLED-MM. If not, see <https://www.gnu.org/licenses/>.
*/
#include "wled.h"
#ifdef ARDUINO_ARCH_ESP32
@@ -353,9 +372,6 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul
// These are the input and output vectors. Input vectors receive computed results from FFT.
static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins
static float vImag[samplesFFT] = {0.0f}; // imaginary parts
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
static float windowWeighingFactors[samplesFFT] = {0.0f};
#endif
#ifdef FFT_MAJORPEAK_HUMAN_EAR
static float pinkFactors[samplesFFT] = {0.0f}; // "pink noise" correction factors
@@ -381,7 +397,14 @@ constexpr float binWidth = SAMPLE_RATE / (float)samplesFFT; // frequency range o
#include <arduinoFFT.h>
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, windowWeighingFactors);
#if defined(FFT_LIB_REV) && FFT_LIB_REV > 0x19
// arduinoFFT 2.x has a slightly different API
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, true);
#else
// recommended version optimized by @softhack007 (API version 1.9)
static float windowWeighingFactors[samplesFFT] = {0.0f}; // cache for FFT windowing factors
static ArduinoFFT<float> FFT = ArduinoFFT<float>( vReal, vImag, samplesFFT, SAMPLE_RATE, windowWeighingFactors);
#endif
#else
static arduinoFFT FFT = arduinoFFT(vReal, vImag, samplesFFT, SAMPLE_RATE);
#endif
@@ -627,9 +650,14 @@ void FFTcode(void * parameter)
#endif
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
FFT.majorPeak(FFT_MajorPeak, FFT_Magnitude); // let the effects know which freq was most dominant
#if defined(FFT_LIB_REV) && FFT_LIB_REV > 0x19
// arduinoFFT 2.x has a slightly different API
FFT.majorPeak(&FFT_MajorPeak, &FFT_Magnitude);
#else
FFT.MajorPeak(&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant
FFT.majorPeak(FFT_MajorPeak, FFT_Magnitude); // let the effects know which freq was most dominant
#endif
#else
FFT.MajorPeak(&FFT_MajorPeak, &FFT_Magnitude);
#endif
if (FFT_MajorPeak < (SAMPLE_RATE / samplesFFT)) {FFT_MajorPeak = 1.0f; FFT_Magnitude = 0;} // too low - use zero
@@ -921,7 +949,7 @@ static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels) // p
if (post_gain < 1.0f) post_gain = ((post_gain -1.0f) * 0.8f) +1.0f;
currentResult *= post_gain;
}
fftResult[i] = constrain((int)currentResult, 0, 255);
fftResult[i] = max(min((int)(currentResult+0.5f), 255), 0); // +0.5 for proper rounding
}
}
////////////////////
@@ -1571,7 +1599,7 @@ class AudioReactive : public Usermod {
transmitData.zeroCrossingCount = zeroCrossingCount;
for (int i = 0; i < NUM_GEQ_CHANNELS; i++) {
transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254);
transmitData.fftResult[i] = fftResult[i];
}
transmitData.FFT_Magnitude = my_magnitude;

View File

@@ -1,4 +1,25 @@
#pragma once
/*
@title MoonModules WLED - audioreactive usermod
@file audio_source.h
@repo https://github.com/MoonModules/WLED, submit changes to this file as PRs to MoonModules/WLED
@Authors https://github.com/MoonModules/WLED/commits/mdev/
@Copyright © 2024 Github MoonModules Commit Authors (contact moonmodules@icloud.com for details)
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
This file is part of the MoonModules WLED fork also known as "WLED-MM".
WLED-MM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
WLED-MM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with WLED-MM. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef ARDUINO_ARCH_ESP32
#include <Wire.h>
#include "wled.h"

View File

@@ -1,5 +1,25 @@
#pragma once
/*
@title MoonModules WLED - auto-playlist usermod
@file usermod_v2_auto_playlist.h
@repo https://github.com/MoonModules/WLED, submit changes to this file as PRs to MoonModules/WLED
@Authors https://github.com/MoonModules/WLED/commits/mdev/
@Copyright © 2024 Github MoonModules Commit Authors (contact moonmodules@icloud.com for details)
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
This file is part of the MoonModules WLED fork also known as "WLED-MM".
WLED-MM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
WLED-MM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with WLED-MM. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef WLED_DEBUG
#ifndef USERMOD_AUTO_PLAYLIST_DEBUG
#define USERMOD_AUTO_PLAYLIST_DEBUG
@@ -302,6 +322,8 @@ class AutoPlaylistUsermod : public Usermod {
if (bri == 0) return;
if(!functionality_enabled) return;
um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {

View File

@@ -1333,12 +1333,12 @@ uint16_t mode_fire_flicker(void) {
byte r = (SEGCOLOR(0) >> 16);
byte g = (SEGCOLOR(0) >> 8);
byte b = (SEGCOLOR(0) );
byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
byte lum = (SEGMENT.palette == 0) ? max(w, max(r, max(g, b))) : 255;
lum /= (((256-SEGMENT.intensity)/16)+1);
for (int i = 0; i < SEGLEN; i++) {
byte flicker = random8(lum);
if (SEGMENT.palette == 0) {
SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0));
SEGMENT.setPixelColor(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0));
} else {
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker));
}
@@ -1369,7 +1369,7 @@ uint16_t gradient_base(bool loading) {
{
val = abs(((i>pp) ? p2:pp) -i);
} else {
val = MIN(abs(pp-i),MIN(abs(p1-i),abs(p2-i)));
val = min(abs(pp-i), min(abs(p1-i), abs(p2-i)));
}
val = (brd > val) ? val/brd * 255 : 255;
SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val));
@@ -2129,7 +2129,7 @@ uint16_t mode_fire_2012() {
// Step 4. Map from heat cells to LED colors
for (int j = 0; j < SEGLEN; j++) {
SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, MIN(heat[j],240), 255, NOBLEND));
SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j],byte(240)), 255, NOBLEND));
}
}
};
@@ -2971,7 +2971,7 @@ uint16_t mode_bouncing_balls(void) {
uint32_t color = SEGCOLOR(0);
if (SEGMENT.palette) {
color = SEGMENT.color_wheel(i*(256/MAX(numBalls, 8)));
color = SEGMENT.color_wheel(i*(256/max(numBalls, uint16_t(8))));
} else if (hasCol2) {
color = SEGCOLOR(i % NUM_COLORS);
}
@@ -3696,6 +3696,7 @@ uint16_t mode_drip(void)
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
if (SEGENV.call == 0) SEGMENT.fill(BLACK); // WLEDMM clear LEDs at startup
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
struct virtualStrip {
@@ -3703,9 +3704,9 @@ uint16_t mode_drip(void)
uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
float gravity = -0.0005 - (SEGMENT.speed/25000.0); //increased gravity (50000 to 25000)
gravity *= max(1, SEGLEN-1);
int sourcedrop = 12;
float gravity = -0.0005f - (float(SEGMENT.speed)/35000.0f); //increased gravity (50000 to 35000)
gravity *= min(max(1, SEGLEN-1), 255); //WLEDMM speed limit 255
const int sourcedrop = 12;
for (int j=0;j<numDrops;j++) {
if (drops[j].colIndex == 0) { //init
@@ -3724,24 +3725,26 @@ uint16_t mode_drip(void)
drops[j].col += map(SEGMENT.custom1, 0, 255, 1, 6); // swelling
if (random16() <= drops[j].col * SEGMENT.custom1 * SEGMENT.custom1 / 10 / 128) { // random drop
uint32_t fallrate = (drops[j].col * (1 + SEGMENT.custom1 * SEGMENT.custom1)) / 192; // WLEDMM specific
if (random16() <= (fallrate / 10)) { // random drop => 1% ... 20% probalibity
drops[j].colIndex=2; //fall
drops[j].col=255;
}
}
if (drops[j].colIndex > 1) { // falling
if (drops[j].pos > 0) { // fall until end of segment
if (drops[j].pos > 0.01f) { // fall until end of segment
drops[j].pos += drops[j].vel;
if (drops[j].pos < 0) drops[j].pos = 0;
drops[j].vel += gravity; // gravity is negative
for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
int intPos = roundf(drops[j].pos) +i; // WLEDMM round it first
uint16_t pos = constrain(intPos, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally // WLEDMM bad cast to uint16_t removed
SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,dropColor,drops[j].col/i)); //spread pixel with fade while falling
}
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(dropColor,BLACK,drops[j].col));
SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(dropColor,BLACK, (2 * drops[j].col)/3)); // WLEDMM reduced brightness
}
} else { // we hit bottom
if (drops[j].colIndex > 2) { // already hit once, so back to forming
@@ -3768,7 +3771,7 @@ uint16_t mode_drip(void)
return FRAMETIME;
}
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,,,,,Overlay;!,!;!;1.5d;m12=1"; //bar WLEDMM 1.5d
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,Fall ratio,,,,Overlay;!,!;!;1.5d;c1=127,m12=1"; //bar WLEDMM 1.5d
/*
@@ -5096,25 +5099,25 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline
SEGMENT.fill(BLACK);
}
uint16_t xscale = SEGMENT.intensity*4;
uint32_t yscale = SEGMENT.speed*8;
uint8_t indexx = 0;
unsigned xscale = SEGMENT.intensity*4;
unsigned yscale = SEGMENT.speed*8;
unsigned indexx = 0;
SEGPALETTE = CRGBPalette16( CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0), CRGB(0,0,0),
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::DarkOrange,
CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange,
CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow);
CRGBPalette16 pal = SEGMENT.check1 ? SEGPALETTE : CRGBPalette16(CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black,
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::DarkOrange,
CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange,
CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow);
for (int j=0; j < cols; j++) {
for (int i=0; i < rows; i++) {
indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map.
SEGMENT.setPixelColorXY(j, i, ColorFromPalette(SEGPALETTE, min(i*(indexx)>>4, 255), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map.
SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*(indexx)>>4, 255U), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
} // for i
} // for j
return FRAMETIME;
} // mode_2Dfirenoise()
static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y scale;;!;2;pal=0"; //WLEDMM pal=0
static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y scale,,,,Palette;;!;2;pal=0"; //WLEDMM pal=0
//////////////////////////////
@@ -5147,117 +5150,191 @@ static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y f
///////////////////////////////////////////
// 2D Cellular Automata Game of life //
///////////////////////////////////////////
typedef struct ColorCount {
CRGB color;
int8_t count;
} colorCount;
uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color
static bool getBitValue(const uint8_t* byteArray, size_t n) {
size_t byteIndex = n / 8;
size_t bitIndex = n % 8;
uint8_t byte = byteArray[byteIndex];
return (byte >> bitIndex) & 1;
}
static void setBitValue(uint8_t* byteArray, size_t n, bool value) {
size_t byteIndex = n / 8;
size_t bitIndex = n % 8;
if (value)
byteArray[byteIndex] |= (1 << bitIndex);
else
byteArray[byteIndex] &= ~(1 << bitIndex);
}
// create game of life struct to hold cells and future cells
struct gameOfLife {
uint8_t* cells;
uint8_t* futureCells;
uint8_t gliderLength;
uint16_t oscillatorCRC;
uint16_t spaceshipCRC;
};
uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/
// and https://github.com/DougHaber/nlife-color , Modified By: Brandon Butler
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled
const uint16_t crcBufferLen = 2; //(SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi)
const size_t dataSize = (SEGMENT.length() / 8) + (((SEGMENT.length() % 8) != 0) ? 1 : 0); // add one byte when extra bits needed (length not a multiple of 8)
const size_t totalSize = dataSize*2 + sizeof(gameOfLife);
if (!SEGENV.allocateData(dataSize + sizeof(uint16_t)*crcBufferLen)) return mode_static(); //allocation failed
CRGB *prevLeds = reinterpret_cast<CRGB*>(SEGENV.data);
uint16_t *crcBuffer = reinterpret_cast<uint16_t*>(SEGENV.data + dataSize);
if (!SEGENV.allocateData(totalSize)) return mode_static(); //allocation failed
gameOfLife* gol = reinterpret_cast<gameOfLife*>(SEGENV.data);
CRGB backgroundColor = SEGCOLOR(1);
if (SEGENV.call == 0) SEGMENT.setUpLeds();
if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
SEGENV.step = strip.now;
SEGENV.aux0 = 0;
random16_set_seed(strip.now>>2); //seed the random generator
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
uint8_t state = random8()%2;
if (state == 0)
SEGMENT.setPixelColorXY(x,y, backgroundColor);
else
SEGMENT.setPixelColorXY(x,y, !SEGMENT.check1?SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0): random16()*random16()); //WLEDMM support all colors
}
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black;
memset(crcBuffer, 0, sizeof(uint16_t)*crcBufferLen);
} else if (strip.now - SEGENV.step < FRAMETIME_FIXED * (uint32_t)map(SEGMENT.speed,0,255,64,4)) {
// update only when appropriate time passes (in 42 FPS slots)
return FRAMETIME;
if (gol->cells == nullptr) {
gol->cells = new uint8_t[dataSize];
gol->futureCells = new uint8_t[dataSize];
}
//copy previous leds (save previous generation)
//NOTE: using lossy getPixelColor() is a benefit as endlessly repeating patterns will eventually fade out causing a reset
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) prevLeds[XY(x,y)] = SEGMENT.getPixelColorXY(x,y);
uint16_t &generation = SEGENV.aux0; //rename aux0 and aux1 for readability (not needed)
uint16_t &pauseFrames = SEGENV.aux1;
CRGB backgroundColor = SEGCOLOR(1);
CRGB color;
//calculate new leds
if (SEGENV.call == 0) {
SEGMENT.setUpLeds();
SEGMENT.fill(BLACK); // to make sure that segment buffer and physical leds are aligned initially
}
//start new game of life
if ((SEGENV.call == 0 || generation == 0) && pauseFrames == 0) {
SEGENV.step = strip.now; // .step = previous call time
generation = 1;
pauseFrames = 75; // show initial state for longer
random16_set_seed(strip.now>>2); //seed the random generator
//Setup Grid
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
uint8_t state = (random8() < 82) ? 1 : 0; // ~32% chance of being alive
if (state == 0) {
setBitValue(gol->cells, y * cols + x, false);
setBitValue(gol->futureCells, y * cols + x, false);
if (SEGMENT.check2) continue;
SEGMENT.setPixelColorXY(x,y, !SEGMENT.check1?backgroundColor : RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0));
}
else {
setBitValue(gol->cells, y * cols + x, true);
setBitValue(gol->futureCells, y * cols + x, true);
color = SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0);
SEGMENT.setPixelColorXY(x,y,!SEGMENT.check1?color : RGBW32(color.r, color.g, color.b, 0));
}
}
//Clear CRCs
gol->oscillatorCRC = 0;
gol->spaceshipCRC = 0;
//Calculate glider length LCM(rows,cols)*4
uint8_t a = rows;
uint8_t b = cols;
while (b) {
uint8_t t = b;
b = a % b;
a = t;
}
gol->gliderLength = cols * rows / a * 4;
return FRAMETIME;
}
//Redraw immediately if overlay to avoid flicker
if (SEGMENT.check2) {
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
//redraw foreground/alive
if (getBitValue(gol->cells, y * cols + x)) {
color = SEGMENT.getPixelColorXY(x,y);
SEGMENT.setPixelColorXY(x,y, !SEGMENT.check1?color : RGBW32(color.r, color.g, color.b, 0));
}
}
}
if (pauseFrames || strip.now - SEGENV.step < FRAMETIME_FIXED * (uint32_t)map(SEGMENT.speed,0,255,64,2)) {
if(pauseFrames) pauseFrames--;
return FRAMETIME; //skip if not enough time has passed
}
//Update Game of Life
bool cellChanged = false; // Detect still live and dead grids
//cell index and coordinates
uint16_t cIndex;
uint16_t cX;
uint16_t cY;
//Loop through all cells. Count neighbors, apply rules, setPixel
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
byte neighbors = 0;
byte colorCount = 0; //track number of valid colors
CRGB nColors[3]; // track 3 colors, dying cells may overwrite but this wont be used
colorCount colorsCount[9]; // count the different colors in the 3*3 matrix
for (int i=0; i<9; i++) colorsCount[i] = {backgroundColor, 0}; // init colorsCount
// iterate through neighbors and count them and their different colors
int neighbors = 0;
for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { // iterate through 3*3 matrix
if (i==0 && j==0) continue; // ignore itself
// wrap around segment
int16_t xx = x+i, yy = y+j;
if (x+i < 0) xx = cols-1; else if (x+i >= cols) xx = 0;
if (y+j < 0) yy = rows-1; else if (y+j >= rows) yy = 0;
uint16_t xy = XY(xx, yy); // previous cell xy to check
// count different neighbours and colors
if (prevLeds[xy] != backgroundColor) {
neighbors++;
bool colorFound = false;
int k;
for (k=0; k<9 && colorsCount[i].count != 0; k++)
if (colorsCount[k].color == prevLeds[xy]) {
colorsCount[k].count++;
colorFound = true;
}
if (!colorFound) colorsCount[k] = {prevLeds[xy], 1}; //add new color found in the array
if (!SEGMENT.check3 || generation % 1500 == 0) { //no wrap disable wrap every 1500 generations to prevent undetected repeats
cX = x+i;
cY = y+j;
if (cX < 0 || cY < 0 || cX >= cols || cY >= rows) continue; //skip if out of bounds
} else { //wrap around
cX = (x+i+cols) % cols;
cY = (y+j+rows) % rows;
}
} // i,j
cIndex = cY * cols + cX;
// count neighbors and store upto 3 neighbor colors
if (getBitValue(gol->cells, cIndex)) { //if alive
neighbors++;
color = SEGMENT.getPixelColorXY(cX, cY);
if (color == backgroundColor) continue; //parent just died, color lost
nColors[colorCount%3] = color;
colorCount++;
}
}
// Rules of Life
CRGB preCol = prevLeds[XY(x,y)];
uint32_t col = RGBW32(preCol.r, preCol.g, preCol.b, 0); // WLEDMM explicit color conversion CRGB -> RGB
uint32_t bgc = RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0);
if ((col != bgc) && (neighbors < 2)) SEGMENT.setPixelColorXY(x,y, bgc); // Loneliness
else if ((col != bgc) && (neighbors > 3)) SEGMENT.setPixelColorXY(x,y, bgc); // Overpopulation
else if ((col == bgc) && (neighbors == 3)) { // Reproduction
bool cellValue = getBitValue(gol->cells, y * cols + x);
if ((cellValue) && (neighbors < 2 || neighbors > 3)) {
// Loneliness or overpopulation
cellChanged = true;
setBitValue(gol->futureCells, y * cols + x, false);
if (!SEGMENT.check2) SEGMENT.setPixelColorXY(x,y, !SEGMENT.check1?backgroundColor : RGBW32(backgroundColor.r, backgroundColor.g, backgroundColor.b, 0));
}
else if (!(cellValue) && (neighbors == 3)) {
// Reproduction
setBitValue(gol->futureCells, y * cols + x, true);
cellChanged = true;
// find dominant color and assign it to a cell
colorCount dominantColorCount = {backgroundColor, 0};
for (int i=0; i<9 && colorsCount[i].count != 0; i++)
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
// assign the dominant color w/ a bit of randomness to avoid "gliders"
if (dominantColorCount.count > 0 && random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color);
} else if ((col == bgc) && (neighbors == 2) && !random8(128)) { // Mutation
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255));
}
// else do nothing!
} //x,y
// no longer storing colors, if parent dies the color is lost
CRGB dominantColor;
if (colorCount == 3) { //All parents survived
if ((nColors[0] == nColors[1]) || (nColors[0] == nColors[2])) dominantColor = nColors[0];
else if (nColors[1] == nColors[2]) dominantColor = nColors[1];
else dominantColor = nColors[random8()%3];
}
else if (colorCount == 2) dominantColor = nColors[random8()%2]; // 1 leading parent died
else if (colorCount == 1) dominantColor = nColors[0]; // 2 leading parents died
else dominantColor = color; // all parents died last used color
// mutate color chance
if (random8() < SEGMENT.intensity) dominantColor = !SEGMENT.check1?SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0): random16()*random16();
if (SEGMENT.check1) dominantColor = RGBW32(dominantColor.r, dominantColor.g, dominantColor.b, 0); //WLEDMM support all colors
SEGMENT.setPixelColorXY(x,y, dominantColor);
}
}
//update cell values
memcpy(gol->cells, gol->futureCells, dataSize);
// Get current crc value
uint16_t crc = crc16((const unsigned char*)gol->cells, dataSize);
// calculate CRC16 of leds
uint16_t crc = crc16((const unsigned char*)prevLeds, dataSize);
// check if we had same CRC and reset if needed
bool repetition = false;
for (int i=0; i<crcBufferLen && !repetition; i++) repetition = (crc == crcBuffer[i]); // (Ewowi)
// same CRC would mean image did not change or was repeating itself
// -> softhack007: not exacly. Different CRC means different image; same CRC means nothing (could be same or slightly different).
if (!repetition) SEGENV.step = strip.now; //if no repetition avoid reset
// remember CRCs across frames
crcBuffer[SEGENV.aux0] = crc;
++SEGENV.aux0 %= crcBufferLen;
if (!cellChanged || crc == gol->oscillatorCRC || crc == gol->spaceshipCRC) repetition = true; //check if cell changed this gen and compare previous stored crc values
if (repetition) {
generation = 0; // reset on next call
pauseFrames = 50;
return FRAMETIME;
}
// Update CRC values
if (generation % 16 == 0) gol->oscillatorCRC = crc;
if (generation % gol->gliderLength == 0) gol->spaceshipCRC = crc;
generation++;
SEGENV.step = strip.now;
return FRAMETIME;
} // mode_2Dgameoflife()
static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!,,,,,All colors ☾;!,!;!;2;c1=0"; //WLEDMM support all colors
static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!,Color Mutation ☾,,,,All Colors ☾,Overlay ☾,Wrap ☾,;!,!;!;2;sx=200,ix=12,c1=0,o3=1";
/////////////////////////
// 2D Hiphotic //
@@ -5956,19 +6033,20 @@ static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur;;!;2
// 2D Crazy Bees //
/////////////////////////
//// Crazy bees by stepko (c)12.02.21 [https://editor.soulmatelights.com/gallery/651-crazy-bees], adapted by Blaz Kristan (AKA blazoncek)
#define MAX_BEES 5
constexpr uint_fast16_t MAX_BEES = 5;
uint16_t mode_2Dcrazybees(void) {
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint_fast16_t cols = SEGMENT.virtualWidth();
const uint_fast16_t rows = SEGMENT.virtualHeight();
byte n = MIN(MAX_BEES, (rows * cols) / 256 + 1);
const byte n = min(MAX_BEES, (rows * cols) / 256 + 1);
typedef struct Bee {
uint8_t posX, posY, aimX, aimY, hue;
int8_t deltaX, deltaY, signX, signY, error;
void aimed(uint16_t w, uint16_t h) {
int8_t signX, signY;
int16_t deltaX, deltaY, error;
void aimed(uint_fast16_t w, uint_fast16_t h) {
if (!true) //WLEDMM SuperSync
random16_set_seed(strip.now);
aimX = random8(0, w);
@@ -6009,7 +6087,7 @@ uint16_t mode_2Dcrazybees(void) {
SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY - 1, CHSV(bee[i].hue, 255, 255));
if (bee[i].posX != bee[i].aimX || bee[i].posY != bee[i].aimY) {
SEGMENT.setPixelColorXY(bee[i].posX, bee[i].posY, CRGB(CHSV(bee[i].hue, 60, 255)));
int8_t error2 = bee[i].error * 2;
int_fast16_t error2 = bee[i].error * 2;
if (error2 > -bee[i].deltaY) {
bee[i].error -= bee[i].deltaY;
bee[i].posX += bee[i].signX;
@@ -6170,7 +6248,7 @@ uint16_t mode_2Dfloatingblobs(void) {
if (blob->grow[i]) {
// enlarge radius until it is >= 4
blob->r[i] += (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f;
if (blob->r[i] >= MIN(cols/4.f,2.f)) {
if (blob->r[i] >= min(cols/4.f,2.f)) {
blob->grow[i] = false;
}
} else {

View File

@@ -106,7 +106,7 @@ bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.
//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x])
//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength()
#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */
#define SEGPALETTE strip._currentPalette
#define SEGPALETTE Segment::getCurrentPalette()
#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
@@ -355,7 +355,7 @@ typedef enum mapping1D2D {
M12_jMap = 4, //WLEDMM jMap
M12_sCircle = 5, //WLEDMM Circle
M12_sBlock = 6, //WLEDMM Block
M12_sPinWheel = 7 //WLEDMM PinWheel
M12_sPinwheel = 7 //WLEDMM Pinwheel
} mapping1D2D_t;
// segment, 72 bytes
@@ -428,6 +428,9 @@ typedef struct Segment {
size_t _dataLen; // WLEDMM uint16_t is too small
static size_t _usedSegmentData; // WLEDMM uint16_t is too small
// perhaps this should be per segment, not static
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
// transition data, valid only if transitional==true, holds values during transition
struct Transition {
uint32_t _colorT[NUM_COLORS];
@@ -561,6 +564,7 @@ typedef struct Segment {
static void addUsedSegmentData(int len) { _usedSegmentData += len; }
void allocLeds(); //WLEDMM
inline static const CRGBPalette16 &getCurrentPalette(void) { return Segment::_currentPalette; }
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed
@@ -605,7 +609,7 @@ typedef struct Segment {
uint8_t currentMode(uint8_t modeNew);
uint32_t currentColor(uint8_t slot, uint32_t colorNew);
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
CRGBPalette16 &currentPalette(CRGBPalette16 &tgt, uint8_t paletteID);
void setCurrentPalette(void);
// 1D strip
uint16_t virtualLength(void) const;
@@ -759,7 +763,6 @@ class WS2812FX { // 96 bytes
panels(1),
#endif
// semi-private (just obscured) used in effect functions through macros
_currentPalette(CRGBPalette16(CRGB::Black)),
_colors_t{0,0,0},
_virtualSegmentLength(0),
// true private variables
@@ -978,7 +981,6 @@ class WS2812FX { // 96 bytes
// end 2D support
void loadCustomPalettes(void); // loads custom palettes from JSON
CRGBPalette16 _currentPalette; // palette used for current effect (includes transition)
std::vector<CRGBPalette16> customPalettes; // TODO: move custom palettes out of WS2812FX class
// using public variables to reduce code size increase due to inline function getSegment() (with bounds checking)

View File

@@ -95,6 +95,8 @@ CRGB *Segment::_globalLeds = nullptr;
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
uint16_t Segment::maxHeight = 1;
CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black);
// copy constructor - creates a new segment by copy from orig, but does not copy buffers. Does not modify orig!
Segment::Segment(const Segment &orig) {
DEBUG_PRINTLN(F("-- Copy segment constructor --"));
@@ -295,7 +297,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK));
byte tcp[76] = { 255 }; //WLEDMM: prevent out-of-range access in loadDynamicGradientPalette()
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip
//default palette. Differs depending on effect
if (pal == 0) switch (mode) {
case FX_MODE_FIRE_2012 : pal = 35; break; // heat palette
@@ -458,18 +460,17 @@ uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) {
return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew;
}
CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
loadPalette(targetPalette, pal);
void Segment::setCurrentPalette() {
loadPalette(_currentPalette, palette);
if (transitional && _t && progress() < 0xFFFFU) {
// blend palettes
// there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time)
// minimum blend time is 100ms maximum is 65535ms
unsigned long timeMS = millis() - _t->_start;
uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends;
for (int i=0; i<noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48);
targetPalette = _t->_palT; // copy transitioning/temporary palette
for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48);
_currentPalette = _t->_palT; // copy transitioning/temporary palette
}
return targetPalette;
}
void Segment::handleTransition() {
@@ -793,14 +794,41 @@ void Segment::deletejMap() {
}
// WLEDMM constants for mapping mode "Pinwheel"
constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
// WLEDMM end
// Constants for mapping mode "Pinwheel"
#ifndef WLED_DISABLE_2D
constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16
constexpr int Pinwheel_Size_Small = 16; // larger than this -> use "Medium"
constexpr int Pinwheel_Steps_Medium = 192; // no holes up to 32x32
constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
constexpr int Pinwheel_Steps_Big = 304; // no holes up to 50x50
constexpr int Pinwheel_Size_Big = 50; // larger than this -> use "XL"
constexpr int Pinwheel_Steps_XL = 368;
constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small; // conversion: from 0...72 to Radians
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...304 to Radians
constexpr float Int_to_Rad_XL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XL; // conversion: from 0...368 to Radians
constexpr int Fixed_Scale = 512; // fixpoint scaling factor (9bit for fraction)
// Pinwheel helper function: pixel index to radians
static float getPinwheelAngle(int i, int vW, int vH) {
int maxXY = max(vW, vH);
if (maxXY <= Pinwheel_Size_Small) return float(i) * Int_to_Rad_Small;
if (maxXY <= Pinwheel_Size_Medium) return float(i) * Int_to_Rad_Med;
if (maxXY <= Pinwheel_Size_Big) return float(i) * Int_to_Rad_Big;
// else
return float(i) * Int_to_Rad_XL;
}
// Pinwheel helper function: matrix dimensions to number of rays
static int getPinwheelLength(int vW, int vH) {
int maxXY = max(vW, vH);
if (maxXY <= Pinwheel_Size_Small) return Pinwheel_Steps_Small;
if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium;
if (maxXY <= Pinwheel_Size_Big) return Pinwheel_Steps_Big;
// else
return Pinwheel_Steps_XL;
}
#endif
// 1D strip
uint16_t Segment::virtualLength() const {
@@ -831,12 +859,8 @@ uint16_t Segment::virtualLength() const {
else
vLen = max(vW,vH) * 0.5; // get the longest dimension
break;
case M12_sPinWheel: //WLEDMM
//vLen = full circle
if (max(vW,vH) <= Pinwheel_Size_Medium)
vLen = Pinwheel_Steps_Medium;
else
vLen = Pinwheel_Steps_Big;
case M12_sPinwheel:
vLen = getPinwheelLength(vW, vH);
break;
}
return vLen;
@@ -978,32 +1002,46 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
}
}
break;
case M12_sPinWheel: { // WLEDMM
// i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
case M12_sPinwheel: {
// i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
float centerX = roundf((vW-1) / 2.0f);
float centerY = roundf((vH-1) / 2.0f);
// int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians
float cosVal = cosf(angleRad);
float sinVal = sinf(angleRad);
// avoid re-painting the same pixel
int lastX = INT_MIN; // impossible position
int lastY = INT_MIN; // impossible position
// draw line at angle, starting at center and ending at the segment edge
// we use fixed point math for better speed. Starting distance is 0.5 for better rounding
constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor
int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point
int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
// int_fast16_t and int_fast32_t types changed to int, minimum bits commented
int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
// draw until we hit any edge
while ((posx > 0) && (posy > 0) && (posx < maxX) && (posy < maxY)) {
// Odd rays start further from center if prevRay started at center.
static int prevRay = INT_MIN; // previous ray number
if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) {
int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel
posx += inc_x * jump;
posy += inc_y * jump;
}
prevRay = i;
// draw ray until we hit any edge
while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) {
// scale down to integer (compiler will replace division with appropriate bitshift)
int x = posx / Fixed_Scale;
int y = posy / Fixed_Scale;
// set pixel
setPixelColorXY(x, y, col);
if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different
lastX = x;
lastY = y;
// advance to next position
posx += inc_x;
posy += inc_y;
@@ -1154,16 +1192,36 @@ uint32_t Segment::getPixelColor(int i)
else
return getPixelColorXY(vW / 2, vH / 2 - i - 1);
break;
case M12_sPinWheel: //WLEDMM
// not 100% accurate, returns outer edge of circle
float distance = max(1.0f, min(vH-1, vW-1) / 2.0f);
float centerX = (vW - 1) / 2.0f;
float centerY = (vH - 1) / 2.0f;
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
int x = roundf(centerX + distance * cosf(angleRad));
int y = roundf(centerY + distance * sinf(angleRad));
case M12_sPinwheel:
// not 100% accurate, returns pixel at outer edge
// i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
float centerX = roundf((vW-1) / 2.0f);
float centerY = roundf((vH-1) / 2.0f);
float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians
float cosVal = cosf(angleRad);
float sinVal = sinf(angleRad);
int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
// trace ray from center until we hit any edge - to avoid rounding problems, we use the same method as in setPixelColor
int x = INT_MIN;
int y = INT_MIN;
while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) {
// scale down to integer (compiler will replace division with appropriate bitshift)
x = posx / Fixed_Scale;
y = posy / Fixed_Scale;
// advance to next position
posx += inc_x;
posy += inc_y;
}
return getPixelColorXY(x, y);
}
break;
}
return 0;
}
#endif
@@ -1460,11 +1518,7 @@ uint32_t Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, u
uint_fast16_t vLen = mapping ? virtualLength() : 1;
if (mapping && vLen > 1) paletteIndex = (i*255)/(vLen -1);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGB fastled_col;
CRGBPalette16 curPal;
if (transitional && _t) curPal = _t->_palT;
else loadPalette(curPal, palette);
fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, 0);
}
@@ -1742,7 +1796,7 @@ void WS2812FX::service() {
_colors_t[0] = seg.currentColor(0, seg.colors[0]);
_colors_t[1] = seg.currentColor(1, seg.colors[1]);
_colors_t[2] = seg.currentColor(2, seg.colors[2]);
seg.currentPalette(_currentPalette, seg.palette);
seg.setCurrentPalette(); // load actual palette
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
@@ -2151,7 +2205,7 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
segStops[s] = segStarts[s] + b->getLength();
#ifndef WLED_DISABLE_2D
if (isMatrix && segStops[s] < Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix
if (isMatrix && segStops[s] <= Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix
if (isMatrix && segStarts[s] < Segment::maxWidth*Segment::maxHeight) segStarts[s] = Segment::maxWidth*Segment::maxHeight;
#endif
@@ -2224,6 +2278,8 @@ void WS2812FX::fixInvalidSegments() {
if (_segments[i].stop > _length) _segments[i].stop = _length;
}
}
// if any segments were deleted free memory
purgeSegments();
// this is always called as the last step after finalizeInit(), update covered bus types
for (segment &seg : _segments)
seg.refreshLightCapabilities();

View File

@@ -40,6 +40,11 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte
#define DEBUG_PRINTF(x...)
#endif
#else
// un-define USER_PRINT macros from bus_wrapper.h
#undef USER_PRINT
#undef USER_PRINTF
#undef USER_PRINTLN
#undef USER_FLUSH
// WLEDMM use wled.h
#include "wled.h"
#endif

View File

@@ -18,6 +18,28 @@
#endif
// temporary end
// WLEDMM TroyHacks support - SLOWPATH has priority over TWOPATH
#ifdef WLEDMM_SLOWPATH
#undef WLEDMM_TWOPATH
#endif
// WLEDMM repeat definition of USER_PRINT
bool canUseSerial(void); // WLEDMM (wled_serial.cpp) returns true if Serial can be used for debug output (i.e. not configured for other purpose)
#if defined(WLED_DEBUG_HOST)
#include "net_debug.h"
extern bool netDebugEnabled;
#define USER_PRINT(x) (netDebugEnabled || !canUseSerial())?NetDebug.print(x):Serial.print(x)
#define USER_PRINTLN(x) (netDebugEnabled || !canUseSerial())?NetDebug.println(x):Serial.println(x)
#define USER_PRINTF(x...) (netDebugEnabled || !canUseSerial())?NetDebug.printf(x):Serial.printf(x)
#define USER_FLUSH() (netDebugEnabled || !canUseSerial())?NetDebug.flush():Serial.flush()
#else
#define USER_PRINT(x) {if (canUseSerial()) Serial.print(x);}
#define USER_PRINTLN(x) {if (canUseSerial()) Serial.println(x);}
#define USER_PRINTF(x...) {if (canUseSerial()) Serial.printf(x);}
#define USER_FLUSH() {if (canUseSerial()) Serial.flush();}
#endif
// WLEDMM end
//Hardware SPI Pins
#define P_8266_HS_MOSI 13
#define P_8266_HS_CLK 14
@@ -390,10 +412,14 @@ class PolyBus {
};
static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
#if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3))
#if defined(WLEDMM_FASTPATH) && !defined(WLEDMM_SLOWPATH) // WLEDMM only for fastpath builds
#if defined(WLEDMM_FASTPATH) && !defined(WLEDMM_SLOWPATH) // WLEDMM only for fastpath builds.
// NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation
// since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation
#if defined(WLEDMM_TWOPATH)
if (channel > 1) channel--; // accommodate I2S1 which is used as 2nd bus on classic ESP32
#else
if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32
#endif
#endif
#endif
void* busPtr = nullptr;
@@ -430,20 +456,20 @@ class PolyBus {
case I_8266_BB_UCS_4: busPtr = new B_8266_BB_UCS_4(len, pins[0]); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); USER_PRINTF("(RMT #%u) ", channel); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break;
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); USER_PRINT("(I2S #0) "); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break;
case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); USER_PRINT("(I2S #1) "); break;
#endif
// case I_32_BB_NEO_3: busPtr = new B_32_BB_NEO_3(len, pins[0], (NeoBusChannel)channel); break;
case I_32_RN_NEO_4: busPtr = new B_32_RN_NEO_4(len, pins[0], (NeoBusChannel)channel); break;
case I_32_RN_NEO_4: busPtr = new B_32_RN_NEO_4(len, pins[0], (NeoBusChannel)channel); USER_PRINTF("(RGBW RMT #%u) ", channel); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); USER_PRINT("(RGBW I2S #0) "); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break;
case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); USER_PRINT("(RGBW I2S #1) "); break;
#endif
// case I_32_BB_NEO_4: busPtr = new B_32_BB_NEO_4(len, pins[0], (NeoBusChannel)channel); break;
case I_32_RN_400_3: busPtr = new B_32_RN_400_3(len, pins[0], (NeoBusChannel)channel); break;
@@ -1199,8 +1225,11 @@ class PolyBus {
if (num > 7) return I_NONE;
#else
if (num > 8) return I_NONE;
//if (num == 1) offset = 2; // use I2S#1 as 2nd bus - seems to be a good compromise for performance, and reduces flickering for some users
if (num == 0) offset = 2; // un-comment to use I2S#1 as 1st bus - sometimes helps, if you experience flickering during Wifi or filesystem activity.
#if defined(WLEDMM_TWOPATH)
if (num == 1) offset = 2; // use I2S#1 as 2nd bus - seems to be a good compromise for performance, and reduces flickering for some users
#else
if (num == 0) offset = 2; // use I2S#1 as 1st bus - sometimes helps, if you experience flickering during Wifi or filesystem activity.
#endif
#endif
#endif
#endif

View File

@@ -795,7 +795,7 @@ void serializeConfig() {
matrix["psl"] = strip.panelO.serpentine;
JsonArray panels = matrix.createNestedArray(F("panels"));
for (uint8_t i=0; i<strip.panel.size(); i++) {
for (size_t i = 0; i < strip.panel.size(); i++) {
JsonObject pnl = panels.createNestedObject();
pnl["b"] = strip.panel[i].bottomStart;
pnl["r"] = strip.panel[i].rightStart;

View File

@@ -253,7 +253,7 @@
#define TYPE_NET_ARTNET_RGB 82 //network ArtNet RGB bus (master broadcast bus, unused)
#define TYPE_NET_DDP_RGBW 88 //network DDP RGBW bus (master broadcast bus)
#define IS_DIGITAL(t) ((t) & 0x10) //digital are 16-31 and 48-63
#define IS_DIGITAL(t) (((t) & 0x10) || ((t)==TYPE_HUB75MATRIX)) //digital are 16-31 and 48-63 // WLEDMM added HUB75
#define IS_PWM(t) ((t) > 40 && (t) < 46)
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
#define IS_2PIN(t) ((t) > 47)

View File

@@ -1951,6 +1951,18 @@ function readState(s,command=false)
if (s.error && s.error != 0) {
var errstr = "";
switch (s.error) {
case 1:
errstr = "Denied!";
break;
case 3:
errstr = "Buffer locked!";
break;
case 8:
errstr = "Effect RAM depleted!";
break;
case 9:
errstr = "JSON parsing error!";
break;
case 10:
errstr = "Could not mount filesystem!";
break;
@@ -1963,6 +1975,9 @@ function readState(s,command=false)
case 13:
errstr = "Missing ir.json.";
break;
case 14:
errstr = "Missing remote.json.";
break;
case 19:
errstr = "A filesystem error has occured.";
break;

View File

@@ -50,6 +50,7 @@ void handleImprovPacket() {
uint8_t rpcCommandType = 0;
char rpcData[128];
rpcData[0] = 0;
if (!Serial) return; // WLEDMM avoid reading from unconnected USB-CDC
while (!timeout) {
if (Serial.available() < 1) {

View File

@@ -516,7 +516,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
//bool didSet = false;
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
Segment &sg = strip.getSegment(s);
if (sg.isSelected()) {
if (sg.isActive() && sg.isSelected()) {
inDeepCall = true; // WLEDMM remember that we are going into recursion
deserializeSegment(segVar, s, presetId);
if (iAmGroot) inDeepCall = false; // WLEDMM toplevel -> reset recursion flag
@@ -731,11 +731,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
nl["dur"] = nightlightDelayMins;
nl["mode"] = nightlightMode;
nl[F("tbri")] = nightlightTargetBri;
if (nightlightActive) {
nl[F("rem")] = (nightlightDelayMs - (millis() - nightlightStartTime)) / 1000; // seconds remaining
} else {
nl[F("rem")] = -1;
}
nl[F("rem")] = nightlightActive ? (int)(nightlightDelayMs - (millis() - nightlightStartTime)) / 1000 : -1; // seconds remaining
JsonObject udpn = root.createNestedObject("udpn");
udpn["send"] = notifyDirect;
@@ -901,9 +897,10 @@ String restartCode2Info(esp_reset_reason_t reason) {
void serializeInfo(JsonObject root)
{
root[F("ver")] = versionString;
root[F("rel")] = releaseString; //WLEDMM to add bin name
root[F("vid")] = VERSION;
//root[F("cn")] = WLED_CODENAME;
//root[F("cn")] = F(WLED_CODENAME); //WLEDMM removed
root[F("release")] = FPSTR(releaseString);
root[F("rel")] = FPSTR(releaseString); //WLEDMM to add bin name
JsonObject leds = root.createNestedObject("leds");
leds[F("count")] = strip.getLengthTotal();
@@ -1022,12 +1019,15 @@ void serializeInfo(JsonObject root)
wifi_info[F("txPower")] = (int) WiFi.getTxPower();
wifi_info[F("sleep")] = (bool) WiFi.getSleep();
#endif
#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
//#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if CONFIG_IDF_TARGET_ESP32
root[F("arch")] = "esp32";
#else
root[F("arch")] = ESP.getChipModel();
#endif
root[F("core")] = ESP.getSdkVersion();
root[F("clock")] = ESP.getCpuFreqMHz();
root[F("flash")] = (ESP.getFlashChipSize()/1024)/1024;
//root[F("maxalloc")] = ESP.getMaxAllocHeap();
#ifdef WLED_DEBUG
root[F("resetReason0")] = (int)rtc_get_reset_reason(0);
@@ -1047,6 +1047,8 @@ void serializeInfo(JsonObject root)
#else
root[F("arch")] = "esp8266";
root[F("core")] = ESP.getCoreVersion();
root[F("clock")] = ESP.getCpuFreqMHz();
root[F("flash")] = (ESP.getFlashChipSize()/1024)/1024;
//root[F("maxalloc")] = ESP.getMaxFreeBlockSize();
#ifdef WLED_DEBUG
root[F("resetReason")] = (int)ESP.getResetInfoPtr()->reason;

View File

@@ -901,7 +901,7 @@ void WLED::initAP(bool resetAP)
USER_PRINT(F("Opening access point ")); // WLEDMM
USER_PRINTLN(apSSID); // WLEDMM
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0));
WiFi.softAP(apSSID, apPass, apChannel, apHide);
WiFi.softAP(apSSID, apPass, apChannel, apHide, 8); // WLED-MM allow up to 8 clients for ad-hoc "in the field" syncing.
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
WiFi.setTxPower(WIFI_POWER_8_5dBm);
#endif

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2405040
#define VERSION 2405241
// WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED.
#define _MoonModules_WLED_
@@ -271,16 +271,17 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
// int arr[]{0,1,2} becomes WLED_GLOBAL int arr[] _INIT_N(({0,1,2}));
#ifndef WLED_DEFINE_GLOBAL_VARS
# define WLED_GLOBAL extern
# define _INIT(x)
# define _INIT_N(x)
#define WLED_GLOBAL extern
#define _INIT(x)
#define _INIT_N(x)
#define _INIT_PROGMEM(x)
#else
# define WLED_GLOBAL
# define _INIT(x) = x
//needed to ignore commas in array definitions
#define UNPACK( ... ) __VA_ARGS__
# define _INIT_N(x) UNPACK x
#define WLED_GLOBAL
#define _INIT(x) = x
//needed to ignore commas in array definitions
#define UNPACK( ... ) __VA_ARGS__
#define _INIT_N(x) UNPACK x
#define _INIT_PROGMEM(x) PROGMEM = x
#endif
#define STRINGIFY(X) #X
@@ -290,9 +291,13 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
#define WLED_VERSION "dev"
#endif
#ifndef WLED_RELEASE_NAME
#define WLED_RELEASE_NAME mdev_release
#endif
// Global Variable definitions
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
WLED_GLOBAL char releaseString[] _INIT(TOSTRING(WLED_RELEASE_NAME)); //WLEDMM: to show on update page
WLED_GLOBAL char releaseString[] _INIT_PROGMEM(TOSTRING(WLED_RELEASE_NAME)); //WLEDMM: to show on update page // somehow this will not work if using "const char releaseString[]
#define WLED_CODENAME "Hoshi"
// AP and OTA default passwords (for maximum security change them!)

View File

@@ -42,6 +42,7 @@ void updateBaudRate(uint32_t rate){
// RGB LED data return as JSON array. Slow, but easy to use on the other end.
void sendJSON(){
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) {
if (!Serial) return; // WLEDMM avoid writing to unconnected USB-CDC
uint16_t used = strip.getLengthTotal();
Serial.write('[');
for (uint16_t i=0; i<used; i++) {
@@ -55,6 +56,7 @@ void sendJSON(){
// RGB LED data returned as bytes in TPM2 format. Faster, and slightly less easy to use on the other end.
void sendBytes(){
if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) {
if (!Serial) return; // WLEDMM avoid writing to unconnected USB-CDC
Serial.write(0xC9); Serial.write(0xDA);
uint16_t used = strip.getLengthTotal();
uint16_t len = used*3;

View File

@@ -186,6 +186,7 @@ void sendDataWs(AsyncWebSocketClient * client)
// WLEDMM function to recover full-bright pixel (based on code from upstream alt-buffer, which is based on code from NeoPixelBrightnessBus)
static uint32_t restoreColorLossy(uint32_t c, uint_fast8_t _restaurationBri) {
if (_restaurationBri == 255) return c;
if (_restaurationBri == 0) return 0;
uint8_t* chan = (uint8_t*) &c;
for (uint_fast8_t i=0; i<4; i++) {
uint_fast16_t val = chan[i];

View File

@@ -196,7 +196,11 @@ void appendGPIOinfo() {
size_t roLen = strlen(ro_gpio);
char pinString[10];
for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { // 49 = highest PIN on ESP32-S3
if(!pinManager.isPinOk(pinNr, false)) {
#if defined(ARDUINO_ARCH_ESP32) && !defined(BOARD_HAS_PSRAM)
if ((!pinManager.isPinOk(pinNr, false)) || (pinManager.getPinOwner(pinNr) == PinOwner::SPI_RAM)) { // WLEDMM add SPIRAM pins as "reserved" (pico boards)
#else
if (!pinManager.isPinOk(pinNr, false)) {
#endif
sprintf(pinString, "%s%d", strlen(rsvd)==rsLen?"":",", pinNr);
strcat(rsvd, pinString);
}
@@ -265,9 +269,9 @@ void appendGPIOinfo() {
// add info about max. # of pins
oappend(SET_F("d.max_gpio="));
#if defined(ESP32)
#if defined(ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S3)
oappendi(NUM_DIGITAL_PINS - 1);
#else //8266
#else //8266 (max=17), or esp32-S3 (max=48)
oappendi(NUM_DIGITAL_PINS); //WLEDMM include pin 17 for Analog
#endif
oappend(SET_F(";"));
@@ -842,7 +846,7 @@ void getSettingsJS(AsyncWebServerRequest* request, byte subPage, char* dest) //W
olen -= 2; //delete ";
oappend(versionString);
oappend(SET_F(" "));
oappend(releaseString);
oappend((char*)FPSTR(releaseString));
oappend(SET_F(".bin<br>("));
#if defined(CONFIG_IDF_TARGET_ESP32C3)
oappend(SET_F("ESP32-C3"));