Merge branch 'MoonModules:mdev' into Strip_Level_Color_Adjust

This commit is contained in:
Troy
2024-04-17 10:04:54 -04:00
committed by GitHub
25 changed files with 789 additions and 71 deletions

View File

@@ -3194,7 +3194,13 @@ static uint16_t mode_popcorn_core(bool useaudio) {
if (SEGLEN == 1) return mode_static();
//allocate segment data
uint16_t strips = SEGMENT.nrOfVStrips();
uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
size_t dataSize = sizeof(spark) * maxNumPopcorn;
uint8_t neededPopcorn = maxNumPopcorn; // WLEDMM
if (strips > 8) { // WLEDMM more than 8 virtual strips --> reduce memory requirements to minimum necessary
neededPopcorn = (SEGMENT.intensity*maxNumPopcorn)/255;
neededPopcorn = min(max(neededPopcorn, uint8_t(2)), uint8_t(maxNumPopcorn));
dataSize = sizeof(spark) * neededPopcorn;
}
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
@@ -3212,7 +3218,7 @@ static uint16_t mode_popcorn_core(bool useaudio) {
struct virtualStrip {
static void runStrip(uint16_t stripNr, Spark* popcorn, bool useaudio, um_data_t *um_data) { // WLEDMM added useaudio and um_data
float gravity = -0.0001 - (SEGMENT.speed/200000.0); // m/s/s
float gravity = -0.0001f - (SEGMENT.speed/200000.0f); // m/s/s
gravity *= SEGLEN;
uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255;
@@ -3267,7 +3273,7 @@ static uint16_t mode_popcorn_core(bool useaudio) {
};
for (int stripNr=0; stripNr<strips; stripNr++)
virtualStrip::runStrip(stripNr, &popcorn[stripNr * maxNumPopcorn], useaudio, um_data); // WLEDMM added useaudio and um_data
virtualStrip::runStrip(stripNr, &popcorn[stripNr * neededPopcorn], useaudio, um_data); // WLEDMM added useaudio and um_data
return FRAMETIME;
}

View File

@@ -65,10 +65,10 @@ void WS2812FX::setUpMatrix() {
}
USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight);
//WLEDMM recreate customMappingTable if more space needed
if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//TroyHack
size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight)); // TroyHacks
USER_PRINTF("setupmatrix customMappingTable alloc %d from %d\n", size, customMappingTableSize);
//if (customMappingTable != nullptr) delete[] customMappingTable;
//customMappingTable = new uint16_t[size];
@@ -80,7 +80,10 @@ void WS2812FX::setUpMatrix() {
if ((size > 0) && (customMappingTable == nullptr)) { // second try
DEBUG_PRINTLN("setUpMatrix: trying to get fresh memory block.");
customMappingTable = (uint16_t*) calloc(size, sizeof(uint16_t));
if (customMappingTable == nullptr) USER_PRINTLN("setUpMatrix: alloc failed");
if (customMappingTable == nullptr) {
USER_PRINTLN("setUpMatrix: alloc failed");
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
}
}
if (customMappingTable != nullptr) customMappingTableSize = size;
}
@@ -159,6 +162,7 @@ void WS2812FX::setUpMatrix() {
} else { // memory allocation error
customMappingTableSize = 0;
USER_PRINTLN(F("Ledmap alloc error."));
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
isMatrix = false; //WLEDMM does not like this done in teh background while end users are confused whats happened...
panels = 0;
panel.clear();

View File

@@ -115,7 +115,7 @@ Segment::Segment(const Segment &orig) {
//WLEDMM: recreate ledsrgb if more space needed (will not free ledsrgb!)
void Segment::allocLeds() {
size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); //TroyHack
size_t size = sizeof(CRGB)*max((size_t) length(), ledmapMaxSize); // TroyHacks
if ((size < sizeof(CRGB)) || (size > 164000)) { //softhack too small (<3) or too large (>160Kb)
DEBUG_PRINTF("allocLeds warning: size == %u !!\n", size);
if (ledsrgb && (ledsrgbSize == 0)) {
@@ -128,10 +128,13 @@ void Segment::allocLeds() {
if (ledsrgb) free(ledsrgb); // we need a bigger buffer, so free the old one first
ledsrgb = (CRGB*)calloc(size, 1);
ledsrgbSize = ledsrgb?size:0;
if (ledsrgb == nullptr) USER_PRINTLN("allocLeds failed!!");
if (ledsrgb == nullptr) {
USER_PRINTLN("allocLeds failed!!");
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
}
}
else {
USER_PRINTF("reuse Leds %u from %u\n", size, ledsrgb?ledsrgbSize:0);
//USER_PRINTF("reuse Leds %u from %u\n", size, ledsrgb?ledsrgbSize:0);
}
}
@@ -212,7 +215,11 @@ bool Segment::allocateData(size_t len) {
//DEBUG_PRINTF("allocateData(%u) start %d, stop %d, vlen %d\n", len, start, stop, virtualLength());
deallocateData();
if (len == 0) return false; // nothing to do
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
//USER_PRINTF("Segment::allocateData: Segment data quota exceeded! used:%u request:%u max:%d\n", Segment::getUsedSegmentData(), len, MAX_SEGMENT_DATA);
if (len > 0) errorFlag = ERR_LOW_SEG_MEM; // WLEDMM raise errorflag
return false; //not enough memory
}
// do not use SPI RAM on ESP32 since it is slow
//#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
//if (psramFound())
@@ -220,10 +227,17 @@ bool Segment::allocateData(size_t len) {
//else
//#endif
data = (byte*) malloc(len);
if (!data) { _dataLen = 0; return false;} //allocation failed // WLEDMM reset dataLen
if (!data) {
_dataLen = 0; // WLEDMM reset dataLen
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
USER_PRINT(F("Segment::allocateData: FAILED to allocate "));
USER_PRINT(len); USER_PRINTLN(F(" bytes."));
return false;
} //allocation failed
Segment::addUsedSegmentData(len);
_dataLen = len;
memset(data, 0, len);
if (errorFlag == ERR_LOW_SEG_MEM) errorFlag = ERR_NONE; // WLEDMM reset errorflag on success
return true;
}
@@ -231,7 +245,7 @@ void Segment::deallocateData() {
if (!data) {_dataLen = 0; return;} // WLEDMM reset dataLen
free(data);
data = nullptr;
//DEBUG_PRINTLN("deallocateData() called free().");
//USER_PRINTF("Segment::deallocateData: free'd %d bytes.\n", _dataLen);
Segment::addUsedSegmentData(-_dataLen);
_dataLen = 0;
}
@@ -482,6 +496,8 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
&& (!grp || (grouping == grp && spacing == spc))
&& (ofs == UINT16_MAX || ofs == offset)) return;
stateChanged = true; // send UDP/WS broadcast
if (stop>start) fill(BLACK); //turn old segment range off // WLEDMM stop > start
if (i2 <= i1) { //disable segment
stop = 0;
@@ -1536,7 +1552,7 @@ void WS2812FX::enumerateLedmaps() {
USER_PRINTF("enumerateLedmaps %s \"%s\"", fileName, name);
if (isMatrix) {
//WLEDMM calc ledmapMaxSize (TroyHack)
//WLEDMM calc ledmapMaxSize (TroyHacks)
char dim[34] = { '\0' };
f.find("\"width\":");
f.readBytesUntil('\n', dim, sizeof(dim)-1); //hack: use fileName as we have this allocated already
@@ -1654,6 +1670,7 @@ void WS2812FX::finalizeInit(void)
//#endif
if (arrSize > 0) Segment::_globalLeds = (CRGB*) malloc(arrSize); // WLEDMM avoid malloc(0)
if ((Segment::_globalLeds != nullptr) && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize); // WLEDMM avoid dereferencing nullptr
if ((Segment::_globalLeds == nullptr) && (arrSize > 0)) errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
}
//segments are created in makeAutoSegments();
@@ -2273,16 +2290,16 @@ void WS2812FX::loadCustomPalettes() {
if (readObjectFromFile(fileName, nullptr, &pDoc)) {
JsonArray pal = pDoc[F("palette")];
if (!pal.isNull() && pal.size()>4) { // not an empty palette (at least 2 entries)
if (!pal.isNull() && pal.size()>3) { // not an empty palette (at least 2 entries)
if (pal[0].is<int>() && pal[1].is<const char *>()) {
// we have an array of index & hex strings
size_t palSize = min(pal.size(), (size_t)36); // WLEDMM use native min/max
palSize -= palSize % 2; // make sure size is multiple of 2
for (size_t i=0, j=0; i<palSize && pal[i].as<int>()<256; i+=2, j+=4) {
for (unsigned i=0, j=0; i<palSize && pal[i].as<int>()<256; i+=2, j+=4) {
uint8_t rgbw[] = {0,0,0,0};
tcp[ j ] = (uint8_t) pal[ i ].as<int>(); // index
colorFromHexString(rgbw, pal[i+1].as<const char *>()); // will catch non-string entires
for (size_t c=0; c<3; c++) tcp[j+1+c] = rgbw[c]; // only use RGB component
for (unsigned c=0; c<3; c++) tcp[j+1+c] = gamma8(rgbw[c]); // only use RGB component
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[j]), int(tcp[j+1]), int(tcp[j+2]), int(tcp[j+3]));
}
} else {
@@ -2290,13 +2307,15 @@ void WS2812FX::loadCustomPalettes() {
palSize -= palSize % 4; // make sure size is multiple of 4
for (size_t i=0; i<palSize && pal[i].as<int>()<256; i+=4) {
tcp[ i ] = (uint8_t) pal[ i ].as<int>(); // index
tcp[i+1] = (uint8_t) pal[i+1].as<int>(); // R
tcp[i+2] = (uint8_t) pal[i+2].as<int>(); // G
tcp[i+3] = (uint8_t) pal[i+3].as<int>(); // B
tcp[i+1] = gamma8((uint8_t) pal[i+1].as<int>()); // R
tcp[i+2] = gamma8((uint8_t) pal[i+2].as<int>()); // G
tcp[i+3] = gamma8((uint8_t) pal[i+3].as<int>()); // B
DEBUG_PRINTF("%d(%d) : %d %d %d\n", i, int(tcp[i]), int(tcp[i+1]), int(tcp[i+2]), int(tcp[i+3]));
}
}
customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
} else {
DEBUG_PRINTLN(F("Wrong palette format."));
}
}
} else {
@@ -2387,7 +2406,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
//WLEDMM recreate customMappingTable if more space needed
if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight));//TroyHack
size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight)); // TroyHacks
USER_PRINTF("deserializemap customMappingTable alloc %u from %u\n", size, customMappingTableSize);
//if (customMappingTable != nullptr) delete[] customMappingTable;
//customMappingTable = new uint16_t[size];
@@ -2399,7 +2418,10 @@ bool WS2812FX::deserializeMap(uint8_t n) {
if ((size > 0) && (customMappingTable == nullptr)) { // second try
DEBUG_PRINTLN("deserializeMap: trying to get fresh memory block.");
customMappingTable = (uint16_t*) calloc(size, sizeof(uint16_t));
if (customMappingTable == nullptr) DEBUG_PRINTLN("deserializeMap: alloc failed!");
if (customMappingTable == nullptr) {
DEBUG_PRINTLN("deserializeMap: alloc failed!");
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
}
}
if (customMappingTable != nullptr) customMappingTableSize = size;
}

View File

@@ -142,6 +142,7 @@
#define USERMOD_ID_WEATHER 91 //Usermod "usermod_v2_weather.h"
#define USERMOD_ID_GAMES 92 //Usermod "usermod_v2_games.h"
#define USERMOD_ID_ANIMARTRIX 93 //Usermod "usermod_v2_animartrix.h"
#define USERMOD_ID_AUTOPLAYLIST 94 // Usermod usermod_v2_auto_playlist.h
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@@ -347,7 +348,9 @@
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
#define ERR_LOW_MEM 33 // low memory (RAM)
#define ERR_LOW_MEM 33 // WLEDMM: low memory (RAM)
#define ERR_LOW_SEG_MEM 34 // WLEDMM: low memory (segment data RAM)
#define ERR_LOW_WS_MEM 35 // WLEDMM: low memory (ws)
// Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
@@ -494,7 +497,10 @@
#define DEFAULT_LED_COUNT 30
#endif
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
#define INTERFACE_UPDATE_COOLDOWN 1200 // time in ms to wait between websockets, alexa, and MQTT updates
#define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct
#define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes
// HW_PIN_SCL & HW_PIN_SDA are used for information in usermods settings page and usermods themselves
// which GPIO pins are actually used in a hardware layout (controller board)

View File

@@ -1968,8 +1968,14 @@ function readState(s,command=false)
errstr = "A filesystem error has occured.";
break;
case 33:
errstr = "Warning: Low Memory (RAM).";
break;
errstr = "Low Memory (generic RAM).";
break;
case 34:
errstr = "Low Memory (effect data).";
break;
case 35:
errstr = "Low Memory (WS data).";
break;
}
showToast('Error ' + s.error + ": " + errstr, true);
}

