mirror of
https://github.com/wled/WLED.git
synced 2025-07-23 02:36:39 +00:00
Merge branch '0_15' of https://github.com/Aircoookie/WLED into ledmaps-realtime
This commit is contained in:
commit
ff59dcd66e
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,3 +22,5 @@ wled-update.sh
|
||||
/wled00/my_config.h
|
||||
/wled00/Release
|
||||
/wled00/wled00.ino.cpp
|
||||
|
||||
/tools/cdataCache.json
|
31
CHANGELOG.md
31
CHANGELOG.md
@ -1,19 +1,42 @@
|
||||
## WLED changelog
|
||||
|
||||
#### Build 2309120 till build 2311120
|
||||
#### Build 2309120 till build 2201060
|
||||
- WLED version 0.15.0-a0
|
||||
- Global JSON buffer guarding (#3648 by @willmmiles, resolves #3641, #3312, #3367, #3637, #3646, #3447)
|
||||
- Effect: Fireworks 1D (fix for matrix trailing strip)
|
||||
- BREAKING: Reduced number of segments (12) on ESP8266 due to less available RAM
|
||||
- Increased available effect data buffer (increases more if board has PSRAM)
|
||||
- Custom palette editor mobile UI enhancement (by @imeszaros)
|
||||
- Per port Auto Brightness Limiter (ABL)
|
||||
- Use PSRAM for JSON buffer (double size, larger ledmaps, up to 2k)
|
||||
- Reduced heap fragmentation by allocating ledmap array only once and not deallocating effect buffer
|
||||
- HTTP retries on failed UI load
|
||||
- UI Search: scroll to top (#3587 by @WoodyLetsCode)
|
||||
- Return to inline iro.js and rangetouch.js (#3597 by @WoodyLetsCode)
|
||||
- Better caching (#3591 by @WoodyLetsCode)
|
||||
- Do not send 404 for missing `skin.css` (#3590 by @WoodyLetsCode)
|
||||
- Simplified UI rework (#3511 by @WoodyLetsCode)
|
||||
- Domoticz device ID for PIR and Temperature usermods
|
||||
- Bugfix for UCS8904 `hasWhite()`
|
||||
- Better search in UI (#3540 by @WoodyLetsCode)
|
||||
- Seeding FastLED PRNG (#3552 by @TripleWhy)
|
||||
- WIZ Smart Button support (#3547 by @micw)
|
||||
- New button type (button switch, fix for #3537)
|
||||
- Pixel Magic Tool update (#3483 by @ajotanc)
|
||||
- Effect: 2D Matrix fix for gaps
|
||||
- Bugfix #3526, #3533, #3561
|
||||
- Spookier Halloween Eyes (#3501)
|
||||
- Compile time options for Multi Relay usermod (#3498)
|
||||
- Fix for Dissolve (#3502)
|
||||
- Effect: Fix for Dissolve (#3502)
|
||||
- Better reverse proxy support (nested paths)
|
||||
- Implement global JSON API boolean toggle (i.e. instead of "var":true or "var":false -> "var":"t").
|
||||
- Sort presets by ID
|
||||
- Fix #3496
|
||||
- Fix for #3641, #3312, #3367, #3637, #3646, #3447, #3632, #3496, #2922, #3593, #3514, #3522, #3578 (partial), #3606 (@WoodyLetsCode)
|
||||
- Improved random bg image and added random bg image options (@WoodyLetsCode, #3481)
|
||||
- Audio palettes (Audioreactive usermod, credit @netmindz)
|
||||
- Better UI tooltips (@ajotnac, #3464)
|
||||
- Better effect filters (filter dropdown)
|
||||
- Fix udp sync (fix for #3487)
|
||||
- UDP sync fix (for #3487)
|
||||
- Power button override (solves #3431)
|
||||
- Additional HTTP request throttling (ESP8266)
|
||||
- Additional UI/UX improvements
|
||||
|
3
pio-scripts/build_ui.py
Normal file
3
pio-scripts/build_ui.py
Normal file
@ -0,0 +1,3 @@
|
||||
Import('env')
|
||||
|
||||
env.Execute("npm run build")
|
@ -155,6 +155,7 @@ extra_scripts =
|
||||
post:pio-scripts/output_bins.py
|
||||
post:pio-scripts/strip-floats.py
|
||||
pre:pio-scripts/user_config_copy.py
|
||||
pre:pio-scripts/build_ui.py
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# COMMON SETTINGS:
|
||||
@ -198,6 +199,8 @@ lib_deps =
|
||||
#For ADS1115 sensor uncomment following
|
||||
; adafruit/Adafruit BusIO @ 1.13.2
|
||||
; adafruit/Adafruit ADS1X15 @ 2.4.0
|
||||
#For MPU6050 IMU uncomment follwoing
|
||||
; electroniccats/MPU6050 @1.0.1
|
||||
|
||||
extra_scripts = ${scripts_defaults.extra_scripts}
|
||||
|
||||
|
@ -22,6 +22,37 @@ const CleanCSS = require("clean-css");
|
||||
const MinifyHTML = require("html-minifier-terser").minify;
|
||||
const packageJson = require("../package.json");
|
||||
|
||||
const CACHE_FILE = __dirname + "/cdataCache.json";
|
||||
const cache = loadCache();
|
||||
cache.version = 1;
|
||||
|
||||
function loadCache() {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(CACHE_FILE));
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function saveCache(file) {
|
||||
const stat = fs.statSync(file);
|
||||
cache[file] = {
|
||||
mtime: stat.mtimeMs,
|
||||
size: stat.size,
|
||||
};
|
||||
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache));
|
||||
}
|
||||
|
||||
function isCached(file) {
|
||||
// If command line argument is set, always rebuild
|
||||
if (process.argv[2] == "--force" || process.argv[2] == "-f") {
|
||||
return false;
|
||||
}
|
||||
const stat = fs.statSync(file);
|
||||
const cached = cache[file];
|
||||
return cached && cached.mtime == stat.mtimeMs && cached.size == stat.size;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -110,6 +141,10 @@ function filter(str, type) {
|
||||
}
|
||||
|
||||
function writeHtmlGzipped(sourceFile, resultFile, page) {
|
||||
if (isCached(sourceFile)) {
|
||||
console.info(`Skipping ${resultFile} as it is cached`);
|
||||
return;
|
||||
}
|
||||
console.info("Reading " + sourceFile);
|
||||
new inliner(sourceFile, function (error, html) {
|
||||
console.info("Inlined " + html.length + " characters");
|
||||
@ -146,6 +181,7 @@ ${array}
|
||||
`;
|
||||
console.info("Writing " + resultFile);
|
||||
fs.writeFileSync(resultFile, src);
|
||||
saveCache(sourceFile);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -182,7 +218,7 @@ ${result}
|
||||
const result = hexdump(buf);
|
||||
const chunk = `
|
||||
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
|
||||
const uint16_t ${s.name}_length = ${result.length};
|
||||
const uint16_t ${s.name}_length = ${buf.length};
|
||||
const uint8_t ${s.name}[] PROGMEM = {
|
||||
${result}
|
||||
};
|
||||
@ -196,6 +232,11 @@ ${result}
|
||||
}
|
||||
|
||||
function writeChunks(srcDir, specs, resultFile) {
|
||||
if (specs.every(s => isCached(srcDir + "/" + s.file))) {
|
||||
console.info(`Skipping ${resultFile} as all files are cached`);
|
||||
return;
|
||||
}
|
||||
|
||||
let src = `/*
|
||||
* More web UI HTML source arrays.
|
||||
* This file is auto generated, please don't make any changes manually.
|
||||
@ -204,12 +245,14 @@ function writeChunks(srcDir, specs, resultFile) {
|
||||
*/
|
||||
`;
|
||||
specs.forEach((s) => {
|
||||
const file = srcDir + "/" + s.file;
|
||||
try {
|
||||
console.info("Reading " + srcDir + "/" + s.file + " as " + s.name);
|
||||
console.info("Reading " + file + " as " + s.name);
|
||||
src += specToChunk(srcDir, s);
|
||||
saveCache(file);
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"Failed " + s.name + " from " + srcDir + "/" + s.file,
|
||||
"Failed " + s.name + " from " + file,
|
||||
e.message.length > 60 ? e.message.substring(0, 60) : e.message
|
||||
);
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ class St7789DisplayUsermod : public Usermod {
|
||||
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
|
||||
tft.print("Current: ");
|
||||
tft.setTextColor(TFT_ORANGE);
|
||||
tft.print(strip.currentMilliamps);
|
||||
tft.print(BusManager::currentMilliamps());
|
||||
tft.print("mA");
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,11 @@ react to the globes orientation. See the blog post on building it <https://www.r
|
||||
|
||||
I2Cdev and MPU6050 must be installed.
|
||||
|
||||
To install them, add I2Cdevlib-MPU6050@fbde122cc5 to lib_deps in the platformio.ini file.
|
||||
|
||||
You also need to change lib_compat_mode from strict to soft in platformio.ini (This ignores that I2Cdevlib-MPU6050 doesn't list platform compatibility)
|
||||
To install them, add electroniccats/MPU6050@1.0.1 to lib_deps in the platformio.ini file.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
lib_compat_mode = soft
|
||||
lib_deps =
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus@2.5.7
|
||||
@ -36,7 +33,7 @@ lib_deps =
|
||||
AsyncTCP@1.0.3
|
||||
Esp Async WebServer@1.2.0
|
||||
IRremoteESP8266@2.7.3
|
||||
jrowberg/I2Cdevlib-MPU6050@^1.0.0
|
||||
electroniccats/MPU6050@1.0.1
|
||||
```
|
||||
|
||||
## Wiring
|
||||
|
219
usermods/mpu6050_imu/usermod_gyro_surge.h
Normal file
219
usermods/mpu6050_imu/usermod_gyro_surge.h
Normal file
@ -0,0 +1,219 @@
|
||||
#pragma once
|
||||
|
||||
/* This usermod uses gyro data to provide a "surge" effect on movement
|
||||
|
||||
Requires lib_deps = bolderflight/Bolder Flight Systems Eigen@^3.0.0
|
||||
|
||||
*/
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
// Eigen include block
|
||||
#ifdef A0
|
||||
namespace { constexpr size_t A0_temp {A0}; }
|
||||
#undef A0
|
||||
static constexpr size_t A0 {A0_temp};
|
||||
#endif
|
||||
|
||||
#ifdef A1
|
||||
namespace { constexpr size_t A1_temp {A1}; }
|
||||
#undef A1
|
||||
static constexpr size_t A1 {A1_temp};
|
||||
#endif
|
||||
|
||||
#ifdef B0
|
||||
namespace { constexpr size_t B0_temp {B0}; }
|
||||
#undef B0
|
||||
static constexpr size_t B0 {B0_temp};
|
||||
#endif
|
||||
|
||||
#ifdef B1
|
||||
namespace { constexpr size_t B1_temp {B1}; }
|
||||
#undef B1
|
||||
static constexpr size_t B1 {B1_temp};
|
||||
#endif
|
||||
|
||||
#ifdef D0
|
||||
namespace { constexpr size_t D0_temp {D0}; }
|
||||
#undef D0
|
||||
static constexpr size_t D0 {D0_temp};
|
||||
#endif
|
||||
|
||||
#ifdef D1
|
||||
namespace { constexpr size_t D1_temp {D1}; }
|
||||
#undef D1
|
||||
static constexpr size_t D1 {D1_temp};
|
||||
#endif
|
||||
|
||||
#ifdef D2
|
||||
namespace { constexpr size_t D2_temp {D2}; }
|
||||
#undef D2
|
||||
static constexpr size_t D2 {D2_temp};
|
||||
#endif
|
||||
|
||||
#ifdef D3
|
||||
namespace { constexpr size_t D3_temp {D3}; }
|
||||
#undef D3
|
||||
static constexpr size_t D3 {D3_temp};
|
||||
#endif
|
||||
|
||||
#include "eigen.h"
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
constexpr auto ESTIMATED_G = 9.801; // m/s^2
|
||||
constexpr auto ESTIMATED_G_COUNTS = 8350.;
|
||||
constexpr auto ESTIMATED_ANGULAR_RATE = (M_PI * 2000) / (INT16_MAX * 180); // radians per second
|
||||
|
||||
// Horribly lame digital filter code
|
||||
// Currently implements a static IIR filter.
|
||||
template<typename T, unsigned C>
|
||||
class xir_filter {
|
||||
typedef Eigen::Array<T, C, 1> array_t;
|
||||
const array_t a_coeff, b_coeff;
|
||||
const T gain;
|
||||
array_t x, y;
|
||||
|
||||
public:
|
||||
xir_filter(T gain_, array_t a, array_t b) : a_coeff(std::move(a)), b_coeff(std::move(b)), gain(gain_), x(array_t::Zero()), y(array_t::Zero()) {};
|
||||
|
||||
T operator()(T input) {
|
||||
x.head(C-1) = x.tail(C-1); // shift by one
|
||||
x(C-1) = input / gain;
|
||||
y.head(C-1) = y.tail(C-1); // shift by one
|
||||
y(C-1) = (x * b_coeff).sum();
|
||||
y(C-1) -= (y.head(C-1) * a_coeff.head(C-1)).sum();
|
||||
return y(C-1);
|
||||
}
|
||||
|
||||
T last() { return y(C-1); };
|
||||
};
|
||||
|
||||
|
||||
|
||||
class GyroSurge : public Usermod {
|
||||
private:
|
||||
static const char _name[];
|
||||
bool enabled = true;
|
||||
|
||||
// Params
|
||||
uint8_t max = 0;
|
||||
float sensitivity = 0;
|
||||
|
||||
// State
|
||||
uint32_t last_sample;
|
||||
// 100hz input
|
||||
// butterworth low pass filter at 20hz
|
||||
xir_filter<float, 3> filter = { 1., { -0.36952738, 0.19581571, 1.}, {0.20657208, 0.41314417, 0.20657208} };
|
||||
// { 1., { 0., 0., 1.}, { 0., 0., 1. } }; // no filter
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
*/
|
||||
void setup() {};
|
||||
|
||||
|
||||
/*
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
|
||||
//save these vars persistently whenever settings are saved
|
||||
top["max"] = max;
|
||||
top["sensitivity"] = sensitivity;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page)
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
*
|
||||
* Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings)
|
||||
*
|
||||
* getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present
|
||||
* The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them
|
||||
*
|
||||
* This function is guaranteed to be called on boot, but could also be called every time settings are updated
|
||||
*/
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
configComplete &= getJsonValue(top["max"], max, 0);
|
||||
configComplete &= getJsonValue(top["sensitivity"], sensitivity, 10);
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// get IMU data
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_IMU)) {
|
||||
// Apply max
|
||||
strip.getSegment(0).fadeToBlackBy(max);
|
||||
return;
|
||||
}
|
||||
uint32_t sample_count = *(uint32_t*)(um_data->u_data[8]);
|
||||
|
||||
if (sample_count != last_sample) {
|
||||
last_sample = sample_count;
|
||||
// Calculate based on new data
|
||||
// We use the raw gyro data (angular rate)
|
||||
auto gyros = (int16_t*)um_data->u_data[4]; // 16384 == 2000 deg/s
|
||||
|
||||
// Compute the overall rotation rate
|
||||
// For my application (a plasma sword) we ignore X axis rotations (eg. around the long axis)
|
||||
auto gyro_q = Eigen::AngleAxis<float> {
|
||||
//Eigen::AngleAxis<float>(ESTIMATED_ANGULAR_RATE * gyros[0], Eigen::Vector3f::UnitX()) *
|
||||
Eigen::AngleAxis<float>(ESTIMATED_ANGULAR_RATE * gyros[1], Eigen::Vector3f::UnitY()) *
|
||||
Eigen::AngleAxis<float>(ESTIMATED_ANGULAR_RATE * gyros[2], Eigen::Vector3f::UnitZ()) };
|
||||
|
||||
// Filter the results
|
||||
filter(std::min(sensitivity * gyro_q.angle(), 1.0f)); // radians per second
|
||||
/*
|
||||
Serial.printf("[%lu] Gy: %d, %d, %d -- ", millis(), (int)gyros[0], (int)gyros[1], (int)gyros[2]);
|
||||
Serial.print(gyro_q.angle());
|
||||
Serial.print(", ");
|
||||
Serial.print(sensitivity * gyro_q.angle());
|
||||
Serial.print(" --> ");
|
||||
Serial.println(filter.last());
|
||||
*/
|
||||
}
|
||||
}; // noop
|
||||
|
||||
/*
|
||||
* handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors.
|
||||
* Use this to blank out some LEDs or set them to a different color regardless of the set effect mode.
|
||||
* Commonly used for custom clocks (Cronixie, 7 segment)
|
||||
*/
|
||||
void handleOverlayDraw()
|
||||
{
|
||||
|
||||
// TODO: some kind of timing analysis for filtering ...
|
||||
|
||||
// Calculate brightness boost
|
||||
auto r_float = std::max(std::min(filter.last(), 1.0f), 0.f);
|
||||
auto result = (uint8_t) (r_float * max);
|
||||
//Serial.printf("[%lu] %d -- ", millis(), result);
|
||||
//Serial.println(r_float);
|
||||
// TODO - multiple segment handling??
|
||||
strip.getSegment(0).fadeToBlackBy(max - result);
|
||||
}
|
||||
};
|
||||
|
||||
const char GyroSurge::_name[] PROGMEM = "GyroSurge";
|
@ -20,11 +20,11 @@
|
||||
XCL not connected
|
||||
AD0 not connected
|
||||
INT D8 (GPIO15) Interrupt pin
|
||||
|
||||
|
||||
Using usermod:
|
||||
1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||
2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||
3. I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h file
|
||||
3. I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h file
|
||||
for both classes must be in the include path of your project. To install the
|
||||
libraries add I2Cdevlib-MPU6050@fbde122cc5 to lib_deps in the platformio.ini file.
|
||||
4. You also need to change lib_compat_mode from strict to soft in platformio.ini (This ignores that I2Cdevlib-MPU6050 doesn't list platform compatibility)
|
||||
@ -33,6 +33,9 @@
|
||||
|
||||
#include "I2Cdev.h"
|
||||
|
||||
#undef DEBUG_PRINT
|
||||
#undef DEBUG_PRINTLN
|
||||
#undef DEBUG_PRINTF
|
||||
#include "MPU6050_6Axis_MotionApps20.h"
|
||||
//#include "MPU6050.h" // not necessary if using MotionApps include file
|
||||
|
||||
@ -42,6 +45,23 @@
|
||||
#include "Wire.h"
|
||||
#endif
|
||||
|
||||
// Restore debug macros
|
||||
// MPU6050 unfortunately uses the same macro names as WLED :(
|
||||
#undef DEBUG_PRINT
|
||||
#undef DEBUG_PRINTLN
|
||||
#undef DEBUG_PRINTF
|
||||
#ifdef WLED_DEBUG
|
||||
#define DEBUG_PRINT(x) DEBUGOUT.print(x)
|
||||
#define DEBUG_PRINTLN(x) DEBUGOUT.println(x)
|
||||
#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define DEBUG_PRINTF(x...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ================================================================
|
||||
// === INTERRUPT DETECTION ROUTINE ===
|
||||
// ================================================================
|
||||
@ -52,21 +72,31 @@ void IRAM_ATTR dmpDataReady() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class MPU6050Driver : public Usermod {
|
||||
private:
|
||||
MPU6050 mpu;
|
||||
bool enabled = true;
|
||||
|
||||
// configuration state
|
||||
// default values are set in readFromConfig
|
||||
// By making this a struct, we enable easy backup and comparison in the readFromConfig class
|
||||
struct config_t {
|
||||
bool enabled;
|
||||
int8_t interruptPin;
|
||||
int16_t gyro_offset[3];
|
||||
int16_t accel_offset[3];
|
||||
};
|
||||
config_t config;
|
||||
|
||||
// MPU control/status vars
|
||||
bool irqBound = false; // set true if we have bound the IRQ pin
|
||||
bool dmpReady = false; // set true if DMP init was successful
|
||||
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
|
||||
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
|
||||
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
|
||||
uint16_t fifoCount; // count of all bytes currently in FIFO
|
||||
uint8_t fifoBuffer[64]; // FIFO storage buffer
|
||||
|
||||
//NOTE: some of these can be removed to save memory, processing time
|
||||
// if the measurement isn't needed
|
||||
// TODO: some of these can be removed to save memory, processing time if the measurement isn't needed
|
||||
Quaternion qat; // [w, x, y, z] quaternion container
|
||||
float euler[3]; // [psi, theta, phi] Euler angle container
|
||||
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container
|
||||
@ -75,17 +105,67 @@ class MPU6050Driver : public Usermod {
|
||||
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
|
||||
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
|
||||
VectorFloat gravity; // [x, y, z] gravity vector
|
||||
uint32 sample_count;
|
||||
|
||||
static const int INTERRUPT_PIN = 15; // use pin 15 on ESP8266
|
||||
// Usermod output
|
||||
um_data_t um_data;
|
||||
|
||||
// config element names as progmem strs
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
static const char _interrupt_pin[];
|
||||
static const char _x_acc_bias[];
|
||||
static const char _y_acc_bias[];
|
||||
static const char _z_acc_bias[];
|
||||
static const char _x_gyro_bias[];
|
||||
static const char _y_gyro_bias[];
|
||||
static const char _z_gyro_bias[];
|
||||
|
||||
public:
|
||||
//Functions called by WLED
|
||||
|
||||
inline bool initDone() { return um_data.u_size != 0; }; // recycle this instead of storing an extra variable
|
||||
|
||||
//Functions called by WLED
|
||||
/*
|
||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||
*/
|
||||
void setup() {
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
dmpReady = false; // Start clean
|
||||
|
||||
// one time init
|
||||
if (!initDone()) {
|
||||
um_data.u_size = 9;
|
||||
um_data.u_type = new um_types_t[um_data.u_size];
|
||||
um_data.u_data = new void*[um_data.u_size];
|
||||
um_data.u_data[0] = &qat;
|
||||
um_data.u_type[0] = UMT_FLOAT_ARR;
|
||||
um_data.u_data[1] = &euler;
|
||||
um_data.u_type[1] = UMT_FLOAT_ARR;
|
||||
um_data.u_data[2] = &ypr;
|
||||
um_data.u_type[2] = UMT_FLOAT_ARR;
|
||||
um_data.u_data[3] = &aa;
|
||||
um_data.u_type[3] = UMT_INT16_ARR;
|
||||
um_data.u_data[4] = &gy;
|
||||
um_data.u_type[4] = UMT_INT16_ARR;
|
||||
um_data.u_data[5] = &aaReal;
|
||||
um_data.u_type[5] = UMT_INT16_ARR;
|
||||
um_data.u_data[6] = &aaWorld;
|
||||
um_data.u_type[6] = UMT_INT16_ARR;
|
||||
um_data.u_data[7] = &gravity;
|
||||
um_data.u_type[7] = UMT_FLOAT_ARR;
|
||||
um_data.u_data[8] = &sample_count;
|
||||
um_data.u_type[8] = UMT_UINT32;
|
||||
}
|
||||
|
||||
if (!config.enabled) return;
|
||||
if (i2c_scl<0 || i2c_sda<0) { DEBUG_PRINTLN(F("MPU6050: I2C is no good.")); return; }
|
||||
// Check the interrupt pin
|
||||
if (config.interruptPin >= 0) {
|
||||
irqBound = pinManager.allocatePin(config.interruptPin, false, PinOwner::UM_IMU);
|
||||
if (!irqBound) { DEBUG_PRINTLN(F("MPU6050: IRQ pin already in use.")); return; }
|
||||
pinMode(config.interruptPin, INPUT);
|
||||
};
|
||||
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||
@ -95,7 +175,6 @@ class MPU6050Driver : public Usermod {
|
||||
// initialize device
|
||||
DEBUG_PRINTLN(F("Initializing I2C devices..."));
|
||||
mpu.initialize();
|
||||
pinMode(INTERRUPT_PIN, INPUT);
|
||||
|
||||
// verify connection
|
||||
DEBUG_PRINTLN(F("Testing device connections..."));
|
||||
@ -105,11 +184,16 @@ class MPU6050Driver : public Usermod {
|
||||
DEBUG_PRINTLN(F("Initializing DMP..."));
|
||||
devStatus = mpu.dmpInitialize();
|
||||
|
||||
// supply your own gyro offsets here, scaled for min sensitivity
|
||||
mpu.setXGyroOffset(220);
|
||||
mpu.setYGyroOffset(76);
|
||||
mpu.setZGyroOffset(-85);
|
||||
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
|
||||
// set offsets (from config)
|
||||
mpu.setXGyroOffset(config.gyro_offset[0]);
|
||||
mpu.setYGyroOffset(config.gyro_offset[1]);
|
||||
mpu.setZGyroOffset(config.gyro_offset[2]);
|
||||
mpu.setXAccelOffset(config.accel_offset[0]);
|
||||
mpu.setYAccelOffset(config.accel_offset[1]);
|
||||
mpu.setZAccelOffset(config.accel_offset[2]);
|
||||
|
||||
// set sample rate
|
||||
mpu.setRate(16); // ~100Hz
|
||||
|
||||
// make sure it worked (returns 0 if so)
|
||||
if (devStatus == 0) {
|
||||
@ -117,17 +201,19 @@ class MPU6050Driver : public Usermod {
|
||||
DEBUG_PRINTLN(F("Enabling DMP..."));
|
||||
mpu.setDMPEnabled(true);
|
||||
|
||||
// enable Arduino interrupt detection
|
||||
DEBUG_PRINTLN(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
|
||||
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
|
||||
mpuIntStatus = mpu.getIntStatus();
|
||||
|
||||
// set our DMP Ready flag so the main loop() function knows it's okay to use it
|
||||
DEBUG_PRINTLN(F("DMP ready! Waiting for first interrupt..."));
|
||||
dmpReady = true;
|
||||
mpuInterrupt = true;
|
||||
if (irqBound) {
|
||||
// enable Arduino interrupt detection
|
||||
DEBUG_PRINTLN(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
|
||||
attachInterrupt(digitalPinToInterrupt(config.interruptPin), dmpDataReady, RISING);
|
||||
}
|
||||
|
||||
// get expected DMP packet size for later comparison
|
||||
packetSize = mpu.dmpGetFIFOPacketSize();
|
||||
|
||||
// set our DMP Ready flag so the main loop() function knows it's okay to use it
|
||||
DEBUG_PRINTLN(F("DMP ready!"));
|
||||
dmpReady = true;
|
||||
} else {
|
||||
// ERROR!
|
||||
// 1 = initial memory load failed
|
||||
@ -137,6 +223,9 @@ class MPU6050Driver : public Usermod {
|
||||
DEBUG_PRINT(devStatus);
|
||||
DEBUG_PRINTLN(")");
|
||||
}
|
||||
|
||||
fifoCount = 0;
|
||||
sample_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -153,28 +242,31 @@ class MPU6050Driver : public Usermod {
|
||||
*/
|
||||
void loop() {
|
||||
// if programming failed, don't try to do anything
|
||||
if (!enabled || !dmpReady || strip.isUpdating()) return;
|
||||
if (!config.enabled || !dmpReady || strip.isUpdating()) return;
|
||||
|
||||
// wait for MPU interrupt or extra packet(s) available
|
||||
// mpuInterrupt is fixed on if interrupt pin is disabled
|
||||
if (!mpuInterrupt && fifoCount < packetSize) return;
|
||||
|
||||
// reset interrupt flag and get INT_STATUS byte
|
||||
mpuInterrupt = false;
|
||||
mpuIntStatus = mpu.getIntStatus();
|
||||
|
||||
// get current FIFO count
|
||||
auto mpuIntStatus = mpu.getIntStatus();
|
||||
// Update current FIFO count
|
||||
fifoCount = mpu.getFIFOCount();
|
||||
|
||||
// check for overflow (this should never happen unless our code is too inefficient)
|
||||
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
|
||||
// reset so we can continue cleanly
|
||||
mpu.resetFIFO();
|
||||
DEBUG_PRINTLN(F("FIFO overflow!"));
|
||||
DEBUG_PRINTLN(F("MPU6050: FIFO overflow!"));
|
||||
|
||||
// otherwise, check for DMP data ready interrupt (this should happen frequently)
|
||||
} else if (mpuIntStatus & 0x02) {
|
||||
// wait for correct available data length, should be a VERY short wait
|
||||
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
|
||||
// otherwise, check for data ready
|
||||
} else if (fifoCount >= packetSize) {
|
||||
// clear local interrupt pending status, if not polling
|
||||
mpuInterrupt = !irqBound;
|
||||
|
||||
// DEBUG_PRINT(F("MPU6050: Processing packet: "));
|
||||
// DEBUG_PRINT(fifoCount);
|
||||
// DEBUG_PRINTLN(F(" bytes in FIFO"));
|
||||
|
||||
// read a packet from FIFO
|
||||
mpu.getFIFOBytes(fifoBuffer, packetSize);
|
||||
@ -183,7 +275,6 @@ class MPU6050Driver : public Usermod {
|
||||
// (this lets us immediately read more without waiting for an interrupt)
|
||||
fifoCount -= packetSize;
|
||||
|
||||
|
||||
//NOTE: some of these can be removed to save memory, processing time
|
||||
// if the measurement isn't needed
|
||||
mpu.dmpGetQuaternion(&qat, fifoBuffer);
|
||||
@ -194,87 +285,141 @@ class MPU6050Driver : public Usermod {
|
||||
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
|
||||
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &qat);
|
||||
mpu.dmpGetYawPitchRoll(ypr, &qat, &gravity);
|
||||
++sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
int reading = 20;
|
||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonObject imu_meas = user.createNestedObject("IMU");
|
||||
JsonArray quat_json = imu_meas.createNestedArray("Quat");
|
||||
// Unfortunately the web UI doesn't know how to print sub-objects: you just see '[object Object]'
|
||||
// For now, we just put everything in the root userdata object.
|
||||
//auto imu_meas = user.createNestedObject("IMU");
|
||||
auto& imu_meas = user;
|
||||
|
||||
// If an element is an array, the UI expects two elements in the form [value, unit]
|
||||
// Since our /value/ is an array, wrap it, eg. [[a, b, c]]
|
||||
JsonArray quat_json = imu_meas.createNestedArray("Quat").createNestedArray();
|
||||
quat_json.add(qat.w);
|
||||
quat_json.add(qat.x);
|
||||
quat_json.add(qat.y);
|
||||
quat_json.add(qat.z);
|
||||
JsonArray euler_json = imu_meas.createNestedArray("Euler");
|
||||
JsonArray euler_json = imu_meas.createNestedArray("Euler").createNestedArray();
|
||||
euler_json.add(euler[0]);
|
||||
euler_json.add(euler[1]);
|
||||
euler_json.add(euler[2]);
|
||||
JsonArray accel_json = imu_meas.createNestedArray("Accel");
|
||||
JsonArray accel_json = imu_meas.createNestedArray("Accel").createNestedArray();
|
||||
accel_json.add(aa.x);
|
||||
accel_json.add(aa.y);
|
||||
accel_json.add(aa.z);
|
||||
JsonArray gyro_json = imu_meas.createNestedArray("Gyro");
|
||||
JsonArray gyro_json = imu_meas.createNestedArray("Gyro").createNestedArray();
|
||||
gyro_json.add(gy.x);
|
||||
gyro_json.add(gy.y);
|
||||
gyro_json.add(gy.z);
|
||||
JsonArray world_json = imu_meas.createNestedArray("WorldAccel");
|
||||
JsonArray world_json = imu_meas.createNestedArray("WorldAccel").createNestedArray();
|
||||
world_json.add(aaWorld.x);
|
||||
world_json.add(aaWorld.y);
|
||||
world_json.add(aaWorld.z);
|
||||
JsonArray real_json = imu_meas.createNestedArray("RealAccel");
|
||||
JsonArray real_json = imu_meas.createNestedArray("RealAccel").createNestedArray();
|
||||
real_json.add(aaReal.x);
|
||||
real_json.add(aaReal.y);
|
||||
real_json.add(aaReal.z);
|
||||
JsonArray grav_json = imu_meas.createNestedArray("Gravity");
|
||||
JsonArray grav_json = imu_meas.createNestedArray("Gravity").createNestedArray();
|
||||
grav_json.add(gravity.x);
|
||||
grav_json.add(gravity.y);
|
||||
grav_json.add(gravity.z);
|
||||
JsonArray orient_json = imu_meas.createNestedArray("Orientation");
|
||||
JsonArray orient_json = imu_meas.createNestedArray("Orientation").createNestedArray();
|
||||
orient_json.add(ypr[0]);
|
||||
orient_json.add(ypr[1]);
|
||||
orient_json.add(ypr[2]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
//void addToJsonState(JsonObject& root)
|
||||
//{
|
||||
//root["user0"] = userVar0;
|
||||
//}
|
||||
|
||||
|
||||
/*
|
||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
||||
* Values in the state object may be modified by connected clients
|
||||
*/
|
||||
//void readFromJsonState(JsonObject& root)
|
||||
//{
|
||||
//if (root["bri"] == 255) DEBUG_PRINTLN(F("Don't burn down your garage!"));
|
||||
//}
|
||||
|
||||
|
||||
/*
|
||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
||||
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
|
||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||
*/
|
||||
// void addToConfig(JsonObject& root)
|
||||
// {
|
||||
// JsonObject top = root.createNestedObject("MPU6050_IMU");
|
||||
// JsonArray pins = top.createNestedArray("pin");
|
||||
// pins.add(HW_PIN_SCL);
|
||||
// pins.add(HW_PIN_SDA);
|
||||
// }
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
|
||||
//save these vars persistently whenever settings are saved
|
||||
top[FPSTR(_enabled)] = config.enabled;
|
||||
top[FPSTR(_interrupt_pin)] = config.interruptPin;
|
||||
top[FPSTR(_x_acc_bias)] = config.accel_offset[0];
|
||||
top[FPSTR(_y_acc_bias)] = config.accel_offset[1];
|
||||
top[FPSTR(_z_acc_bias)] = config.accel_offset[2];
|
||||
top[FPSTR(_x_gyro_bias)] = config.gyro_offset[0];
|
||||
top[FPSTR(_y_gyro_bias)] = config.gyro_offset[1];
|
||||
top[FPSTR(_z_gyro_bias)] = config.gyro_offset[2];
|
||||
}
|
||||
|
||||
/*
|
||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
||||
* This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page)
|
||||
*
|
||||
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
|
||||
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
|
||||
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||
*
|
||||
* Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings)
|
||||
*
|
||||
* getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present
|
||||
* The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them
|
||||
*
|
||||
* This function is guaranteed to be called on boot, but could also be called every time settings are updated
|
||||
*/
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
auto old_cfg = config;
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
|
||||
bool configComplete = top.isNull();
|
||||
// Ensure default configuration is loaded
|
||||
configComplete &= getJsonValue(top[FPSTR(_enabled)], config.enabled, true);
|
||||
configComplete &= getJsonValue(top[FPSTR(_interrupt_pin)], config.interruptPin, -1);
|
||||
configComplete &= getJsonValue(top[FPSTR(_x_acc_bias)], config.accel_offset[0], 0);
|
||||
configComplete &= getJsonValue(top[FPSTR(_y_acc_bias)], config.accel_offset[1], 0);
|
||||
configComplete &= getJsonValue(top[FPSTR(_z_acc_bias)], config.accel_offset[2], 0);
|
||||
configComplete &= getJsonValue(top[FPSTR(_x_gyro_bias)], config.gyro_offset[0], 0);
|
||||
configComplete &= getJsonValue(top[FPSTR(_y_gyro_bias)], config.gyro_offset[1], 0);
|
||||
configComplete &= getJsonValue(top[FPSTR(_z_gyro_bias)], config.gyro_offset[2], 0);
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
} else if (!initDone()) {
|
||||
DEBUG_PRINTLN(F(": config loaded."));
|
||||
} else if (memcmp(&config, &old_cfg, sizeof(config)) == 0) {
|
||||
DEBUG_PRINTLN(F(": config unchanged."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(": config updated."));
|
||||
// Previously loaded and config changed
|
||||
if (irqBound && ((old_cfg.interruptPin != config.interruptPin) || !config.enabled)) {
|
||||
detachInterrupt(old_cfg.interruptPin);
|
||||
pinManager.deallocatePin(old_cfg.interruptPin, PinOwner::UM_IMU);
|
||||
irqBound = false;
|
||||
}
|
||||
|
||||
// Just re-init
|
||||
setup();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
bool getUMData(um_data_t **data)
|
||||
{
|
||||
if (!data || !config.enabled || !dmpReady) return false; // no pointer provided by caller or not enabled -> exit
|
||||
*data = &um_data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||
@ -285,3 +430,14 @@ class MPU6050Driver : public Usermod {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
const char MPU6050Driver::_name[] PROGMEM = "MPU6050_IMU";
|
||||
const char MPU6050Driver::_enabled[] PROGMEM = "enabled";
|
||||
const char MPU6050Driver::_interrupt_pin[] PROGMEM = "interrupt_pin";
|
||||
const char MPU6050Driver::_x_acc_bias[] PROGMEM = "x_acc_bias";
|
||||
const char MPU6050Driver::_y_acc_bias[] PROGMEM = "y_acc_bias";
|
||||
const char MPU6050Driver::_z_acc_bias[] PROGMEM = "z_acc_bias";
|
||||
const char MPU6050Driver::_x_gyro_bias[] PROGMEM = "x_gyro_bias";
|
||||
const char MPU6050Driver::_y_gyro_bias[] PROGMEM = "y_gyro_bias";
|
||||
const char MPU6050Driver::_z_gyro_bias[] PROGMEM = "z_gyro_bias";
|
||||
|
@ -84,11 +84,11 @@ class QuinLEDAnPentaUsermod : public Usermod
|
||||
void getCurrentUsedLedPins()
|
||||
{
|
||||
for (int8_t lp = 0; lp <= 4; lp++) currentLedPins[lp] = 0;
|
||||
byte numBusses = busses.getNumBusses();
|
||||
byte numBusses = BusManager::getNumBusses();
|
||||
byte numUsedPins = 0;
|
||||
|
||||
for (int8_t b = 0; b < numBusses; b++) {
|
||||
Bus* curBus = busses.getBus(b);
|
||||
Bus* curBus = BusManager::getBus(b);
|
||||
if (curBus != nullptr) {
|
||||
uint8_t pins[5] = {0, 0, 0, 0, 0};
|
||||
currentBussesNumPins[b] = curBus->getPins(pins);
|
||||
@ -104,11 +104,11 @@ class QuinLEDAnPentaUsermod : public Usermod
|
||||
|
||||
void getCurrentLedcValues()
|
||||
{
|
||||
byte numBusses = busses.getNumBusses();
|
||||
byte numBusses = BusManager::getNumBusses();
|
||||
byte numLedc = 0;
|
||||
|
||||
for (int8_t b = 0; b < numBusses; b++) {
|
||||
Bus* curBus = busses.getBus(b);
|
||||
Bus* curBus = BusManager::getBus(b);
|
||||
if (curBus != nullptr) {
|
||||
uint32_t curPixColor = curBus->getPixelColor(0);
|
||||
uint8_t _data[5] = {255, 255, 255, 255, 255};
|
||||
|
@ -3444,8 +3444,8 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc
|
||||
uint16_t mode_exploding_fireworks(void)
|
||||
{
|
||||
if (SEGLEN == 1) return mode_static();
|
||||
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
|
||||
const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
|
||||
const uint16_t cols = SEGMENT.is2D() ? SEGMENT.virtualWidth() : 1;
|
||||
const uint16_t rows = SEGMENT.is2D() ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
|
||||
|
||||
//allocate segment data
|
||||
uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640
|
||||
@ -3476,11 +3476,11 @@ uint16_t mode_exploding_fireworks(void)
|
||||
if (SEGENV.aux0 < 2) { //FLARE
|
||||
if (SEGENV.aux0 == 0) { //init flare
|
||||
flare->pos = 0;
|
||||
flare->posX = strip.isMatrix ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D
|
||||
flare->posX = SEGMENT.is2D() ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D
|
||||
uint16_t peakHeight = 75 + random8(180); //0-255
|
||||
peakHeight = (peakHeight * (rows -1)) >> 8;
|
||||
flare->vel = sqrtf(-2.0f * gravity * peakHeight);
|
||||
flare->velX = strip.isMatrix ? (random8(9)-4)/32.f : 0; // no X velocity on 1D
|
||||
flare->velX = SEGMENT.is2D() ? (random8(9)-4)/64.0f : 0; // no X velocity on 1D
|
||||
flare->col = 255; //brightness
|
||||
SEGENV.aux0 = 1;
|
||||
}
|
||||
@ -3488,12 +3488,14 @@ uint16_t mode_exploding_fireworks(void)
|
||||
// launch
|
||||
if (flare->vel > 12 * gravity) {
|
||||
// flare
|
||||
if (strip.isMatrix) SEGMENT.setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col);
|
||||
else SEGMENT.setPixelColor(int(flare->posX) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col);
|
||||
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col);
|
||||
else SEGMENT.setPixelColor((flare->posX > 0.0f) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col);
|
||||
flare->pos += flare->vel;
|
||||
flare->posX += flare->velX;
|
||||
flare->pos = constrain(flare->pos, 0, rows-1);
|
||||
flare->posX = constrain(flare->posX, 0, cols-strip.isMatrix);
|
||||
if (SEGMENT.is2D()) {
|
||||
flare->posX += flare->velX;
|
||||
flare->posX = constrain(flare->posX, 0, cols-1);
|
||||
}
|
||||
flare->vel += gravity;
|
||||
flare->col -= 2;
|
||||
} else {
|
||||
@ -3516,12 +3518,12 @@ uint16_t mode_exploding_fireworks(void)
|
||||
sparks[i].posX = flare->posX;
|
||||
sparks[i].vel = (float(random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1
|
||||
sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips
|
||||
sparks[i].velX = strip.isMatrix ? (float(random16(10001)) / 10000.0f) - 0.5f : 0; // from -0.5 to 0.5
|
||||
sparks[i].velX = SEGMENT.is2D() ? (float(random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1
|
||||
sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
|
||||
//sparks[i].col = constrain(sparks[i].col, 0, 345);
|
||||
sparks[i].colIndex = random8();
|
||||
sparks[i].vel *= flare->pos/rows; // proportional to height
|
||||
sparks[i].velX *= strip.isMatrix ? flare->posX/cols : 0; // proportional to width
|
||||
sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width
|
||||
sparks[i].vel *= -gravity *50;
|
||||
}
|
||||
//sparks[1].col = 345; // this will be our known spark
|
||||
@ -3534,11 +3536,11 @@ uint16_t mode_exploding_fireworks(void)
|
||||
sparks[i].pos += sparks[i].vel;
|
||||
sparks[i].posX += sparks[i].velX;
|
||||
sparks[i].vel += *dying_gravity;
|
||||
sparks[i].velX += strip.isMatrix ? *dying_gravity : 0;
|
||||
sparks[i].velX += SEGMENT.is2D() ? *dying_gravity : 0;
|
||||
if (sparks[i].col > 3) sparks[i].col -= 4;
|
||||
|
||||
if (sparks[i].pos > 0 && sparks[i].pos < rows) {
|
||||
if (strip.isMatrix && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue;
|
||||
if (SEGMENT.is2D() && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue;
|
||||
uint16_t prog = sparks[i].col;
|
||||
uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0);
|
||||
CRGB c = CRGB::Black; //HeatColor(sparks[i].col);
|
||||
@ -3550,7 +3552,7 @@ uint16_t mode_exploding_fireworks(void)
|
||||
c.g = qsub8(c.g, cooling);
|
||||
c.b = qsub8(c.b, cooling * 2);
|
||||
}
|
||||
if (strip.isMatrix) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue);
|
||||
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue);
|
||||
else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue);
|
||||
}
|
||||
}
|
||||
@ -5292,7 +5294,6 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
memset(SEGMENT.data, 0, dataSize); // no falling spawns
|
||||
SEGMENT.fill(BLACK);
|
||||
SEGENV.step = 0;
|
||||
}
|
||||
|
153
wled00/FX.h
153
wled00/FX.h
@ -62,10 +62,10 @@
|
||||
//#define FRAMETIME _frametime
|
||||
#define FRAMETIME strip.getFrameTime()
|
||||
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
/* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#ifdef ESP8266
|
||||
#define MAX_NUM_SEGMENTS 16
|
||||
#define MAX_NUM_SEGMENTS 12
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#define MAX_SEGMENT_DATA 5120
|
||||
#else
|
||||
@ -73,9 +73,13 @@
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_SEGMENT_DATA 24576
|
||||
#if defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1024 // 32k by default
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default
|
||||
#endif
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA 32767
|
||||
#define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -278,7 +282,7 @@
|
||||
#define FX_MODE_RIPPLEPEAK 148
|
||||
#define FX_MODE_2DFIRENOISE 149
|
||||
#define FX_MODE_2DSQUAREDSWIRL 150
|
||||
#define FX_MODE_2DFIRE2012 151
|
||||
// #define FX_MODE_2DFIRE2012 151
|
||||
#define FX_MODE_2DDNA 152
|
||||
#define FX_MODE_2DMATRIX 153
|
||||
#define FX_MODE_2DMETABALLS 154
|
||||
@ -288,7 +292,7 @@
|
||||
#define FX_MODE_GRAVFREQ 158
|
||||
#define FX_MODE_DJLIGHT 159
|
||||
#define FX_MODE_2DFUNKYPLANK 160
|
||||
#define FX_MODE_2DCENTERBARS 161
|
||||
//#define FX_MODE_2DCENTERBARS 161
|
||||
#define FX_MODE_2DPULSER 162
|
||||
#define FX_MODE_BLURZ 163
|
||||
#define FX_MODE_2DDRIFT 164
|
||||
@ -531,7 +535,7 @@ typedef struct Segment {
|
||||
#endif
|
||||
static void handleRandomPalette();
|
||||
|
||||
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, uint8_t segId = 255);
|
||||
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
|
||||
void setCCT(uint16_t k);
|
||||
void setOpacity(uint8_t o);
|
||||
@ -543,9 +547,9 @@ typedef struct Segment {
|
||||
|
||||
// runtime data functions
|
||||
inline uint16_t dataSize(void) const { return _dataLen; }
|
||||
bool allocateData(size_t len);
|
||||
void deallocateData(void);
|
||||
void resetIfRequired(void);
|
||||
bool allocateData(size_t len); // allocates effect data buffer in heap and clears it
|
||||
void deallocateData(void); // deallocates (frees) effect data buffer from heap
|
||||
void resetIfRequired(void); // sets all SEGENV variables to 0 and clears data buffer
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
@ -555,17 +559,17 @@ typedef struct Segment {
|
||||
inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true)
|
||||
|
||||
// transition functions
|
||||
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
||||
void stopTransition(void);
|
||||
void startTransition(uint16_t dur); // transition has to start before actual segment values change
|
||||
void stopTransition(void); // ends transition mode by destroying transition structure
|
||||
void handleTransition(void);
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
void swapSegenv(tmpsegd_t &tmpSegD);
|
||||
void restoreSegenv(tmpsegd_t &tmpSegD);
|
||||
void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
|
||||
void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
|
||||
#endif
|
||||
uint16_t progress(void); //transition progression between 0-65535
|
||||
uint8_t currentBri(bool useCct = false);
|
||||
uint8_t currentMode(void);
|
||||
uint32_t currentColor(uint8_t slot);
|
||||
uint16_t progress(void); // transition progression between 0-65535
|
||||
uint8_t currentBri(bool useCct = false); // current segment brightness/CCT (blended while in transition)
|
||||
uint8_t currentMode(void); // currently active effect/mode (while in transition)
|
||||
uint32_t currentColor(uint8_t slot); // currently active segment color (blended while in transition)
|
||||
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
|
||||
CRGBPalette16 ¤tPalette(CRGBPalette16 &tgt, uint8_t paletteID);
|
||||
|
||||
@ -594,9 +598,9 @@ typedef struct Segment {
|
||||
uint32_t color_wheel(uint8_t pos);
|
||||
|
||||
// 2D matrix
|
||||
uint16_t virtualWidth(void) const;
|
||||
uint16_t virtualHeight(void) const;
|
||||
uint16_t nrOfVStrips(void) const;
|
||||
uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing)
|
||||
uint16_t virtualHeight(void) const; // segment height in virtual pixels (accounts for groupping and spacing)
|
||||
uint16_t nrOfVStrips(void) const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment
|
||||
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
@ -682,10 +686,7 @@ class WS2812FX { // 96 bytes
|
||||
WS2812FX() :
|
||||
paletteFade(0),
|
||||
paletteBlend(0),
|
||||
milliampsPerLed(55),
|
||||
cctBlending(0),
|
||||
ablMilliampsMax(ABL_MILLIAMPS_DEFAULT),
|
||||
currentMilliamps(0),
|
||||
now(millis()),
|
||||
timebase(0),
|
||||
isMatrix(false),
|
||||
@ -697,6 +698,7 @@ class WS2812FX { // 96 bytes
|
||||
_colors_t{0,0,0},
|
||||
_virtualSegmentLength(0),
|
||||
// true private variables
|
||||
_suspend(false),
|
||||
_length(DEFAULT_LED_COUNT),
|
||||
_brightness(DEFAULT_BRIGHTNESS),
|
||||
_transitionDur(750),
|
||||
@ -745,38 +747,39 @@ class WS2812FX { // 96 bytes
|
||||
|
||||
void
|
||||
#ifdef WLED_DEBUG
|
||||
printSize(),
|
||||
printSize(), // prints memory usage for strip components
|
||||
#endif
|
||||
finalizeInit(),
|
||||
service(void),
|
||||
setMode(uint8_t segid, uint8_t m),
|
||||
setColor(uint8_t slot, uint32_t c),
|
||||
setCCT(uint16_t k),
|
||||
setBrightness(uint8_t b, bool direct = false),
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||
purgeSegments(bool force = false),
|
||||
finalizeInit(), // initialises strip components
|
||||
service(void), // executes effect functions when due and calls strip.show()
|
||||
setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API)
|
||||
setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API)
|
||||
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
|
||||
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
|
||||
purgeSegments(void), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1),
|
||||
setMainSegmentId(uint8_t n),
|
||||
resetSegments(),
|
||||
makeAutoSegments(bool forceReset = false),
|
||||
fixInvalidSegments(),
|
||||
setPixelColor(int n, uint32_t c),
|
||||
show(void),
|
||||
resetSegments(), // marks all segments for reset
|
||||
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
||||
fixInvalidSegments(), // fixes incorrect segment configuration
|
||||
setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c
|
||||
show(void), // initiates LED output
|
||||
setTargetFps(uint8_t fps),
|
||||
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name), // add effect to the list; defined in FX.cpp
|
||||
setupEffectData(void); // add default effects to the list; defined in FX.cpp
|
||||
setupEffectData(void); // add default effects to the list; defined in FX.cpp
|
||||
|
||||
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
|
||||
inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); }
|
||||
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
||||
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
||||
inline void fill(uint32_t c) { for (int i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
// outsmart the compiler :) by correctly overloading
|
||||
inline void setPixelColor(int n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(int n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
||||
inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
||||
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
||||
inline void setTransition(uint16_t t) { _transitionDur = t; }
|
||||
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
||||
inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
inline void trigger(void) { _triggered = true; } // Forces the next frame to be computed on all active segments.
|
||||
inline void setShowCallback(show_callback cb) { _callback = cb; }
|
||||
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
|
||||
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
|
||||
inline void suspend(void) { _suspend = true; } // will suspend (and canacel) strip.service() execution
|
||||
inline void resume(void) { _suspend = false; } // will resume strip.service() execution
|
||||
|
||||
bool
|
||||
paletteFade,
|
||||
@ -787,13 +790,14 @@ class WS2812FX { // 96 bytes
|
||||
isUpdating(void),
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; }
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
||||
inline bool isServicing(void) { return _isServicing; } // returns true if strip.service() is executing
|
||||
inline bool hasWhiteChannel(void) { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
||||
inline bool isOffRefreshRequired(void) { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
||||
inline bool isSuspended(void) { return _suspend; } // returns true if strip.service() execution is suspended
|
||||
inline bool needsUpdate(void) { return _triggered; } // returns true if strip received a trigger() request
|
||||
|
||||
uint8_t
|
||||
paletteBlend,
|
||||
milliampsPerLed,
|
||||
cctBlending,
|
||||
getActiveSegmentsNum(void),
|
||||
getFirstSelectedSegId(void),
|
||||
@ -801,35 +805,33 @@ class WS2812FX { // 96 bytes
|
||||
getActiveSegsLightCapabilities(bool selectedOnly = false),
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
inline uint8_t getBrightness(void) { return _brightness; }
|
||||
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; }
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; }
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count
|
||||
inline uint8_t getTargetFps() { return _targetFps; }
|
||||
inline uint8_t getModeCount() { return _modeCount; }
|
||||
inline uint8_t getBrightness(void) { return _brightness; } // returns current strip brightness
|
||||
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; } // returns main segment index
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count
|
||||
inline uint8_t getTargetFps() { return _targetFps; } // returns rough FPS value for las 2s interval
|
||||
inline uint8_t getModeCount() { return _modeCount; } // returns number of registered modes/effects
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
getLengthPhysical(void),
|
||||
getLengthTotal(void), // will include virtual/nonexistent pixels in matrix
|
||||
getFps(),
|
||||
getMappedPixelIndex(uint16_t index);
|
||||
|
||||
inline uint16_t getFrameTime(void) { return _frametime; }
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getLength(void) { return _length; } // 2D matrix may have less pixels than W*H
|
||||
inline uint16_t getTransition(void) { return _transitionDur; }
|
||||
inline uint16_t getFrameTime(void) { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength(void) { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition(void) { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
getPixelColor(uint16_t);
|
||||
|
||||
inline uint32_t getLastShow(void) { return _lastShow; }
|
||||
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; }
|
||||
inline uint32_t getLastShow(void) { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
||||
|
||||
const char *
|
||||
getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
@ -838,9 +840,9 @@ class WS2812FX { // 96 bytes
|
||||
getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||
|
||||
Segment& getSegment(uint8_t id);
|
||||
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; }
|
||||
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; }
|
||||
inline Segment* getSegments(void) { return &(_segments[0]); }
|
||||
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
|
||||
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; } // returns reference to main segment
|
||||
inline Segment* getSegments(void) { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
|
||||
|
||||
// 2D support (panels)
|
||||
bool
|
||||
@ -876,10 +878,10 @@ class WS2812FX { // 96 bytes
|
||||
std::vector<Panel> panel;
|
||||
#endif
|
||||
|
||||
void setUpMatrix();
|
||||
void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration
|
||||
|
||||
// outsmart the compiler :) by correctly overloading
|
||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(y * Segment::maxWidth + x, c); }
|
||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
|
||||
@ -900,6 +902,8 @@ class WS2812FX { // 96 bytes
|
||||
friend class Segment;
|
||||
|
||||
private:
|
||||
volatile bool _suspend;
|
||||
|
||||
uint16_t _length;
|
||||
uint8_t _brightness;
|
||||
uint16_t _transitionDur;
|
||||
@ -933,9 +937,10 @@ class WS2812FX { // 96 bytes
|
||||
uint16_t _qStart, _qStop, _qStartY, _qStopY;
|
||||
uint8_t _qGrouping, _qSpacing;
|
||||
uint16_t _qOffset;
|
||||
|
||||
/*
|
||||
void
|
||||
setUpSegmentFromQueuedChanges(void);
|
||||
*/
|
||||
};
|
||||
|
||||
extern const char JSON_mode_names[];
|
||||
|
@ -36,14 +36,9 @@
|
||||
// so matrix should disable regular ledmap processing
|
||||
void WS2812FX::setUpMatrix() {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
// erase old ledmap, just in case.
|
||||
if (customMappingTable != nullptr) delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
customMappingSize = 0;
|
||||
|
||||
// isMatrix is set in cfg.cpp or set.cpp
|
||||
if (isMatrix) {
|
||||
// calculate width dynamically because it will have gaps
|
||||
// calculate width dynamically because it may have gaps
|
||||
Segment::maxWidth = 1;
|
||||
Segment::maxHeight = 1;
|
||||
for (size_t i = 0; i < panel.size(); i++) {
|
||||
@ -68,15 +63,17 @@ void WS2812FX::setUpMatrix() {
|
||||
return;
|
||||
}
|
||||
|
||||
customMappingTable = new uint16_t[Segment::maxWidth * Segment::maxHeight];
|
||||
customMappingSize = 0; // prevent use of mapping if anything goes wrong
|
||||
|
||||
if (customMappingTable == nullptr) customMappingTable = new uint16_t[getLengthTotal()];
|
||||
|
||||
if (customMappingTable != nullptr) {
|
||||
customMappingSize = Segment::maxWidth * Segment::maxHeight;
|
||||
customMappingSize = getLengthTotal();
|
||||
|
||||
// fill with empty in case we don't fill the entire matrix
|
||||
for (size_t i = 0; i< customMappingSize; i++) {
|
||||
customMappingTable[i] = (uint16_t)-1;
|
||||
}
|
||||
unsigned matrixSize = Segment::maxWidth * Segment::maxHeight;
|
||||
for (unsigned i = 0; i<matrixSize; i++) customMappingTable[i] = 0xFFFFU;
|
||||
for (unsigned i = matrixSize; i<getLengthTotal(); i++) customMappingTable[i] = i; // trailing LEDs for ledmap (after matrix) if it exist
|
||||
|
||||
// we will try to load a "gap" array (a JSON file)
|
||||
// the array has to have the same amount of values as mapping array (or larger)
|
||||
@ -94,14 +91,14 @@ void WS2812FX::setUpMatrix() {
|
||||
DEBUG_PRINT(F("Reading LED gap from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
// read the array into global JSON buffer
|
||||
if (readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
if (readObjectFromFile(fileName, nullptr, pDoc)) {
|
||||
// the array is similar to ledmap, except it has only 3 values:
|
||||
// -1 ... missing pixel (do not increase pixel count)
|
||||
// 0 ... inactive pixel (it does count, but should be mapped out (-1))
|
||||
// 1 ... active pixel (it will count and will be mapped)
|
||||
JsonArray map = doc.as<JsonArray>();
|
||||
JsonArray map = pDoc->as<JsonArray>();
|
||||
gapSize = map.size();
|
||||
if (!map.isNull() && gapSize >= customMappingSize) { // not an empty map
|
||||
if (!map.isNull() && gapSize >= matrixSize) { // not an empty map
|
||||
gapTable = new int8_t[gapSize];
|
||||
if (gapTable) for (size_t i = 0; i < gapSize; i++) {
|
||||
gapTable[i] = constrain(map[i], -1, 1);
|
||||
|
@ -143,27 +143,28 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// allocates effect data buffer on heap and initialises (erases) it
|
||||
bool IRAM_ATTR Segment::allocateData(size_t len) {
|
||||
if (len == 0) return false; // nothing to do
|
||||
if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation)
|
||||
if (call == 0) memset(data, 0, len); // erase buffer if called during effect initialisation
|
||||
return true;
|
||||
}
|
||||
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
|
||||
deallocateData();
|
||||
if (len == 0) return false; // nothing to do
|
||||
deallocateData(); // if the old buffer was smaller release it first
|
||||
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
|
||||
// not enough memory
|
||||
DEBUG_PRINT(F("!!! Effect RAM depleted: "));
|
||||
DEBUG_PRINTF("%d/%d !!!\n", len, Segment::getUsedSegmentData());
|
||||
errorFlag = ERR_NORAM;
|
||||
return false;
|
||||
}
|
||||
// do not use SPI RAM on ESP32 since it is slow
|
||||
data = (byte*) malloc(len);
|
||||
data = (byte*)calloc(len, sizeof(byte));
|
||||
if (!data) { DEBUG_PRINTLN(F("!!! Allocation failed. !!!")); return false; } // allocation failed
|
||||
Segment::addUsedSegmentData(len);
|
||||
//DEBUG_PRINTF("--- Allocated data (%p): %d/%d -> %p\n", this, len, Segment::getUsedSegmentData(), data);
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -194,7 +195,7 @@ void IRAM_ATTR Segment::deallocateData() {
|
||||
void Segment::resetIfRequired() {
|
||||
if (!reset) return;
|
||||
//DEBUG_PRINTF("-- Segment reset: %p\n", this);
|
||||
deallocateData();
|
||||
if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData())
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
reset = false;
|
||||
}
|
||||
@ -468,7 +469,7 @@ void Segment::handleRandomPalette() {
|
||||
}
|
||||
|
||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t segId) {
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
||||
// return if neither bounds nor grouping have changed
|
||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -561,35 +562,36 @@ void Segment::setOption(uint8_t n, bool val) {
|
||||
}
|
||||
|
||||
void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
// skip reserved
|
||||
while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++;
|
||||
if (fx >= strip.getModeCount()) fx = 0; // set solid mode
|
||||
// if we have a valid mode & is not reserved
|
||||
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
|
||||
if (fx != mode) {
|
||||
if (fx != mode) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
||||
#endif
|
||||
mode = fx;
|
||||
// load default values from effect string
|
||||
if (loadDefaults) {
|
||||
int16_t sOpt;
|
||||
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
||||
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
|
||||
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
|
||||
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
|
||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
|
||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||
}
|
||||
markForReset();
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
mode = fx;
|
||||
// load default values from effect string
|
||||
if (loadDefaults) {
|
||||
int16_t sOpt;
|
||||
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
||||
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
|
||||
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
|
||||
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
|
||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
|
||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||
}
|
||||
markForReset();
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
}
|
||||
|
||||
@ -751,10 +753,10 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
uint32_t tmpCol = col;
|
||||
// set all the pixels in the group
|
||||
for (int j = 0; j < grouping; j++) {
|
||||
uint16_t indexSet = i + ((reverse) ? -j : j);
|
||||
unsigned indexSet = i + ((reverse) ? -j : j);
|
||||
if (indexSet >= start && indexSet < stop) {
|
||||
if (mirror) { //set the corresponding mirrored pixel
|
||||
uint16_t indexMir = stop - indexSet + start - 1;
|
||||
unsigned indexMir = stop - indexSet + start - 1;
|
||||
indexMir += offset; // offset/phase
|
||||
if (indexMir >= stop) indexMir -= len; // wrap
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
@ -897,8 +899,8 @@ void Segment::refreshLightCapabilities() {
|
||||
segStopIdx = stop;
|
||||
}
|
||||
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
for (unsigned b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (!bus->isOk()) continue;
|
||||
if (bus->getStart() >= segStopIdx) continue;
|
||||
@ -1083,7 +1085,7 @@ void WS2812FX::finalizeInit(void) {
|
||||
_hasWhiteChannel = _isOffRefreshRequired = false;
|
||||
|
||||
//if busses failed to load, add default (fresh install, FS issue, ...)
|
||||
if (busses.getNumBusses() == 0) {
|
||||
if (BusManager::getNumBusses() == 0) {
|
||||
DEBUG_PRINTLN(F("No busses, init default"));
|
||||
const uint8_t defDataPins[] = {DATA_PINS};
|
||||
const uint16_t defCounts[] = {PIXEL_COUNTS};
|
||||
@ -1096,13 +1098,13 @@ void WS2812FX::finalizeInit(void) {
|
||||
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
prevLen += count;
|
||||
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY);
|
||||
if (busses.add(defCfg) == -1) break;
|
||||
if (BusManager::add(defCfg) == -1) break;
|
||||
}
|
||||
}
|
||||
|
||||
_length = 0;
|
||||
for (int i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
for (int i=0; i<BusManager::getNumBusses(); i++) {
|
||||
Bus *bus = BusManager::getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
@ -1120,29 +1122,28 @@ void WS2812FX::finalizeInit(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (isMatrix) setUpMatrix();
|
||||
else {
|
||||
Segment::maxWidth = _length;
|
||||
Segment::maxHeight = 1;
|
||||
}
|
||||
Segment::maxWidth = _length;
|
||||
Segment::maxHeight = 1;
|
||||
|
||||
//segments are created in makeAutoSegments();
|
||||
DEBUG_PRINTLN(F("Loading custom palettes"));
|
||||
loadCustomPalettes(); // (re)load all custom palettes
|
||||
DEBUG_PRINTLN(F("Loading custom ledmaps"));
|
||||
deserializeMap(); // (re)load default ledmap
|
||||
deserializeMap(); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist)
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return;
|
||||
bool doShow = false;
|
||||
|
||||
_isServicing = true;
|
||||
_segment_index = 0;
|
||||
Segment::handleRandomPalette(); // move it into for loop when each segment has individual random palette
|
||||
for (segment &seg : _segments) {
|
||||
if (_suspend) return; // immediately stop processing segments if suspend requested during service()
|
||||
|
||||
// process transition (mode changes in the middle of transition)
|
||||
seg.handleTransition();
|
||||
// reset the segment runtime data if needed
|
||||
@ -1162,7 +1163,7 @@ void WS2812FX::service() {
|
||||
_colors_t[1] = gamma32(seg.currentColor(1));
|
||||
_colors_t[2] = gamma32(seg.currentColor(2));
|
||||
seg.currentPalette(_currentPalette, seg.palette); // we need to pass reference
|
||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(true), correctWB);
|
||||
if (!cctFromRgb || correctWB) BusManager::setSegmentCCT(seg.currentBri(true), correctWB);
|
||||
// Effect blending
|
||||
// When two effects are being blended, each may have different segment data, this
|
||||
// data needs to be saved first and then restored before running previous mode.
|
||||
@ -1189,11 +1190,11 @@ void WS2812FX::service() {
|
||||
|
||||
seg.next_time = nowUp + delay;
|
||||
}
|
||||
if (_segment_index == _queuedChangesSegId) setUpSegmentFromQueuedChanges();
|
||||
// if (_segment_index == _queuedChangesSegId) setUpSegmentFromQueuedChanges();
|
||||
_segment_index++;
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
busses.setSegmentCCT(-1);
|
||||
BusManager::setSegmentCCT(-1);
|
||||
_isServicing = false;
|
||||
_triggered = false;
|
||||
|
||||
@ -1209,16 +1210,16 @@ void WS2812FX::service() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col) {
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
|
||||
i = getMappedPixelIndex(i);
|
||||
if (i >= _length) return;
|
||||
busses.setPixelColor(i, col);
|
||||
BusManager::setPixelColor(i, col);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) {
|
||||
i = getMappedPixelIndex(i);
|
||||
if (i >= _length) return 0;
|
||||
return busses.getPixelColor(i);
|
||||
return BusManager::getPixelColor(i);
|
||||
}
|
||||
|
||||
void WS2812FX::show(void) {
|
||||
@ -1229,7 +1230,7 @@ void WS2812FX::show(void) {
|
||||
// some buses send asynchronously and this method will return before
|
||||
// all of the data has been sent.
|
||||
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
|
||||
busses.show();
|
||||
BusManager::show();
|
||||
|
||||
unsigned long showNow = millis();
|
||||
size_t diff = showNow - _lastShow;
|
||||
@ -1244,7 +1245,7 @@ void WS2812FX::show(void) {
|
||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
||||
*/
|
||||
bool WS2812FX::isUpdating() {
|
||||
return !busses.canAllShow();
|
||||
return !BusManager::canAllShow();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1303,7 +1304,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
}
|
||||
// setting brightness with NeoPixelBusLg has no effect on already painted pixels,
|
||||
// so we need to force an update to existing buffer
|
||||
busses.setBrightness(b);
|
||||
BusManager::setBrightness(b);
|
||||
if (!direct) {
|
||||
unsigned long t = millis();
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
@ -1359,8 +1360,8 @@ uint16_t WS2812FX::getLengthTotal(void) {
|
||||
|
||||
uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
uint16_t len = 0;
|
||||
for (size_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
|
||||
len += bus->getLength();
|
||||
}
|
||||
@ -1371,8 +1372,8 @@ uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
//returns if there is an RGBW bus (supports RGB and White, not only white)
|
||||
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
||||
bool WS2812FX::hasRGBWBus(void) {
|
||||
for (size_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
if (bus->hasRGB() && bus->hasWhite()) return true;
|
||||
}
|
||||
@ -1381,8 +1382,8 @@ bool WS2812FX::hasRGBWBus(void) {
|
||||
|
||||
bool WS2812FX::hasCCTBus(void) {
|
||||
if (cctFromRgb && !correctWB) return false;
|
||||
for (size_t b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
switch (bus->getType()) {
|
||||
case TYPE_ANALOG_5CH:
|
||||
@ -1393,18 +1394,18 @@ bool WS2812FX::hasCCTBus(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WS2812FX::purgeSegments(bool force) {
|
||||
void WS2812FX::purgeSegments() {
|
||||
// remove all inactive segments (from the back)
|
||||
int deleted = 0;
|
||||
if (_segments.size() <= 1) return;
|
||||
for (size_t i = _segments.size()-1; i > 0; i--)
|
||||
if (_segments[i].stop == 0 || force) {
|
||||
if (_segments[i].stop == 0) {
|
||||
deleted++;
|
||||
_segments.erase(_segments.begin() + i);
|
||||
}
|
||||
if (deleted) {
|
||||
_segments.shrink_to_fit();
|
||||
/*if (_mainSegment >= _segments.size())*/ setMainSegmentId(0);
|
||||
setMainSegmentId(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1419,7 +1420,7 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
|
||||
appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
|
||||
/*
|
||||
if (_queuedChangesSegId == segId) _queuedChangesSegId = 255; // cancel queued change if already queued for this segment
|
||||
|
||||
if (segId < getMaxSegments() && segId == getCurrSegmentId() && isServicing()) { // queue change to prevent concurrent access
|
||||
@ -1431,17 +1432,19 @@ void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t group
|
||||
DEBUG_PRINT(F("Segment queued: ")); DEBUG_PRINTLN(segId);
|
||||
return; // queued changes are applied immediately after effect function returns
|
||||
}
|
||||
|
||||
*/
|
||||
suspend();
|
||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
resume();
|
||||
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
|
||||
}
|
||||
|
||||
/*
|
||||
void WS2812FX::setUpSegmentFromQueuedChanges() {
|
||||
if (_queuedChangesSegId >= getSegmentsNum()) return;
|
||||
getSegment(_queuedChangesSegId).setUp(_qStart, _qStop, _qGrouping, _qSpacing, _qOffset, _qStartY, _qStopY);
|
||||
_segments[_queuedChangesSegId].setUp(_qStart, _qStop, _qGrouping, _qSpacing, _qOffset, _qStartY, _qStopY);
|
||||
_queuedChangesSegId = 255;
|
||||
}
|
||||
|
||||
*/
|
||||
void WS2812FX::resetSegments() {
|
||||
_segments.clear(); // destructs all Segment as part of clearing
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -1468,8 +1471,8 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = s; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
for (size_t i = s; i < BusManager::getNumBusses(); i++) {
|
||||
Bus* b = BusManager::getBus(i);
|
||||
|
||||
segStarts[s] = b->getStart();
|
||||
segStops[s] = segStarts[s] + b->getLength();
|
||||
@ -1558,8 +1561,8 @@ void WS2812FX::fixInvalidSegments() {
|
||||
bool WS2812FX::checkSegmentAlignment() {
|
||||
bool aligned = false;
|
||||
for (segment &seg : _segments) {
|
||||
for (unsigned b = 0; b<busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
||||
}
|
||||
if (seg.start == 0 && seg.stop == _length) aligned = true;
|
||||
@ -1657,40 +1660,30 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
strcat_P(fileName, PSTR(".json"));
|
||||
bool isFile = WLED_FS.exists(fileName);
|
||||
|
||||
if (!isFile) {
|
||||
// erase custom mapping if selecting nonexistent ledmap.json (n==0)
|
||||
if (!isMatrix && !n && customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
}
|
||||
customMappingSize = 0; // prevent use of mapping if anything goes wrong
|
||||
|
||||
if (!isFile && n==0 && isMatrix) {
|
||||
setUpMatrix();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!requestJSONBufferLock(7)) return false;
|
||||
if (!isFile || !requestJSONBufferLock(7)) return false; // this will trigger setUpMatrix() when called from wled.cpp
|
||||
|
||||
if (!readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
if (!readObjectFromFile(fileName, nullptr, pDoc)) {
|
||||
DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName);
|
||||
releaseJSONBufferLock();
|
||||
return false; //if file does not exist just exit
|
||||
return false; // if file does not load properly then exit
|
||||
}
|
||||
|
||||
DEBUG_PRINT(F("Reading LED map from "));
|
||||
DEBUG_PRINTLN(fileName);
|
||||
DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName);
|
||||
|
||||
// erase old custom ledmap
|
||||
if (customMappingTable != nullptr) {
|
||||
customMappingSize = 0;
|
||||
delete[] customMappingTable;
|
||||
customMappingTable = nullptr;
|
||||
}
|
||||
if (customMappingTable == nullptr) customMappingTable = new uint16_t[getLengthTotal()];
|
||||
|
||||
JsonArray map = doc[F("map")];
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
JsonArray map = root[F("map")];
|
||||
if (!map.isNull() && map.size()) { // not an empty map
|
||||
customMappingSize = map.size();
|
||||
customMappingTable = new uint16_t[customMappingSize];
|
||||
for (unsigned i=0; i<customMappingSize; i++) {
|
||||
customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
|
||||
}
|
||||
customMappingSize = min((unsigned)map.size(), (unsigned)getLengthTotal());
|
||||
for (unsigned i=0; i<customMappingSize; i++) customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
|
||||
}
|
||||
|
||||
releaseJSONBufferLock();
|
||||
|
@ -125,7 +125,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
|
||||
_valid = (_busPtr != nullptr);
|
||||
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType);
|
||||
DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n", _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], _pins[1], _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||
}
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
@ -150,7 +150,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
bool useWackyWS2815PowerModel = false;
|
||||
byte actualMilliampsPerLed = _milliAmpsPerLed;
|
||||
|
||||
if (_milliAmpsMax < MA_FOR_ESP || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
|
||||
if (_milliAmpsMax < MA_FOR_ESP/BusManager::getNumBusses() || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
|
||||
return _bri;
|
||||
}
|
||||
|
||||
@ -159,7 +159,12 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
actualMilliampsPerLed = 12; // from testing an actual strip
|
||||
}
|
||||
|
||||
size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP); //100mA for ESP power
|
||||
size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power
|
||||
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
|
||||
powerBudget -= getLength();
|
||||
} else {
|
||||
powerBudget = 0;
|
||||
}
|
||||
|
||||
uint32_t busPowerSum = 0;
|
||||
for (unsigned i = 0; i < getLength(); i++) { //sum up the usage of each LED
|
||||
@ -178,29 +183,26 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
|
||||
busPowerSum >>= 2; //same as /= 4
|
||||
}
|
||||
|
||||
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
|
||||
powerBudget -= getLength();
|
||||
} else {
|
||||
powerBudget = 0;
|
||||
}
|
||||
|
||||
// powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps
|
||||
busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765;
|
||||
_milliAmpsTotal = busPowerSum * _bri / 255;
|
||||
|
||||
uint8_t newBri = _bri;
|
||||
if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit
|
||||
float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri);
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
if (scale >= 1.0f) return _bri;
|
||||
_milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale);
|
||||
uint8_t scaleB = min((int)(scale * 255), 255);
|
||||
newBri = unsigned(_bri * scaleB) / 256 + 1;
|
||||
}
|
||||
return newBri;
|
||||
}
|
||||
|
||||
void BusDigital::show() {
|
||||
_milliAmpsTotal = 0;
|
||||
if (!_valid) return;
|
||||
|
||||
uint8_t newBri = estimateCurrentAndLimitBri();
|
||||
uint8_t newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal
|
||||
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
|
||||
|
||||
if (_data) { // use _buffering this causes ~20% FPS drop
|
||||
@ -258,23 +260,8 @@ void BusDigital::setBrightness(uint8_t b) {
|
||||
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit();
|
||||
}
|
||||
#endif
|
||||
uint8_t prevBri = _bri;
|
||||
Bus::setBrightness(b);
|
||||
PolyBus::setBrightness(_busPtr, _iType, b);
|
||||
/*
|
||||
if (_data) return; // use _buffering this causes ~20% FPS drop
|
||||
|
||||
// must update/repaint every LED in the NeoPixelBus buffer to the new brightness
|
||||
// the only case where repainting is unnecessary is when all pixels are set after the brightness change but before the next show
|
||||
// (which we can't rely on)
|
||||
uint16_t hwLen = _len;
|
||||
if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||
for (unsigned i = 0; i < hwLen; i++) {
|
||||
// use 0 as color order, actual order does not matter here as we just update the channel values as-is
|
||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, 0), prevBri);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, i, c, 0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//If LEDs are skipped, it is possible to use the first as a status LED.
|
||||
@ -661,9 +648,12 @@ void BusManager::removeAll() {
|
||||
}
|
||||
|
||||
void BusManager::show() {
|
||||
_milliAmpsUsed = 0;
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
busses[i]->show();
|
||||
_milliAmpsUsed += busses[i]->getUsedCurrent();
|
||||
}
|
||||
if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP;
|
||||
}
|
||||
|
||||
void BusManager::setStatusPixel(uint32_t c) {
|
||||
@ -729,3 +719,11 @@ uint16_t BusManager::getTotalLength() {
|
||||
int16_t Bus::_cct = -1;
|
||||
uint8_t Bus::_cctBlend = 0;
|
||||
uint8_t Bus::_gAWM = 255;
|
||||
|
||||
uint16_t BusDigital::_milliAmpsTotal = 0;
|
||||
|
||||
uint8_t BusManager::numBusses = 0;
|
||||
Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
ColorOrderMap BusManager::colorOrderMap = {};
|
||||
uint16_t BusManager::_milliAmpsUsed = 0;
|
||||
uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT;
|
@ -137,6 +137,7 @@ class Bus {
|
||||
virtual uint8_t skippedLeds() { return 0; }
|
||||
virtual uint16_t getFrequency() { return 0U; }
|
||||
virtual uint16_t getLEDCurrent() { return 0; }
|
||||
virtual uint16_t getUsedCurrent() { return 0; }
|
||||
virtual uint16_t getMaxCurrent() { return 0; }
|
||||
inline void setReversed(bool reversed) { _reversed = reversed; }
|
||||
inline uint16_t getStart() { return _start; }
|
||||
@ -219,6 +220,7 @@ class BusDigital : public Bus {
|
||||
uint16_t getFrequency() { return _frequencykHz; }
|
||||
uint8_t estimateCurrentAndLimitBri();
|
||||
uint16_t getLEDCurrent() { return _milliAmpsPerLed; }
|
||||
uint16_t getUsedCurrent() { return _milliAmpsTotal; }
|
||||
uint16_t getMaxCurrent() { return _milliAmpsMax; }
|
||||
void reinit();
|
||||
void cleanup();
|
||||
@ -233,7 +235,8 @@ class BusDigital : public Bus {
|
||||
uint16_t _milliAmpsMax;
|
||||
void * _busPtr;
|
||||
const ColorOrderMap &_colorOrderMap;
|
||||
//bool _buffering; // temporary until we figure out why comparison "_data" causes severe FPS drop
|
||||
|
||||
static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show()
|
||||
|
||||
inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) {
|
||||
if (restoreBri < 255) {
|
||||
@ -314,39 +317,44 @@ class BusNetwork : public Bus {
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() : numBusses(0) {};
|
||||
BusManager() {};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
static uint16_t currentMilliamps(void) { return _milliAmpsUsed; }
|
||||
static uint16_t ablMilliampsMax(void) { return _milliAmpsMax; }
|
||||
|
||||
int add(BusConfig &bc);
|
||||
static int add(BusConfig &bc);
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void removeAll();
|
||||
static void removeAll();
|
||||
|
||||
void show();
|
||||
bool canAllShow();
|
||||
void setStatusPixel(uint32_t c);
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
void setBrightness(uint8_t b);
|
||||
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
static void show();
|
||||
static bool canAllShow();
|
||||
static void setStatusPixel(uint32_t c);
|
||||
static void setPixelColor(uint16_t pix, uint32_t c);
|
||||
static void setBrightness(uint8_t b);
|
||||
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
static void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
||||
static uint32_t getPixelColor(uint16_t pix);
|
||||
|
||||
Bus* getBus(uint8_t busNr);
|
||||
static Bus* getBus(uint8_t busNr);
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
uint16_t getTotalLength();
|
||||
inline uint8_t getNumBusses() const { return numBusses; }
|
||||
static uint16_t getTotalLength();
|
||||
static uint8_t getNumBusses() { return numBusses; }
|
||||
|
||||
inline void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); }
|
||||
inline const ColorOrderMap& getColorOrderMap() const { return colorOrderMap; }
|
||||
static void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); }
|
||||
static const ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
|
||||
|
||||
private:
|
||||
uint8_t numBusses;
|
||||
Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
ColorOrderMap colorOrderMap;
|
||||
static uint8_t numBusses;
|
||||
static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES];
|
||||
static ColorOrderMap colorOrderMap;
|
||||
static uint16_t _milliAmpsUsed;
|
||||
static uint16_t _milliAmpsMax;
|
||||
|
||||
inline uint8_t getNumVirtualBusses() {
|
||||
static uint8_t getNumVirtualBusses() {
|
||||
int j = 0;
|
||||
for (int i=0; i<numBusses; i++) if (busses[i]->getType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++;
|
||||
return j;
|
||||
|
@ -347,10 +347,10 @@ void handleButton()
|
||||
void esp32RMTInvertIdle()
|
||||
{
|
||||
bool idle_out;
|
||||
for (uint8_t u = 0; u < busses.getNumBusses(); u++)
|
||||
for (uint8_t u = 0; u < BusManager::getNumBusses(); u++)
|
||||
{
|
||||
if (u > 7) return; // only 8 RMT channels, TODO: ESP32 variants have less RMT channels
|
||||
Bus *bus = busses.getBus(u);
|
||||
Bus *bus = BusManager::getBus(u);
|
||||
if (!bus || bus->getLength()==0 || !IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType())) continue;
|
||||
//assumes that bus number to rmt channel mapping stays 1:1
|
||||
rmt_channel_t ch = static_cast<rmt_channel_t>(u);
|
||||
|
@ -79,7 +79,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
|
||||
noWifiSleep = !noWifiSleep;
|
||||
//int wifi_phy = doc[F("wifi")][F("phy")]; //force phy mode n?
|
||||
force802_3g = doc[F("wifi")][F("phy")] | force802_3g; //force phy mode g?
|
||||
|
||||
JsonObject hw = doc[F("hw")];
|
||||
|
||||
@ -87,8 +87,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
JsonObject hw_led = hw["led"];
|
||||
|
||||
uint16_t total = hw_led[F("total")] | strip.getLengthTotal();
|
||||
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
|
||||
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); // no longer used
|
||||
uint16_t ablMilliampsMax = hw_led[F("maxpwr")] | BusManager::ablMilliampsMax();
|
||||
BusManager::setMilliampsMax(ablMilliampsMax);
|
||||
Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED);
|
||||
CJSON(correctWB, hw_led["cct"]);
|
||||
CJSON(cctFromRgb, hw_led[F("cr")]);
|
||||
@ -138,7 +138,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
if (fromFS || !ins.isNull()) {
|
||||
uint8_t s = 0; // bus iterator
|
||||
if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback
|
||||
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
|
||||
uint32_t mem = 0, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
bool busesChanged = false;
|
||||
@ -164,8 +164,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
bool refresh = elm["ref"] | false;
|
||||
uint16_t freqkHz = elm[F("freq")] | 0; // will be in kHz for DotStar and Hz for PWM (not yet implemented fully)
|
||||
uint8_t AWmode = elm[F("rgbwm")] | RGBW_MODE_MANUAL_ONLY;
|
||||
uint8_t maPerLed = elm[F("ledma")] | strip.milliampsPerLed; // replace with 55 when removing strip.milliampsPerLed
|
||||
uint16_t maMax = elm[F("maxpwr")] | (strip.ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
|
||||
uint8_t maPerLed = elm[F("ledma")] | 55;
|
||||
uint16_t maMax = elm[F("maxpwr")] | (ablMilliampsMax * length) / total; // rough (incorrect?) per strip ABL calculation when no config exists
|
||||
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 (we choose output max current)
|
||||
if ((ledType > TYPE_TM1814 && ledType < TYPE_WS2801) || ledType >= TYPE_NET_DDP_RGB) { // analog and virtual
|
||||
maPerLed = 0;
|
||||
@ -179,7 +179,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
maxlen = start + length;
|
||||
globalBufMem = maxlen * 4;
|
||||
}
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) if (busses.add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
|
||||
} else {
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||
@ -190,7 +190,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
doInitBusses = busesChanged;
|
||||
// finalization done in beginStrip()
|
||||
}
|
||||
if (hw_led["rev"]) busses.getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||
if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||
|
||||
// read color order map configuration
|
||||
JsonArray hw_com = hw[F("com")];
|
||||
@ -205,7 +205,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
com.add(start, len, colorOrder);
|
||||
s++;
|
||||
}
|
||||
busses.updateColorOrderMap(com);
|
||||
BusManager::updateColorOrderMap(com);
|
||||
}
|
||||
|
||||
// read multiple button configuration
|
||||
@ -610,7 +610,7 @@ void deserializeConfigFromFS() {
|
||||
|
||||
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
|
||||
|
||||
success = readObjectFromFile("/cfg.json", nullptr, &doc);
|
||||
success = readObjectFromFile("/cfg.json", nullptr, pDoc);
|
||||
if (!success) { // if file does not exist, optionally try reading from EEPROM and then save defaults to FS
|
||||
releaseJSONBufferLock();
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
@ -631,7 +631,8 @@ void deserializeConfigFromFS() {
|
||||
|
||||
// NOTE: This routine deserializes *and* applies the configuration
|
||||
// Therefore, must also initialize ethernet from this function
|
||||
bool needsSave = deserializeConfig(doc.as<JsonObject>(), true);
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
bool needsSave = deserializeConfig(root, true);
|
||||
releaseJSONBufferLock();
|
||||
|
||||
if (needsSave) serializeConfig(); // usermods required new parameters
|
||||
@ -644,19 +645,21 @@ void serializeConfig() {
|
||||
|
||||
if (!requestJSONBufferLock(2)) return;
|
||||
|
||||
JsonArray rev = doc.createNestedArray("rev");
|
||||
JsonObject root = pDoc->to<JsonObject>();
|
||||
|
||||
JsonArray rev = root.createNestedArray("rev");
|
||||
rev.add(1); //major settings revision
|
||||
rev.add(0); //minor settings revision
|
||||
|
||||
doc[F("vid")] = VERSION;
|
||||
root[F("vid")] = VERSION;
|
||||
|
||||
JsonObject id = doc.createNestedObject("id");
|
||||
JsonObject id = root.createNestedObject("id");
|
||||
id[F("mdns")] = cmDNS;
|
||||
id[F("name")] = serverDescription;
|
||||
id[F("inv")] = alexaInvocationName;
|
||||
id[F("sui")] = simplifiedUI;
|
||||
|
||||
JsonObject nw = doc.createNestedObject("nw");
|
||||
JsonObject nw = root.createNestedObject("nw");
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
nw[F("espnow")] = enableESPNow;
|
||||
nw[F("linked_remote")] = linked_remote;
|
||||
@ -678,7 +681,7 @@ void serializeConfig() {
|
||||
nw_ins_0_sn.add(staticSubnet[i]);
|
||||
}
|
||||
|
||||
JsonObject ap = doc.createNestedObject("ap");
|
||||
JsonObject ap = root.createNestedObject("ap");
|
||||
ap[F("ssid")] = apSSID;
|
||||
ap[F("pskl")] = strlen(apPass);
|
||||
ap[F("chan")] = apChannel;
|
||||
@ -691,12 +694,12 @@ void serializeConfig() {
|
||||
ap_ip.add(2);
|
||||
ap_ip.add(1);
|
||||
|
||||
JsonObject wifi = doc.createNestedObject("wifi");
|
||||
JsonObject wifi = root.createNestedObject("wifi");
|
||||
wifi[F("sleep")] = !noWifiSleep;
|
||||
//wifi[F("phy")] = 1;
|
||||
wifi[F("phy")] = (int)force802_3g;
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
JsonObject ethernet = doc.createNestedObject("eth");
|
||||
JsonObject ethernet = root.createNestedObject("eth");
|
||||
ethernet["type"] = ethernetType;
|
||||
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||
JsonArray pins = ethernet.createNestedArray("pin");
|
||||
@ -719,12 +722,12 @@ void serializeConfig() {
|
||||
}
|
||||
#endif
|
||||
|
||||
JsonObject hw = doc.createNestedObject("hw");
|
||||
JsonObject hw = root.createNestedObject("hw");
|
||||
|
||||
JsonObject hw_led = hw.createNestedObject("led");
|
||||
hw_led[F("total")] = strip.getLengthTotal(); //provided for compatibility on downgrade and per-output ABL
|
||||
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
|
||||
hw_led[F("ledma")] = strip.milliampsPerLed; // no longer used
|
||||
hw_led[F("maxpwr")] = BusManager::ablMilliampsMax();
|
||||
hw_led[F("ledma")] = 0; // no longer used
|
||||
hw_led["cct"] = correctWB;
|
||||
hw_led[F("cr")] = cctFromRgb;
|
||||
hw_led[F("cb")] = strip.cctBlending;
|
||||
@ -754,8 +757,8 @@ void serializeConfig() {
|
||||
|
||||
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
|
||||
|
||||
for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
for (uint8_t s = 0; s < BusManager::getNumBusses(); s++) {
|
||||
Bus *bus = BusManager::getBus(s);
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
JsonObject ins = hw_led_ins.createNestedObject();
|
||||
ins["start"] = bus->getStart();
|
||||
@ -776,7 +779,7 @@ void serializeConfig() {
|
||||
}
|
||||
|
||||
JsonArray hw_com = hw.createNestedArray(F("com"));
|
||||
const ColorOrderMap& com = busses.getColorOrderMap();
|
||||
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
||||
for (uint8_t s = 0; s < com.count(); s++) {
|
||||
const ColorOrderMapEntry *entry = com.get(s);
|
||||
if (!entry) break;
|
||||
@ -831,7 +834,7 @@ void serializeConfig() {
|
||||
//JsonObject hw_status = hw.createNestedObject("status");
|
||||
//hw_status["pin"] = -1;
|
||||
|
||||
JsonObject light = doc.createNestedObject(F("light"));
|
||||
JsonObject light = root.createNestedObject(F("light"));
|
||||
light[F("scale-bri")] = briMultiplier;
|
||||
light[F("pal-mode")] = strip.paletteBlend;
|
||||
light[F("aseg")] = autoSegments;
|
||||
@ -854,12 +857,12 @@ void serializeConfig() {
|
||||
light_nl[F("tbri")] = nightlightTargetBri;
|
||||
light_nl["macro"] = macroNl;
|
||||
|
||||
JsonObject def = doc.createNestedObject("def");
|
||||
JsonObject def = root.createNestedObject("def");
|
||||
def["ps"] = bootPreset;
|
||||
def["on"] = turnOnAtBoot;
|
||||
def["bri"] = briS;
|
||||
|
||||
JsonObject interfaces = doc.createNestedObject("if");
|
||||
JsonObject interfaces = root.createNestedObject("if");
|
||||
|
||||
JsonObject if_sync = interfaces.createNestedObject("sync");
|
||||
if_sync[F("port0")] = udpPort;
|
||||
@ -963,7 +966,7 @@ void serializeConfig() {
|
||||
if_ntp[F("ln")] = longitude;
|
||||
if_ntp[F("lt")] = latitude;
|
||||
|
||||
JsonObject ol = doc.createNestedObject("ol");
|
||||
JsonObject ol = root.createNestedObject("ol");
|
||||
ol[F("clock")] = overlayCurrent;
|
||||
ol[F("cntdwn")] = countdownMode;
|
||||
|
||||
@ -973,7 +976,7 @@ void serializeConfig() {
|
||||
ol[F("o5m")] = analogClock5MinuteMarks;
|
||||
ol[F("osec")] = analogClockSecondsTrail;
|
||||
|
||||
JsonObject timers = doc.createNestedObject(F("timers"));
|
||||
JsonObject timers = root.createNestedObject(F("timers"));
|
||||
|
||||
JsonObject cntdwn = timers.createNestedObject(F("cntdwn"));
|
||||
JsonArray goal = cntdwn.createNestedArray(F("goal"));
|
||||
@ -1001,14 +1004,14 @@ void serializeConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject ota = doc.createNestedObject("ota");
|
||||
JsonObject ota = root.createNestedObject("ota");
|
||||
ota[F("lock")] = otaLock;
|
||||
ota[F("lock-wifi")] = wifiLock;
|
||||
ota[F("pskl")] = strlen(otaPass);
|
||||
ota[F("aota")] = aOtaEnabled;
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
JsonObject dmx = doc.createNestedObject("dmx");
|
||||
JsonObject dmx = root.createNestedObject("dmx");
|
||||
dmx[F("chan")] = DMXChannels;
|
||||
dmx[F("gap")] = DMXGap;
|
||||
dmx["start"] = DMXStart;
|
||||
@ -1022,11 +1025,11 @@ void serializeConfig() {
|
||||
dmx[F("e131proxy")] = e131ProxyUniverse;
|
||||
#endif
|
||||
|
||||
JsonObject usermods_settings = doc.createNestedObject("um");
|
||||
JsonObject usermods_settings = root.createNestedObject("um");
|
||||
usermods.addToConfig(usermods_settings);
|
||||
|
||||
File f = WLED_FS.open("/cfg.json", "w");
|
||||
if (f) serializeJson(doc, f);
|
||||
if (f) serializeJson(root, f);
|
||||
f.close();
|
||||
releaseJSONBufferLock();
|
||||
|
||||
@ -1039,19 +1042,21 @@ bool deserializeConfigSec() {
|
||||
|
||||
if (!requestJSONBufferLock(3)) return false;
|
||||
|
||||
bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
|
||||
bool success = readObjectFromFile("/wsec.json", nullptr, pDoc);
|
||||
if (!success) {
|
||||
releaseJSONBufferLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonObject nw_ins_0 = doc["nw"]["ins"][0];
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
|
||||
JsonObject nw_ins_0 = root["nw"]["ins"][0];
|
||||
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
|
||||
|
||||
JsonObject ap = doc["ap"];
|
||||
JsonObject ap = root["ap"];
|
||||
getStringFromJson(apPass, ap["psk"] , 65);
|
||||
|
||||
[[maybe_unused]] JsonObject interfaces = doc["if"];
|
||||
[[maybe_unused]] JsonObject interfaces = root["if"];
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces["mqtt"];
|
||||
@ -1062,10 +1067,10 @@ bool deserializeConfigSec() {
|
||||
getStringFromJson(hueApiKey, interfaces["hue"][F("key")], 47);
|
||||
#endif
|
||||
|
||||
getStringFromJson(settingsPIN, doc["pin"], 5);
|
||||
getStringFromJson(settingsPIN, root["pin"], 5);
|
||||
correctPIN = !strlen(settingsPIN);
|
||||
|
||||
JsonObject ota = doc["ota"];
|
||||
JsonObject ota = root["ota"];
|
||||
getStringFromJson(otaPass, ota[F("pwd")], 33);
|
||||
CJSON(otaLock, ota[F("lock")]);
|
||||
CJSON(wifiLock, ota[F("lock-wifi")]);
|
||||
@ -1080,17 +1085,19 @@ void serializeConfigSec() {
|
||||
|
||||
if (!requestJSONBufferLock(4)) return;
|
||||
|
||||
JsonObject nw = doc.createNestedObject("nw");
|
||||
JsonObject root = pDoc->to<JsonObject>();
|
||||
|
||||
JsonObject nw = root.createNestedObject("nw");
|
||||
|
||||
JsonArray nw_ins = nw.createNestedArray("ins");
|
||||
|
||||
JsonObject nw_ins_0 = nw_ins.createNestedObject();
|
||||
nw_ins_0["psk"] = clientPass;
|
||||
|
||||
JsonObject ap = doc.createNestedObject("ap");
|
||||
JsonObject ap = root.createNestedObject("ap");
|
||||
ap["psk"] = apPass;
|
||||
|
||||
[[maybe_unused]] JsonObject interfaces = doc.createNestedObject("if");
|
||||
[[maybe_unused]] JsonObject interfaces = root.createNestedObject("if");
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
|
||||
if_mqtt["psk"] = mqttPass;
|
||||
@ -1100,16 +1107,16 @@ void serializeConfigSec() {
|
||||
if_hue[F("key")] = hueApiKey;
|
||||
#endif
|
||||
|
||||
doc["pin"] = settingsPIN;
|
||||
root["pin"] = settingsPIN;
|
||||
|
||||
JsonObject ota = doc.createNestedObject("ota");
|
||||
JsonObject ota = root.createNestedObject("ota");
|
||||
ota[F("pwd")] = otaPass;
|
||||
ota[F("lock")] = otaLock;
|
||||
ota[F("lock-wifi")] = wifiLock;
|
||||
ota[F("aota")] = aOtaEnabled;
|
||||
|
||||
File f = WLED_FS.open("/wsec.json", "w");
|
||||
if (f) serializeJson(doc, f);
|
||||
if (f) serializeJson(root, f);
|
||||
f.close();
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
|
@ -256,10 +256,11 @@
|
||||
#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_PWM(t) ((t) > 40 && (t) < 46)
|
||||
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
|
||||
#define IS_DIGITAL(t) ((t) < 80 && ((t) & 0x10)) //digital are 16-31 and 48-63
|
||||
#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)
|
||||
#define IS_VIRTUAL(t) ((t) >= 80)
|
||||
|
||||
//Color orders
|
||||
#define COL_ORDER_GRB 0 //GRB(w),defaut
|
||||
@ -345,6 +346,7 @@
|
||||
#define ERR_CONCURRENCY 2 // Conurrency (client active)
|
||||
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
||||
#define ERR_NOT_IMPL 4 // Not implemented
|
||||
#define ERR_NORAM 8 // effect RAM depleted
|
||||
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
|
||||
@ -449,7 +451,11 @@
|
||||
#ifdef ESP8266
|
||||
#define JSON_BUFFER_SIZE 10240
|
||||
#else
|
||||
#define JSON_BUFFER_SIZE 24576
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define JSON_BUFFER_SIZE 24576
|
||||
#else
|
||||
#define JSON_BUFFER_SIZE 32767
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#define MIN_HEAP_SIZE (8k for AsyncWebServer)
|
||||
|
@ -1,6 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
@ -45,6 +46,7 @@
|
||||
width: 7px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
touch-action: none;
|
||||
}
|
||||
.color-picker-marker {
|
||||
height: 7px;
|
||||
@ -94,9 +96,14 @@
|
||||
line-height: 1;
|
||||
}
|
||||
.wrap {
|
||||
width: 800px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media (min-width: 800px) {
|
||||
.wrap {
|
||||
width: 800px;
|
||||
}
|
||||
}
|
||||
.palette {
|
||||
height: 20px;
|
||||
}
|
||||
@ -136,6 +143,9 @@
|
||||
.sendSpan, .editSpan{
|
||||
cursor: pointer;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -349,24 +359,31 @@
|
||||
var gradientLength = maxX - minX + 1;
|
||||
|
||||
elmnt.onmousedown = dragMouseDown;
|
||||
elmnt.ontouchstart = dragMouseDown;
|
||||
|
||||
function dragMouseDown(e) {
|
||||
removeTrashcan(event)
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
var isTouch = e.type.startsWith('touch');
|
||||
if (!isTouch) e.preventDefault();
|
||||
// get the mouse cursor position at startup:
|
||||
mousePos = e.clientX;
|
||||
mousePos = isTouch ? e.touches[0].clientX : e.clientX;
|
||||
d.onmouseup = closeDragElement;
|
||||
d.ontouchcancel = closeDragElement;
|
||||
d.ontouchend = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
d.onmousemove = elementDrag;
|
||||
d.ontouchmove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
var isTouch = e.type.startsWith('touch');
|
||||
if (!isTouch) e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
posNew = mousePos - e.clientX;
|
||||
mousePos = e.clientX;
|
||||
var clientX = isTouch ? e.touches[0].clientX : e.clientX;
|
||||
posNew = mousePos - clientX;
|
||||
mousePos = clientX;
|
||||
mousePosInGradient = mousePos - (minX + 1)
|
||||
|
||||
truePos = Math.round((mousePosInGradient/gradientLength)*256);
|
||||
@ -393,7 +410,10 @@
|
||||
function closeDragElement() {
|
||||
/* stop moving when mouse button is released:*/
|
||||
d.onmouseup = null;
|
||||
d.ontouchcancel = null;
|
||||
d.ontouchend = null;
|
||||
d.onmousemove = null;
|
||||
d.ontouchmove = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,7 +785,7 @@ input[type=range]::-moz-range-thumb {
|
||||
|
||||
#picker {
|
||||
margin-top: 8px !important;
|
||||
max-width: 260px;
|
||||
max-width: max-content;
|
||||
}
|
||||
|
||||
/* buttons */
|
||||
@ -1566,9 +1566,6 @@ dialog {
|
||||
max-width: 280px;
|
||||
font-size: 18px;
|
||||
}
|
||||
#picker {
|
||||
width: 230px;
|
||||
}
|
||||
#putil .btn-s {
|
||||
width: 114px;
|
||||
}
|
||||
|
@ -32,13 +32,14 @@ var cfg = {
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
|
||||
css:true, hdays:false, fxdef:true, on:0, off:0, idsort: false}
|
||||
};
|
||||
// [year, month (0 -> January, 11 -> December), day, duration in days, image url]
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
[0,2,17,1,"https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day
|
||||
[2025,3,20,2,"https://aircoookie.github.io/easter.png"],
|
||||
[2024,2,31,2,"https://aircoookie.github.io/easter.png"],
|
||||
[0,6,4,1,"https://images.alphacoders.com/516/516792.jpg"], // 4th of July
|
||||
[0,0,1,1,"https://images.alphacoders.com/119/1198800.jpg"] // new year
|
||||
[0, 11, 24, 4, "https://aircoookie.github.io/xmas.png"], // christmas
|
||||
[0, 2, 17, 1, "https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day
|
||||
[2025, 3, 20, 2, "https://aircoookie.github.io/easter.png"], // easter 2025
|
||||
[2024, 2, 31, 2, "https://aircoookie.github.io/easter.png"], // easter 2024
|
||||
[0, 6, 4, 1, "https://images.alphacoders.com/516/516792.jpg"], // 4th of July
|
||||
[0, 0, 1, 1, "https://images.alphacoders.com/119/1198800.jpg"] // new year
|
||||
];
|
||||
|
||||
var cpick = new iro.ColorPicker("#picker", {
|
||||
@ -175,19 +176,19 @@ function cTheme(light) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadBg(iUrl)
|
||||
{
|
||||
let bg = gId('bg');
|
||||
let img = d.createElement("img");
|
||||
function loadBg() {
|
||||
const { url: iUrl, rnd: iRnd } = cfg.theme.bg;
|
||||
const bg = gId('bg');
|
||||
const img = d.createElement("img");
|
||||
img.src = iUrl;
|
||||
if (iUrl == "" || iUrl==="https://picsum.photos/1920/1080") {
|
||||
var today = new Date();
|
||||
for (var h of (hol||[])) {
|
||||
var yr = h[0]==0 ? today.getFullYear() : h[0];
|
||||
var hs = new Date(yr,h[1],h[2]);
|
||||
var he = new Date(hs);
|
||||
he.setDate(he.getDate() + h[3]);
|
||||
if (today>=hs && today<=he) img.src = h[4];
|
||||
if (!iUrl || iRnd) {
|
||||
const today = new Date();
|
||||
for (const holiday of (hol || [])) {
|
||||
const year = holiday[0] == 0 ? today.getFullYear() : holiday[0];
|
||||
const holidayStart = new Date(year, holiday[1], holiday[2]);
|
||||
const holidayEnd = new Date(holidayStart);
|
||||
holidayEnd.setDate(holidayEnd.getDate() + holiday[3]);
|
||||
if (today >= holidayStart && today <= holidayEnd) img.src = holiday[4];
|
||||
}
|
||||
}
|
||||
img.addEventListener('load', (e) => {
|
||||
@ -195,7 +196,6 @@ function loadBg(iUrl)
|
||||
if (isNaN(a)) a = 0.6;
|
||||
bg.style.opacity = a;
|
||||
bg.style.backgroundImage = `url(${img.src})`;
|
||||
img = null;
|
||||
gId('namelabel').style.color = "var(--c-c)"; // improve namelabel legibility on background image
|
||||
});
|
||||
}
|
||||
@ -266,10 +266,10 @@ function onLoad()
|
||||
console.log("No array of holidays in holidays.json. Defaults loaded.");
|
||||
})
|
||||
.finally(()=>{
|
||||
loadBg(cfg.theme.bg.url);
|
||||
loadBg();
|
||||
});
|
||||
} else
|
||||
loadBg(cfg.theme.bg.url);
|
||||
loadBg();
|
||||
|
||||
selectSlot(0);
|
||||
updateTablinks(0);
|
||||
@ -329,7 +329,6 @@ function openTab(tabI, force = false)
|
||||
var timeout;
|
||||
function showToast(text, error = false)
|
||||
{
|
||||
if (error) gId('connind').style.backgroundColor = "var(--c-r)";
|
||||
var x = gId('toast');
|
||||
//if (error) text += '<i class="icons btn-icon" style="transform:rotate(45deg);position:absolute;top:10px;right:0px;" onclick="clearErrorToast(100);"></i>';
|
||||
x.innerHTML = text;
|
||||
@ -342,6 +341,7 @@ function showToast(text, error = false)
|
||||
|
||||
function showErrorToast()
|
||||
{
|
||||
gId('connind').style.backgroundColor = "var(--c-r)";
|
||||
showToast('Connection to light failed!', true);
|
||||
}
|
||||
|
||||
@ -1492,25 +1492,31 @@ function readState(s,command=false)
|
||||
gId('checkO3').checked = !(!i.o3);
|
||||
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "Preset not found.";
|
||||
break;
|
||||
case 13:
|
||||
errstr = "Missing ir.json.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 8:
|
||||
errstr = "Effect RAM depleted!";
|
||||
break;
|
||||
case 9:
|
||||
errstr = "JSON parsing error!";
|
||||
break;
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "Preset not found.";
|
||||
break;
|
||||
case 13:
|
||||
errstr = "Missing ir.json.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
|
||||
selectedPal = i.pal;
|
||||
|
@ -16,6 +16,11 @@
|
||||
function B(){window.open(getURL("/settings"),"_self");}
|
||||
function gId(n){return d.getElementById(n);}
|
||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||
function isPWM(t) { return t > 40 && t < 46; } // is PWM type
|
||||
function isAna(t) { return t == 40 || isPWM(t); } // is analog type
|
||||
function isDig(t) { return t < 80 && (t & 0x10); }// is digital type
|
||||
function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type
|
||||
function isVir(t) { return t >= 80; } // is virtual type
|
||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||
function loadJS(FILE_URL, async = true) {
|
||||
let scE = d.createElement("script");
|
||||
@ -26,8 +31,8 @@
|
||||
// success event
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();
|
||||
setABL();
|
||||
checkSi();
|
||||
setABL();
|
||||
d.Sf.addEventListener("submit", trySubmit);
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
pinDropdowns();
|
||||
@ -107,44 +112,50 @@
|
||||
e.preventDefault();
|
||||
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
|
||||
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
|
||||
if (!d.Sf.ABL.checked || d.Sf.PPL.checked) d.Sf.MA.value = 0; // submit 0 as ABL (PPL will handle it)
|
||||
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
|
||||
}
|
||||
function enABL()
|
||||
{
|
||||
var en = d.Sf["ABL"].checked;
|
||||
d.Sf["MA"].min = en ? 250 : 0;
|
||||
var en = d.Sf.ABL.checked;
|
||||
gId('abl').style.display = (en) ? 'inline':'none';
|
||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||
if (!en) d.Sf["PPL"].checked = false;
|
||||
if (!en) d.Sf.PPL.checked = false;
|
||||
enPPL();
|
||||
UI();
|
||||
}
|
||||
function enPPL()
|
||||
{
|
||||
const abl = d.Sf["ABL"].checked;
|
||||
const en = d.Sf["PPL"].checked;
|
||||
d.Sf["MA"].readonly = en;
|
||||
gId("ppldis").style.display = en ? 'inline' : 'none';
|
||||
const abl = d.Sf.ABL.checked;
|
||||
const ppl = d.Sf.PPL.checked;
|
||||
let sumMA = 0;
|
||||
d.Sf.MA.readonly = ppl;
|
||||
d.Sf.MA.min = abl && !ppl ? 250 : 0;
|
||||
gId("psuMA").style.display = ppl ? 'none' : 'inline';
|
||||
gId("ppldis").style.display = ppl ? 'inline' : 'none';
|
||||
// set PPL minimum value and clear actual PPL limit if ABL disabled
|
||||
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{
|
||||
gId("PSU"+n).style.display = en ? "inline" : "none";
|
||||
gId("PSU"+n).style.display = ppl ? "inline" : "none";
|
||||
const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||
i.min = en && !((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 250 : 0;
|
||||
i.min = ppl && !(isVir(t) || isAna(t)) ? 250 : 0;
|
||||
if (!abl) i.value = 0;
|
||||
else if (ppl) sumMA += parseInt(i.value,10);
|
||||
});
|
||||
if (ppl) d.Sf.MA.value = sumMA; // populate UI ABL value if PPL used
|
||||
}
|
||||
function enLA(s,n)
|
||||
{
|
||||
const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT
|
||||
gId('LAdis'+n).style.display = s.selectedIndex==5 ? "inline" : "none";
|
||||
d.Sf["LA"+n].value = s.value==="0" ? 55 : s.value;
|
||||
d.Sf["LA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 1;
|
||||
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
|
||||
}
|
||||
function setABL()
|
||||
{
|
||||
d.Sf["ABL"].checked = false;
|
||||
d.Sf.ABL.checked = parseInt(d.Sf.MA.value) > 0;
|
||||
// check if ABL is enabled (max mA entered per output)
|
||||
d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{
|
||||
if (parseInt(i.value) > 0) d.Sf["ABL"].checked = true;
|
||||
if (parseInt(i.value) > 0) d.Sf.ABL.checked = true;
|
||||
});
|
||||
// select appropriate LED current
|
||||
d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,n)=>{
|
||||
@ -190,20 +201,17 @@
|
||||
let isRGBW = false, gRGBW = false, memu = 0;
|
||||
let sumMA = 0, busMA = 0;
|
||||
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
|
||||
const ablEN = d.Sf["ABL"].checked;
|
||||
const pplEN = d.Sf["PPL"].checked;
|
||||
const ablEN = d.Sf.ABL.checked;
|
||||
const pplEN = d.Sf.PPL.checked;
|
||||
|
||||
// enable/disable LED fields
|
||||
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
|
||||
// is the field a LED type?
|
||||
var n = s.name.substring(2);
|
||||
var t = parseInt(s.value);
|
||||
let isDig = ((t >= 16 && t < 32) || (t >= 50 && t < 64));
|
||||
let isVir = (t >= 80 && t < 96);
|
||||
let isPwm = (t >= 40 && t < 48);
|
||||
gId("p0d"+n).innerHTML = (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
||||
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
||||
gId("abl"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? "none" : "inline";
|
||||
gId("p0d"+n).innerHTML = isVir(t) ? "IP address:" : isD2P(t) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
||||
gId("p1d"+n).innerHTML = isD2P(t) ? "Clk GPIO:" : "";
|
||||
gId("abl"+n).style.display = (!ablEN || isVir(t) || isAna(t)) ? "none" : "inline";
|
||||
//var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||
|
||||
memu += getMem(t, n); // calc memory
|
||||
@ -212,7 +220,7 @@
|
||||
for (p=1; p<5; p++) {
|
||||
var LK = d.Sf["L"+p+n]; // 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 ((isVir(t) && p<4) || (isD2P(t) && p==1) || (isPWM(t) && (p+40 < t))) // TYPE_xxxx values from const.h
|
||||
{
|
||||
// display pin field
|
||||
LK.style.display = "inline";
|
||||
@ -226,25 +234,25 @@
|
||||
}
|
||||
if (change) {
|
||||
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
|
||||
if (t > 31 && t < 48) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
|
||||
d.Sf["LA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 1;
|
||||
d.Sf["MA"+n].min = ((t >= 80 && t < 96) || (t >= 40 && t < 48)) ? 0 : 250;
|
||||
if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
|
||||
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
|
||||
d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250;
|
||||
}
|
||||
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("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(t > 28 && t < 32)) d.Sf["WO"+n].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+"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("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
|
||||
if (ablEN && pplEN && !((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
|
||||
sumMA += parseInt(d.Sf["MA"+n].value);
|
||||
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
|
||||
gId("dig"+n+"w").style.display = (isDig(t) && isRGBW) ? "inline":"none"; // show swap channels dropdown
|
||||
if (!(isDig(t) && isRGBW)) d.Sf["WO"+n].value = 0; // reset swapping
|
||||
gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog
|
||||
gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual
|
||||
gId("dig"+n+"s").style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide skip 1st for virtual & analog
|
||||
gId("dig"+n+"f").style.display = (isDig(t)) ? "inline":"none"; // hide refresh
|
||||
gId("dig"+n+"a").style.display = (isRGBW) ? "inline":"none"; // auto calculate white
|
||||
gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off)
|
||||
gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
||||
//gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description
|
||||
if (ablEN && pplEN && !(isVir(t) || isAna(t))) {
|
||||
sumMA += parseInt(d.Sf["MA"+n].value); // summarize PPL ABL limit (fields)
|
||||
}
|
||||
});
|
||||
// display global white channel overrides
|
||||
@ -268,12 +276,13 @@
|
||||
let s = parseInt(gId("ls"+n).value); //start value
|
||||
if (s+c > sLC) sLC = s+c; //update total count
|
||||
if (c > maxLC) maxLC = c; //max per output
|
||||
if (t < 80) sPC += c; //virtual out busses do not count towards physical LEDs
|
||||
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) sDI += c;
|
||||
if (!((t >= 80 && t < 96) || (t >= 40 && t < 48))) {
|
||||
if (!isVir(t)) sPC += c; //virtual out busses do not count towards physical LEDs
|
||||
//if (!(isVir(t) || isPWM(t))) sDI += c;
|
||||
if (!(isVir(t) || isAna(t))) {
|
||||
sDI += c; // summarize digital LED count
|
||||
let maPL = parseInt(d.Sf["LA"+n].value);
|
||||
if (maPL == 255) maPL = 12;
|
||||
busMA += maPL*c;
|
||||
busMA += maPL*c; // summarize maximum bus current (calculated)
|
||||
}
|
||||
} // increase led count
|
||||
return;
|
||||
@ -284,7 +293,7 @@
|
||||
}
|
||||
// ignore IP address (stored in pins for virtual busses)
|
||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
|
||||
if (t>=80) {
|
||||
if (isVir(t)) {
|
||||
LC.max = 255;
|
||||
LC.min = 0;
|
||||
LC.style.color="#fff";
|
||||
@ -306,7 +315,7 @@
|
||||
if (n2.substring(0,1)==="L") {
|
||||
let m = nList[j].name.substring(2);
|
||||
let t2 = parseInt(d.Sf["LT"+m].value, 10);
|
||||
if (t2 >= 80) continue;
|
||||
if (isVir(t2)) continue;
|
||||
}
|
||||
if (nList[j].value!="" && nList[j].value!="-1") p.push(parseInt(nList[j].value,10)); // add current pin
|
||||
}
|
||||
@ -316,14 +325,18 @@
|
||||
else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff";
|
||||
}
|
||||
});
|
||||
// distribute ABL current if not using PPL, otherwise sumMA contains summarized ABL limit
|
||||
d.Sf.querySelectorAll("#mLC input[name^=LC]").forEach((s,n)=>{
|
||||
let c = parseInt(s.value,10); //get LED count
|
||||
let t = parseInt(d.Sf["LT"+n].value);
|
||||
if (ablEN) {
|
||||
let v = Math.round(parseInt(d.Sf["MA"].value,10)*c/sDI);
|
||||
if (!pplEN && !((t >= 80 && t < 96) || (t >= 40 && t < 48))) d.Sf["MA"+n].value = v;
|
||||
} else d.Sf["MA"+n].value = 0;
|
||||
let t = parseInt(d.Sf["LT"+n].value); //get LED type
|
||||
if (!ablEN || isVir(t) || isAna(t)) {
|
||||
// virtual and analog LEDs have no limiter
|
||||
d.Sf["MA"+n].value = 0;
|
||||
return;
|
||||
}
|
||||
if (!pplEN) d.Sf["MA"+n].value = Math.round(parseInt(d.Sf.MA.value,10)*c/sDI);
|
||||
});
|
||||
if (pplEN) d.Sf.MA.value = sumMA; // update global ABL if using PPL
|
||||
// update total led count
|
||||
gId("lc").textContent = sLC;
|
||||
gId("pc").textContent = (sLC == sPC) ? "":"(" + sPC + " physical)";
|
||||
@ -336,7 +349,6 @@
|
||||
gId('ledwarning').style.color = (maxLC > Math.max(maxPB,800) || bquot > 100) ? 'red':'orange';
|
||||
gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>ERROR: Using over ${maxM}B!</b>)` : "") : "800 LEDs per output";
|
||||
// calculate power
|
||||
if (pplEN) d.Sf.MA.value = sumMA;
|
||||
gId('ampwarning').style.display = (parseInt(d.Sf.MA.value,10) > 7200) ? 'inline':'none';
|
||||
var val = Math.ceil((100 + busMA)/500)/2;
|
||||
val = (val > 5) ? Math.ceil(val) : val;
|
||||
@ -409,7 +421,7 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();">
|
||||
<option value="0">Custom</option>
|
||||
</select><br>
|
||||
<div id="LAdis${i}" style="display: none;">max. mA/LED: <input name="LA${i}" type="number" min="1" max="254" oninput="UI()"> mA<br></div>
|
||||
<div id="PSU${i}">PSU: <input name="MA${i}" type="number" class="xl" min="250" max="65000" oninput="UI()"> mA<br></div>
|
||||
<div id="PSU${i}">PSU: <input name="MA${i}" type="number" class="xl" min="250" max="65000" oninput="UI()" value="250"> mA<br></div>
|
||||
</div>
|
||||
<div id="co${i}" style="display:inline">Color Order:
|
||||
<select name="CO${i}">
|
||||
@ -445,7 +457,10 @@ mA/LED: <select name="LAsel${i}" onchange="enLA(this,${i});UI();">
|
||||
gId("+").style.display = (i<maxB+maxV-1) ? "inline":"none";
|
||||
gId("-").style.display = (i>0) ? "inline":"none";
|
||||
|
||||
if (!init) UI();
|
||||
if (!init) {
|
||||
enPPL();
|
||||
UI();
|
||||
}
|
||||
}
|
||||
|
||||
function addCOM(start=0,len=1,co=0) {
|
||||
@ -750,7 +765,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if poweing LEDs directly from the ESP 5V pin!<br>
|
||||
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
|
||||
Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
|
||||
Use per-output limiter: <input type="checkbox" name="PPL" onchange="enPPL()"><br>
|
||||
<div id="ppldis" style="display:none;">
|
||||
<i>Make sure you enter correct values in each LED output.<br>
|
||||
|
@ -192,6 +192,7 @@
|
||||
<option value="3">Never (not recommended)</option></select><br>
|
||||
AP IP: <span class="sip"> Not active </span><br>
|
||||
<h3>Experimental</h3>
|
||||
Force 802.11g mode (ESP8266 only): <input type="checkbox" name="FG"><br>
|
||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||
<i>Can help with connectivity issues.<br>
|
||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
||||
|
@ -360,6 +360,22 @@ um_data_t* simulateSound(uint8_t simulationId);
|
||||
void enumerateLedmaps();
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
|
||||
// RAII guard class for the JSON Buffer lock
|
||||
// Modeled after std::lock_guard
|
||||
class JSONBufferGuard {
|
||||
bool holding_lock;
|
||||
public:
|
||||
inline JSONBufferGuard(uint8_t module=255) : holding_lock(requestJSONBufferLock(module)) {};
|
||||
inline ~JSONBufferGuard() { if (holding_lock) releaseJSONBufferLock(); };
|
||||
inline JSONBufferGuard(const JSONBufferGuard&) = delete; // Noncopyable
|
||||
inline JSONBufferGuard& operator=(const JSONBufferGuard&) = delete;
|
||||
inline JSONBufferGuard(JSONBufferGuard&& r) : holding_lock(r.holding_lock) { r.holding_lock = false; }; // but movable
|
||||
inline JSONBufferGuard& operator=(JSONBufferGuard&& r) { holding_lock |= r.holding_lock; r.holding_lock = false; return *this; };
|
||||
inline bool owns_lock() const { return holding_lock; }
|
||||
explicit inline operator bool() const { return owns_lock(); };
|
||||
inline void release() { if (holding_lock) releaseJSONBufferLock(); holding_lock = false; }
|
||||
};
|
||||
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
//wled_eeprom.cpp
|
||||
void applyMacro(byte index);
|
||||
|
@ -7,302 +7,312 @@
|
||||
*/
|
||||
|
||||
// Autogenerated from wled00/data/cpal/cpal.htm, do not edit!!
|
||||
const uint16_t PAGE_cpal_L = 4721;
|
||||
const uint16_t PAGE_cpal_L = 4891;
|
||||
const uint8_t PAGE_cpal[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xbd, 0x3b, 0x7f, 0x73, 0xdb, 0xb6,
|
||||
0x92, 0xff, 0xe7, 0x53, 0x20, 0x4c, 0x5f, 0x42, 0xd6, 0x14, 0x45, 0xd2, 0xb6, 0x64, 0x4b, 0xa2,
|
||||
0x3b, 0xa9, 0x93, 0x77, 0xce, 0x8d, 0xdd, 0x64, 0x5e, 0x7c, 0x6e, 0x7b, 0x3e, 0xbf, 0x31, 0x4d,
|
||||
0x42, 0x12, 0x1b, 0x8a, 0xe0, 0x03, 0x21, 0xd9, 0xae, 0xac, 0xef, 0x7e, 0xbb, 0x00, 0x48, 0x91,
|
||||
0x94, 0xe4, 0x24, 0xd7, 0x37, 0xd7, 0xf1, 0x44, 0x20, 0xb0, 0x58, 0xec, 0x2e, 0xf6, 0x17, 0x16,
|
||||
0xe8, 0xe8, 0xe5, 0xbb, 0x8f, 0xa7, 0x97, 0xbf, 0x7f, 0x7a, 0x4f, 0xa6, 0x62, 0x96, 0x9e, 0x90,
|
||||
0x51, 0xf9, 0x43, 0xc3, 0x18, 0x7e, 0x66, 0x54, 0x84, 0x30, 0x22, 0xf2, 0x0e, 0xfd, 0xd7, 0x3c,
|
||||
0x59, 0x04, 0xc6, 0x69, 0x18, 0x4d, 0x69, 0xe7, 0x94, 0x65, 0x82, 0xb3, 0xd4, 0x20, 0x2f, 0x22,
|
||||
0x68, 0xd1, 0x4c, 0x04, 0x46, 0xc6, 0x3a, 0x11, 0x8e, 0xd9, 0x04, 0x5a, 0x85, 0x60, 0x1c, 0x5a,
|
||||
0xb3, 0x79, 0x21, 0x3a, 0x9c, 0x2e, 0xc2, 0x34, 0x89, 0x43, 0x41, 0x8d, 0x6d, 0x08, 0x3f, 0xf1,
|
||||
0x70, 0x32, 0x0b, 0xb7, 0x61, 0xda, 0x0a, 0xfe, 0xfe, 0x21, 0x4f, 0x38, 0x2d, 0x0c, 0x52, 0x81,
|
||||
0xbb, 0x08, 0x27, 0x12, 0x91, 0xd2, 0x93, 0x17, 0xbf, 0x9e, 0xbf, 0x7f, 0x47, 0x4e, 0x61, 0x55,
|
||||
0x36, 0x23, 0x9f, 0xc2, 0x94, 0x0a, 0x41, 0xc9, 0xfb, 0x38, 0x01, 0x6a, 0x46, 0x5d, 0x05, 0x42,
|
||||
0x46, 0x45, 0xc4, 0x93, 0x5c, 0x10, 0xf1, 0x98, 0xd3, 0xc0, 0x10, 0xf4, 0x41, 0x74, 0xff, 0x08,
|
||||
0x17, 0xa1, 0xea, 0x35, 0x4e, 0x5e, 0x8c, 0xe7, 0x59, 0x24, 0x12, 0x96, 0x91, 0xc9, 0x87, 0xd8,
|
||||
0xa4, 0xd6, 0x92, 0x53, 0x31, 0xe7, 0x19, 0x89, 0x9d, 0x09, 0x15, 0xef, 0x53, 0x3a, 0x83, 0x35,
|
||||
0x7f, 0x7e, 0x94, 0x43, 0xab, 0x0a, 0x34, 0x7a, 0xdf, 0x80, 0x8c, 0x38, 0x05, 0x6e, 0x35, 0x30,
|
||||
0x02, 0x2e, 0x42, 0x4e, 0xe2, 0x20, 0x66, 0xd1, 0x1c, 0x7b, 0x5e, 0x8c, 0xba, 0x6a, 0x35, 0x24,
|
||||
0x46, 0x3c, 0x22, 0xdd, 0x77, 0x2c, 0x7e, 0x5c, 0x8e, 0x81, 0xa3, 0xce, 0x38, 0x9c, 0x25, 0xe9,
|
||||
0xe3, 0xe0, 0x2d, 0x4f, 0xc2, 0xd4, 0x2e, 0xc2, 0xac, 0xe8, 0x14, 0x94, 0x27, 0xe3, 0xe1, 0x5d,
|
||||
0x18, 0x7d, 0x99, 0x70, 0x36, 0xcf, 0xe2, 0x4e, 0xc4, 0x52, 0xc6, 0x07, 0xaf, 0x3c, 0xcf, 0x1b,
|
||||
0xca, 0x29, 0x45, 0xf2, 0x27, 0x1d, 0x78, 0xbd, 0xfc, 0x61, 0xa8, 0x47, 0xe2, 0x38, 0x1e, 0xce,
|
||||
0x42, 0x3e, 0x49, 0xb2, 0x81, 0x4b, 0x3c, 0x17, 0x06, 0xd2, 0x24, 0xa3, 0x9d, 0x29, 0x4d, 0x26,
|
||||
0x53, 0x31, 0x70, 0x0e, 0x57, 0xaf, 0xf2, 0x90, 0x03, 0x21, 0x1d, 0x94, 0x61, 0x08, 0x43, 0x7c,
|
||||
0x99, 0xb3, 0x22, 0x41, 0x56, 0x06, 0x9c, 0xa6, 0xa1, 0x48, 0x16, 0x74, 0x78, 0x9f, 0xc4, 0x62,
|
||||
0x3a, 0xf0, 0x5c, 0xf7, 0x6f, 0x43, 0x3d, 0xd1, 0x07, 0x4c, 0xab, 0x57, 0x77, 0x4c, 0x80, 0x74,
|
||||
0x4f, 0x37, 0x67, 0x86, 0x77, 0x05, 0x4b, 0xe7, 0x82, 0xea, 0xa5, 0x3b, 0x82, 0xe5, 0x83, 0x43,
|
||||
0x39, 0x65, 0xc2, 0xc3, 0x38, 0xc1, 0xf5, 0xee, 0xd8, 0xc3, 0x72, 0x13, 0x2f, 0xb6, 0x57, 0x8e,
|
||||
0xa4, 0xbd, 0x03, 0x73, 0xbf, 0x50, 0x6e, 0xeb, 0xaf, 0x3c, 0x89, 0xe0, 0x4b, 0x77, 0x6e, 0x59,
|
||||
0xe9, 0x8e, 0xf1, 0x18, 0xc6, 0x11, 0xfd, 0xbc, 0x18, 0xec, 0x03, 0xa3, 0x1b, 0x62, 0x2a, 0x92,
|
||||
0x74, 0x41, 0xb9, 0x86, 0x1c, 0xf8, 0xf9, 0x03, 0x81, 0xb9, 0x49, 0x4c, 0xf8, 0xe4, 0x2e, 0x34,
|
||||
0x7b, 0x47, 0xb6, 0xfa, 0x73, 0x0e, 0xad, 0xe1, 0x9f, 0x9d, 0x24, 0x8b, 0xe9, 0xc3, 0xc0, 0x6f,
|
||||
0xd2, 0xb2, 0xd4, 0x54, 0xee, 0xa3, 0x1c, 0x15, 0xf1, 0x7d, 0x68, 0x29, 0xee, 0xfe, 0x36, 0x14,
|
||||
0x1c, 0xf6, 0x68, 0xcc, 0xf8, 0x6c, 0x20, 0x5b, 0x20, 0x3c, 0xfa, 0xbb, 0xd9, 0x81, 0x11, 0x6b,
|
||||
0xb5, 0x95, 0x09, 0x8d, 0xad, 0xbf, 0x81, 0xcc, 0x3b, 0x44, 0x29, 0xc4, 0x14, 0x94, 0x96, 0xee,
|
||||
0xe6, 0x58, 0x4f, 0x3f, 0xac, 0xa6, 0x63, 0xeb, 0x1b, 0xc4, 0xf0, 0x6a, 0x3c, 0x1e, 0x97, 0x42,
|
||||
0xd8, 0xaf, 0x84, 0xf0, 0xea, 0xf8, 0xce, 0x3f, 0xf2, 0x8f, 0xe4, 0xfa, 0xbe, 0x0f, 0xdc, 0x6c,
|
||||
0xc8, 0x40, 0x11, 0xbf, 0x9b, 0x10, 0xaf, 0x22, 0xc4, 0xab, 0x08, 0x91, 0xcd, 0x92, 0xa5, 0x0a,
|
||||
0xa5, 0x57, 0x92, 0x59, 0x53, 0xdf, 0xad, 0x4a, 0xbd, 0x72, 0xee, 0xe6, 0xa0, 0x62, 0x59, 0x94,
|
||||
0x86, 0x45, 0xb1, 0xcc, 0xc3, 0x38, 0x4e, 0xb2, 0xc9, 0xc0, 0xad, 0x34, 0x7a, 0x08, 0xfb, 0x29,
|
||||
0x92, 0x28, 0x4c, 0x3b, 0xe0, 0x56, 0x26, 0xd9, 0x40, 0x29, 0xe4, 0x0e, 0x5c, 0x6d, 0x75, 0x25,
|
||||
0x45, 0x1e, 0x66, 0xcb, 0x38, 0x29, 0xf2, 0x34, 0x7c, 0x1c, 0x24, 0x99, 0x34, 0x8c, 0x71, 0x4a,
|
||||
0x1f, 0x86, 0x12, 0x59, 0x27, 0x11, 0x74, 0x56, 0x0c, 0x22, 0x50, 0x56, 0x50, 0x9a, 0x9a, 0xe8,
|
||||
0x6a, 0x86, 0x06, 0x3a, 0xd4, 0x26, 0x61, 0x96, 0xc4, 0x71, 0x4a, 0x57, 0xaf, 0x92, 0x6c, 0xcc,
|
||||
0x2a, 0xe4, 0x86, 0x31, 0x44, 0xef, 0xa2, 0x41, 0xbe, 0x8a, 0x72, 0xd3, 0x02, 0x6b, 0x76, 0xb4,
|
||||
0x61, 0xc4, 0x20, 0xa5, 0x7b, 0x1e, 0xe6, 0xda, 0x9a, 0x8e, 0x5c, 0x1c, 0xaf, 0x4c, 0x3e, 0x9c,
|
||||
0x0b, 0xb6, 0x72, 0x72, 0xe5, 0xff, 0x96, 0x75, 0xeb, 0x2d, 0x3b, 0xff, 0x43, 0x5b, 0x64, 0xb1,
|
||||
0x44, 0xde, 0x61, 0x6f, 0x6a, 0x40, 0x9b, 0xea, 0x54, 0x4d, 0x2b, 0x2e, 0x40, 0x88, 0xcb, 0x96,
|
||||
0x7d, 0xd7, 0x3c, 0x85, 0x04, 0xbc, 0x64, 0x79, 0xb9, 0xe6, 0x38, 0x51, 0x3e, 0x06, 0x56, 0xfa,
|
||||
0x8b, 0xb2, 0x68, 0xf1, 0x0e, 0xcb, 0x94, 0x2c, 0x7c, 0x92, 0xae, 0xac, 0x92, 0xfa, 0xae, 0xbd,
|
||||
0xdc, 0x42, 0x51, 0x5b, 0xbe, 0xff, 0x56, 0x0a, 0x95, 0x0e, 0x17, 0xef, 0x92, 0xc5, 0x56, 0x6d,
|
||||
0xd3, 0x6b, 0xa7, 0x74, 0xdc, 0x30, 0x66, 0xb9, 0x47, 0x14, 0x02, 0xd6, 0x67, 0x50, 0x53, 0xdb,
|
||||
0x29, 0x68, 0x16, 0x63, 0x6b, 0x19, 0xcd, 0x79, 0x01, 0x94, 0xe4, 0x2c, 0x41, 0xba, 0x56, 0x18,
|
||||
0x41, 0x64, 0xe0, 0x20, 0xa3, 0xae, 0x0e, 0xd4, 0x18, 0x41, 0xe0, 0x27, 0x4e, 0x16, 0x24, 0x89,
|
||||
0x03, 0x03, 0x95, 0x03, 0x62, 0x24, 0x9a, 0x90, 0xfe, 0xd0, 0x83, 0x2f, 0xe4, 0xc4, 0xc0, 0x68,
|
||||
0xc8, 0xeb, 0x0f, 0x88, 0x98, 0xc9, 0xf8, 0xb1, 0x94, 0x8c, 0x66, 0x1f, 0xa7, 0x4c, 0xbd, 0xed,
|
||||
0x33, 0x36, 0x25, 0x8c, 0xd0, 0xc5, 0x62, 0x52, 0x81, 0x2b, 0x8e, 0xf6, 0x31, 0x2c, 0x95, 0x1e,
|
||||
0xb4, 0x57, 0x29, 0x69, 0x87, 0xcb, 0x1e, 0xe8, 0x30, 0xc8, 0x22, 0xa1, 0xf7, 0x3f, 0xb3, 0x07,
|
||||
0x08, 0xe4, 0xc4, 0x25, 0xfb, 0x3e, 0xfc, 0x19, 0x27, 0xa3, 0x3c, 0x14, 0x53, 0xf2, 0x62, 0x9c,
|
||||
0xa4, 0x69, 0x60, 0xbc, 0x72, 0xdd, 0x7d, 0xd8, 0x02, 0x03, 0x42, 0xa8, 0x71, 0xd1, 0x23, 0xbe,
|
||||
0x3f, 0x3d, 0x5a, 0x1c, 0x9c, 0xf5, 0xfe, 0xbc, 0xf0, 0x0e, 0x88, 0x77, 0x30, 0x3d, 0x58, 0x1c,
|
||||
0x4d, 0x3b, 0x07, 0xf0, 0x75, 0x04, 0xb1, 0xae, 0xfa, 0xf2, 0x7d, 0xd2, 0x43, 0xb8, 0x69, 0xe7,
|
||||
0xe8, 0x4f, 0xa3, 0x7b, 0x02, 0x02, 0x5b, 0x4c, 0x4e, 0x5e, 0x00, 0x89, 0x20, 0x4e, 0x29, 0x21,
|
||||
0x94, 0x9b, 0x71, 0xf2, 0x5c, 0xc2, 0x80, 0xa0, 0x52, 0xc2, 0x1e, 0xfe, 0x0b, 0xc2, 0x2b, 0x45,
|
||||
0x88, 0xd3, 0xdb, 0x11, 0xd4, 0xa8, 0x09, 0xbf, 0x1e, 0xef, 0x80, 0x17, 0x3d, 0xb5, 0x8e, 0xe1,
|
||||
0xfb, 0x36, 0xa1, 0xc4, 0x5b, 0x5a, 0x21, 0x26, 0x4b, 0x6a, 0x67, 0xeb, 0x76, 0xd9, 0x82, 0x04,
|
||||
0x33, 0xac, 0x14, 0x40, 0x7f, 0x02, 0xff, 0xa7, 0x73, 0x8e, 0x74, 0xa7, 0x8f, 0x24, 0xc9, 0xc8,
|
||||
0xbc, 0xa0, 0x24, 0x52, 0xbc, 0x97, 0x88, 0x48, 0x8b, 0xda, 0xbf, 0x4e, 0x34, 0xfa, 0x44, 0xb9,
|
||||
0x72, 0x0a, 0xa1, 0x84, 0x40, 0xb2, 0x24, 0xa6, 0x94, 0x94, 0x12, 0x22, 0x54, 0xca, 0x9a, 0x08,
|
||||
0x46, 0xc0, 0xcf, 0x93, 0x8c, 0xde, 0x13, 0x69, 0x73, 0xa4, 0x80, 0xf0, 0x04, 0x79, 0x00, 0x02,
|
||||
0xab, 0x19, 0xb2, 0x9b, 0xc6, 0x04, 0x44, 0x4a, 0xee, 0x68, 0xca, 0xee, 0x65, 0xaf, 0x02, 0xc3,
|
||||
0xe9, 0xd1, 0x34, 0xcc, 0x26, 0x94, 0x24, 0xa2, 0x50, 0xa0, 0x8e, 0x5e, 0x10, 0xa1, 0x9a, 0xf3,
|
||||
0x20, 0x1c, 0x81, 0xeb, 0xc6, 0x55, 0xcd, 0x30, 0x8b, 0x31, 0x8f, 0x1c, 0x27, 0x7c, 0x66, 0x21,
|
||||
0x12, 0x15, 0x7d, 0x1d, 0xf2, 0x31, 0x8b, 0x28, 0x19, 0x27, 0x59, 0x52, 0x4c, 0x69, 0x6c, 0x83,
|
||||
0x14, 0x4b, 0x4c, 0x21, 0xe7, 0x88, 0x21, 0x42, 0x36, 0x18, 0x99, 0xe7, 0x29, 0x0b, 0x63, 0x40,
|
||||
0x08, 0x6d, 0x1c, 0x8d, 0x69, 0x91, 0xe0, 0x5a, 0x45, 0xca, 0x84, 0x43, 0x2e, 0x99, 0xe4, 0x8e,
|
||||
0xd0, 0x87, 0x04, 0x64, 0x94, 0x4d, 0x4a, 0x19, 0xd7, 0xf1, 0xe5, 0x34, 0x8b, 0x92, 0x54, 0x22,
|
||||
0x74, 0xc8, 0x8b, 0x2d, 0x42, 0xff, 0x7e, 0x99, 0x4b, 0xed, 0x2c, 0x04, 0x38, 0xa5, 0xe8, 0x53,
|
||||
0xa5, 0x2f, 0x5f, 0x51, 0x17, 0x04, 0xdf, 0xa9, 0x32, 0x6f, 0x17, 0x61, 0x92, 0x86, 0x77, 0x29,
|
||||
0x48, 0x5b, 0x62, 0xfd, 0x9a, 0xae, 0xc8, 0x9f, 0x51, 0x57, 0x3b, 0x24, 0x9d, 0x6d, 0xbf, 0xd8,
|
||||
0x95, 0x6e, 0x63, 0x6a, 0x5c, 0x6a, 0x03, 0x7a, 0x01, 0xcc, 0xba, 0x9b, 0x06, 0x64, 0xd9, 0x11,
|
||||
0xac, 0x18, 0x05, 0x1d, 0xcf, 0xce, 0x1f, 0x4e, 0x59, 0x1a, 0x2c, 0x57, 0xb6, 0xd0, 0xbf, 0x9c,
|
||||
0x46, 0x22, 0xa8, 0x4d, 0xc7, 0x24, 0xfd, 0x67, 0xcc, 0x01, 0x40, 0xde, 0xb0, 0xff, 0xd0, 0xf9,
|
||||
0x0f, 0x80, 0x30, 0x2d, 0xbb, 0x84, 0x39, 0xa7, 0xd9, 0x44, 0x4c, 0x03, 0x9c, 0xe7, 0x48, 0x0f,
|
||||
0x65, 0xcf, 0x3e, 0x8e, 0xc7, 0x45, 0x70, 0x01, 0xfe, 0xc6, 0x91, 0xd9, 0x83, 0xd9, 0x04, 0xed,
|
||||
0xfa, 0x87, 0xbd, 0xae, 0x6f, 0x75, 0x0e, 0x6d, 0xcd, 0xf6, 0x5b, 0xce, 0xc3, 0xc7, 0xe0, 0xfa,
|
||||
0xc6, 0x06, 0x87, 0xf2, 0x39, 0x5c, 0xd0, 0xe0, 0x8d, 0x74, 0x7b, 0x0d, 0xaf, 0xe7, 0x1f, 0xae,
|
||||
0xbd, 0x1e, 0xb6, 0x5b, 0x4e, 0xce, 0x3f, 0x80, 0xbf, 0xd2, 0xc9, 0x49, 0x1f, 0x87, 0x21, 0x46,
|
||||
0xba, 0x37, 0xdf, 0xb7, 0x3d, 0xff, 0xad, 0xe7, 0xda, 0x1e, 0x02, 0xc2, 0x0f, 0xf1, 0x7c, 0xdb,
|
||||
0x6f, 0xf6, 0x6c, 0x05, 0x69, 0x42, 0x20, 0xc8, 0x45, 0x1f, 0xfe, 0x39, 0x87, 0x31, 0xaf, 0x7f,
|
||||
0xe5, 0x1d, 0x9c, 0x79, 0xbd, 0x2b, 0xcf, 0x3d, 0xf3, 0xfc, 0xab, 0xfe, 0x39, 0x0e, 0xfc, 0x77,
|
||||
0xe5, 0x14, 0xdf, 0x20, 0x27, 0xe8, 0xf3, 0xfe, 0xbd, 0x9c, 0x20, 0x51, 0xa7, 0x3d, 0xe7, 0xa0,
|
||||
0x6f, 0xfb, 0x40, 0x31, 0x36, 0x24, 0xe1, 0xa7, 0x48, 0x8f, 0x73, 0xb8, 0x4f, 0xd4, 0x90, 0xaf,
|
||||
0xf8, 0x3b, 0x95, 0x7d, 0xf8, 0xe9, 0x97, 0xe3, 0xbe, 0x82, 0xd6, 0x53, 0xf5, 0xb8, 0x84, 0xbe,
|
||||
0xf0, 0x0e, 0x1d, 0xcf, 0xee, 0x3b, 0x6e, 0xff, 0x14, 0x5a, 0xfe, 0x81, 0x6c, 0x12, 0x68, 0xee,
|
||||
0x1f, 0x41, 0xd3, 0xf3, 0xb1, 0x79, 0x08, 0x2d, 0x7f, 0xff, 0xdc, 0xeb, 0x39, 0xfd, 0xbe, 0x7d,
|
||||
0xe4, 0x1c, 0xc2, 0x02, 0xf0, 0xd3, 0x87, 0xb1, 0xbe, 0x7d, 0x2c, 0xc1, 0xe5, 0xc8, 0xb1, 0xe3,
|
||||
0x1f, 0x9d, 0x03, 0x38, 0x34, 0x3d, 0x57, 0xb6, 0xf7, 0x01, 0x08, 0x20, 0x71, 0xee, 0x01, 0x36,
|
||||
0x11, 0xcd, 0x29, 0x34, 0x8f, 0x7c, 0x8d, 0xfb, 0xc0, 0x39, 0xee, 0x55, 0x2b, 0x2a, 0x32, 0x2e,
|
||||
0x60, 0x96, 0xb7, 0x0f, 0xb3, 0x8e, 0x3c, 0x44, 0xe6, 0x1d, 0x23, 0xb2, 0xa3, 0xfe, 0xf9, 0x31,
|
||||
0xf6, 0xc2, 0x42, 0xc7, 0xfb, 0x67, 0x08, 0x76, 0x85, 0x68, 0xfa, 0xe7, 0x6b, 0xe0, 0xda, 0x1e,
|
||||
0x0c, 0xab, 0xb3, 0x24, 0xa8, 0xe6, 0xc7, 0xb1, 0x89, 0xa7, 0xc9, 0xff, 0x37, 0xd5, 0xae, 0x1d,
|
||||
0x64, 0xd3, 0xe4, 0xcb, 0xc7, 0xac, 0x4c, 0xad, 0xd4, 0xa1, 0x76, 0xc6, 0x16, 0xf4, 0x92, 0x87,
|
||||
0xc5, 0x34, 0x0a, 0x33, 0xe8, 0xb1, 0xc1, 0x51, 0x9f, 0x9a, 0x35, 0xa4, 0xd4, 0x61, 0xb0, 0x0c,
|
||||
0x15, 0xbf, 0x75, 0x9b, 0xe8, 0x7f, 0x04, 0xf4, 0x56, 0xed, 0x90, 0x2c, 0xe7, 0x51, 0x1b, 0x4e,
|
||||
0xec, 0x86, 0xb5, 0x04, 0x53, 0x22, 0x1c, 0x4d, 0x9a, 0x05, 0x2f, 0x3d, 0xc8, 0xb3, 0xb2, 0x42,
|
||||
0x90, 0xb0, 0xc1, 0xee, 0xbf, 0xe6, 0x94, 0x3f, 0x7e, 0x06, 0x87, 0x1c, 0x81, 0xab, 0x7e, 0x9b,
|
||||
0xa6, 0xa6, 0xd1, 0x38, 0x96, 0x19, 0xd6, 0x30, 0x19, 0x9b, 0xa1, 0x03, 0x47, 0xaf, 0xf7, 0x61,
|
||||
0x34, 0x35, 0x4d, 0x61, 0x73, 0x2b, 0x38, 0x59, 0x0a, 0x94, 0xd3, 0x5b, 0x21, 0x78, 0x02, 0x19,
|
||||
0x18, 0x35, 0x8d, 0x38, 0x14, 0x61, 0x47, 0xf0, 0x39, 0x85, 0x8c, 0xcd, 0xb0, 0x82, 0x80, 0xbe,
|
||||
0x7e, 0x6d, 0xc2, 0x9a, 0xae, 0xb5, 0x02, 0x4e, 0x9c, 0x54, 0x52, 0x7a, 0xe2, 0xf5, 0xcb, 0x5e,
|
||||
0x9b, 0x59, 0xea, 0x18, 0x8f, 0xd8, 0xe9, 0x89, 0xfb, 0xfa, 0x35, 0x1d, 0xf9, 0x87, 0x87, 0x16,
|
||||
0x2c, 0x63, 0xa2, 0xab, 0xca, 0x02, 0x6f, 0x98, 0x8d, 0x02, 0xaf, 0xf7, 0xfa, 0x35, 0x1f, 0x41,
|
||||
0x73, 0x6f, 0xcf, 0x92, 0x1e, 0x4b, 0x92, 0x76, 0xa1, 0x28, 0xdb, 0xcb, 0xac, 0xa7, 0x27, 0x93,
|
||||
0x07, 0x99, 0x35, 0xa4, 0x29, 0x84, 0x58, 0x1e, 0xd0, 0xa1, 0x61, 0x04, 0x81, 0x80, 0x45, 0x80,
|
||||
0xfb, 0x57, 0xc6, 0x9e, 0xe9, 0xf5, 0xfa, 0xfd, 0xbe, 0xef, 0x1d, 0xfe, 0xa8, 0xe4, 0x08, 0x71,
|
||||
0x88, 0xcd, 0x4c, 0x6b, 0x34, 0x72, 0x2d, 0x47, 0xb0, 0xcf, 0x40, 0x7c, 0x36, 0x01, 0x18, 0x0b,
|
||||
0xf2, 0xdc, 0xf8, 0xb3, 0x08, 0xb9, 0x30, 0x7b, 0xb6, 0xe1, 0x1a, 0x96, 0xa5, 0x25, 0x95, 0x06,
|
||||
0xd1, 0x7b, 0xd3, 0xc0, 0xfc, 0x04, 0xc4, 0x90, 0x3a, 0xd2, 0x65, 0xff, 0x12, 0xce, 0xc0, 0x6a,
|
||||
0x1b, 0x22, 0xb2, 0x53, 0x07, 0xbd, 0x7b, 0x83, 0x36, 0xbe, 0x5e, 0xc0, 0x82, 0xf1, 0x62, 0xb7,
|
||||
0xb0, 0x6c, 0xfa, 0x0c, 0x00, 0xe0, 0x34, 0x6c, 0xb1, 0x03, 0x40, 0xe9, 0x83, 0xa1, 0xf4, 0x0f,
|
||||
0x61, 0x60, 0xeb, 0xdf, 0x2f, 0x50, 0x31, 0x20, 0x12, 0x52, 0x48, 0x96, 0x40, 0x5e, 0x18, 0x02,
|
||||
0x0d, 0x1b, 0x72, 0x8f, 0xfc, 0xef, 0x73, 0x0e, 0xa1, 0x90, 0x7f, 0xe2, 0x2c, 0x97, 0xf8, 0xd0,
|
||||
0xfd, 0x38, 0x98, 0x18, 0x3f, 0xaf, 0xb9, 0x3f, 0x52, 0x6b, 0x4f, 0x2e, 0xb0, 0x67, 0x80, 0x5b,
|
||||
0xd2, 0x82, 0x49, 0xa4, 0x60, 0x92, 0x2c, 0x9f, 0x0b, 0x54, 0x10, 0x47, 0x45, 0x1d, 0x29, 0x00,
|
||||
0xc3, 0x4e, 0x9c, 0x45, 0x98, 0xce, 0x69, 0x20, 0xa0, 0xb5, 0x21, 0x32, 0x75, 0xd0, 0x45, 0xa0,
|
||||
0x4a, 0x64, 0x9f, 0x54, 0x57, 0x53, 0x64, 0xc9, 0x16, 0x66, 0xd4, 0x7a, 0xf6, 0x3c, 0xc7, 0x22,
|
||||
0x57, 0x69, 0x3c, 0xdb, 0x41, 0x35, 0xdf, 0x51, 0x7e, 0x9a, 0x7e, 0x29, 0x77, 0xb3, 0xa8, 0xef,
|
||||
0x66, 0xb1, 0x8b, 0xb4, 0x6a, 0x53, 0x8b, 0x36, 0x85, 0x5b, 0xb7, 0xb6, 0x78, 0x66, 0x71, 0x96,
|
||||
0xe2, 0xea, 0x00, 0x52, 0x93, 0x75, 0x5d, 0xf0, 0x40, 0xf9, 0x8e, 0x11, 0x4d, 0x71, 0x5c, 0xa7,
|
||||
0x98, 0xa3, 0x95, 0x70, 0xb4, 0x12, 0xd0, 0xef, 0xb8, 0x4e, 0x7e, 0xa3, 0x98, 0x61, 0xd8, 0xb1,
|
||||
0x24, 0x5c, 0x75, 0x6e, 0xa5, 0x39, 0xde, 0x4d, 0x33, 0x05, 0xd3, 0x56, 0x33, 0x4f, 0x91, 0x71,
|
||||
0x2c, 0xaa, 0x21, 0xfc, 0x0e, 0x32, 0xd7, 0x7a, 0xb4, 0xae, 0x0a, 0xc8, 0x79, 0x81, 0xd6, 0x81,
|
||||
0x8a, 0xf7, 0x5d, 0xe3, 0x75, 0x4f, 0x14, 0xe6, 0x90, 0xa6, 0xc5, 0xa7, 0xd3, 0x24, 0x8d, 0xcd,
|
||||
0xc4, 0xda, 0x39, 0x94, 0xee, 0x1e, 0x02, 0x23, 0x70, 0x5f, 0x06, 0xfc, 0xf5, 0x6b, 0x10, 0x92,
|
||||
0xfc, 0xdd, 0x05, 0x18, 0x5b, 0x76, 0x5d, 0x9c, 0xb3, 0xf0, 0x0b, 0xbd, 0xa0, 0xef, 0x78, 0x38,
|
||||
0x31, 0xd1, 0xcb, 0xa0, 0x39, 0x5b, 0xb0, 0x6f, 0x54, 0x5c, 0x32, 0x96, 0x8a, 0x24, 0x57, 0x52,
|
||||
0xac, 0x8f, 0x35, 0x75, 0xd0, 0xac, 0xb9, 0xdf, 0xf6, 0xc8, 0x52, 0x6d, 0x25, 0xfd, 0x4e, 0xa7,
|
||||
0xbb, 0x91, 0x82, 0xd1, 0x0d, 0x17, 0xac, 0x10, 0x33, 0x99, 0xca, 0xd1, 0x6b, 0x7e, 0x03, 0x94,
|
||||
0x39, 0x9c, 0x42, 0xfe, 0x1a, 0xd1, 0xa6, 0xa3, 0xb4, 0x1b, 0x76, 0x66, 0x59, 0x4a, 0xf6, 0xc3,
|
||||
0xef, 0x9b, 0xa7, 0xfb, 0x60, 0xf6, 0xf6, 0x1d, 0x65, 0xb6, 0xc4, 0xf5, 0xfc, 0xe0, 0x33, 0x4e,
|
||||
0x8e, 0x59, 0x55, 0x78, 0x92, 0xb0, 0xcf, 0x85, 0x17, 0x3b, 0xfb, 0x8a, 0xcf, 0x0a, 0xb5, 0x00,
|
||||
0xaf, 0xb3, 0x1b, 0x58, 0x1b, 0x45, 0x78, 0x1d, 0x42, 0x6b, 0xb5, 0x56, 0x1d, 0x65, 0x0c, 0x81,
|
||||
0x81, 0xa5, 0x82, 0x90, 0x77, 0xca, 0x6e, 0x13, 0x8e, 0x18, 0xf2, 0xcc, 0x6c, 0xd8, 0x1f, 0xef,
|
||||
0xfe, 0xc0, 0x10, 0x0f, 0x9d, 0x3c, 0xa1, 0x85, 0x29, 0xf1, 0x59, 0xeb, 0x4d, 0xb8, 0x86, 0x10,
|
||||
0x7b, 0x83, 0xdb, 0xd0, 0xc4, 0xb8, 0x17, 0xdc, 0xda, 0xe4, 0x87, 0xa5, 0x58, 0xc1, 0x3f, 0x74,
|
||||
0x95, 0x3f, 0xdc, 0x6e, 0xac, 0xb9, 0x17, 0x18, 0x96, 0xd1, 0x50, 0xe1, 0xb6, 0xcc, 0x82, 0xe6,
|
||||
0x84, 0xb5, 0x6e, 0xb5, 0xdc, 0x38, 0xe6, 0x0d, 0xd4, 0xc1, 0x4e, 0xfc, 0x0a, 0x27, 0x21, 0x02,
|
||||
0xd5, 0x75, 0x51, 0x79, 0xa0, 0xed, 0xe9, 0xc5, 0x96, 0x89, 0xb6, 0xd4, 0x08, 0xa7, 0xe0, 0x91,
|
||||
0xae, 0xa9, 0x37, 0x34, 0xa3, 0x52, 0x0a, 0xd4, 0x01, 0xe9, 0x2e, 0x1a, 0x4b, 0xe5, 0x3b, 0x56,
|
||||
0x5a, 0x48, 0x1f, 0xfd, 0x2c, 0x99, 0x35, 0xf3, 0x03, 0x04, 0x18, 0xfe, 0x45, 0xe0, 0xda, 0xfc,
|
||||
0x9b, 0xb2, 0x32, 0x16, 0x70, 0x47, 0x6e, 0x98, 0x1d, 0x42, 0x4b, 0x7a, 0xd5, 0x2c, 0x60, 0x9d,
|
||||
0x70, 0xcf, 0x5b, 0xa7, 0x7a, 0xa9, 0xc9, 0xad, 0x25, 0x24, 0x0a, 0xfc, 0xe9, 0xe9, 0x1e, 0x4e,
|
||||
0xa5, 0xec, 0xde, 0x51, 0x54, 0x39, 0x39, 0x97, 0x8d, 0x77, 0x74, 0x1c, 0xce, 0x53, 0xc4, 0x26,
|
||||
0x3a, 0x1c, 0x59, 0x83, 0xbe, 0xdf, 0x20, 0x81, 0x5a, 0xb7, 0x67, 0x0c, 0xce, 0xf0, 0x9f, 0x58,
|
||||
0xf1, 0xa1, 0xca, 0xd9, 0x02, 0xd1, 0x31, 0x61, 0x11, 0x98, 0x02, 0x4a, 0x09, 0x23, 0x75, 0x85,
|
||||
0xdc, 0x84, 0xee, 0x66, 0x32, 0x4b, 0xb3, 0x59, 0x1a, 0x5f, 0x6a, 0x78, 0xfa, 0xbc, 0x86, 0x6b,
|
||||
0xb4, 0xe8, 0xa4, 0x74, 0x53, 0xb9, 0xaa, 0x35, 0x86, 0x97, 0x81, 0x1e, 0xc0, 0x74, 0x47, 0x83,
|
||||
0xf4, 0x0e, 0x7e, 0x12, 0xd3, 0xa4, 0xf8, 0x28, 0x13, 0x83, 0xc0, 0x1d, 0x94, 0x58, 0xbc, 0x63,
|
||||
0xbf, 0x3e, 0xd0, 0x1f, 0xd4, 0x3e, 0xf6, 0xe5, 0xe6, 0x6c, 0x4b, 0x06, 0x32, 0x69, 0x4b, 0x1a,
|
||||
0x47, 0x3d, 0x0b, 0xd0, 0x8a, 0xf2, 0x7f, 0xf2, 0x1b, 0x72, 0x91, 0xfa, 0x8a, 0x5f, 0x45, 0xd6,
|
||||
0x88, 0x64, 0x7f, 0x01, 0x4f, 0xcb, 0x09, 0xee, 0x42, 0x43, 0x9f, 0x4d, 0xd6, 0x4a, 0x69, 0x6c,
|
||||
0x46, 0x07, 0xba, 0x19, 0x15, 0x6a, 0x3a, 0x9e, 0x40, 0x24, 0x88, 0x1d, 0x96, 0x49, 0xdd, 0x98,
|
||||
0xe7, 0x41, 0x36, 0x4f, 0x53, 0xbb, 0xea, 0x40, 0x93, 0x91, 0x5d, 0x2b, 0x5a, 0x76, 0x81, 0x9a,
|
||||
0x66, 0x41, 0x39, 0x7d, 0xb7, 0x61, 0x99, 0x34, 0xa0, 0x5f, 0x57, 0x6b, 0xe0, 0xb0, 0x54, 0xe5,
|
||||
0x3a, 0x11, 0x49, 0x8b, 0x82, 0x74, 0x55, 0xf3, 0x35, 0x9b, 0xfc, 0x2d, 0xdb, 0xa2, 0x91, 0x57,
|
||||
0x7d, 0x86, 0x7d, 0x0b, 0xae, 0xee, 0x59, 0x6d, 0x5e, 0x91, 0x01, 0x79, 0x06, 0x06, 0xfd, 0xbf,
|
||||
0xb5, 0xba, 0xad, 0x49, 0xab, 0x99, 0x82, 0x68, 0x97, 0x80, 0xb9, 0x50, 0x9c, 0x2c, 0x20, 0x38,
|
||||
0xa2, 0xf6, 0xbe, 0xab, 0x69, 0x45, 0x50, 0x77, 0x5a, 0x36, 0x8e, 0x9e, 0xae, 0x77, 0x5e, 0xc6,
|
||||
0xc7, 0xf6, 0x8c, 0x86, 0x9a, 0xa8, 0xd5, 0x4a, 0x0d, 0x01, 0xdd, 0x58, 0xa3, 0xa8, 0xeb, 0xf0,
|
||||
0xf7, 0x22, 0xaa, 0x54, 0xad, 0x8d, 0xee, 0x5b, 0x11, 0xed, 0xd0, 0x5c, 0x9b, 0x43, 0x1e, 0x43,
|
||||
0xb9, 0x32, 0xdf, 0xdf, 0x02, 0xcf, 0xd5, 0x1d, 0xbf, 0x35, 0xc4, 0xb0, 0xcb, 0x63, 0x3a, 0x0f,
|
||||
0x9d, 0xc6, 0x7c, 0x3d, 0xf9, 0xf7, 0x6f, 0x9b, 0xfc, 0xb8, 0x07, 0x67, 0x6a, 0x21, 0x13, 0x4c,
|
||||
0x81, 0x9a, 0x68, 0xe0, 0x47, 0x06, 0x19, 0xe4, 0xd9, 0xe5, 0xc5, 0xb9, 0x2e, 0x6c, 0x6c, 0xa9,
|
||||
0x5c, 0x90, 0x87, 0x59, 0x9a, 0x15, 0x81, 0x81, 0x37, 0xcc, 0x83, 0x6e, 0xf7, 0xfe, 0xfe, 0xde,
|
||||
0xb9, 0xdf, 0x77, 0x18, 0x9f, 0x74, 0x7d, 0xd7, 0x75, 0xf1, 0x68, 0x6e, 0x10, 0x79, 0x96, 0x0e,
|
||||
0x0c, 0xbc, 0xff, 0x33, 0x88, 0x2a, 0x85, 0xe8, 0x2f, 0x5d, 0xf7, 0xd0, 0x05, 0x13, 0x2c, 0x7f,
|
||||
0x0c, 0x5e, 0x1d, 0x1d, 0xc1, 0x44, 0x77, 0x08, 0x9d, 0x9c, 0x7d, 0xa1, 0x03, 0x02, 0x1d, 0xf8,
|
||||
0x5f, 0xd9, 0xd1, 0x51, 0x65, 0x15, 0xd2, 0xc1, 0x4b, 0x04, 0xdd, 0x15, 0x03, 0xbd, 0x21, 0x56,
|
||||
0x95, 0x06, 0xc4, 0x75, 0x3c, 0x9b, 0x1c, 0x0d, 0x55, 0xa9, 0xfb, 0xd8, 0xde, 0xbf, 0x3a, 0x38,
|
||||
0x3b, 0xb8, 0xea, 0x9d, 0x1d, 0x5e, 0x79, 0xc7, 0x6f, 0x7d, 0xdb, 0x97, 0xe5, 0x1d, 0x97, 0xf4,
|
||||
0x6d, 0xdf, 0x3b, 0xf3, 0xfa, 0xb5, 0x1e, 0x2c, 0x39, 0x1c, 0x03, 0xa0, 0xef, 0xc2, 0x0c, 0xef,
|
||||
0xf0, 0x6a, 0xff, 0xec, 0xf8, 0xa2, 0x6f, 0xf7, 0xce, 0xb0, 0xf4, 0x73, 0x7c, 0xd6, 0xbf, 0xea,
|
||||
0x01, 0xb2, 0xa3, 0x2b, 0xaf, 0x7f, 0xe6, 0x79, 0x57, 0x47, 0x30, 0x86, 0x05, 0x08, 0xf9, 0x79,
|
||||
0x08, 0x9f, 0xde, 0x7e, 0xbd, 0x18, 0x24, 0xb4, 0xcf, 0x29, 0x6f, 0x38, 0x02, 0xa3, 0xbc, 0xf3,
|
||||
0x33, 0xaa, 0x31, 0xe9, 0x9c, 0xf4, 0xe6, 0x2a, 0xc7, 0x5b, 0x8e, 0x40, 0x30, 0xd5, 0x03, 0xbf,
|
||||
0xab, 0x81, 0xd8, 0xc1, 0x42, 0x60, 0x23, 0xc9, 0x05, 0xef, 0x20, 0x9e, 0xcf, 0xf4, 0x85, 0xa3,
|
||||
0xca, 0xeb, 0xbf, 0xb0, 0x98, 0x3a, 0xca, 0xbf, 0xac, 0xa7, 0xb6, 0xf5, 0x73, 0x17, 0x68, 0x0b,
|
||||
0x6e, 0x87, 0xf1, 0x3c, 0x37, 0x7d, 0x03, 0xd8, 0x6a, 0xdb, 0xf0, 0x57, 0x67, 0xef, 0x58, 0xfb,
|
||||
0x1b, 0x57, 0xdd, 0x92, 0xcf, 0x6f, 0x4f, 0x90, 0x9e, 0x39, 0x39, 0x35, 0xdd, 0xf3, 0x57, 0x32,
|
||||
0x9e, 0x8d, 0x74, 0x6c, 0x29, 0xad, 0x49, 0x55, 0x65, 0x95, 0x61, 0x21, 0x06, 0x11, 0x72, 0x30,
|
||||
0x44, 0x0c, 0xf4, 0xd0, 0x83, 0x89, 0x80, 0xfc, 0x31, 0xe5, 0xef, 0x4e, 0xd6, 0x70, 0x10, 0x29,
|
||||
0x55, 0x9d, 0xdf, 0x44, 0x6c, 0x3d, 0x8f, 0x9b, 0x7e, 0xf9, 0xb5, 0x7e, 0x68, 0x41, 0x82, 0xe4,
|
||||
0xbd, 0x16, 0x46, 0x11, 0xf9, 0x25, 0x2f, 0x74, 0xac, 0x61, 0x59, 0x8e, 0xfa, 0x15, 0x0d, 0x6d,
|
||||
0xd4, 0x73, 0xdd, 0x9f, 0x4a, 0xdd, 0xd4, 0x45, 0x74, 0x7c, 0x60, 0x92, 0x51, 0x63, 0xb0, 0xd1,
|
||||
0xad, 0xee, 0xe7, 0x8c, 0xda, 0x9a, 0x61, 0x1a, 0xfd, 0xe7, 0xe7, 0x8f, 0xbf, 0x98, 0xaa, 0x5e,
|
||||
0x45, 0x83, 0x37, 0xcb, 0xb2, 0x84, 0x6e, 0x0c, 0xae, 0xdf, 0x0c, 0xf5, 0x83, 0x8f, 0x56, 0x42,
|
||||
0x2e, 0x5a, 0xf9, 0x38, 0x9c, 0x8a, 0x64, 0x3e, 0x2e, 0x30, 0x67, 0x32, 0x29, 0xa4, 0xd9, 0x36,
|
||||
0x0a, 0x11, 0x12, 0x72, 0x4c, 0xc7, 0x6d, 0xe3, 0x87, 0x25, 0x77, 0x0a, 0x60, 0x9f, 0x9a, 0x9e,
|
||||
0xb5, 0x32, 0x30, 0x2f, 0x47, 0x98, 0x9b, 0x15, 0x98, 0x42, 0x2d, 0x4c, 0x67, 0x60, 0x8c, 0xa0,
|
||||
0x09, 0xff, 0x25, 0xaf, 0x1c, 0x70, 0x63, 0xd4, 0xe5, 0x83, 0x24, 0x6f, 0x4d, 0xa7, 0x7d, 0xdb,
|
||||
0xd5, 0x04, 0x62, 0x96, 0xef, 0xfc, 0x51, 0xb0, 0xec, 0xb6, 0x71, 0x06, 0xac, 0xe6, 0xc0, 0x29,
|
||||
0x41, 0xc5, 0x2f, 0x1e, 0xe0, 0xad, 0xcb, 0x6f, 0x17, 0xe7, 0x67, 0xe0, 0x03, 0xff, 0x41, 0xe1,
|
||||
0x04, 0x58, 0x08, 0xc8, 0x5e, 0xb1, 0xf3, 0xe7, 0x94, 0xdd, 0xc1, 0x79, 0xe2, 0xc6, 0x5e, 0x62,
|
||||
0x1d, 0x65, 0x60, 0x80, 0x11, 0xa7, 0x78, 0x75, 0x02, 0xa8, 0xba, 0x88, 0xda, 0x58, 0xc1, 0xe9,
|
||||
0x7f, 0x8b, 0xe6, 0xe1, 0x22, 0x86, 0x6d, 0x96, 0x67, 0x41, 0x86, 0x1e, 0x83, 0x4d, 0xa4, 0x72,
|
||||
0xc3, 0xee, 0x17, 0x39, 0xf4, 0xd1, 0x4b, 0xfa, 0x20, 0x6c, 0x83, 0x74, 0x88, 0x21, 0x6d, 0xc3,
|
||||
0xc1, 0xbb, 0x85, 0x39, 0x16, 0x8b, 0x18, 0x70, 0xf3, 0x19, 0x4e, 0x9f, 0xe1, 0xa4, 0xd4, 0x9f,
|
||||
0x0f, 0x82, 0xce, 0x60, 0xb3, 0x53, 0x1a, 0x7f, 0x0a, 0x53, 0xbc, 0x0f, 0xd0, 0x59, 0x05, 0x82,
|
||||
0x22, 0x2d, 0xce, 0x94, 0xd3, 0x71, 0x60, 0x74, 0x81, 0x1c, 0x7b, 0x1b, 0x39, 0x94, 0x73, 0x2c,
|
||||
0xff, 0xd0, 0x16, 0x39, 0xc6, 0x7b, 0xec, 0x1f, 0x10, 0x59, 0xe8, 0x6a, 0x0c, 0x90, 0xcf, 0x92,
|
||||
0x98, 0x41, 0x9b, 0x36, 0x4c, 0x3d, 0x92, 0x19, 0x65, 0x73, 0x61, 0x4a, 0xe6, 0x56, 0xb6, 0x47,
|
||||
0xf7, 0x2d, 0xb9, 0x2a, 0x03, 0xf7, 0x66, 0x1a, 0x9f, 0x3e, 0x7e, 0xbe, 0x84, 0xdd, 0xed, 0x2a,
|
||||
0x39, 0x83, 0x32, 0xa2, 0x80, 0x43, 0x29, 0xcb, 0xbf, 0x33, 0x3e, 0x7b, 0x07, 0x89, 0x45, 0xa9,
|
||||
0x34, 0xa1, 0x76, 0x89, 0x2a, 0xdd, 0x80, 0x63, 0x26, 0x56, 0xd3, 0xb8, 0xbc, 0xf1, 0x35, 0x43,
|
||||
0xcb, 0x7e, 0xe9, 0xad, 0xc2, 0xe2, 0x31, 0x8b, 0xc8, 0xfa, 0x39, 0x12, 0x15, 0x1f, 0xb2, 0x31,
|
||||
0x03, 0x5d, 0x4c, 0xc6, 0xe6, 0xb4, 0x10, 0xc1, 0x9a, 0x7d, 0x06, 0x3b, 0x06, 0x3d, 0x65, 0x35,
|
||||
0xd3, 0xb5, 0x04, 0x7f, 0xac, 0x2c, 0x25, 0xbc, 0x0f, 0x13, 0x41, 0xc6, 0x54, 0x80, 0x32, 0x96,
|
||||
0x71, 0xce, 0xd8, 0x03, 0xf0, 0x3d, 0x43, 0x6e, 0x62, 0x57, 0x5e, 0xd0, 0xa1, 0x15, 0x29, 0x48,
|
||||
0x2a, 0xb5, 0xc6, 0xb4, 0x86, 0x72, 0x4a, 0x79, 0x85, 0x64, 0x9a, 0xea, 0x12, 0x46, 0x38, 0xf2,
|
||||
0x17, 0x42, 0xb0, 0xb0, 0x3a, 0xa0, 0xaf, 0x40, 0x02, 0xe0, 0xa5, 0x56, 0x25, 0x59, 0x29, 0x6c,
|
||||
0x2c, 0xcf, 0xc8, 0xd2, 0x67, 0xb3, 0xd7, 0x00, 0x9b, 0xce, 0x98, 0x20, 0x49, 0x0c, 0xfb, 0x93,
|
||||
0x8c, 0x1f, 0x09, 0x52, 0x0e, 0x19, 0x56, 0x8b, 0xd3, 0xe6, 0xc2, 0x80, 0xbb, 0x7e, 0xf3, 0xa2,
|
||||
0x99, 0x0c, 0xdc, 0x21, 0x96, 0x64, 0xd1, 0x2c, 0xe1, 0x3c, 0x31, 0x14, 0xa3, 0x80, 0x0e, 0xc5,
|
||||
0xde, 0xde, 0xda, 0x41, 0xdc, 0x6a, 0x56, 0x7f, 0x58, 0x02, 0xab, 0xab, 0xb5, 0x55, 0x08, 0x6d,
|
||||
0x15, 0xc3, 0xb5, 0x8c, 0x44, 0x43, 0x46, 0xa0, 0x0c, 0x5c, 0x77, 0x88, 0x52, 0x14, 0x0d, 0x02,
|
||||
0xf2, 0x79, 0x31, 0x85, 0x83, 0x9b, 0x66, 0x5d, 0xb4, 0x59, 0xbf, 0x95, 0x6a, 0xa5, 0x90, 0xe1,
|
||||
0xad, 0x1f, 0x5a, 0x1b, 0x19, 0x73, 0x36, 0x93, 0x07, 0xef, 0x01, 0xb9, 0x85, 0x8d, 0x5e, 0xad,
|
||||
0xb6, 0xb0, 0x34, 0xf2, 0xc0, 0x3f, 0x6c, 0xae, 0x54, 0x72, 0x3f, 0xb8, 0x76, 0xed, 0x7e, 0xf9,
|
||||
0x07, 0x47, 0xae, 0xea, 0xe3, 0x66, 0x55, 0x56, 0x28, 0x44, 0x80, 0x8b, 0xa1, 0x03, 0x2e, 0xa8,
|
||||
0xd9, 0x30, 0x24, 0x54, 0x9e, 0x96, 0x15, 0xc9, 0xfa, 0x39, 0x50, 0x8f, 0x62, 0xd4, 0x42, 0xc3,
|
||||
0x3b, 0x61, 0x08, 0xbd, 0x52, 0xc3, 0xe8, 0x89, 0x7f, 0x70, 0x68, 0xe9, 0x9a, 0x1b, 0xf6, 0x82,
|
||||
0x1f, 0xc0, 0x65, 0x44, 0x92, 0xcd, 0xe9, 0x4a, 0x4d, 0xe0, 0x81, 0xee, 0xc7, 0x6d, 0xc0, 0xf2,
|
||||
0xf9, 0xb0, 0x8e, 0x8c, 0x8d, 0x09, 0x97, 0xa8, 0x5e, 0x2a, 0x6e, 0x92, 0x42, 0xfe, 0x82, 0x80,
|
||||
0x9f, 0x9e, 0x0e, 0x5e, 0x06, 0x01, 0xd5, 0x7c, 0x5b, 0x4b, 0x79, 0x07, 0x70, 0xc7, 0x69, 0xf8,
|
||||
0x65, 0xb5, 0x46, 0x20, 0x10, 0x01, 0xb5, 0x60, 0xbe, 0x91, 0xcd, 0x67, 0x77, 0x90, 0x61, 0x42,
|
||||
0xbc, 0x01, 0x37, 0x04, 0xbd, 0xe2, 0xe9, 0x49, 0x8c, 0x5c, 0xf8, 0xe7, 0x04, 0xe4, 0xf0, 0xf4,
|
||||
0xf4, 0xf2, 0x17, 0x39, 0x0e, 0x0b, 0x7c, 0xc8, 0x04, 0x9d, 0x80, 0xc9, 0x0b, 0xab, 0x81, 0x74,
|
||||
0x85, 0x44, 0xb0, 0xaf, 0x30, 0x03, 0xc7, 0xf4, 0x6b, 0xae, 0x49, 0xea, 0x78, 0x37, 0x28, 0x1d,
|
||||
0x59, 0xad, 0x0b, 0xc2, 0x6b, 0xf7, 0x66, 0xad, 0x57, 0xd7, 0x8e, 0xe3, 0x84, 0x37, 0x43, 0x0a,
|
||||
0x9d, 0x01, 0xee, 0x02, 0x57, 0xbb, 0x04, 0x0a, 0xbf, 0x2a, 0x41, 0xda, 0xf1, 0x00, 0x24, 0xea,
|
||||
0xcc, 0xc2, 0x7c, 0x5d, 0x9a, 0x31, 0x97, 0xb0, 0x3e, 0xc4, 0x9f, 0x71, 0x1a, 0xca, 0x90, 0xbe,
|
||||
0x4d, 0xc1, 0x60, 0x99, 0xd2, 0x88, 0x60, 0x8c, 0x0b, 0xd3, 0xb8, 0xc4, 0x5b, 0x70, 0x7c, 0x17,
|
||||
0x89, 0x82, 0xa9, 0xee, 0x60, 0x21, 0xd8, 0x92, 0x59, 0x52, 0x14, 0xc9, 0x44, 0x29, 0xd9, 0x23,
|
||||
0x9b, 0x73, 0x72, 0xc7, 0xd9, 0x7d, 0x01, 0x12, 0x21, 0xbf, 0xb3, 0x39, 0x29, 0xa6, 0x6c, 0x9e,
|
||||
0xc6, 0x24, 0xe7, 0xec, 0x2e, 0xbc, 0x4b, 0x1f, 0x89, 0x76, 0x40, 0xfa, 0xce, 0x7a, 0x16, 0xc2,
|
||||
0xa6, 0x43, 0x2a, 0x00, 0xcb, 0x64, 0x31, 0xc1, 0x8d, 0x04, 0xc5, 0x97, 0xd7, 0xda, 0x30, 0x21,
|
||||
0xa7, 0x1c, 0x26, 0x8c, 0xf1, 0x82, 0x1e, 0x2f, 0xab, 0xcb, 0x35, 0x15, 0x15, 0x58, 0x91, 0x02,
|
||||
0x69, 0x83, 0x8b, 0x85, 0xb8, 0x44, 0xee, 0x28, 0x80, 0x51, 0x8d, 0x1c, 0xf5, 0x7e, 0x4a, 0x39,
|
||||
0x75, 0xc0, 0x19, 0x5e, 0x20, 0x71, 0xf0, 0x2d, 0x27, 0xc5, 0x15, 0x92, 0x97, 0xe0, 0x1d, 0xcb,
|
||||
0xc9, 0xda, 0xd6, 0xdf, 0x25, 0x8b, 0xa2, 0x9e, 0x8c, 0x6c, 0x1d, 0xae, 0x36, 0x62, 0xe3, 0x41,
|
||||
0xe6, 0xfa, 0x79, 0x04, 0x3a, 0xb3, 0xcd, 0xe1, 0xd6, 0x9d, 0x38, 0x9a, 0xb9, 0x92, 0x37, 0xca,
|
||||
0x0d, 0x0e, 0xe8, 0x11, 0xa6, 0x29, 0x90, 0xba, 0x40, 0xec, 0x4e, 0x52, 0x81, 0x07, 0xcb, 0xe0,
|
||||
0x44, 0x1e, 0xdb, 0x67, 0xd2, 0xd0, 0xbb, 0xff, 0xd4, 0xf8, 0xff, 0x27, 0xfe, 0xa1, 0x0b, 0x5b,
|
||||
0xd6, 0xd2, 0x54, 0x6e, 0xb5, 0x33, 0xd5, 0xca, 0x41, 0x71, 0x70, 0x50, 0x7c, 0xb4, 0xc5, 0xe2,
|
||||
0x87, 0x7c, 0xed, 0xb1, 0x58, 0x50, 0x07, 0xb8, 0xe6, 0x37, 0x76, 0x18, 0xb4, 0x5f, 0x92, 0xea,
|
||||
0x53, 0x66, 0xe8, 0xd4, 0x1e, 0x83, 0x18, 0x7b, 0xdc, 0x0e, 0x55, 0xd1, 0x1d, 0x23, 0x1e, 0x86,
|
||||
0xbf, 0x4a, 0x12, 0x46, 0xe9, 0x18, 0xb2, 0x52, 0x27, 0xbf, 0xd0, 0xc7, 0xc2, 0x64, 0x16, 0x28,
|
||||
0x2f, 0x60, 0xc1, 0xc0, 0x03, 0x21, 0x0d, 0x2b, 0xbc, 0xf2, 0xf8, 0xa1, 0xbc, 0x47, 0x21, 0x6b,
|
||||
0x7b, 0xe0, 0x9d, 0x4d, 0x76, 0x9d, 0xdd, 0xac, 0x6f, 0x9c, 0x76, 0x10, 0x93, 0xd6, 0x89, 0x29,
|
||||
0xf3, 0x54, 0x20, 0xaa, 0xba, 0x90, 0xd9, 0x31, 0x4f, 0xdd, 0xb3, 0xac, 0x5f, 0x49, 0x21, 0x1f,
|
||||
0x49, 0x9b, 0x8f, 0xda, 0xf0, 0xfa, 0xb2, 0x64, 0x03, 0x61, 0x75, 0x73, 0x22, 0x9f, 0x32, 0xe8,
|
||||
0x27, 0x53, 0x88, 0xaf, 0x70, 0xf0, 0x15, 0x21, 0x24, 0x96, 0xeb, 0x7a, 0x05, 0x38, 0xa4, 0x66,
|
||||
0x26, 0x05, 0x8e, 0x1c, 0x2f, 0x03, 0xb6, 0x95, 0x0f, 0x8c, 0xcf, 0x14, 0xdf, 0x87, 0xa8, 0x17,
|
||||
0x33, 0xb5, 0x97, 0x2a, 0xf8, 0xbc, 0x83, 0x00, 0x7e, 0xbc, 0x41, 0x59, 0x9f, 0x31, 0xf5, 0x73,
|
||||
0x00, 0xbb, 0x68, 0x33, 0x51, 0x51, 0x54, 0xb2, 0x10, 0xed, 0x64, 0x21, 0x92, 0x2c, 0x94, 0xef,
|
||||
0xbf, 0x90, 0x85, 0x68, 0x1b, 0x0b, 0x48, 0x38, 0xe4, 0x13, 0x78, 0x67, 0x2f, 0xe9, 0x8f, 0x76,
|
||||
0x94, 0x3f, 0x4e, 0x59, 0xfe, 0xa8, 0xa8, 0x85, 0x1c, 0x73, 0x55, 0x9a, 0x1e, 0xb2, 0xa0, 0x98,
|
||||
0xb9, 0x85, 0xbc, 0xa7, 0xc9, 0x01, 0xa2, 0x84, 0xbe, 0x16, 0x07, 0x15, 0x41, 0x78, 0xaf, 0xb2,
|
||||
0x5d, 0xd5, 0xaa, 0x07, 0x85, 0xa8, 0x12, 0xa0, 0xf3, 0x79, 0x60, 0x18, 0x95, 0x01, 0x50, 0x30,
|
||||
0x00, 0x3a, 0x42, 0x75, 0x2a, 0x15, 0x1f, 0x32, 0x5c, 0xdf, 0xaa, 0xc2, 0x2f, 0x8e, 0xa0, 0x47,
|
||||
0x46, 0x5f, 0xaf, 0xd4, 0x0f, 0x6f, 0x4b, 0x95, 0xaf, 0x57, 0x63, 0x7b, 0xde, 0x8d, 0x95, 0x43,
|
||||
0xc6, 0xfc, 0xea, 0x87, 0x65, 0xd5, 0x81, 0x95, 0x6c, 0xd1, 0x05, 0x1f, 0xfc, 0xa3, 0xe7, 0xba,
|
||||
0xab, 0xbf, 0xd9, 0xe4, 0x56, 0x5e, 0xb7, 0x2e, 0x11, 0x4e, 0xbe, 0xee, 0xad, 0xc3, 0x62, 0xed,
|
||||
0x5b, 0x7f, 0xf9, 0x8d, 0xaf, 0x7d, 0xfc, 0xf2, 0xac, 0x0d, 0x5c, 0x98, 0x84, 0xfb, 0x10, 0xa7,
|
||||
0x83, 0x5c, 0x27, 0xe7, 0xae, 0xdd, 0xf1, 0xb7, 0xdd, 0x2b, 0x7d, 0x98, 0x81, 0xf3, 0x0c, 0x6e,
|
||||
0x77, 0xd5, 0xeb, 0x71, 0xa9, 0x7c, 0x65, 0xdd, 0x96, 0x46, 0xaa, 0x6e, 0xc6, 0x36, 0xde, 0x2f,
|
||||
0x82, 0xb6, 0x95, 0x46, 0x1b, 0x04, 0xd9, 0x4f, 0x49, 0xeb, 0xfa, 0x68, 0x10, 0xe9, 0x75, 0xd5,
|
||||
0xf3, 0xb9, 0x73, 0x3c, 0x7f, 0x1b, 0xf2, 0x3d, 0x86, 0xcd, 0x5f, 0x06, 0x32, 0x25, 0x7b, 0xfd,
|
||||
0xba, 0x39, 0x29, 0xc2, 0xfb, 0xed, 0xd6, 0xfd, 0x54, 0xd8, 0xbe, 0xcb, 0x6a, 0x2c, 0x4a, 0x1b,
|
||||
0xa3, 0xa1, 0x05, 0x11, 0xaa, 0xd9, 0x51, 0xab, 0xc2, 0xd5, 0x55, 0x90, 0x62, 0x05, 0x71, 0xe3,
|
||||
0xe6, 0xe8, 0x8d, 0xbc, 0x15, 0xbd, 0x4e, 0xe2, 0x7f, 0x36, 0xaf, 0x53, 0x6f, 0xde, 0xac, 0x0f,
|
||||
0x47, 0x98, 0x92, 0xd3, 0x5d, 0x07, 0x46, 0x7d, 0xc5, 0xb7, 0x89, 0x18, 0x8d, 0xa5, 0x86, 0x57,
|
||||
0x57, 0xa3, 0x6e, 0x6c, 0xd2, 0x1a, 0x68, 0xd4, 0x79, 0x1b, 0xc3, 0x8d, 0x32, 0xd6, 0x77, 0x11,
|
||||
0x34, 0x54, 0x19, 0x67, 0x2d, 0xcf, 0x9a, 0xd4, 0x42, 0x8f, 0xb1, 0x47, 0xad, 0x6d, 0xc5, 0xc4,
|
||||
0xd2, 0xc3, 0x1a, 0x96, 0xd5, 0x32, 0x0a, 0xb1, 0xcd, 0x22, 0x20, 0xaf, 0xaa, 0xb2, 0xaa, 0xad,
|
||||
0x46, 0x21, 0x94, 0x45, 0x30, 0xf9, 0x98, 0x40, 0x7d, 0x28, 0xdd, 0x67, 0x01, 0x68, 0xfe, 0x25,
|
||||
0x3b, 0xa3, 0x0f, 0xa6, 0xea, 0xb6, 0x85, 0xd4, 0x78, 0xf9, 0xb3, 0x7f, 0x63, 0x29, 0xad, 0x96,
|
||||
0x2f, 0x31, 0xb8, 0xcd, 0xaa, 0x93, 0x54, 0x11, 0x71, 0x06, 0x92, 0x75, 0x6d, 0xb7, 0xbe, 0xc7,
|
||||
0x15, 0x2a, 0x48, 0x5b, 0x6c, 0xbe, 0x0e, 0x54, 0x26, 0x1d, 0x8d, 0xbc, 0x1e, 0xa4, 0x60, 0xa3,
|
||||
0xa3, 0x27, 0xde, 0x7c, 0xb0, 0xa0, 0x4f, 0x37, 0x48, 0x96, 0xe1, 0x1a, 0x58, 0x37, 0x04, 0x37,
|
||||
0x67, 0xf6, 0x3a, 0xac, 0xcc, 0xf5, 0xf6, 0xd8, 0xaa, 0x3a, 0xc8, 0x94, 0xab, 0xef, 0x3a, 0x40,
|
||||
0xe2, 0x91, 0xff, 0x19, 0x20, 0x38, 0x49, 0x26, 0x7f, 0xd2, 0x12, 0xac, 0x71, 0xa3, 0xba, 0xf3,
|
||||
0xe6, 0xbb, 0xf1, 0xbc, 0x45, 0x3f, 0x65, 0x71, 0xf5, 0x2f, 0x3e, 0xf3, 0xd8, 0xa8, 0xb7, 0xd4,
|
||||
0xff, 0x5f, 0x8d, 0xae, 0xfa, 0x5f, 0x63, 0xfe, 0x17, 0x66, 0xba, 0xb1, 0x98, 0x32, 0x33, 0x00,
|
||||
0x00
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0xbd, 0x3b, 0x6b, 0x73, 0xdb, 0x38,
|
||||
0x92, 0xdf, 0xf3, 0x2b, 0x10, 0x26, 0x93, 0x90, 0x63, 0x8a, 0x22, 0x29, 0x5b, 0xb2, 0x25, 0xd1,
|
||||
0xd9, 0x8c, 0x93, 0x3d, 0xe7, 0xca, 0x9e, 0xa4, 0x36, 0x3e, 0xcf, 0xcc, 0xf9, 0xbc, 0x65, 0x9a,
|
||||
0x84, 0x24, 0x4e, 0x28, 0x82, 0x0b, 0x42, 0xb2, 0x1d, 0x59, 0xff, 0xfd, 0xba, 0x01, 0x90, 0x22,
|
||||
0xf5, 0x70, 0x92, 0x9b, 0xad, 0x9b, 0x72, 0x45, 0x20, 0xd0, 0x68, 0x74, 0x37, 0xfa, 0x05, 0x34,
|
||||
0x66, 0xf8, 0xfc, 0xdd, 0xc7, 0x93, 0x8b, 0x3f, 0x3e, 0xbd, 0x27, 0x13, 0x31, 0x4d, 0x8f, 0xc9,
|
||||
0xb0, 0xfc, 0xa1, 0x61, 0x0c, 0x3f, 0x53, 0x2a, 0x42, 0x92, 0x85, 0x53, 0x1a, 0x18, 0xf3, 0x84,
|
||||
0xde, 0xe5, 0x8c, 0x0b, 0x83, 0x3c, 0x8b, 0x58, 0x26, 0x68, 0x26, 0x02, 0xe3, 0x2e, 0x89, 0xc5,
|
||||
0x24, 0x88, 0xe9, 0x3c, 0x89, 0x68, 0x4b, 0x7e, 0xd8, 0x49, 0x96, 0x88, 0x24, 0x4c, 0x5b, 0x45,
|
||||
0x14, 0xa6, 0x34, 0xf0, 0xec, 0x29, 0x74, 0x4c, 0x67, 0xd3, 0xf2, 0xdb, 0x28, 0x91, 0x3e, 0x9b,
|
||||
0x08, 0x91, 0xb7, 0xe8, 0xbf, 0x66, 0xc9, 0x3c, 0x30, 0x4e, 0xc2, 0x68, 0x42, 0x5b, 0x27, 0x80,
|
||||
0x96, 0xb3, 0xd4, 0x20, 0x15, 0xfe, 0x8c, 0xb5, 0x22, 0x1c, 0xb2, 0x09, 0xb4, 0x0a, 0xc1, 0x38,
|
||||
0xb4, 0xa6, 0xb3, 0x42, 0xb4, 0x38, 0x9d, 0x87, 0x69, 0x12, 0x87, 0x82, 0x6e, 0x47, 0xf8, 0x89,
|
||||
0x87, 0xe3, 0x69, 0xb8, 0x05, 0x53, 0x05, 0x5e, 0x87, 0x7e, 0x7f, 0x9f, 0x27, 0x9c, 0x16, 0x35,
|
||||
0x70, 0x17, 0xe0, 0x9e, 0x0d, 0x45, 0x22, 0x52, 0x7a, 0xfc, 0xdb, 0xd9, 0xfb, 0x77, 0xe4, 0x04,
|
||||
0x56, 0x65, 0x53, 0xf2, 0x09, 0x98, 0x10, 0x82, 0x92, 0xf7, 0x71, 0x02, 0xd4, 0x0c, 0xdb, 0x0a,
|
||||
0x82, 0x0c, 0x8b, 0x88, 0x27, 0xb9, 0x20, 0xe2, 0x21, 0x07, 0x49, 0x09, 0x7a, 0x2f, 0xda, 0x7f,
|
||||
0x86, 0xf3, 0x50, 0xf5, 0x1a, 0xc7, 0xcf, 0x46, 0xb3, 0x2c, 0x12, 0x09, 0xcb, 0xc8, 0xf8, 0x43,
|
||||
0x6c, 0x52, 0x6b, 0xc1, 0xa9, 0x98, 0xf1, 0x8c, 0xc4, 0xce, 0x98, 0x8a, 0xf7, 0x29, 0x9d, 0xc2,
|
||||
0x9a, 0xbf, 0x3c, 0xc8, 0xa1, 0x65, 0x05, 0x1a, 0xbd, 0x6f, 0x40, 0x46, 0x9c, 0x02, 0xb7, 0x1a,
|
||||
0x18, 0x01, 0xe7, 0x21, 0x27, 0x71, 0x10, 0xb3, 0x68, 0x86, 0x3d, 0xcf, 0x86, 0x6d, 0xb5, 0x1a,
|
||||
0x12, 0x23, 0x1e, 0x80, 0xa8, 0x67, 0xb7, 0x2c, 0x7e, 0x58, 0x8c, 0x80, 0xa3, 0xd6, 0x28, 0x9c,
|
||||
0x26, 0xe9, 0x43, 0xff, 0x2d, 0x87, 0x8d, 0xb1, 0x8b, 0x30, 0x2b, 0x5a, 0x05, 0xe5, 0xc9, 0x68,
|
||||
0x70, 0x1b, 0x46, 0x5f, 0xc6, 0x9c, 0xcd, 0xb2, 0xb8, 0x15, 0xb1, 0x94, 0xf1, 0xfe, 0x0b, 0xcf,
|
||||
0xf3, 0x06, 0x72, 0x4a, 0x91, 0x7c, 0xa5, 0x7d, 0xaf, 0x9b, 0xdf, 0x0f, 0xf4, 0x48, 0x1c, 0xc7,
|
||||
0x83, 0x69, 0xc8, 0xc7, 0x49, 0xd6, 0x77, 0x89, 0xe7, 0xc2, 0x40, 0x9a, 0x64, 0xb4, 0x35, 0xa1,
|
||||
0xc9, 0x78, 0x22, 0xfa, 0xce, 0xc1, 0xf2, 0x45, 0x1e, 0x72, 0x20, 0xa4, 0x85, 0x32, 0x0c, 0x61,
|
||||
0x88, 0x2f, 0x72, 0x56, 0x24, 0xc8, 0x4a, 0x9f, 0xd3, 0x34, 0x14, 0xc9, 0x9c, 0x0e, 0xa4, 0x8a,
|
||||
0xf4, 0x3d, 0xd7, 0xfd, 0x69, 0xa0, 0x27, 0xfa, 0x80, 0x69, 0xf9, 0xe2, 0x96, 0x09, 0x90, 0xee,
|
||||
0xc9, 0xe6, 0xcc, 0xf0, 0xb6, 0x60, 0xe9, 0x4c, 0x50, 0xbd, 0x74, 0x4b, 0xb0, 0xbc, 0x7f, 0x20,
|
||||
0xa7, 0x8c, 0x79, 0x18, 0x27, 0xb8, 0xde, 0x2d, 0xbb, 0x5f, 0x6c, 0xe2, 0xc5, 0xf6, 0xd2, 0x91,
|
||||
0xb4, 0xb7, 0x60, 0xee, 0x17, 0xca, 0x6d, 0xfd, 0x95, 0x27, 0x11, 0x7c, 0xe9, 0xce, 0x2d, 0x2b,
|
||||
0xdd, 0x32, 0x1e, 0xc3, 0x38, 0xa2, 0x9f, 0x15, 0xfd, 0x0e, 0x30, 0xba, 0x21, 0xa6, 0x22, 0x49,
|
||||
0xe7, 0x94, 0x6b, 0xc8, 0xbe, 0x9f, 0xdf, 0x13, 0x98, 0x9b, 0xc4, 0x84, 0x8f, 0x6f, 0x43, 0xb3,
|
||||
0x7b, 0x68, 0xab, 0x3f, 0xe7, 0xc0, 0x1a, 0x7c, 0x6d, 0x25, 0x59, 0x4c, 0xef, 0xfb, 0x7e, 0x93,
|
||||
0x96, 0x85, 0xa6, 0xb2, 0x83, 0x72, 0x54, 0xc4, 0xf7, 0xa0, 0xa5, 0xb8, 0xfb, 0x69, 0x20, 0x38,
|
||||
0xec, 0xd1, 0x88, 0xf1, 0x69, 0x5f, 0xb6, 0x40, 0x78, 0xf4, 0x0f, 0xb3, 0x05, 0x23, 0x16, 0x80,
|
||||
0xcc, 0xa2, 0x49, 0x2b, 0x94, 0x2a, 0xd2, 0xcf, 0x58, 0x46, 0x97, 0x5b, 0xd9, 0xd2, 0xf8, 0x7b,
|
||||
0x1b, 0xe8, 0xbd, 0x03, 0x94, 0x4b, 0x4c, 0x41, 0x8d, 0xe9, 0x6e, 0x19, 0xe8, 0xe9, 0x07, 0xd5,
|
||||
0x74, 0x6c, 0x7d, 0x87, 0x60, 0x5e, 0x8c, 0x46, 0xa3, 0x52, 0x2c, 0x9d, 0x4a, 0x2c, 0x2f, 0x8e,
|
||||
0x6e, 0xfd, 0x43, 0xff, 0x50, 0xae, 0xef, 0xfb, 0xc0, 0xdf, 0x86, 0x54, 0x14, 0xf1, 0xbb, 0x09,
|
||||
0xf1, 0x2a, 0x42, 0xbc, 0x8a, 0x10, 0xd9, 0x2c, 0x59, 0xaa, 0x50, 0x7a, 0x25, 0x99, 0x35, 0x85,
|
||||
0xde, 0xaa, 0xe6, 0x4b, 0xe7, 0x76, 0x06, 0x4a, 0x97, 0x45, 0x69, 0x58, 0x14, 0x8b, 0x3c, 0x8c,
|
||||
0xe3, 0x24, 0x1b, 0xf7, 0xdd, 0x4a, 0xc7, 0x07, 0xb0, 0xc3, 0x22, 0x01, 0xa7, 0xd5, 0x02, 0x47,
|
||||
0x33, 0xce, 0xfa, 0x4a, 0x45, 0x77, 0xe0, 0x5a, 0x57, 0x60, 0x52, 0xe4, 0x61, 0xb6, 0x88, 0x93,
|
||||
0x22, 0x4f, 0xc3, 0x87, 0x7e, 0x92, 0x49, 0x53, 0x19, 0xa5, 0xf4, 0x7e, 0x20, 0x91, 0xb5, 0x12,
|
||||
0x41, 0xa7, 0x45, 0x3f, 0x02, 0xf5, 0x05, 0x35, 0xaa, 0x89, 0xae, 0x66, 0x7a, 0xa0, 0x55, 0xeb,
|
||||
0x24, 0x4c, 0x93, 0x38, 0x4e, 0xe9, 0xf2, 0x45, 0x92, 0x8d, 0x58, 0x85, 0xdc, 0x30, 0x06, 0xe8,
|
||||
0x6f, 0x34, 0xc8, 0x37, 0x51, 0x6e, 0xda, 0x64, 0xcd, 0xb2, 0x36, 0xcc, 0x1a, 0xa4, 0x74, 0xc7,
|
||||
0xc3, 0xbc, 0x6e, 0x5f, 0x95, 0x0f, 0x08, 0x67, 0x82, 0x2d, 0xff, 0x36, 0xa5, 0x71, 0x12, 0x12,
|
||||
0x13, 0xbc, 0xbc, 0xf2, 0xff, 0xfd, 0x43, 0x17, 0x90, 0x58, 0x8b, 0xfa, 0x3c, 0xd9, 0xb5, 0x5c,
|
||||
0x3a, 0xb9, 0x72, 0x9e, 0x8b, 0xba, 0xe9, 0x97, 0x9d, 0xff, 0xa1, 0xcd, 0xb9, 0x58, 0xa0, 0x98,
|
||||
0x60, 0x1b, 0x6b, 0x40, 0x9b, 0x9a, 0x57, 0x4d, 0x2b, 0xce, 0x41, 0xde, 0x8b, 0x35, 0xe7, 0x50,
|
||||
0x73, 0x33, 0x12, 0xf0, 0x82, 0xe5, 0xe5, 0x9a, 0xa3, 0x44, 0x39, 0x28, 0x58, 0xe9, 0x2f, 0x8a,
|
||||
0x6d, 0x4d, 0x4c, 0xb0, 0x4c, 0xc9, 0xc2, 0x27, 0xe9, 0x07, 0xab, 0x0d, 0xda, 0xb5, 0xed, 0x5b,
|
||||
0x28, 0x5a, 0xdf, 0x8a, 0x7f, 0x2b, 0x85, 0x4a, 0xdd, 0x8b, 0x77, 0xc9, 0x7c, 0xab, 0x62, 0xea,
|
||||
0xb5, 0x53, 0x3a, 0x6a, 0xd8, 0xbd, 0xdc, 0x23, 0xd8, 0x63, 0xf1, 0x19, 0x34, 0xda, 0x76, 0x0a,
|
||||
0x9a, 0xc5, 0xd8, 0x5a, 0x44, 0x33, 0x5e, 0x00, 0x25, 0x39, 0x4b, 0x90, 0xae, 0xe5, 0xc4, 0x5b,
|
||||
0xd4, 0xe8, 0x71, 0xba, 0x9c, 0x4e, 0x97, 0x18, 0x92, 0x64, 0x24, 0x22, 0xc3, 0xb6, 0x4e, 0x27,
|
||||
0x30, 0x24, 0xc1, 0x4f, 0x9c, 0xcc, 0x49, 0x12, 0x43, 0xfa, 0x00, 0x3a, 0x02, 0x41, 0x17, 0x2d,
|
||||
0x50, 0x7f, 0xe8, 0xc1, 0x67, 0x72, 0x62, 0x60, 0x34, 0x64, 0xf8, 0x27, 0x84, 0xe0, 0x64, 0xf4,
|
||||
0x50, 0x4a, 0x4b, 0x8b, 0x04, 0xa7, 0x4c, 0xbc, 0xed, 0x33, 0x36, 0xa5, 0x8e, 0xd0, 0xc5, 0x7c,
|
||||
0x5c, 0x81, 0x2b, 0x2e, 0x3b, 0x18, 0xe7, 0x4a, 0x97, 0x8c, 0x6d, 0x2d, 0x0c, 0x2e, 0x7b, 0xa0,
|
||||
0xc3, 0x20, 0x98, 0xfd, 0xfc, 0xc2, 0xee, 0x21, 0x33, 0x20, 0x2e, 0xe9, 0xf8, 0xf0, 0x67, 0x1c,
|
||||
0x0f, 0xf3, 0x50, 0x4c, 0xc8, 0xb3, 0x51, 0x92, 0xa6, 0x81, 0xf1, 0xc2, 0x75, 0x3b, 0xb0, 0x2d,
|
||||
0x06, 0xc4, 0x64, 0xe3, 0xbc, 0x4b, 0x7c, 0x7f, 0x72, 0x38, 0xdf, 0x3f, 0xed, 0x7e, 0x3d, 0xf7,
|
||||
0xf6, 0x89, 0xb7, 0x3f, 0xd9, 0x9f, 0x1f, 0x4e, 0x5a, 0xfb, 0xf0, 0x75, 0x08, 0xc1, 0xb3, 0xfa,
|
||||
0xf2, 0x7d, 0xd2, 0x45, 0xb8, 0x49, 0xeb, 0xf0, 0xab, 0xd1, 0x3e, 0x06, 0x81, 0xcd, 0xc7, 0xc7,
|
||||
0xcf, 0x80, 0x44, 0x10, 0xb1, 0x94, 0x10, 0xca, 0xcd, 0x78, 0x32, 0x03, 0x41, 0x50, 0x29, 0x61,
|
||||
0x0f, 0xff, 0x05, 0xe1, 0x95, 0x22, 0xc4, 0xe9, 0xeb, 0x21, 0xd9, 0xa8, 0x09, 0xbf, 0x1e, 0x40,
|
||||
0x81, 0x17, 0x3d, 0xb5, 0x8e, 0xe1, 0xc7, 0x36, 0xa1, 0xc4, 0x5b, 0x5a, 0x26, 0xe6, 0x89, 0x6a,
|
||||
0x67, 0xeb, 0xb6, 0xba, 0x06, 0x09, 0xa6, 0x59, 0x29, 0x80, 0xfe, 0x04, 0xfe, 0x4f, 0x66, 0x1c,
|
||||
0xe9, 0x4e, 0x1f, 0x48, 0x92, 0x91, 0x59, 0x41, 0x49, 0xa4, 0x78, 0x2f, 0x11, 0x91, 0x35, 0x6a,
|
||||
0xff, 0x3a, 0xd1, 0xe8, 0x52, 0xe5, 0xca, 0x29, 0x44, 0x22, 0x02, 0xd9, 0x97, 0x98, 0x50, 0x52,
|
||||
0x4a, 0x88, 0x50, 0x29, 0x6b, 0x22, 0x18, 0x81, 0x30, 0x41, 0x32, 0x7a, 0x47, 0xa4, 0x1d, 0x92,
|
||||
0x02, 0xa2, 0x1b, 0x24, 0x16, 0x08, 0xac, 0x66, 0xc8, 0x6e, 0x1a, 0x13, 0x10, 0x29, 0xb9, 0xa5,
|
||||
0x29, 0xbb, 0x93, 0xbd, 0x0a, 0x0c, 0xa7, 0x47, 0x93, 0x30, 0x1b, 0x53, 0x92, 0x88, 0x42, 0x81,
|
||||
0x3a, 0x7a, 0x41, 0x84, 0x6a, 0xce, 0x83, 0x68, 0x06, 0x9e, 0x1f, 0x57, 0x35, 0xc3, 0x2c, 0xc6,
|
||||
0xc4, 0x74, 0x94, 0xf0, 0xa9, 0x85, 0x48, 0x54, 0xf0, 0x76, 0xc8, 0xc7, 0x2c, 0xa2, 0x64, 0x04,
|
||||
0xe9, 0x75, 0x31, 0xa1, 0xb1, 0x0d, 0x52, 0x2c, 0x31, 0x85, 0x9c, 0x23, 0x86, 0x08, 0xd9, 0x60,
|
||||
0x64, 0x96, 0xa7, 0x2c, 0x8c, 0x01, 0x21, 0xb4, 0x71, 0x34, 0xa6, 0x45, 0x82, 0x6b, 0x15, 0x29,
|
||||
0x13, 0x0e, 0xb9, 0x60, 0x92, 0x3b, 0x42, 0xef, 0x13, 0x90, 0x51, 0x36, 0x2e, 0x65, 0x5c, 0xc7,
|
||||
0x97, 0xd3, 0x2c, 0x4a, 0x52, 0x89, 0xd0, 0x81, 0xac, 0x78, 0x53, 0xe8, 0x3f, 0x2e, 0x73, 0xa9,
|
||||
0x9d, 0x85, 0x00, 0x47, 0x15, 0x7d, 0xaa, 0xf4, 0xe5, 0x1b, 0xea, 0x82, 0xe0, 0x3b, 0x55, 0xe6,
|
||||
0xed, 0x3c, 0x4c, 0xd2, 0xf0, 0x36, 0x05, 0x69, 0x4b, 0xac, 0xdf, 0xd2, 0x15, 0xf9, 0x33, 0x6c,
|
||||
0x6b, 0x87, 0xa4, 0xd3, 0xf7, 0x67, 0xbb, 0xf2, 0x77, 0xcc, 0xb5, 0x4b, 0x6d, 0x40, 0x2f, 0x80,
|
||||
0x69, 0x7c, 0xd3, 0x80, 0x2c, 0x3b, 0x82, 0x15, 0xa3, 0xa0, 0xe5, 0xd9, 0xf9, 0xfd, 0x09, 0x4b,
|
||||
0x83, 0xc5, 0xd2, 0x16, 0xfa, 0x97, 0xd3, 0x48, 0x04, 0xb5, 0xe9, 0x98, 0xf5, 0xff, 0x82, 0x29,
|
||||
0x04, 0xc8, 0x1b, 0xf6, 0x1f, 0x3a, 0xff, 0x01, 0x10, 0xa6, 0x65, 0x97, 0x30, 0x67, 0x34, 0x1b,
|
||||
0xc3, 0xb9, 0x0a, 0xe7, 0x39, 0xea, 0x54, 0x35, 0xfd, 0x38, 0x1a, 0x15, 0xc1, 0x39, 0xf8, 0x1b,
|
||||
0x47, 0x26, 0x1f, 0x66, 0x13, 0xb4, 0xed, 0x1f, 0x74, 0xdb, 0xbe, 0xd5, 0x3a, 0xb0, 0x35, 0xdb,
|
||||
0x6f, 0x39, 0x0f, 0x1f, 0x82, 0xab, 0x6b, 0x1b, 0x1c, 0xca, 0xe7, 0x70, 0x4e, 0x83, 0xd7, 0xd2,
|
||||
0xed, 0x35, 0xbc, 0x9e, 0x7f, 0xb0, 0xf2, 0x7a, 0xd8, 0x5e, 0x73, 0x72, 0xfe, 0x3e, 0xfc, 0x95,
|
||||
0x4e, 0x4e, 0xfa, 0x38, 0x0c, 0x3b, 0xd2, 0xbd, 0xf9, 0xbe, 0xed, 0xf9, 0x6f, 0x3d, 0xd7, 0xf6,
|
||||
0x10, 0x10, 0x7e, 0x88, 0xe7, 0xdb, 0x7e, 0xb3, 0x67, 0x2b, 0x48, 0x13, 0x02, 0x41, 0xce, 0x7b,
|
||||
0xf0, 0xcf, 0x19, 0x8c, 0x79, 0xbd, 0x4b, 0x6f, 0xff, 0xd4, 0xeb, 0x5e, 0x7a, 0xee, 0xa9, 0xe7,
|
||||
0x5f, 0xf6, 0xce, 0x70, 0xe0, 0xbf, 0x2b, 0xa7, 0xf8, 0x1a, 0x39, 0x41, 0x9f, 0xf7, 0xef, 0xe5,
|
||||
0x04, 0x89, 0x3a, 0xe9, 0x3a, 0xfb, 0x3d, 0xdb, 0x07, 0x8a, 0xb1, 0x21, 0x09, 0x3f, 0x41, 0x7a,
|
||||
0x9c, 0x83, 0x0e, 0x51, 0x43, 0xbe, 0xe2, 0xef, 0x44, 0xf6, 0xe1, 0xa7, 0x5f, 0x8e, 0xfb, 0x0a,
|
||||
0x5a, 0x4f, 0xd5, 0xe3, 0x12, 0xfa, 0xdc, 0x3b, 0x70, 0x3c, 0xbb, 0xe7, 0xb8, 0xbd, 0x13, 0x68,
|
||||
0xf9, 0xfb, 0xb2, 0x49, 0xa0, 0xd9, 0x39, 0x84, 0xa6, 0xe7, 0x63, 0xf3, 0x00, 0x5a, 0x7e, 0xe7,
|
||||
0xcc, 0xeb, 0x3a, 0xbd, 0x9e, 0x7d, 0xe8, 0x1c, 0xc0, 0x02, 0xf0, 0xd3, 0x83, 0xb1, 0x9e, 0x7d,
|
||||
0x24, 0xc1, 0xe5, 0xc8, 0x91, 0xe3, 0x1f, 0x9e, 0x01, 0x38, 0x34, 0x3d, 0x57, 0xb6, 0x3b, 0x00,
|
||||
0x04, 0x90, 0x38, 0x77, 0x1f, 0x9b, 0x88, 0xe6, 0x04, 0x9a, 0x87, 0xbe, 0xc6, 0xbd, 0xef, 0x1c,
|
||||
0x75, 0xab, 0x15, 0x15, 0x19, 0xe7, 0x30, 0xcb, 0xeb, 0xc0, 0xac, 0x43, 0x0f, 0x91, 0x79, 0x47,
|
||||
0x88, 0xec, 0xb0, 0x77, 0x76, 0x84, 0xbd, 0xb0, 0xd0, 0x51, 0xe7, 0x14, 0xc1, 0x2e, 0x11, 0x4d,
|
||||
0xef, 0x6c, 0x05, 0x5c, 0xdb, 0x83, 0x41, 0x75, 0x38, 0x05, 0xd5, 0xfc, 0x38, 0x32, 0xf1, 0x78,
|
||||
0xfa, 0xff, 0xa6, 0xda, 0xb5, 0x93, 0x71, 0x9a, 0x7c, 0xf9, 0x98, 0x95, 0xe9, 0x96, 0x3a, 0x25,
|
||||
0x4f, 0xd9, 0x9c, 0x5e, 0xf0, 0xb0, 0x98, 0x44, 0x61, 0x06, 0x3d, 0x36, 0x38, 0xea, 0x13, 0xb3,
|
||||
0x86, 0x94, 0x3a, 0x0c, 0x96, 0xa1, 0xe2, 0xf7, 0x76, 0x13, 0xfd, 0xcf, 0x80, 0xde, 0xaa, 0x9d,
|
||||
0xba, 0xe5, 0x3c, 0x6a, 0x8b, 0xc0, 0x30, 0xac, 0x05, 0x98, 0x12, 0xe1, 0x68, 0xd2, 0x2c, 0x78,
|
||||
0xee, 0x41, 0xee, 0x95, 0x15, 0x82, 0x84, 0x0d, 0x76, 0xff, 0x35, 0xa3, 0xfc, 0xe1, 0x33, 0x38,
|
||||
0xe4, 0x08, 0x5c, 0xf5, 0xdb, 0x34, 0x35, 0x8d, 0xc6, 0x39, 0xcf, 0xb0, 0x06, 0xc9, 0xc8, 0x0c,
|
||||
0x1d, 0x38, 0xcb, 0xbd, 0x0f, 0xa3, 0x89, 0x69, 0x0a, 0x9b, 0x5b, 0xc1, 0xf1, 0x42, 0xa0, 0x9c,
|
||||
0xde, 0x0a, 0xc1, 0x13, 0xc8, 0xca, 0xa8, 0x69, 0xc4, 0xa1, 0x08, 0x5b, 0x82, 0xcf, 0x28, 0x64,
|
||||
0x71, 0x86, 0x15, 0x04, 0xf4, 0xd5, 0x2b, 0x13, 0xd6, 0x74, 0xad, 0x25, 0x70, 0xe2, 0xa4, 0x92,
|
||||
0xd2, 0x63, 0xaf, 0x57, 0xf6, 0xda, 0xcc, 0x52, 0xf7, 0x02, 0x88, 0x9d, 0x1e, 0xbb, 0xaf, 0x5e,
|
||||
0xd1, 0xa1, 0x7f, 0x70, 0x60, 0xc1, 0x32, 0x26, 0xba, 0xaa, 0x2c, 0xf0, 0x06, 0xd9, 0x30, 0xf0,
|
||||
0xba, 0xaf, 0x5e, 0xf1, 0x21, 0x34, 0xf7, 0xf6, 0x2c, 0xe9, 0xb1, 0x24, 0x69, 0xe7, 0x8a, 0xb2,
|
||||
0xbd, 0xcc, 0x7a, 0x7c, 0x34, 0x79, 0x90, 0x59, 0x03, 0x9a, 0x42, 0x88, 0xe5, 0x01, 0x1d, 0x18,
|
||||
0x46, 0x10, 0x08, 0x58, 0x04, 0xb8, 0x7f, 0x61, 0xec, 0x99, 0x5e, 0xb7, 0xd7, 0xeb, 0xf9, 0xde,
|
||||
0xc1, 0xcf, 0x4a, 0x8e, 0x10, 0x87, 0xd8, 0xd4, 0xb4, 0x86, 0x43, 0xd7, 0x72, 0x04, 0xfb, 0x0c,
|
||||
0xc4, 0x67, 0x63, 0x80, 0xb1, 0x20, 0xf7, 0x8d, 0x3f, 0x8b, 0x90, 0x0b, 0xb3, 0x6b, 0x1b, 0xae,
|
||||
0x61, 0x59, 0x5a, 0x52, 0x69, 0x10, 0xbd, 0x37, 0x0d, 0xcc, 0x4f, 0x40, 0x0c, 0xa9, 0x23, 0x5d,
|
||||
0xf6, 0xaf, 0xf2, 0x2a, 0xa9, 0x21, 0x22, 0x3b, 0x75, 0xd0, 0xbb, 0x37, 0x68, 0xe3, 0xab, 0x05,
|
||||
0x2c, 0x18, 0x2f, 0x76, 0x0b, 0xcb, 0xa6, 0x4f, 0x00, 0x00, 0x4e, 0xc3, 0x16, 0x3b, 0x00, 0x94,
|
||||
0x3e, 0x18, 0x4a, 0xff, 0x10, 0x06, 0xb6, 0xfe, 0xfd, 0x1c, 0x15, 0x03, 0x22, 0x21, 0x85, 0x64,
|
||||
0x09, 0xe4, 0x85, 0x21, 0xd0, 0xb0, 0x21, 0xf7, 0xc8, 0xff, 0x3e, 0xe3, 0x10, 0x0a, 0xf9, 0x27,
|
||||
0xce, 0x72, 0x89, 0x0f, 0xdd, 0x8f, 0x83, 0xc9, 0xf2, 0xd3, 0x9a, 0xfb, 0x33, 0xb5, 0xf6, 0xe4,
|
||||
0x02, 0x7b, 0x06, 0xb8, 0x25, 0x2d, 0x98, 0x44, 0x0a, 0x26, 0xc9, 0xf2, 0x99, 0x40, 0x05, 0x71,
|
||||
0x54, 0xd4, 0x91, 0x02, 0x30, 0xec, 0xc4, 0x99, 0x87, 0xe9, 0x8c, 0x06, 0x02, 0x5a, 0x1b, 0x22,
|
||||
0x53, 0xe7, 0x64, 0x04, 0xaa, 0x44, 0xf6, 0x49, 0x75, 0x35, 0x45, 0x96, 0x6c, 0x61, 0x46, 0xad,
|
||||
0x67, 0xcf, 0x72, 0xbc, 0x35, 0x2b, 0x8d, 0x67, 0x3b, 0xa8, 0xe6, 0x3b, 0xca, 0x4f, 0xd2, 0x2f,
|
||||
0xe5, 0x6e, 0xc6, 0xf5, 0xdd, 0x8c, 0x77, 0x91, 0x56, 0x6d, 0x6a, 0xbc, 0x4e, 0xe1, 0xd6, 0xad,
|
||||
0x8d, 0x9f, 0x58, 0x9c, 0xa5, 0xb8, 0x3a, 0x80, 0xd4, 0x64, 0x5d, 0x17, 0x3c, 0x50, 0xbe, 0x63,
|
||||
0x44, 0x53, 0x5c, 0xd4, 0x29, 0xe6, 0x68, 0x25, 0x1c, 0xad, 0x04, 0xf4, 0xbb, 0xa8, 0x93, 0xdf,
|
||||
0xb8, 0x0b, 0x81, 0xcd, 0x96, 0x84, 0xab, 0xce, 0xad, 0x34, 0x17, 0xbb, 0x69, 0xa6, 0x60, 0xda,
|
||||
0x6a, 0xe6, 0x09, 0x32, 0x8e, 0xb7, 0x74, 0x08, 0xbf, 0x83, 0xcc, 0x95, 0x1e, 0xad, 0x2e, 0x15,
|
||||
0xe4, 0xbc, 0x40, 0xeb, 0x40, 0xc5, 0xfb, 0xae, 0xf1, 0xba, 0x27, 0x0a, 0x73, 0x48, 0xd3, 0xe2,
|
||||
0x93, 0x49, 0x92, 0xc6, 0x66, 0x62, 0xed, 0x1c, 0x4a, 0x77, 0x0f, 0xc5, 0x96, 0xed, 0x3e, 0x0f,
|
||||
0xf8, 0xab, 0x57, 0x20, 0x24, 0xf9, 0xbb, 0x0b, 0x10, 0xac, 0xa5, 0x2e, 0xce, 0x69, 0xf8, 0x85,
|
||||
0x9e, 0xd3, 0x77, 0x3c, 0x1c, 0x9b, 0xe8, 0x65, 0xd0, 0x9c, 0x2d, 0x60, 0x9b, 0x8a, 0x0b, 0xc6,
|
||||
0x52, 0x91, 0xe4, 0x4a, 0x8a, 0xf5, 0xb1, 0xa6, 0x0e, 0x9a, 0x35, 0xf7, 0xbb, 0x3e, 0xb2, 0x50,
|
||||
0x5b, 0x49, 0x7f, 0xd0, 0xe9, 0x6e, 0xa4, 0x60, 0x74, 0xc3, 0x05, 0x2b, 0xc4, 0x4c, 0xa6, 0x72,
|
||||
0xf4, 0x8a, 0x5f, 0x03, 0x65, 0x0e, 0xa7, 0x90, 0xbf, 0x46, 0xb4, 0xe9, 0x28, 0xed, 0x86, 0x9d,
|
||||
0x59, 0x96, 0x92, 0xfd, 0xe0, 0xc7, 0xe6, 0xe9, 0x3e, 0x98, 0xbd, 0x7d, 0x47, 0x99, 0x2d, 0x71,
|
||||
0x3d, 0x3d, 0xf8, 0x84, 0x93, 0x63, 0x56, 0x15, 0x9e, 0x24, 0xec, 0x53, 0xe1, 0xc5, 0xce, 0xbe,
|
||||
0xe1, 0xb3, 0x42, 0x2d, 0xc0, 0xab, 0xec, 0x1a, 0xd6, 0x46, 0x11, 0x5e, 0x85, 0xd0, 0x5a, 0xae,
|
||||
0x54, 0x47, 0x19, 0x43, 0x60, 0xe0, 0xf5, 0x41, 0xc8, 0x5b, 0x65, 0xb7, 0x09, 0x47, 0x0c, 0x79,
|
||||
0x66, 0x36, 0xec, 0x8f, 0xb7, 0x7f, 0x62, 0x88, 0x87, 0x4e, 0x9e, 0xd0, 0xc2, 0x94, 0xf8, 0xac,
|
||||
0xd5, 0x26, 0x5c, 0x41, 0x88, 0xbd, 0xc6, 0x6d, 0x68, 0x62, 0xdc, 0x0b, 0x6e, 0x6c, 0xf2, 0x72,
|
||||
0x21, 0x96, 0xf0, 0x0f, 0x5d, 0xe6, 0xf7, 0x37, 0x1b, 0x6b, 0xee, 0x05, 0x86, 0x65, 0x34, 0x54,
|
||||
0x78, 0x5d, 0x66, 0x41, 0x73, 0xc2, 0x4a, 0xb7, 0xd6, 0xdc, 0x38, 0xe6, 0x0d, 0xd4, 0xc1, 0x4e,
|
||||
0xfc, 0x0a, 0xc7, 0x21, 0x02, 0xd5, 0x75, 0x51, 0x79, 0xa0, 0xed, 0xe9, 0xc5, 0x96, 0x89, 0xb6,
|
||||
0xd4, 0x08, 0xa7, 0xe0, 0x91, 0xbe, 0xa4, 0x6f, 0x68, 0x46, 0xa5, 0x14, 0xa8, 0x03, 0xd2, 0x5d,
|
||||
0x34, 0x96, 0xca, 0x77, 0xac, 0x34, 0x97, 0x3e, 0xfa, 0x49, 0x32, 0x6b, 0xe6, 0x07, 0x08, 0x30,
|
||||
0xfc, 0x8b, 0xc0, 0xb5, 0xf9, 0x77, 0x65, 0x65, 0x2c, 0xe0, 0x8e, 0xdc, 0x30, 0x3b, 0x84, 0x96,
|
||||
0xf4, 0xaa, 0x59, 0xc0, 0x5a, 0xe1, 0x9e, 0xb7, 0x4a, 0xf5, 0xd2, 0x9d, 0x74, 0x0d, 0x70, 0x31,
|
||||
0x1e, 0x98, 0x34, 0xa0, 0x8f, 0x8f, 0x77, 0x70, 0x62, 0x65, 0x77, 0x8e, 0x1a, 0x91, 0x21, 0x0d,
|
||||
0x88, 0x86, 0xa4, 0xa0, 0xf8, 0x2d, 0x11, 0x13, 0xd3, 0x90, 0xf7, 0xd6, 0xe8, 0x87, 0x1f, 0x1f,
|
||||
0xa9, 0x93, 0x73, 0x09, 0xf6, 0x8e, 0x8e, 0xc2, 0x59, 0x8a, 0x74, 0x88, 0x80, 0xbf, 0xa1, 0x8e,
|
||||
0x84, 0xa1, 0xc5, 0x95, 0x7b, 0x8d, 0x12, 0x02, 0x80, 0xdf, 0xfb, 0xb4, 0x6c, 0x81, 0x2f, 0x64,
|
||||
0xd9, 0x94, 0xcd, 0x0a, 0x3a, 0xcb, 0x83, 0x42, 0x7e, 0x49, 0x70, 0xa0, 0x26, 0xa2, 0x69, 0xbd,
|
||||
0x07, 0xdc, 0x94, 0xfe, 0x94, 0xe0, 0x48, 0x77, 0x90, 0xac, 0x86, 0xd5, 0xf7, 0x4a, 0x7c, 0x89,
|
||||
0xc9, 0x95, 0xd4, 0x58, 0x00, 0xd9, 0x10, 0xff, 0x6e, 0x46, 0xd8, 0xe3, 0x23, 0xdf, 0x60, 0x44,
|
||||
0x4a, 0x24, 0x0d, 0xd8, 0x1b, 0xbe, 0x8d, 0x19, 0x5e, 0xb6, 0x06, 0xa2, 0x95, 0x02, 0xcf, 0xa9,
|
||||
0x2d, 0x29, 0xfc, 0xc4, 0x8a, 0x0f, 0x55, 0x36, 0x1b, 0x88, 0x96, 0x09, 0xe2, 0x07, 0x91, 0x80,
|
||||
0xb9, 0xc2, 0x48, 0xdd, 0x54, 0x37, 0xa1, 0xdb, 0x99, 0xcc, 0x5f, 0x6d, 0x96, 0xc6, 0x17, 0x1a,
|
||||
0x9e, 0x3e, 0x6d, 0xfb, 0x1a, 0x2d, 0xba, 0x6f, 0xdd, 0x54, 0x4e, 0x7c, 0x85, 0xe1, 0x79, 0xa0,
|
||||
0x07, 0x30, 0x11, 0xd4, 0x20, 0xdd, 0xfd, 0x37, 0x62, 0x92, 0x14, 0x1f, 0x65, 0xca, 0x14, 0xb8,
|
||||
0xfd, 0x12, 0x8b, 0x77, 0xe4, 0xd7, 0x07, 0x7a, 0xfd, 0xda, 0x47, 0x47, 0xaa, 0xed, 0xb6, 0x34,
|
||||
0x29, 0x93, 0x5e, 0x46, 0xe3, 0xa8, 0xe7, 0x47, 0xda, 0x84, 0xfe, 0x4f, 0x1e, 0x55, 0x2e, 0x52,
|
||||
0x5f, 0xf1, 0x9b, 0xc8, 0x1a, 0x31, 0xfe, 0x2f, 0xe0, 0x59, 0x0b, 0x0f, 0xbb, 0xd0, 0xd0, 0x27,
|
||||
0xd3, 0xd8, 0x52, 0x1a, 0x9b, 0x71, 0x93, 0x6e, 0xc6, 0xcb, 0x9a, 0xf5, 0x17, 0x10, 0x23, 0xeb,
|
||||
0xa6, 0x91, 0xcd, 0xd2, 0x74, 0xc3, 0x3a, 0x9a, 0x9d, 0x68, 0x20, 0x55, 0xcf, 0xca, 0x46, 0x9a,
|
||||
0x40, 0x55, 0xd7, 0x92, 0x96, 0x50, 0x60, 0x15, 0x19, 0xe8, 0x2c, 0x2d, 0x41, 0xa4, 0x55, 0x04,
|
||||
0x69, 0x8d, 0x96, 0x4d, 0xd2, 0x17, 0xeb, 0x5c, 0xcb, 0x82, 0xa9, 0x61, 0xdf, 0x80, 0x7f, 0x7f,
|
||||
0x52, 0x51, 0x97, 0xa4, 0x4f, 0x9e, 0x80, 0xc1, 0xa0, 0x67, 0x2d, 0x6f, 0x6a, 0x82, 0x68, 0xe6,
|
||||
0x5d, 0xda, 0x0f, 0x62, 0x02, 0x18, 0x27, 0x73, 0x30, 0x57, 0x54, 0xcc, 0x77, 0xb5, 0x0d, 0x0f,
|
||||
0xea, 0x9e, 0xda, 0xc6, 0xd1, 0x93, 0xd5, 0xa6, 0xca, 0xa4, 0x60, 0x7d, 0x46, 0x43, 0x03, 0xd4,
|
||||
0x6a, 0xe5, 0xe6, 0xc3, 0xb6, 0xaf, 0x50, 0xd4, 0xd5, 0xf3, 0x47, 0x11, 0x55, 0x5a, 0xb4, 0x8e,
|
||||
0xee, 0x7b, 0x11, 0xed, 0x50, 0x4a, 0x9b, 0xc3, 0xa6, 0x53, 0xae, 0x2c, 0xf3, 0xf7, 0xc0, 0x73,
|
||||
0x75, 0xc7, 0xef, 0x0d, 0x31, 0xec, 0x0a, 0x13, 0xce, 0x7d, 0xab, 0x31, 0x5f, 0x4f, 0xfe, 0xe3,
|
||||
0xfb, 0x26, 0x3f, 0xec, 0x79, 0x1d, 0x5b, 0xc8, 0xac, 0x5a, 0x60, 0xfc, 0x30, 0xf0, 0x23, 0x83,
|
||||
0xb4, 0xf9, 0xf4, 0xe2, 0xfc, 0x4c, 0xdf, 0xe6, 0x6c, 0xb9, 0xae, 0x21, 0xf7, 0xd3, 0x34, 0x2b,
|
||||
0x02, 0x03, 0xeb, 0xf4, 0xfd, 0x76, 0xfb, 0xee, 0xee, 0xce, 0xb9, 0xeb, 0x38, 0x8c, 0x8f, 0xdb,
|
||||
0xbe, 0xeb, 0xba, 0x78, 0x1f, 0x61, 0x10, 0xf5, 0xfc, 0xc0, 0xc0, 0x2a, 0xaa, 0x41, 0xd4, 0xfd,
|
||||
0x8f, 0xfe, 0xd2, 0x97, 0x3d, 0xfa, 0x96, 0x08, 0xef, 0x7c, 0xfa, 0x2f, 0x0e, 0x0f, 0x61, 0xa2,
|
||||
0x3b, 0x80, 0x4e, 0xce, 0xbe, 0xd0, 0x3e, 0x81, 0x0e, 0xfc, 0xaf, 0xec, 0xd0, 0xf5, 0x2b, 0xd2,
|
||||
0xc2, 0x6a, 0x8a, 0xee, 0x8a, 0x81, 0xde, 0x10, 0xaf, 0xd2, 0xfa, 0xc4, 0x75, 0x3c, 0x9b, 0x1c,
|
||||
0x0e, 0xd4, 0xfd, 0xfe, 0x91, 0xdd, 0xb9, 0xdc, 0x3f, 0xdd, 0xbf, 0xec, 0x9e, 0x1e, 0x5c, 0x7a,
|
||||
0x47, 0x6f, 0x7d, 0xdb, 0x97, 0x77, 0x5a, 0x2e, 0xe9, 0xd9, 0xbe, 0x77, 0xea, 0xf5, 0x6a, 0x3d,
|
||||
0x78, 0xcf, 0x72, 0x04, 0x80, 0xbe, 0x0b, 0x33, 0xbc, 0x83, 0xcb, 0xce, 0xe9, 0xd1, 0x79, 0xcf,
|
||||
0xee, 0x9e, 0xe2, 0x7d, 0xd7, 0xd1, 0x69, 0xef, 0xb2, 0x0b, 0xc8, 0x0e, 0x2f, 0xbd, 0xde, 0xa9,
|
||||
0xe7, 0x5d, 0x1e, 0xc2, 0x18, 0xde, 0xba, 0xc8, 0xcf, 0x03, 0xf8, 0xf4, 0x3a, 0xf5, 0x1b, 0x30,
|
||||
0xa1, 0xdd, 0x49, 0x59, 0xea, 0x09, 0x8c, 0xb2, 0x4e, 0x6a, 0x54, 0x63, 0xd2, 0xef, 0xe8, 0xcd,
|
||||
0x55, 0x3e, 0xb5, 0x1c, 0x81, 0x0c, 0x42, 0x0f, 0xfc, 0xa1, 0x06, 0x62, 0x07, 0x6f, 0x3f, 0x1b,
|
||||
0x99, 0x3d, 0xe4, 0x1a, 0xe2, 0xe9, 0xe3, 0x8d, 0x70, 0x54, 0x4d, 0xe1, 0x57, 0x16, 0x53, 0x47,
|
||||
0x65, 0x05, 0xab, 0xa9, 0xeb, 0xfa, 0xb9, 0x0b, 0x74, 0x0d, 0x6e, 0x87, 0xf1, 0x3c, 0x35, 0x7d,
|
||||
0x03, 0xd8, 0x5a, 0xb7, 0xe1, 0x6f, 0xce, 0xde, 0xb1, 0xf6, 0x77, 0xae, 0xba, 0xe5, 0x10, 0xb3,
|
||||
0x3d, 0x2b, 0x7c, 0xe2, 0x88, 0xdb, 0x4c, 0xaa, 0xbe, 0x91, 0xe6, 0x6d, 0xe4, 0xa0, 0x0b, 0x69,
|
||||
0x4d, 0xea, 0x2a, 0x5a, 0x19, 0x16, 0x62, 0x00, 0x9f, 0x0c, 0x86, 0x88, 0x31, 0x1c, 0x7a, 0x30,
|
||||
0xc6, 0xcb, 0x1f, 0x53, 0xfe, 0xee, 0x64, 0x0d, 0x07, 0x91, 0x52, 0xd5, 0xf9, 0x5d, 0xc4, 0xd6,
|
||||
0x93, 0xd7, 0xc9, 0x97, 0xdf, 0xea, 0x27, 0x35, 0x24, 0x48, 0x16, 0xf3, 0x30, 0xaf, 0x93, 0x5f,
|
||||
0xb2, 0x8a, 0x65, 0x0d, 0xca, 0x3b, 0xb8, 0xdf, 0xd0, 0xd0, 0x86, 0x5d, 0xd7, 0x7d, 0x53, 0xea,
|
||||
0xa6, 0xae, 0x1c, 0xe0, 0x33, 0x9d, 0x8c, 0x1a, 0xfd, 0x8d, 0x6e, 0x55, 0xa8, 0x34, 0x6a, 0x6b,
|
||||
0x86, 0x69, 0xf4, 0x9f, 0x9f, 0x3f, 0xfe, 0x6a, 0xaa, 0x4b, 0x3a, 0x1a, 0xbc, 0x5e, 0x94, 0x75,
|
||||
0x03, 0xa3, 0x7f, 0xf5, 0x7a, 0xa0, 0x9f, 0xcd, 0xac, 0x9d, 0x42, 0xc4, 0xda, 0x21, 0x04, 0x8e,
|
||||
0x82, 0xf2, 0x10, 0x22, 0x30, 0x1d, 0x32, 0x29, 0x9c, 0x2d, 0x6c, 0x14, 0x22, 0x9c, 0x42, 0xf0,
|
||||
0x0c, 0x62, 0x1b, 0x2f, 0x17, 0xdc, 0x29, 0x80, 0x7d, 0x6a, 0x7a, 0xd6, 0xd2, 0xc0, 0xc3, 0x08,
|
||||
0xc2, 0x5c, 0x2f, 0xc1, 0x14, 0x6a, 0x09, 0xa4, 0x7c, 0xf0, 0x24, 0xe8, 0x7f, 0xc9, 0x3a, 0x0b,
|
||||
0x6e, 0x8c, 0xaa, 0xb8, 0x48, 0xf2, 0x56, 0x74, 0xda, 0x37, 0x6d, 0x4d, 0x20, 0x1e, 0x6d, 0x9c,
|
||||
0x3f, 0x0b, 0x96, 0xdd, 0x34, 0x0e, 0xbe, 0xd5, 0x1c, 0x38, 0x1a, 0xa9, 0xf8, 0xc5, 0x03, 0x2c,
|
||||
0x35, 0xfd, 0x7e, 0x7e, 0x76, 0x0a, 0x3e, 0xf0, 0x1f, 0x14, 0x8e, 0xbd, 0x85, 0x80, 0x94, 0x1d,
|
||||
0x3b, 0x7f, 0x49, 0xd9, 0x2d, 0x1c, 0xa2, 0xae, 0xed, 0x05, 0x26, 0xa8, 0x7d, 0x03, 0x8c, 0x38,
|
||||
0xc5, 0x7a, 0x11, 0xa0, 0x6a, 0x23, 0x6a, 0x63, 0x09, 0xa9, 0xf6, 0x16, 0xcd, 0xc3, 0x45, 0x0c,
|
||||
0xdb, 0x2c, 0x0f, 0xc0, 0x0c, 0x3d, 0x06, 0x1b, 0x4b, 0xe5, 0x86, 0xdd, 0x2f, 0x72, 0xe8, 0xa3,
|
||||
0x17, 0xf4, 0x5e, 0xd8, 0x06, 0x69, 0x11, 0x43, 0xda, 0x06, 0x66, 0xbf, 0x62, 0x86, 0x37, 0x64,
|
||||
0x0c, 0xb8, 0xf9, 0x0c, 0x47, 0xee, 0x70, 0x5c, 0xea, 0xcf, 0x07, 0x41, 0xa7, 0xb0, 0xd9, 0x29,
|
||||
0x8d, 0x3f, 0x85, 0x29, 0x16, 0x41, 0x74, 0xf2, 0x8c, 0xa0, 0x48, 0x8b, 0x33, 0xe1, 0x74, 0x14,
|
||||
0x18, 0x6d, 0x20, 0xc7, 0xde, 0x46, 0x0e, 0xe5, 0x1c, 0xef, 0xbc, 0xe8, 0x1a, 0x39, 0xc6, 0x7b,
|
||||
0xec, 0xef, 0x13, 0x79, 0xbb, 0xd7, 0x18, 0x20, 0x9f, 0x25, 0x31, 0xfd, 0x75, 0xda, 0x30, 0xf5,
|
||||
0x48, 0xa6, 0x94, 0xcd, 0x84, 0x29, 0x99, 0x5b, 0xda, 0x1e, 0xed, 0x58, 0x72, 0x55, 0x06, 0xee,
|
||||
0xcd, 0x34, 0x3e, 0x7d, 0xfc, 0x7c, 0x01, 0xbb, 0xdb, 0x56, 0x72, 0x36, 0x54, 0xa6, 0x1e, 0x4a,
|
||||
0x59, 0xfe, 0x9d, 0xf1, 0xe9, 0x3b, 0x48, 0x2c, 0x4a, 0xa5, 0x09, 0xb5, 0x4b, 0x54, 0xe9, 0x06,
|
||||
0x9c, 0xad, 0xf1, 0x0a, 0x91, 0xcb, 0xd2, 0xb7, 0x19, 0x5a, 0xf6, 0x73, 0x6f, 0x19, 0x16, 0x0f,
|
||||
0x59, 0x44, 0x56, 0x8f, 0xba, 0xa8, 0xf8, 0x90, 0x8d, 0x18, 0xe8, 0x62, 0x32, 0x32, 0x21, 0x2d,
|
||||
0x0a, 0x56, 0xec, 0x33, 0xd8, 0x31, 0xe8, 0x29, 0xaf, 0x70, 0x5d, 0x4b, 0xf0, 0x87, 0xca, 0x52,
|
||||
0xc2, 0xbb, 0x30, 0x11, 0x64, 0x44, 0x05, 0x28, 0x63, 0x19, 0xe7, 0x8c, 0x3d, 0x00, 0xdf, 0x33,
|
||||
0xe4, 0x26, 0xb6, 0x65, 0x55, 0x12, 0xad, 0x48, 0x41, 0x52, 0xa9, 0x35, 0x70, 0xca, 0x90, 0x53,
|
||||
0xca, 0xba, 0x99, 0x69, 0xaa, 0xca, 0x93, 0x70, 0xe4, 0x2f, 0x84, 0x60, 0x61, 0xb5, 0x40, 0x5f,
|
||||
0x81, 0x04, 0xc0, 0x4b, 0xad, 0x4a, 0xb2, 0x52, 0xd8, 0x78, 0x27, 0x25, 0xef, 0x7b, 0x9b, 0xbd,
|
||||
0x06, 0xd8, 0x74, 0xc6, 0x04, 0x49, 0x62, 0xd8, 0x9f, 0x64, 0xf4, 0x40, 0x90, 0x72, 0xc8, 0xb0,
|
||||
0xd6, 0x38, 0x6d, 0x2e, 0x0c, 0xb8, 0xeb, 0xe5, 0x26, 0xcd, 0x64, 0xe0, 0x0e, 0xf0, 0x1e, 0x1a,
|
||||
0xcd, 0x12, 0x8e, 0x0a, 0x03, 0x31, 0x0c, 0xe8, 0x40, 0xec, 0xed, 0xad, 0x1c, 0xc4, 0x8d, 0x66,
|
||||
0xf5, 0xe5, 0x02, 0x58, 0x5d, 0xae, 0xac, 0x42, 0x68, 0xab, 0x18, 0xac, 0x64, 0x24, 0x1a, 0x32,
|
||||
0x02, 0x65, 0xe0, 0xba, 0x43, 0x94, 0xa2, 0x68, 0x10, 0x90, 0xcf, 0x8a, 0x09, 0x1c, 0xe7, 0x34,
|
||||
0xeb, 0x62, 0x9d, 0xf5, 0x1b, 0xa9, 0x56, 0x0a, 0x19, 0x96, 0x3a, 0xd1, 0xda, 0xc8, 0x88, 0xb3,
|
||||
0xa9, 0xbc, 0x6d, 0xe8, 0x93, 0x1b, 0xd8, 0xe8, 0xe5, 0x72, 0x0b, 0x4b, 0x43, 0x0f, 0xfc, 0xc3,
|
||||
0xe6, 0x4a, 0x25, 0xf7, 0xfd, 0x2b, 0xd7, 0xee, 0x95, 0x7f, 0x70, 0x9a, 0xaa, 0x3e, 0xae, 0x97,
|
||||
0xe5, 0xb5, 0x8c, 0x08, 0x70, 0x31, 0x74, 0xc0, 0x05, 0x35, 0x1b, 0x86, 0x84, 0xca, 0xb3, 0x66,
|
||||
0x45, 0xb2, 0x68, 0x00, 0xd4, 0xa3, 0x18, 0xb5, 0xd0, 0xb0, 0x10, 0x0e, 0xa1, 0x57, 0x6a, 0x18,
|
||||
0x3d, 0xf6, 0xf7, 0x0f, 0x2c, 0x7d, 0xd1, 0x88, 0xbd, 0xe0, 0x07, 0x70, 0x19, 0x91, 0x64, 0x33,
|
||||
0xba, 0x54, 0x13, 0x78, 0xa0, 0xfb, 0x71, 0x1b, 0xb0, 0x66, 0x30, 0xa8, 0x23, 0x63, 0x23, 0xc2,
|
||||
0x25, 0xaa, 0xe7, 0x8a, 0x9b, 0xa4, 0x90, 0xbf, 0x20, 0xe0, 0xc7, 0xc7, 0xfd, 0xe7, 0x41, 0x40,
|
||||
0x35, 0xdf, 0xd6, 0x42, 0x16, 0x3e, 0x6e, 0x39, 0x0d, 0xbf, 0x2c, 0x57, 0x08, 0x04, 0x22, 0xa0,
|
||||
0x16, 0xcc, 0x37, 0xb2, 0xd9, 0xf4, 0x16, 0x32, 0x4c, 0x88, 0x37, 0xe0, 0x86, 0xa0, 0x57, 0x3c,
|
||||
0x3e, 0x8a, 0xa1, 0x0b, 0xff, 0x1c, 0x83, 0x1c, 0x1e, 0x1f, 0x9f, 0xff, 0x2a, 0xc7, 0x61, 0x81,
|
||||
0x0f, 0x99, 0xa0, 0x63, 0x30, 0x79, 0x61, 0x35, 0x90, 0x2e, 0x91, 0x08, 0xf6, 0x0d, 0x66, 0xc2,
|
||||
0x80, 0x5f, 0x71, 0x4d, 0x52, 0xcb, 0xbb, 0x46, 0xe9, 0xc8, 0x2b, 0xca, 0x20, 0x84, 0xd3, 0xf5,
|
||||
0x4a, 0xaf, 0xae, 0x1c, 0xc7, 0x09, 0xaf, 0x07, 0x14, 0x3a, 0x03, 0xdc, 0x05, 0xae, 0x76, 0x09,
|
||||
0x14, 0x7e, 0x59, 0x82, 0xac, 0xc7, 0x03, 0x90, 0xa8, 0x33, 0x0d, 0xf3, 0xd5, 0x7d, 0x94, 0xb9,
|
||||
0x80, 0xf5, 0x21, 0xfe, 0x8c, 0xd2, 0x50, 0x86, 0xf4, 0x6d, 0x0a, 0x06, 0xcb, 0x94, 0x46, 0x04,
|
||||
0x63, 0x5c, 0x98, 0xc6, 0x05, 0x96, 0xfe, 0xf1, 0x75, 0x29, 0x0a, 0xa6, 0x2a, 0x3c, 0x43, 0xb0,
|
||||
0x25, 0xd3, 0xa4, 0x28, 0x92, 0xb1, 0x52, 0xb2, 0x07, 0x36, 0xe3, 0xe4, 0x96, 0xb3, 0xbb, 0x02,
|
||||
0x24, 0x42, 0xfe, 0x60, 0x33, 0x52, 0x4c, 0xd8, 0x2c, 0x8d, 0x49, 0xce, 0xd9, 0x6d, 0x78, 0x9b,
|
||||
0x3e, 0x10, 0xed, 0x80, 0x74, 0xa1, 0x7e, 0x1a, 0xc2, 0xa6, 0x43, 0x2a, 0x00, 0xcb, 0x64, 0x31,
|
||||
0xc1, 0x8d, 0x04, 0xc5, 0x97, 0xb5, 0x7c, 0x98, 0x90, 0x53, 0x0e, 0x13, 0x46, 0xf8, 0x2a, 0x01,
|
||||
0x2b, 0xf4, 0xe5, 0x9a, 0x8a, 0x0a, 0xbc, 0x86, 0x03, 0x69, 0x83, 0x8b, 0x85, 0xb8, 0x44, 0x6e,
|
||||
0x29, 0x80, 0x51, 0x8d, 0x1c, 0xf5, 0x7e, 0x42, 0x39, 0x75, 0xc0, 0x19, 0x9e, 0x23, 0x71, 0xf0,
|
||||
0x2d, 0x27, 0xc5, 0x15, 0x92, 0xe7, 0xe0, 0x1d, 0xcb, 0xc9, 0xda, 0xd6, 0xdf, 0x25, 0xf3, 0xa2,
|
||||
0x9e, 0x8c, 0x6c, 0x1d, 0xae, 0x36, 0x62, 0xe3, 0x59, 0xeb, 0xea, 0x4d, 0x08, 0x3a, 0xb3, 0xcd,
|
||||
0xe1, 0xb5, 0x87, 0x00, 0x68, 0xe6, 0x4a, 0xde, 0x28, 0x37, 0x38, 0x7b, 0x47, 0x98, 0xa6, 0x40,
|
||||
0xea, 0x02, 0xb1, 0x3b, 0x49, 0x05, 0x1e, 0x2c, 0x83, 0x63, 0x79, 0x22, 0x9f, 0x4a, 0x43, 0x6f,
|
||||
0xff, 0x53, 0xe3, 0xff, 0x9f, 0xf8, 0x65, 0x1b, 0xb6, 0x6c, 0x4d, 0x53, 0xb9, 0xb5, 0x9e, 0xa9,
|
||||
0x56, 0x0e, 0x8a, 0x83, 0x83, 0xe2, 0xc3, 0x2d, 0x16, 0x3f, 0xe0, 0x2b, 0x8f, 0xc5, 0x82, 0x3a,
|
||||
0xc0, 0x15, 0xbf, 0xb6, 0xc3, 0x60, 0xfd, 0x3d, 0xae, 0x3e, 0x65, 0x86, 0x4e, 0xed, 0x05, 0x8c,
|
||||
0xb1, 0xc7, 0xed, 0x50, 0x55, 0x1a, 0x30, 0xe2, 0x61, 0xf8, 0xab, 0x24, 0x61, 0x94, 0x8e, 0x21,
|
||||
0x2b, 0x75, 0xf2, 0x0b, 0x7d, 0x28, 0x4c, 0x66, 0x81, 0xf2, 0x02, 0x16, 0x0c, 0x3c, 0x10, 0xd2,
|
||||
0xf0, 0x5a, 0x5b, 0x1e, 0x3f, 0x94, 0xf7, 0x28, 0xe4, 0x85, 0x26, 0x78, 0x67, 0x93, 0x5d, 0x65,
|
||||
0xd7, 0xab, 0x32, 0xdb, 0x0e, 0x62, 0xd2, 0x3a, 0x31, 0x65, 0x9e, 0x0a, 0x44, 0x55, 0x55, 0xa8,
|
||||
0x1d, 0xf3, 0x54, 0x71, 0x69, 0xf5, 0x5c, 0x0c, 0xf9, 0x48, 0xd6, 0xf9, 0xa8, 0x0d, 0x5b, 0x55,
|
||||
0xbd, 0x65, 0x03, 0xa1, 0x2e, 0xbe, 0xa8, 0x9a, 0x4a, 0xf9, 0x76, 0x0c, 0xf1, 0x15, 0x0e, 0xbe,
|
||||
0xbc, 0x84, 0xc4, 0x32, 0x28, 0x75, 0x0a, 0xa3, 0x67, 0x33, 0x93, 0x02, 0x47, 0x8e, 0xc5, 0x93,
|
||||
0x6d, 0xd7, 0x07, 0xc6, 0x67, 0x8a, 0x8f, 0x62, 0xd4, 0x33, 0xa1, 0xda, 0xf3, 0x1c, 0x7c, 0xd3,
|
||||
0x42, 0x00, 0x3f, 0x56, 0x5d, 0x56, 0x67, 0x4c, 0xfd, 0x06, 0xc2, 0x2e, 0xd6, 0x99, 0xa8, 0x28,
|
||||
0x2a, 0x59, 0x88, 0x76, 0xb2, 0x10, 0x49, 0x16, 0xca, 0x87, 0x70, 0xc8, 0x42, 0xb4, 0x8d, 0x05,
|
||||
0x24, 0x1c, 0xf2, 0x09, 0x7c, 0xa8, 0x20, 0xe9, 0x8f, 0x76, 0x5c, 0x7f, 0x9c, 0xb0, 0xfc, 0x41,
|
||||
0x51, 0x0b, 0x39, 0xe6, 0xb2, 0x34, 0x3d, 0x64, 0x41, 0x31, 0x73, 0x03, 0x79, 0x4f, 0x93, 0x03,
|
||||
0x44, 0x09, 0x7d, 0x6b, 0x1c, 0x54, 0x04, 0x61, 0x31, 0x69, 0xbb, 0xaa, 0x55, 0x2f, 0x2b, 0x51,
|
||||
0x25, 0x40, 0xe7, 0xf3, 0xc0, 0x30, 0x2a, 0x03, 0xa0, 0x60, 0x00, 0x74, 0x88, 0xea, 0x54, 0x2a,
|
||||
0x3e, 0x64, 0xb8, 0xbe, 0x55, 0x85, 0x5f, 0x1c, 0x41, 0x8f, 0x8c, 0xbe, 0x5e, 0xa9, 0x1f, 0x96,
|
||||
0x88, 0x95, 0xaf, 0x57, 0x63, 0x7b, 0xde, 0xb5, 0x95, 0x43, 0xc6, 0xfc, 0xe2, 0xe5, 0xa2, 0xea,
|
||||
0xc0, 0xeb, 0x7b, 0xd1, 0x06, 0x1f, 0xfc, 0xb3, 0xe7, 0xba, 0xcb, 0x9f, 0x6c, 0x72, 0x23, 0x6b,
|
||||
0xcc, 0x0b, 0x84, 0x93, 0x6f, 0xa4, 0xeb, 0xb0, 0x78, 0xe1, 0xaf, 0xbf, 0xfc, 0xc6, 0x57, 0x07,
|
||||
0xbf, 0x3c, 0x6b, 0x03, 0x17, 0x26, 0xe1, 0x3e, 0xc4, 0xe9, 0x20, 0xd7, 0xc9, 0xb9, 0x6b, 0xb7,
|
||||
0xfc, 0x6d, 0xc5, 0xb4, 0x0f, 0x53, 0x70, 0x9e, 0xc1, 0xcd, 0xae, 0x22, 0x05, 0x2e, 0x95, 0x2f,
|
||||
0xad, 0x9b, 0xd2, 0x48, 0x55, 0x39, 0x70, 0xe3, 0x21, 0x27, 0x68, 0x5b, 0x69, 0xb4, 0x41, 0x90,
|
||||
0xbd, 0x49, 0xd6, 0x4a, 0x61, 0xfd, 0x48, 0xaf, 0xab, 0xde, 0x0c, 0x9e, 0xe1, 0xf9, 0xdb, 0x90,
|
||||
0x8f, 0x50, 0x6c, 0xfe, 0x3c, 0x90, 0x29, 0xd9, 0xab, 0x57, 0xcd, 0x49, 0x11, 0x16, 0xf5, 0xd7,
|
||||
0x8a, 0x72, 0xe1, 0x7a, 0x01, 0xaf, 0xb1, 0x28, 0x6d, 0x8c, 0x86, 0x16, 0x44, 0xa8, 0x66, 0xc7,
|
||||
0x72, 0xe5, 0x9b, 0xeb, 0x2a, 0x48, 0xf1, 0x72, 0x70, 0xa3, 0x5c, 0xf6, 0x5a, 0x96, 0x82, 0xaf,
|
||||
0x92, 0xf8, 0x9f, 0xcd, 0x1a, 0xf2, 0xf5, 0xeb, 0xd5, 0xe1, 0x08, 0x53, 0x72, 0xba, 0xeb, 0xc0,
|
||||
0x28, 0xeb, 0x9a, 0xdb, 0x10, 0xa3, 0xb1, 0xd4, 0xf0, 0xea, 0xdb, 0xa8, 0x6b, 0x9b, 0xac, 0x0d,
|
||||
0x34, 0xae, 0x70, 0x1b, 0xc3, 0x8d, 0x6b, 0xac, 0x1f, 0x22, 0x68, 0xa0, 0x32, 0xce, 0x5a, 0x9e,
|
||||
0x35, 0xae, 0x85, 0x1e, 0x63, 0x8f, 0x5a, 0xdb, 0x2e, 0x13, 0x4b, 0x0f, 0x6b, 0x58, 0xd6, 0x9a,
|
||||
0x51, 0x88, 0x6d, 0x16, 0x01, 0x79, 0x55, 0x95, 0x55, 0x6d, 0x35, 0x0a, 0xa1, 0x2c, 0x82, 0xc9,
|
||||
0x17, 0x14, 0xea, 0x43, 0xe9, 0x3e, 0x0b, 0x40, 0xf3, 0x2f, 0xd8, 0x29, 0xbd, 0x37, 0x55, 0xb7,
|
||||
0x2d, 0xa4, 0xc6, 0xcb, 0x9f, 0xce, 0xb5, 0xa5, 0xb4, 0x5a, 0x3e, 0x3f, 0xe1, 0x36, 0xab, 0x4e,
|
||||
0x52, 0x45, 0xc4, 0x19, 0x48, 0xd6, 0xb5, 0xdd, 0xfa, 0x1e, 0x57, 0xa8, 0x20, 0x6d, 0xb1, 0xf9,
|
||||
0x2a, 0x50, 0x99, 0x74, 0x38, 0xf4, 0xba, 0x90, 0x82, 0x0d, 0x0f, 0x1f, 0x79, 0xf3, 0x95, 0x86,
|
||||
0x3e, 0xdd, 0x20, 0x59, 0x86, 0x6b, 0xe0, 0xbd, 0x21, 0xb8, 0x39, 0xb3, 0xdb, 0x62, 0x65, 0xae,
|
||||
0xb7, 0xc7, 0x96, 0xd5, 0x41, 0xa6, 0x5c, 0x7d, 0xd7, 0x01, 0x12, 0x8f, 0xfc, 0x4f, 0x00, 0xc1,
|
||||
0x49, 0x32, 0xf9, 0x4a, 0x4b, 0xb0, 0x46, 0x19, 0x79, 0x67, 0xb9, 0xbf, 0xf1, 0xa6, 0x47, 0xbf,
|
||||
0xdf, 0x71, 0xf5, 0x2f, 0xbe, 0x6d, 0xd9, 0xb8, 0x6f, 0xa9, 0xff, 0x1f, 0x2f, 0x6d, 0xf5, 0x7f,
|
||||
0x2d, 0xfd, 0x2f, 0x9e, 0xe7, 0x3b, 0x04, 0xcd, 0x34, 0x00, 0x00
|
||||
};
|
||||
|
@ -377,7 +377,7 @@ const uint8_t PAGE_404[] PROGMEM = {
|
||||
|
||||
|
||||
// Autogenerated from wled00/data/favicon.ico, do not edit!!
|
||||
const uint16_t favicon_length = 954;
|
||||
const uint16_t favicon_length = 156;
|
||||
const uint8_t favicon[] PROGMEM = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x86, 0x00,
|
||||
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
|
||||
|
File diff suppressed because it is too large
Load Diff
5557
wled00/html_ui.h
5557
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -643,8 +643,8 @@ void decodeIRJson(uint32_t code)
|
||||
// this may fail for two reasons: ir.json does not exist or IR code not found
|
||||
// if the IR code is not found readObjectFromFile() will clean() doc JSON document
|
||||
// so we can differentiate between the two
|
||||
readObjectFromFile("/ir.json", objKey, &doc);
|
||||
fdo = doc.as<JsonObject>();
|
||||
readObjectFromFile("/ir.json", objKey, pDoc);
|
||||
fdo = pDoc->as<JsonObject>();
|
||||
lastValidCode = 0;
|
||||
if (fdo.isNull()) {
|
||||
//the received code does not exist
|
||||
|
@ -117,9 +117,8 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
|
||||
// update segment (delete if necessary)
|
||||
// do not call seg.setUp() here, as it may cause a crash due to concurrent access if the segment is currently drawing effects
|
||||
// WS2812FX handles queueing of the change
|
||||
strip.setSegment(id, start, stop, grp, spc, of, startY, stopY);
|
||||
seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues
|
||||
|
||||
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
|
||||
|
||||
if (seg.reset && seg.stop == 0) {
|
||||
@ -210,7 +209,14 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
#endif
|
||||
|
||||
byte fx = seg.mode;
|
||||
if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
||||
byte last = strip.getModeCount();
|
||||
// partial fix for #3605
|
||||
if (!elem["fx"].isNull() && elem["fx"].is<const char*>()) {
|
||||
const char *tmp = elem["fx"].as<const char *>();
|
||||
if (strlen(tmp) > 3 && (strchr(tmp,'r') || strchr(tmp,'~') != strrchr(tmp,'~'))) last = 0; // we have "X~Y(r|[w]~[-])" form
|
||||
}
|
||||
// end fix
|
||||
if (getVal(elem["fx"], &fx, 0, last)) { //load effect ('r' random, '~' inc/dec, 0-255 exact value, 5~10r pick random between 5 & 10)
|
||||
if (!presetId && currentPlaylist>=0) unloadPlaylist();
|
||||
if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]);
|
||||
}
|
||||
@ -381,6 +387,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (!segVar.isNull()) strip.suspend();
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
@ -408,6 +415,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments
|
||||
}
|
||||
strip.resume();
|
||||
|
||||
usermods.readFromJsonState(root);
|
||||
|
||||
@ -605,9 +613,9 @@ void serializeInfo(JsonObject root)
|
||||
|
||||
JsonObject leds = root.createNestedObject("leds");
|
||||
leds[F("count")] = strip.getLengthTotal();
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("pwr")] = BusManager::currentMilliamps();
|
||||
leds["fps"] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds[F("maxpwr")] = BusManager::currentMilliamps()>0 ? BusManager::ablMilliampsMax() : 0;
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
//leds[F("actseg")] = strip.getActiveSegmentsNum();
|
||||
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
|
||||
@ -1009,15 +1017,19 @@ void serializeModeNames(JsonArray arr)
|
||||
}
|
||||
}
|
||||
|
||||
static volatile bool servingClient = false;
|
||||
|
||||
// Global buffer locking response helper class
|
||||
class GlobalBufferAsyncJsonResponse: public JSONBufferGuard, public AsyncJsonResponse {
|
||||
public:
|
||||
inline GlobalBufferAsyncJsonResponse(bool isArray) : JSONBufferGuard(17), AsyncJsonResponse(pDoc, isArray) {};
|
||||
virtual ~GlobalBufferAsyncJsonResponse() {};
|
||||
|
||||
// Other members are inherited
|
||||
};
|
||||
|
||||
|
||||
void serveJson(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (servingClient) {
|
||||
serveJsonError(request, 503, ERR_CONCURRENCY);
|
||||
return;
|
||||
}
|
||||
servingClient = true;
|
||||
|
||||
byte subJson = 0;
|
||||
const String& url = request->url();
|
||||
if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE;
|
||||
@ -1031,31 +1043,27 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
servingClient = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
else if (url.indexOf("pal") > 0) {
|
||||
request->send_P(200, "application/json", JSON_palette_names);
|
||||
servingClient = false;
|
||||
return;
|
||||
}
|
||||
else if (url.indexOf("cfg") > 0 && handleFileRead(request, "/cfg.json")) {
|
||||
servingClient = false;
|
||||
return;
|
||||
}
|
||||
else if (url.length() > 6) { //not just /json
|
||||
serveJsonError(request, 501, ERR_NOT_IMPL);
|
||||
servingClient = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestJSONBufferLock(17)) {
|
||||
GlobalBufferAsyncJsonResponse *response = new GlobalBufferAsyncJsonResponse(subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
if (!response->owns_lock()) {
|
||||
serveJsonError(request, 503, ERR_NOBUF);
|
||||
servingClient = false;
|
||||
delete response;
|
||||
return;
|
||||
}
|
||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||
|
||||
JsonVariant lDoc = response->getRoot();
|
||||
|
||||
@ -1098,8 +1106,6 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
|
||||
|
||||
request->send(response);
|
||||
releaseJSONBufferLock();
|
||||
servingClient = false;
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_JSONLIVE
|
||||
|
@ -109,8 +109,8 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
|
||||
return;
|
||||
}
|
||||
if (payloadStr[0] == '{') { //JSON API
|
||||
deserializeJson(doc, payloadStr);
|
||||
deserializeState(doc.as<JsonObject>());
|
||||
deserializeJson(*pDoc, payloadStr);
|
||||
deserializeState(pDoc->as<JsonObject>());
|
||||
} else { //HTTP API
|
||||
String apireq = "win"; apireq += '&'; // reduce flash string usage
|
||||
apireq += payloadStr;
|
||||
|
@ -15,11 +15,11 @@ void _overlayAnalogClock()
|
||||
float minuteP = ((float)minute(localTime))/60.0f;
|
||||
hourP = hourP + minuteP/12.0f;
|
||||
float secondP = ((float)second(localTime))/60.0f;
|
||||
int hourPixel = floorf(analogClock12pixel + overlaySize*hourP);
|
||||
unsigned hourPixel = floorf(analogClock12pixel + overlaySize*hourP);
|
||||
if (hourPixel > overlayMax) hourPixel = overlayMin -1 + hourPixel - overlayMax;
|
||||
int minutePixel = floorf(analogClock12pixel + overlaySize*minuteP);
|
||||
unsigned minutePixel = floorf(analogClock12pixel + overlaySize*minuteP);
|
||||
if (minutePixel > overlayMax) minutePixel = overlayMin -1 + minutePixel - overlayMax;
|
||||
int secondPixel = floorf(analogClock12pixel + overlaySize*secondP);
|
||||
unsigned secondPixel = floorf(analogClock12pixel + overlaySize*secondP);
|
||||
if (secondPixel > overlayMax) secondPixel = overlayMin -1 + secondPixel - overlayMax;
|
||||
if (analogClockSecondsTrail)
|
||||
{
|
||||
@ -36,7 +36,7 @@ void _overlayAnalogClock()
|
||||
{
|
||||
for (byte i = 0; i <= 12; i++)
|
||||
{
|
||||
int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
|
||||
unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i);
|
||||
if (pix > overlayMax) pix -= overlaySize;
|
||||
strip.setPixelColor(pix, 0x00FFAA);
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
||||
// Check if supplied GPIO is ok to use
|
||||
bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
{
|
||||
#ifdef ESP32
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (digitalPinIsValid(gpio)) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// strapping pins: 2, 8, & 9
|
||||
@ -257,6 +257,9 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
// GPIO46 is input only and pulled down
|
||||
#else
|
||||
if (gpio > 5 && gpio < 12) return false; //SPI flash pins
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
if (gpio == 16 || gpio == 17) return false; //PSRAM pins
|
||||
#endif
|
||||
#endif
|
||||
if (output) return digitalPinCanOutput(gpio);
|
||||
else return true;
|
||||
|
@ -41,7 +41,7 @@ enum struct PinOwner : uint8_t {
|
||||
UM_Temperature = USERMOD_ID_TEMPERATURE, // 0x03 // Usermod "usermod_temperature.h"
|
||||
// #define USERMOD_ID_FIXNETSERVICES // 0x04 // Usermod "usermod_Fix_unreachable_netservices.h" -- Does not allocate pins
|
||||
UM_PIR = USERMOD_ID_PIRSWITCH, // 0x05 // Usermod "usermod_PIR_sensor_switch.h"
|
||||
// #define USERMOD_ID_IMU // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins
|
||||
UM_IMU = USERMOD_ID_IMU, // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Interrupt pin
|
||||
UM_FourLineDisplay = USERMOD_ID_FOUR_LINE_DISP, // 0x07 // Usermod "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins
|
||||
UM_RotaryEncoderUI = USERMOD_ID_ROTARY_ENC_UI, // 0x08 // Usermod "usermod_v2_rotary_encoder_ui.h"
|
||||
// #define USERMOD_ID_AUTO_SAVE // 0x09 // Usermod "usermod_v2_auto_save.h" -- Does not allocate pins
|
||||
|
@ -24,10 +24,12 @@ static void doSaveState() {
|
||||
bool persist = (presetToSave < 251);
|
||||
const char *filename = getFileName(persist);
|
||||
|
||||
unsigned long start = millis();
|
||||
while (strip.isUpdating() && millis()-start < (2*FRAMETIME_FIXED)+1) yield(); // wait 2 frames
|
||||
if (!requestJSONBufferLock(10)) return; // will set fileDoc
|
||||
|
||||
initPresetsFile(); // just in case if someone deleted presets.json using /edit
|
||||
JsonObject sObj = doc.to<JsonObject>();
|
||||
JsonObject sObj = pDoc->to<JsonObject>();
|
||||
|
||||
DEBUG_PRINTLN(F("Serialize current state"));
|
||||
if (playlistSave) {
|
||||
@ -42,7 +44,7 @@ static void doSaveState() {
|
||||
/*
|
||||
#ifdef WLED_DEBUG
|
||||
DEBUG_PRINTLN(F("Serialized preset"));
|
||||
serializeJson(doc,Serial);
|
||||
serializeJson(*pDoc,Serial);
|
||||
DEBUG_PRINTLN();
|
||||
#endif
|
||||
*/
|
||||
@ -83,9 +85,9 @@ bool getPresetName(byte index, String& name)
|
||||
{
|
||||
if (!requestJSONBufferLock(9)) return false;
|
||||
bool presetExists = false;
|
||||
if (readObjectFromFileUsingId(getFileName(), index, &doc))
|
||||
if (readObjectFromFileUsingId(getFileName(), index, pDoc))
|
||||
{
|
||||
JsonObject fdo = doc.as<JsonObject>();
|
||||
JsonObject fdo = pDoc->as<JsonObject>();
|
||||
if (fdo["n"]) {
|
||||
name = (const char*)(fdo["n"]);
|
||||
presetExists = true;
|
||||
@ -132,7 +134,9 @@ void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID,
|
||||
void handlePresets()
|
||||
{
|
||||
if (presetToSave) {
|
||||
strip.suspend();
|
||||
doSaveState();
|
||||
strip.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -123,8 +123,8 @@ static bool remoteJson(int button)
|
||||
sprintf_P(objKey, PSTR("\"%d\":"), button);
|
||||
|
||||
// attempt to read command from remote.json
|
||||
readObjectFromFile("/remote.json", objKey, &doc);
|
||||
JsonObject fdo = doc.as<JsonObject>();
|
||||
readObjectFromFile("/remote.json", objKey, pDoc);
|
||||
JsonObject fdo = pDoc->as<JsonObject>();
|
||||
if (fdo.isNull()) {
|
||||
// the received button does not exist
|
||||
if (!WLED_FS.exists("/remote.json")) errorFlag = ERR_FS_RMLOAD; //warn if file itself doesn't exist
|
||||
|
@ -46,6 +46,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
if (t != apChannel) forceReconnect = true;
|
||||
if (t > 0 && t < 14) apChannel = t;
|
||||
|
||||
force802_3g = request->hasArg(F("FG"));
|
||||
noWifiSleep = request->hasArg(F("WS"));
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
@ -98,8 +99,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
uint16_t length, start, maMax;
|
||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||
|
||||
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
|
||||
//strip.milliampsPerLed = request->arg(F("LA")).toInt();
|
||||
uint16_t ablMilliampsMax = request->arg(F("MA")).toInt();
|
||||
BusManager::setMilliampsMax(ablMilliampsMax);
|
||||
|
||||
autoSegments = request->hasArg(F("MS"));
|
||||
correctWB = request->hasArg(F("CCT"));
|
||||
@ -145,30 +146,30 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
break; // no parameter
|
||||
}
|
||||
awmode = request->arg(aw).toInt();
|
||||
uint16_t freqHz = request->arg(sp).toInt();
|
||||
if (type > TYPE_ONOFF && type < 49) {
|
||||
switch (freqHz) {
|
||||
case 0 : freqHz = WLED_PWM_FREQ/3; break;
|
||||
case 1 : freqHz = WLED_PWM_FREQ/2; break;
|
||||
uint16_t freq = request->arg(sp).toInt();
|
||||
if (IS_PWM(type)) {
|
||||
switch (freq) {
|
||||
case 0 : freq = WLED_PWM_FREQ/3; break;
|
||||
case 1 : freq = WLED_PWM_FREQ/2; break;
|
||||
default:
|
||||
case 2 : freqHz = WLED_PWM_FREQ; break;
|
||||
case 3 : freqHz = WLED_PWM_FREQ*2; break;
|
||||
case 4 : freqHz = WLED_PWM_FREQ*3; break;
|
||||
case 2 : freq = WLED_PWM_FREQ; break;
|
||||
case 3 : freq = WLED_PWM_FREQ*4/3; break;
|
||||
case 4 : freq = WLED_PWM_FREQ*2; break;
|
||||
}
|
||||
} else if (type > 48 && type < 64) {
|
||||
switch (freqHz) {
|
||||
} else if (IS_DIGITAL(type) && IS_2PIN(type)) {
|
||||
switch (freq) {
|
||||
default:
|
||||
case 0 : freqHz = 1000; break;
|
||||
case 1 : freqHz = 2000; break;
|
||||
case 2 : freqHz = 5000; break;
|
||||
case 3 : freqHz = 10000; break;
|
||||
case 4 : freqHz = 20000; break;
|
||||
case 0 : freq = 1000; break;
|
||||
case 1 : freq = 2000; break;
|
||||
case 2 : freq = 5000; break;
|
||||
case 3 : freq = 10000; break;
|
||||
case 4 : freq = 20000; break;
|
||||
}
|
||||
} else {
|
||||
freqHz = 0;
|
||||
freq = 0;
|
||||
}
|
||||
channelSwap = Bus::hasWhite(type) ? request->arg(wo).toInt() : 0;
|
||||
if ((type > TYPE_TM1814 && type < TYPE_WS2801) || type >= TYPE_NET_DDP_RGB) { // analog and virtual
|
||||
if (type == TYPE_ONOFF || IS_PWM(type) || IS_VIRTUAL(type)) { // analog and virtual
|
||||
maPerLed = 0;
|
||||
maMax = 0;
|
||||
} else {
|
||||
@ -179,7 +180,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||
if (busConfigs[s] != nullptr) delete busConfigs[s];
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freqHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
|
||||
busesChanged = true;
|
||||
}
|
||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||
@ -196,7 +197,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
com.add(start, length, colorOrder);
|
||||
}
|
||||
}
|
||||
busses.updateColorOrderMap(com);
|
||||
BusManager::updateColorOrderMap(com);
|
||||
|
||||
// upate other pins
|
||||
int hw_ir_pin = request->arg(F("IR")).toInt();
|
||||
@ -626,7 +627,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject um = doc.createNestedObject("um");
|
||||
JsonObject um = pDoc->createNestedObject("um");
|
||||
|
||||
size_t args = request->args();
|
||||
uint16_t j=0;
|
||||
|
@ -286,10 +286,10 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
uint16_t stopY = version > 11 ? (udpIn[34+ofs] << 8 | udpIn[35+ofs]) : 1;
|
||||
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
|
||||
if (!receiveSegmentOptions) {
|
||||
//selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||
DEBUG_PRINTF("Set segment w/o options: %d [%d,%d;%d,%d]\n", id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
strip.resume();
|
||||
continue; // we do receive bounds, but not options
|
||||
}
|
||||
selseg.options = (selseg.options & 0x0071U) | (udpIn[9 +ofs] & 0x0E); // ignore selected, freeze, reset & transitional
|
||||
@ -326,12 +326,14 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
}
|
||||
if (receiveSegmentBounds) {
|
||||
DEBUG_PRINTF("Set segment w/ options: %d [%d,%d;%d,%d]\n", id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||
strip.setSegment(id, start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||
strip.resume();
|
||||
} else {
|
||||
// we have to use strip.setSegment() instead of selseg.setUp() to prevent crash if segment would change during drawing
|
||||
DEBUG_PRINTF("Set segment grouping: %d [%d,%d]\n", id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
||||
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||
strip.resume();
|
||||
}
|
||||
}
|
||||
stateChanged = true;
|
||||
@ -434,6 +436,8 @@ void exitRealtime() {
|
||||
realtimeIP[0] = 0;
|
||||
if (useMainSegmentOnly) { // unfreeze live segment again
|
||||
strip.getMainSegment().freeze = false;
|
||||
} else {
|
||||
strip.show(); // possible fix for #3589
|
||||
}
|
||||
updateInterfaces(CALL_MODE_WS_SEND);
|
||||
}
|
||||
@ -664,8 +668,8 @@ void handleNotifications()
|
||||
apireq += (char*)udpIn;
|
||||
handleSet(nullptr, apireq);
|
||||
} else if (udpIn[0] == '{') { //JSON API
|
||||
DeserializationError error = deserializeJson(doc, udpIn);
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
DeserializationError error = deserializeJson(*pDoc, udpIn);
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (!error && !root.isNull()) deserializeState(root);
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
|
@ -197,6 +197,13 @@
|
||||
#include "../usermods/pwm_outputs/usermod_pwm_outputs.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_MPU6050_IMU
|
||||
#include "../usermods/mpu6050_imu/usermod_mpu6050_imu.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_MPU6050_IMU
|
||||
#include "../usermods/mpu6050_imu/usermod_gyro_surge.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
@ -206,6 +213,7 @@ void registerUsermods()
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
|
||||
#ifdef USERMOD_BATTERY
|
||||
usermods.add(new UsermodBattery());
|
||||
#endif
|
||||
@ -373,4 +381,12 @@ void registerUsermods()
|
||||
#ifdef USERMOD_INTERNAL_TEMPERATURE
|
||||
usermods.add(new InternalTemperatureUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_MPU6050_IMU
|
||||
static MPU6050Driver mpu6050; usermods.add(&mpu6050);
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_GYRO_SURGE
|
||||
static GyroSurge gyro_surge; usermods.add(&gyro_surge);
|
||||
#endif
|
||||
}
|
||||
|
@ -209,6 +209,10 @@ bool isAsterisksOnly(const char* str, byte maxLen)
|
||||
//threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994
|
||||
bool requestJSONBufferLock(uint8_t module)
|
||||
{
|
||||
if (pDoc == nullptr) {
|
||||
DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!"));
|
||||
return false;
|
||||
}
|
||||
unsigned long now = millis();
|
||||
|
||||
while (jsonBufferLock && millis()-now < 1000) delay(1); // wait for a second for buffer lock
|
||||
@ -224,8 +228,8 @@ bool requestJSONBufferLock(uint8_t module)
|
||||
DEBUG_PRINT(F("JSON buffer locked. ("));
|
||||
DEBUG_PRINT(jsonBufferLock);
|
||||
DEBUG_PRINTLN(")");
|
||||
fileDoc = &doc; // used for applying presets (presets.cpp)
|
||||
doc.clear();
|
||||
fileDoc = pDoc; // used for applying presets (presets.cpp)
|
||||
pDoc->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -556,11 +560,12 @@ void enumerateLedmaps() {
|
||||
|
||||
#ifndef ESP8266
|
||||
if (requestJSONBufferLock(21)) {
|
||||
if (readObjectFromFile(fileName, nullptr, &doc)) {
|
||||
if (readObjectFromFile(fileName, nullptr, pDoc)) {
|
||||
size_t len = 0;
|
||||
if (!doc["n"].isNull()) {
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (!root["n"].isNull()) {
|
||||
// name field exists
|
||||
const char *name = doc["n"].as<const char*>();
|
||||
const char *name = root["n"].as<const char*>();
|
||||
if (name != nullptr) len = strlen(name);
|
||||
if (len > 0 && len < 33) {
|
||||
ledmapNames[i-1] = new char[len+1];
|
||||
|
@ -108,7 +108,7 @@ void WLED::loop()
|
||||
handlePresets();
|
||||
yield();
|
||||
|
||||
if (!offMode || strip.isOffRefreshRequired())
|
||||
if (!offMode || strip.isOffRefreshRequired() || strip.needsUpdate())
|
||||
strip.service();
|
||||
#ifdef ESP8266
|
||||
else if (!noWifiSleep)
|
||||
@ -157,7 +157,7 @@ void WLED::loop()
|
||||
doInitBusses = false;
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
||||
busses.removeAll();
|
||||
BusManager::removeAll();
|
||||
uint32_t mem = 0, globalBufMem = 0;
|
||||
uint16_t maxlen = 0;
|
||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
|
||||
@ -168,7 +168,7 @@ void WLED::loop()
|
||||
globalBufMem = maxlen * 4;
|
||||
}
|
||||
if (mem + globalBufMem <= MAX_LED_MEMORY) {
|
||||
busses.add(*busConfigs[i]);
|
||||
BusManager::add(*busConfigs[i]);
|
||||
}
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
@ -178,7 +178,7 @@ void WLED::loop()
|
||||
doSerializeConfig = true;
|
||||
}
|
||||
if (loadLedmap >= 0) {
|
||||
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
||||
strip.deserializeMap(loadLedmap);
|
||||
loadLedmap = -1;
|
||||
}
|
||||
yield();
|
||||
@ -346,6 +346,11 @@ void WLED::setup()
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
/*
|
||||
* The following code is obsolete as PinManager::isPinOK() will return false for reserved GPIO.
|
||||
* Additionally xml.cpp will inform UI about reserved GPIO.
|
||||
*
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// S3: reserve GPIO 33-37 for "octal" PSRAM
|
||||
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
||||
@ -363,12 +368,17 @@ void WLED::setup()
|
||||
managed_pin_type pins[] = { {16, true}, {17, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#endif
|
||||
*/
|
||||
#if defined(WLED_USE_PSRAM)
|
||||
pDoc = new PSRAMDynamicJsonDocument(2*JSON_BUFFER_SIZE);
|
||||
if (!pDoc) pDoc = new PSRAMDynamicJsonDocument(JSON_BUFFER_SIZE); // falback if double sized buffer could not be allocated
|
||||
// if the above still fails requestJsonBufferLock() will always return false preventing crashes
|
||||
if (psramFound()) {
|
||||
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
|
||||
DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
|
||||
}
|
||||
#else
|
||||
if (!pDoc) pDoc = &gDoc; // just in case ... (it should be globally assigned)
|
||||
DEBUG_PRINTLN(F("PSRAM not used."));
|
||||
#endif
|
||||
#endif
|
||||
@ -699,7 +709,7 @@ void WLED::initConnection()
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
|
||||
if (staticIP[0] != 0 && staticGateway[0] != 0) {
|
||||
@ -723,9 +733,10 @@ void WLED::initConnection()
|
||||
WiFi.mode(WIFI_STA);
|
||||
}
|
||||
}
|
||||
showWelcomePage = false;
|
||||
|
||||
if (WLED_WIFI_CONFIGURED) {
|
||||
showWelcomePage = false;
|
||||
|
||||
DEBUG_PRINT(F("Connecting to "));
|
||||
DEBUG_PRINT(clientSSID);
|
||||
DEBUG_PRINTLN("...");
|
||||
@ -846,7 +857,7 @@ void WLED::handleConnection()
|
||||
DEBUG_PRINT(F("Heap too low! "));
|
||||
DEBUG_PRINTLN(heap);
|
||||
forceReconnect = true;
|
||||
strip.purgeSegments(true); // remove all but one segments from memory
|
||||
strip.resetSegments();
|
||||
} else if (heap < MIN_HEAP_SIZE) {
|
||||
strip.purgeSegments();
|
||||
}
|
||||
@ -959,7 +970,7 @@ void WLED::handleStatusLED()
|
||||
#if STATUSLED>=0
|
||||
digitalWrite(STATUSLED, ledStatusState);
|
||||
#else
|
||||
busses.setStatusPixel(ledStatusState ? c : 0);
|
||||
BusManager::setStatusPixel(ledStatusState ? c : 0);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
@ -970,7 +981,7 @@ void WLED::handleStatusLED()
|
||||
digitalWrite(STATUSLED, LOW);
|
||||
#endif
|
||||
#else
|
||||
busses.setStatusPixel(0);
|
||||
BusManager::setStatusPixel(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2312190
|
||||
#define VERSION 2401060
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -319,6 +319,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling
|
||||
#else
|
||||
WLED_GLOBAL bool noWifiSleep _INIT(false);
|
||||
#endif
|
||||
WLED_GLOBAL bool force802_3g _INIT(false);
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified
|
||||
@ -759,7 +760,12 @@ WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN);
|
||||
#endif
|
||||
|
||||
// global ArduinoJson buffer
|
||||
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> doc;
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
WLED_GLOBAL JsonDocument *pDoc _INIT(nullptr);
|
||||
#else
|
||||
WLED_GLOBAL StaticJsonDocument<JSON_BUFFER_SIZE> gDoc;
|
||||
WLED_GLOBAL JsonDocument *pDoc _INIT(&gDoc);
|
||||
#endif
|
||||
WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
|
||||
|
||||
// enable additional debug output
|
||||
|
@ -99,7 +99,7 @@ void loadSettingsFromEEPROM()
|
||||
bool skipFirst = EEPROM.read(2204);
|
||||
bool reversed = EEPROM.read(252);
|
||||
BusConfig bc = BusConfig(EEPROM.read(372) ? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, length, colorOrder, reversed, skipFirst);
|
||||
busses.add(bc);
|
||||
BusManager::add(bc);
|
||||
|
||||
notifyButton = EEPROM.read(230);
|
||||
if (EEPROM.read(231)) udpNumRetries = 1;
|
||||
@ -371,7 +371,7 @@ void deEEP() {
|
||||
DEBUGFS_PRINTLN(F("Allocating saving buffer for dEEP"));
|
||||
if (!requestJSONBufferLock(8)) return;
|
||||
|
||||
JsonObject sObj = doc.to<JsonObject>();
|
||||
JsonObject sObj = pDoc->to<JsonObject>();
|
||||
sObj.createNestedObject("0");
|
||||
|
||||
EEPROM.begin(EEPSIZE);
|
||||
@ -448,7 +448,7 @@ void deEEP() {
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
serializeJson(doc, f);
|
||||
serializeJson(*pDoc, f);
|
||||
f.close();
|
||||
|
||||
releaseJSONBufferLock();
|
||||
|
@ -115,21 +115,21 @@ void handleSerial()
|
||||
bool verboseResponse = false;
|
||||
if (!requestJSONBufferLock(16)) return;
|
||||
Serial.setTimeout(100);
|
||||
DeserializationError error = deserializeJson(doc, Serial);
|
||||
DeserializationError error = deserializeJson(*pDoc, Serial);
|
||||
if (error) {
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
verboseResponse = deserializeState(doc.as<JsonObject>());
|
||||
verboseResponse = deserializeState(pDoc->as<JsonObject>());
|
||||
//only send response if TX pin is unused for other purposes
|
||||
if (verboseResponse && (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut)) {
|
||||
doc.clear();
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
pDoc->clear();
|
||||
JsonObject state = pDoc->createNestedObject("state");
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
JsonObject info = pDoc->createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
|
||||
serializeJson(doc, Serial);
|
||||
serializeJson(*pDoc, Serial);
|
||||
Serial.println();
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
|
@ -15,8 +15,9 @@
|
||||
* Integrated HTTP web server page declarations
|
||||
*/
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request);
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response);
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest* request, int code, uint16_t eTagSuffix = 0);
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0);
|
||||
void handleStaticContent(AsyncWebServerRequest *request, const String &path, int code, const String &contentType, const uint8_t *content, size_t len, bool gzip = true, uint16_t eTagSuffix = 0);
|
||||
|
||||
// define flash strings once (saves flash memory)
|
||||
static const char s_redirecting[] PROGMEM = "Redirecting...";
|
||||
@ -113,22 +114,14 @@ void initServer()
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*");
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
#ifndef WLED_DISABLE_2D
|
||||
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveviewws2D, PAGE_liveviewws2D_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
server.on("/liveview2D", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, "text/html", PAGE_liveviewws2D, PAGE_liveviewws2D_length);
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_liveview, PAGE_liveview_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, "text/html", PAGE_liveview, PAGE_liveview_length);
|
||||
});
|
||||
|
||||
//settings page
|
||||
@ -138,17 +131,12 @@ void initServer()
|
||||
|
||||
// "/settings/settings.js&p=x" request also handled by serveSettings()
|
||||
|
||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "/style.css", 200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length);
|
||||
});
|
||||
|
||||
server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
if (handleFileRead(request, "/favicon.ico")) return;
|
||||
request->send_P(200, "image/x-icon", favicon, 156);
|
||||
handleStaticContent(request, "/favicon.ico", 200, "image/x-icon", favicon, favicon_length, false);
|
||||
});
|
||||
|
||||
server.on("/skin.css", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
@ -180,8 +168,8 @@ void initServer()
|
||||
|
||||
if (!requestJSONBufferLock(14)) return;
|
||||
|
||||
DeserializationError error = deserializeJson(doc, (uint8_t*)(request->_tempObject));
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
DeserializationError error = deserializeJson(*pDoc, (uint8_t*)(request->_tempObject));
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
serveJsonError(request, 400, ERR_JSON);
|
||||
@ -236,12 +224,8 @@ void initServer()
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_USERMOD_PAGE
|
||||
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_usermod, PAGE_usermod_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
server.on("/u", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "", 200, "text/html", PAGE_usermod, PAGE_usermod_length);
|
||||
});
|
||||
#endif
|
||||
|
||||
@ -289,8 +273,9 @@ void initServer()
|
||||
#endif
|
||||
usermods.onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init)
|
||||
lastEditTime = millis(); // make sure PIN does not lock during update
|
||||
strip.suspend();
|
||||
#ifdef ESP8266
|
||||
strip.purgeSegments(true); // free as much memory as you can
|
||||
strip.resetSegments(); // free as much memory as you can
|
||||
Update.runAsync(true);
|
||||
#endif
|
||||
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
|
||||
@ -301,6 +286,7 @@ void initServer()
|
||||
DEBUG_PRINTLN(F("Update Success"));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Update Failed"));
|
||||
strip.resume();
|
||||
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
WLED::instance().enableWatchdog();
|
||||
@ -325,44 +311,29 @@ void initServer()
|
||||
});
|
||||
#endif
|
||||
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
if (captivePortal(request)) return;
|
||||
if (!showWelcomePage || request->hasArg(F("sliders"))){
|
||||
serveIndex(request);
|
||||
if (!showWelcomePage || request->hasArg(F("sliders"))) {
|
||||
handleStaticContent(request, "/index.htm", 200, "text/html", PAGE_index, PAGE_index_L);
|
||||
} else {
|
||||
serveSettings(request);
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
server.on("/pixart.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/pixart.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_pixart, PAGE_pixart_L);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
#ifdef WLED_ENABLE_PIXART
|
||||
server.on("/pixart.htm", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "/pixart.htm", 200, "text/html", PAGE_pixart, PAGE_pixart_L);
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
server.on("/pxmagic.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/pxmagic.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_pxmagic, PAGE_pxmagic_L);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
#ifndef WLED_DISABLE_PXMAGIC
|
||||
server.on("/pxmagic.htm", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "/pxmagic.htm", 200, "text/html", PAGE_pxmagic, PAGE_pxmagic_L);
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
server.on("/cpal.htm", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
if (handleFileRead(request, "/cpal.htm")) return;
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_cpal, PAGE_cpal_L);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
server.on("/cpal.htm", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleStaticContent(request, "/cpal.htm", 200, "text/html", PAGE_cpal, PAGE_cpal_L);
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
@ -388,26 +359,34 @@ void initServer()
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if(espalexa.handleAlexaApiCall(request)) return;
|
||||
#endif
|
||||
if(handleFileRead(request, request->url())) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(404, "text/html", PAGE_404, PAGE_404_length);
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
handleStaticContent(request, request->url(), 404, "text/html", PAGE_404, PAGE_404_length);
|
||||
});
|
||||
}
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest *request) {
|
||||
void generateEtag(char *etag, uint16_t eTagSuffix) {
|
||||
sprintf_P(etag, PSTR("%7d-%02x-%04x"), VERSION, cacheInvalidate, eTagSuffix);
|
||||
}
|
||||
|
||||
bool handleIfNoneMatchCacheHeader(AsyncWebServerRequest *request, int code, uint16_t eTagSuffix) {
|
||||
// Only send 304 (Not Modified) if response code is 200 (OK)
|
||||
if (code != 200) return false;
|
||||
|
||||
AsyncWebHeader *header = request->getHeader("If-None-Match");
|
||||
char etag[11];
|
||||
sprintf_P(etag, PSTR("%7d-%02x"), VERSION, cacheInvalidate);
|
||||
char etag[14];
|
||||
generateEtag(etag, eTagSuffix);
|
||||
if (header && header->value() == etag) {
|
||||
request->send(304);
|
||||
AsyncWebServerResponse *response = request->beginResponse(304);
|
||||
setStaticContentCacheHeaders(response, code, eTagSuffix);
|
||||
request->send(response);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response) {
|
||||
void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix) {
|
||||
// Only send ETag for 200 (OK) responses
|
||||
if (code != 200) return;
|
||||
|
||||
// https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c
|
||||
#ifndef WLED_DEBUG
|
||||
// this header name is misleading, "no-cache" will not disable cache,
|
||||
@ -416,25 +395,37 @@ void setStaticContentCacheHeaders(AsyncWebServerResponse *response) {
|
||||
#else
|
||||
response->addHeader(F("Cache-Control"), "no-store,max-age=0"); // prevent caching if debug build
|
||||
#endif
|
||||
char etag[11];
|
||||
sprintf_P(etag, PSTR("%7d-%02x"), VERSION, cacheInvalidate);
|
||||
char etag[14];
|
||||
generateEtag(etag, eTagSuffix);
|
||||
response->addHeader(F("ETag"), etag);
|
||||
}
|
||||
|
||||
void serveIndex(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (handleFileRead(request, "/index.htm")) return;
|
||||
|
||||
if (handleIfNoneMatchCacheHeader(request)) return;
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L);
|
||||
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
/**
|
||||
* Handels the request for a static file.
|
||||
* If the file was found in the filesystem, it will be sent to the client.
|
||||
* Otherwise it will be checked if the browser cached the file and if so, a 304 response will be sent.
|
||||
* If the file was not found in the filesystem and not in the browser cache, the request will be handled as a 200 response with the content of the page.
|
||||
*
|
||||
* @param request The request object
|
||||
* @param path If a file with this path exists in the filesystem, it will be sent to the client. Set to "" to skip this check.
|
||||
* @param code The HTTP status code
|
||||
* @param contentType The content type of the web page
|
||||
* @param content Content of the web page
|
||||
* @param len Length of the content
|
||||
* @param gzip Optional. Defaults to true. If false, the gzip header will not be added.
|
||||
* @param eTagSuffix Optional. Defaults to 0. A suffix that will be added to the ETag header. This can be used to invalidate the cache for a specific page.
|
||||
*/
|
||||
void handleStaticContent(AsyncWebServerRequest *request, const String &path, int code, const String &contentType, const uint8_t *content, size_t len, bool gzip, uint16_t eTagSuffix) {
|
||||
if (path != "" && handleFileRead(request, path)) return;
|
||||
if (handleIfNoneMatchCacheHeader(request, code, eTagSuffix)) return;
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(code, contentType, content, len);
|
||||
if (gzip) response->addHeader(FPSTR(s_content_enc), "gzip");
|
||||
setStaticContentCacheHeaders(response, code, eTagSuffix);
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
String msgProcessor(const String& var)
|
||||
{
|
||||
if (var == "MSG") {
|
||||
@ -536,13 +527,11 @@ void serveSettingsJS(AsyncWebServerRequest* request)
|
||||
}
|
||||
|
||||
|
||||
void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
{
|
||||
void serveSettings(AsyncWebServerRequest* request, bool post) {
|
||||
byte subPage = 0, originalSubPage = 0;
|
||||
const String& url = request->url();
|
||||
|
||||
if (url.indexOf("sett") >= 0)
|
||||
{
|
||||
if (url.indexOf("sett") >= 0) {
|
||||
if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS;
|
||||
else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS;
|
||||
else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI;
|
||||
@ -603,22 +592,25 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
}
|
||||
}
|
||||
|
||||
AsyncWebServerResponse *response;
|
||||
switch (subPage)
|
||||
{
|
||||
case SUBPAGE_WIFI : response = request->beginResponse_P(200, "text/html", PAGE_settings_wifi, PAGE_settings_wifi_length); break;
|
||||
case SUBPAGE_LEDS : response = request->beginResponse_P(200, "text/html", PAGE_settings_leds, PAGE_settings_leds_length); break;
|
||||
case SUBPAGE_UI : response = request->beginResponse_P(200, "text/html", PAGE_settings_ui, PAGE_settings_ui_length); break;
|
||||
case SUBPAGE_SYNC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sync, PAGE_settings_sync_length); break;
|
||||
case SUBPAGE_TIME : response = request->beginResponse_P(200, "text/html", PAGE_settings_time, PAGE_settings_time_length); break;
|
||||
case SUBPAGE_SEC : response = request->beginResponse_P(200, "text/html", PAGE_settings_sec, PAGE_settings_sec_length); break;
|
||||
int code = 200;
|
||||
String contentType = "text/html";
|
||||
const uint8_t* content;
|
||||
size_t len;
|
||||
|
||||
switch (subPage) {
|
||||
case SUBPAGE_WIFI : content = PAGE_settings_wifi; len = PAGE_settings_wifi_length; break;
|
||||
case SUBPAGE_LEDS : content = PAGE_settings_leds; len = PAGE_settings_leds_length; break;
|
||||
case SUBPAGE_UI : content = PAGE_settings_ui; len = PAGE_settings_ui_length; break;
|
||||
case SUBPAGE_SYNC : content = PAGE_settings_sync; len = PAGE_settings_sync_length; break;
|
||||
case SUBPAGE_TIME : content = PAGE_settings_time; len = PAGE_settings_time_length; break;
|
||||
case SUBPAGE_SEC : content = PAGE_settings_sec; len = PAGE_settings_sec_length; break;
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
case SUBPAGE_DMX : response = request->beginResponse_P(200, "text/html", PAGE_settings_dmx, PAGE_settings_dmx_length); break;
|
||||
case SUBPAGE_DMX : content = PAGE_settings_dmx; len = PAGE_settings_dmx_length; break;
|
||||
#endif
|
||||
case SUBPAGE_UM : response = request->beginResponse_P(200, "text/html", PAGE_settings_um, PAGE_settings_um_length); break;
|
||||
case SUBPAGE_UPDATE : response = request->beginResponse_P(200, "text/html", PAGE_update, PAGE_update_length); break;
|
||||
case SUBPAGE_UM : content = PAGE_settings_um; len = PAGE_settings_um_length; break;
|
||||
case SUBPAGE_UPDATE : content = PAGE_update; len = PAGE_update_length; break;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
case SUBPAGE_2D : response = request->beginResponse_P(200, "text/html", PAGE_settings_2D, PAGE_settings_2D_length); break;
|
||||
case SUBPAGE_2D : content = PAGE_settings_2D; len = PAGE_settings_2D_length; break;
|
||||
#endif
|
||||
case SUBPAGE_LOCK : {
|
||||
correctPIN = !strlen(settingsPIN); // lock if a pin is set
|
||||
@ -626,13 +618,11 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
||||
serveMessage(request, 200, strlen(settingsPIN) > 0 ? PSTR("Settings locked") : PSTR("No PIN set"), FPSTR(s_redirecting), 1);
|
||||
return;
|
||||
}
|
||||
case SUBPAGE_PINREQ : response = request->beginResponse_P(401, "text/html", PAGE_settings_pin, PAGE_settings_pin_length); break;
|
||||
case SUBPAGE_CSS : response = request->beginResponse_P(200, "text/css", PAGE_settingsCss, PAGE_settingsCss_length); break;
|
||||
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||
case SUBPAGE_WELCOME : response = request->beginResponse_P(200, "text/html", PAGE_welcome, PAGE_welcome_length); break;
|
||||
default: response = request->beginResponse_P(200, "text/html", PAGE_settings, PAGE_settings_length); break;
|
||||
case SUBPAGE_PINREQ : content = PAGE_settings_pin; len = PAGE_settings_pin_length; code = 401; break;
|
||||
case SUBPAGE_CSS : content = PAGE_settingsCss; len = PAGE_settingsCss_length; contentType = "text/css"; break;
|
||||
case SUBPAGE_JS : serveSettingsJS(request); return;
|
||||
case SUBPAGE_WELCOME : content = PAGE_welcome; len = PAGE_welcome_length; break;
|
||||
default: content = PAGE_settings; len = PAGE_settings_length; break;
|
||||
}
|
||||
response->addHeader(FPSTR(s_content_enc),"gzip");
|
||||
setStaticContentCacheHeaders(response);
|
||||
request->send(response);
|
||||
handleStaticContent(request, "", code, contentType, content, len);
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
bool verboseResponse = false;
|
||||
if (!requestJSONBufferLock(11)) return;
|
||||
|
||||
DeserializationError error = deserializeJson(doc, data, len);
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
DeserializationError error = deserializeJson(*pDoc, data, len);
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
@ -103,13 +103,13 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
|
||||
if (!requestJSONBufferLock(12)) return;
|
||||
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
JsonObject state = pDoc->createNestedObject("state");
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
JsonObject info = pDoc->createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
|
||||
size_t len = measureJson(doc);
|
||||
DEBUG_PRINTF("JSON buffer size: %u for WS request (%u).\n", doc.memoryUsage(), len);
|
||||
size_t len = measureJson(*pDoc);
|
||||
DEBUG_PRINTF("JSON buffer size: %u for WS request (%u).\n", pDoc->memoryUsage(), len);
|
||||
|
||||
size_t heap1 = ESP.getFreeHeap();
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
@ -136,7 +136,7 @@ void sendDataWs(AsyncWebSocketClient * client)
|
||||
}
|
||||
|
||||
buffer->lock();
|
||||
serializeJson(doc, (char *)buffer->get(), len);
|
||||
serializeJson(*pDoc, (char *)buffer->get(), len);
|
||||
|
||||
DEBUG_PRINT(F("Sending WS data "));
|
||||
if (client) {
|
||||
|
@ -133,7 +133,7 @@ void appendGPIOinfo() {
|
||||
// usermod pin reservations will become unnecessary when settings pages will read cfg.json directly
|
||||
if (requestJSONBufferLock(6)) {
|
||||
// if we can't allocate JSON buffer ignore usermod pins
|
||||
JsonObject mods = doc.createNestedObject(F("um"));
|
||||
JsonObject mods = pDoc->createNestedObject(F("um"));
|
||||
usermods.addToConfig(mods);
|
||||
if (!mods.isNull()) fillUMPins(mods);
|
||||
releaseJSONBufferLock();
|
||||
@ -277,6 +277,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappends('s',SET_F("AP"),fapass);
|
||||
|
||||
sappend('v',SET_F("AC"),apChannel);
|
||||
sappend('c',SET_F("FG"),force802_3g);
|
||||
sappend('c',SET_F("WS"),noWifiSleep);
|
||||
|
||||
#ifndef WLED_DISABLE_ESPNOW
|
||||
@ -355,8 +356,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("LD"),useGlobalLedBuffer);
|
||||
|
||||
uint16_t sumMa = 0;
|
||||
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
|
||||
Bus* bus = busses.getBus(s);
|
||||
for (uint8_t s=0; s < BusManager::getNumBusses(); s++) {
|
||||
Bus* bus = BusManager::getBus(s);
|
||||
if (bus == nullptr) continue;
|
||||
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
|
||||
@ -376,7 +377,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
for (uint8_t i = 0; i < nPins; i++) {
|
||||
lp[1] = 48+i;
|
||||
if (pinManager.isPinOk(pins[i]) || bus->getType()>=TYPE_NET_DDP_RGB) sappend('v',lp,pins[i]);
|
||||
if (pinManager.isPinOk(pins[i]) || IS_VIRTUAL(bus->getType())) sappend('v',lp,pins[i]);
|
||||
}
|
||||
sappend('v',lc,bus->getLength());
|
||||
sappend('v',lt,bus->getType());
|
||||
@ -388,16 +389,16 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',aw,bus->getAutoWhiteMode());
|
||||
sappend('v',wo,bus->getColorOrder() >> 4);
|
||||
uint16_t speed = bus->getFrequency();
|
||||
if (bus->getType() > TYPE_ONOFF && bus->getType() < 48) {
|
||||
if (IS_PWM(bus->getType())) {
|
||||
switch (speed) {
|
||||
case WLED_PWM_FREQ/3 : speed = 0; break;
|
||||
case WLED_PWM_FREQ/2 : speed = 1; break;
|
||||
case WLED_PWM_FREQ/3 : speed = 0; break;
|
||||
case WLED_PWM_FREQ/2 : speed = 1; break;
|
||||
default:
|
||||
case WLED_PWM_FREQ : speed = 2; break;
|
||||
case WLED_PWM_FREQ*2 : speed = 3; break;
|
||||
case WLED_PWM_FREQ*3 : speed = 4; break;
|
||||
case WLED_PWM_FREQ : speed = 2; break;
|
||||
case WLED_PWM_FREQ*4/3 : speed = 3; break;
|
||||
case WLED_PWM_FREQ*2 : speed = 4; break;
|
||||
}
|
||||
} else {
|
||||
} else if (IS_DIGITAL(bus->getType()) && IS_2PIN(bus->getType())) {
|
||||
switch (speed) {
|
||||
case 1000 : speed = 0; break;
|
||||
case 2000 : speed = 1; break;
|
||||
@ -412,22 +413,13 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',ma,bus->getMaxCurrent());
|
||||
sumMa += bus->getMaxCurrent();
|
||||
}
|
||||
sappend('c',SET_F("PPL"),(sumMa>0 && abs(sumMa - strip.ablMilliampsMax)>2)); // approxiamte detection if per-output limiter is enabled
|
||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||
/*
|
||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||
if (strip.currentMilliamps)
|
||||
{
|
||||
sappends('m',SET_F("(\"pow\")[0]"),(char*)"");
|
||||
olen -= 2; //delete ";
|
||||
oappendi(strip.currentMilliamps);
|
||||
oappend(SET_F("mA\";"));
|
||||
}
|
||||
*/
|
||||
sappend('v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa);
|
||||
sappend('c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0);
|
||||
|
||||
oappend(SET_F("resetCOM("));
|
||||
oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10));
|
||||
oappend(SET_F(");"));
|
||||
const ColorOrderMap& com = busses.getColorOrderMap();
|
||||
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
||||
for (uint8_t s=0; s < com.count(); s++) {
|
||||
const ColorOrderMapEntry* entry = com.get(s);
|
||||
if (entry == nullptr) break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user