View File

@@ -231,11 +231,16 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
if (e131_data[dataOffset+3] != seg.intensity) seg.intensity = e131_data[dataOffset+3];
if (e131_data[dataOffset+4] != seg.palette) seg.setPalette(e131_data[dataOffset+4]);
uint8_t segOption = (uint8_t)floor(e131_data[dataOffset+5]/64.0);
if (segOption == 0 && (seg.mirror || seg.reverse )) {seg.setOption(SEG_OPTION_MIRROR, false); seg.setOption(SEG_OPTION_REVERSED, false);}
if (segOption == 1 && (seg.mirror || !seg.reverse)) {seg.setOption(SEG_OPTION_MIRROR, false); seg.setOption(SEG_OPTION_REVERSED, true);}
if (segOption == 2 && (!seg.mirror || seg.reverse )) {seg.setOption(SEG_OPTION_MIRROR, true); seg.setOption(SEG_OPTION_REVERSED, false);}
if (segOption == 3 && (!seg.mirror || !seg.reverse)) {seg.setOption(SEG_OPTION_MIRROR, true); seg.setOption(SEG_OPTION_REVERSED, true);}
if ((e131_data[dataOffset+5] & 0b00000010) != seg.reverse_y) { seg.setOption(SEG_OPTION_REVERSED_Y, e131_data[dataOffset+5] & 0b00000010); }
if ((e131_data[dataOffset+5] & 0b00000100) != seg.mirror_y) { seg.setOption(SEG_OPTION_MIRROR_Y, e131_data[dataOffset+5] & 0b00000100); }
if ((e131_data[dataOffset+5] & 0b00001000) != seg.transpose) { seg.setOption(SEG_OPTION_TRANSPOSED, e131_data[dataOffset+5] & 0b00001000); }
if ((e131_data[dataOffset+5] & 0b00110000) / 8 != seg.map1D2D) {
seg.map1D2D = (e131_data[dataOffset+5] & 0b00110000) / 8;
}
// To maintain backwards compatibility with prior e1.31 values, reverse is fixed to mask 0x01000000
if ((e131_data[dataOffset+5] & 0b01000000) != seg.reverse) { seg.setOption(SEG_OPTION_REVERSED, e131_data[dataOffset+5] & 0b01000000); }
// To maintain backwards compatibility with prior e1.31 values, mirror is fixed to mask 0x10000000
if ((e131_data[dataOffset+5] & 0b10000000) != seg.mirror) { seg.setOption(SEG_OPTION_MIRROR, e131_data[dataOffset+5] & 0b10000000); }
uint32_t colors[3];
byte whites[3] = {0,0,0};

View File

@@ -208,6 +208,7 @@ void _overlayAnalogCountdown();
void _overlayAnalogClock();
//playlist.cpp
void suspendPlaylist(); // WLEDMM support function for auto playlist usermod
void shufflePlaylist();
void unloadPlaylist();
int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0);
@@ -370,9 +371,11 @@ void releaseJSONBufferLock();
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
void checkSettingsPIN(const char *pin);
uint16_t __attribute__((pure)) crc16(const unsigned char* data_p, size_t length); // WLEDMM: added attribute pure
um_data_t* simulateSound(uint8_t simulationId);
// WLEDMM enumerateLedmaps(); moved to FX.h
uint8_t get_random_wheel_index(uint8_t pos);
CRGB getCRGBForBand(int x, uint8_t *fftResult, int pal); //WLEDMM netmindz ar palette
char *cleanUpName(char *in); // to clean up a name that was read from file

View File

@@ -210,7 +210,7 @@ void sendImprovInfoResponse() {
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
char vString[32];
snprintf_P(vString, sizeof(vString)-1, PSTR("0.14.1-b30.36/%i"),VERSION);
snprintf_P(vString, sizeof(vString)-1, PSTR("0.14.1-b30.37/%i"),VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);

View File

@@ -105,6 +105,7 @@ void stateUpdated(byte callMode) {
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
if (bri != briOld && nodeBroadcastEnabled) sendSysInfoUDP(); // update on state
//set flag to update ws and mqtt
interfaceUpdateCallMode = callMode;
@@ -139,6 +140,8 @@ void stateUpdated(byte callMode) {
jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) {
jsonTransitionOnce = false;
transitionActive = false;
applyFinalBri();
strip.trigger();
return;
@@ -161,8 +164,12 @@ void stateUpdated(byte callMode) {
void updateInterfaces(uint8_t callMode)
{
if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return;
sendDataWs();
lastInterfaceUpdate = millis();
interfaceUpdateCallMode = 0; //disable
if (callMode == CALL_MODE_WS_SEND) return;
#ifndef WLED_DISABLE_ALEXA
@@ -172,14 +179,13 @@ void updateInterfaces(uint8_t callMode)
}
#endif
doPublishMqtt = true;
interfaceUpdateCallMode = 0; //disable
}
void handleTransitions()
{
//handle still pending interface update
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN) updateInterfaces(interfaceUpdateCallMode);
updateInterfaces(interfaceUpdateCallMode);
#ifndef WLED_DISABLE_MQTT
if (doPublishMqtt) publishMqtt();
#endif
@@ -190,12 +196,15 @@ void handleTransitions()
if (tper >= 1.0f)
{
strip.setTransitionMode(false);
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
transitionActive = false;
jsonTransitionOnce = false;
tperLast = 0;
applyFinalBri();
return;
}
if (tper - tperLast < 0.004) return;
if (tper - tperLast < 0.004f) return;
tperLast = tper;
briT = briOld + ((bri - briOld) * tper);
@@ -205,7 +214,7 @@ void handleTransitions()
// legacy method, applies values from col, effectCurrent, ... to selected segments
void colorUpdated(byte callMode){
void colorUpdated(byte callMode) {
applyValuesToSelectedSegs();
stateUpdated(callMode);
}

View File

@@ -41,6 +41,12 @@ void shufflePlaylist() {
DEBUG_PRINTLN(F("Playlist shuffle."));
}
// WLEDMM supporting function for auto_playlist usermod
// prevents the active playlist from progressing (until it gets unloaded)
static bool playlistSuspended = false;
void suspendPlaylist() {
playlistSuspended = true;
}
void unloadPlaylist() {
if (playlistEntries != nullptr) {
@@ -49,6 +55,7 @@ void unloadPlaylist() {
}
currentPlaylist = playlistIndex = -1;
playlistLen = playlistEntryDur = playlistOptions = 0;
playlistSuspended = false; // WLEDMM
DEBUG_PRINTLN(F("Playlist unloaded."));
}
@@ -125,6 +132,11 @@ void handlePlaylist() {
// if fileDoc is not null JSON buffer is in use so just quit
if (currentPlaylist < 0 || playlistEntries == nullptr || fileDoc != nullptr) return;
if (playlistSuspended) { // WLEDMM
if (millis() - presetCycledTime > (100*playlistEntryDur)) presetCycledTime = millis(); // keep updating timer
return; // but don't progress to next extry, and don't shuffle
}
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
presetCycledTime = millis();
if (bri == 0 || nightlightActive) return;

View File

@@ -712,6 +712,7 @@ void sendSysInfoUDP()
#else
data[38] = NODE_TYPE_ID_UNDEFINED;
#endif
if (bri) data[38] |= 0x80U; // add on/off state
data[39] = ip[3]; // unit ID == last IP number
uint32_t build = VERSION;

View File

@@ -203,6 +203,9 @@
#ifdef USERMOD_ANIMARTRIX
#include "../usermods/usermod_v2_animartrix/usermod_v2_animartrix.h"
#endif
#ifdef USERMOD_AUTO_PLAYLIST
#include "../usermods/usermod_v2_auto_playlist/usermod_v2_auto_playlist.h"
#endif
void registerUsermods()
{
@@ -402,4 +405,9 @@ void registerUsermods()
usermods.add(new AnimartrixUsermod("Animartrix", false));
#endif
#ifdef USERMOD_AUTO_PLAYLIST
usermods.add(new AutoPlaylistUsermod(false));
#endif
}

View File

@@ -204,7 +204,7 @@ bool requestJSONBufferLock(uint8_t module)
{
unsigned long now = millis();
while (jsonBufferLock && millis()-now < 1200) delay(1); // wait for fraction for buffer lock
while (jsonBufferLock && millis()-now < 1100) delay(1); // wait for fraction for buffer lock
if (jsonBufferLock) {
USER_PRINT(F("ERROR: Locking JSON buffer failed! (still locked by "));
@@ -239,9 +239,10 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
{
if (src == JSON_mode_names || src == nullptr) {
if (mode < strip.getModeCount()) {
char lineBuffer[256];
char lineBuffer[256] = { '\0' };
//strcpy_P(lineBuffer, (const char*)pgm_read_dword(&(WS2812FX::_modeData[mode])));
strcpy_P(lineBuffer, strip.getModeData(mode));
strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
size_t len = strlen(lineBuffer);
size_t j = 0;
for (; j < maxLen && j < len; j++) {
@@ -253,6 +254,12 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
} else return 0;
}
if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) {
snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode);
dest[maxLen-1] = '\0';
return strlen(dest);
}
uint8_t qComma = 0;
bool insideQuotes = false;
uint8_t printedChars = 0;
@@ -363,9 +370,9 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
{
if (mode < strip.getModeCount()) {
char lineBuffer[128] = "";
strncpy_P(lineBuffer, strip.getModeData(mode), 127);
lineBuffer[127] = '\0'; // terminate string
char lineBuffer[256] = { '\0' };
strncpy_P(lineBuffer, strip.getModeData(mode), sizeof(lineBuffer)/sizeof(char)-1);
lineBuffer[sizeof(lineBuffer)/sizeof(char)-1] = '\0'; // terminate string
if (lineBuffer[0] != 0) {
char* startPtr = strrchr(lineBuffer, ';'); // last ";" in FX data
if (!startPtr) return -1;
@@ -381,6 +388,16 @@ int16_t extractModeDefaults(uint8_t mode, const char *segVar)
}
void checkSettingsPIN(const char* pin) {
if (!pin) return;
if (!correctPIN && millis() - lastEditTime < PIN_RETRY_COOLDOWN) return; // guard against PIN brute force
bool correctBefore = correctPIN;
correctPIN = (strlen(settingsPIN) == 0 || strncmp(settingsPIN, pin, 4) == 0);
if (correctBefore != correctPIN) createEditHandler(correctPIN);
lastEditTime = millis();
}
uint16_t crc16(const unsigned char* data_p, size_t length) {
uint8_t x;
uint16_t crc = 0xFFFF;
@@ -401,9 +418,9 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
// (only 2 used as stored in 1 bit in segment options, consider switching to a single global simulation type)
typedef enum UM_SoundSimulations {
UMS_BeatSin = 0,
UMS_WeWillRockYou
//UMS_10_13,
//UMS_14_3
UMS_WeWillRockYou,
UMS_10_13,
UMS_14_3
} um_soundSimulations_t;
um_data_t* simulateSound(uint8_t simulationId)
@@ -491,7 +508,7 @@ um_data_t* simulateSound(uint8_t simulationId)
fftResult[i] = 0;
}
break;
/*case UMS_10_3:
case UMS_10_13:
for (int i = 0; i<16; i++)
fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
volumeSmth = fftResult[8];
@@ -500,11 +517,11 @@ um_data_t* simulateSound(uint8_t simulationId)
for (int i = 0; i<16; i++)
fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
volumeSmth = fftResult[8];
break;*/
break;
}
samplePeak = random8() > 250;
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // WLEDMM 21hz...8200hz
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
maxVol = 31; // this gets feedback fro UI
binNum = 8; // this gets feedback fro UI
volumeRaw = volumeSmth;
@@ -545,6 +562,20 @@ CRGB getCRGBForBand(int x, uint8_t *fftResult, int pal) {
return value;
}
/*
* Returns a new, random color wheel index with a minimum distance of 42 from pos.
*/
uint8_t get_random_wheel_index(uint8_t pos) {
uint8_t r = 0, x = 0, y = 0, d = 0;
while (d < 42) {
r = random8();
x = abs(pos - r);
y = 255 - x;
d = MIN(x, y);
}
return r;
}
// WLEDMM extended "trim string" function to support enumerateLedmaps
// The function takes char* as input, and removes all leading and trailing "decorations" like spaces, tabs, line endings, quotes, colons
// The conversion is "in place" (destructive).

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2402252
#define VERSION 2404161
// 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_

View File

@@ -220,6 +220,8 @@ void initServer()
if (verboseResponse) {
if (!isConfig) {
lastInterfaceUpdate = millis(); // prevent WS update until cooldown
interfaceUpdateCallMode = CALL_MODE_WS_SEND; // schedule WS update
serveJson(request); return; //if JSON contains "v"
} else {
doSerializeConfig = true; //serializeConfig(); //Save new settings to FS

View File

@@ -62,14 +62,15 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
}
releaseJSONBufferLock(); // will clean fileDoc
// force broadcast in 500ms after updating client
if (verboseResponse) {
sendDataWs(client);
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
} else {
// we have to send something back otherwise WS connection closes
client->text(F("{\"success\":true}"));
lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500);
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
if (verboseResponse) {
sendDataWs(client);
} else {
// we have to send something back otherwise WS connection closes
client->text(F("{\"success\":true}"));
}
// force broadcast in 500ms after updating client
//lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500); // ESP8266 does not like this
}
}
} else {
@@ -161,6 +162,7 @@ void sendDataWs(AsyncWebSocketClient * client)
ws.closeAll(1013); //code 1013 = temporary overload, try again later
ws.cleanupClients(0); //disconnect all clients to release memory
ws._cleanBuffers();
errorFlag = ERR_LOW_WS_MEM;
return; //out of memory
}