Porównaj commity

...

11 Commity

Autor SHA1 Wiadomość Data
Christian Schwinne be64e80ae6
Merge 028b77d3f7 into 6f3d7e76c9 2024-04-19 21:11:30 -03:00
Christian Schwinne 028b77d3f7 Proper debug statements 2024-04-13 20:06:33 +02:00
Christian Schwinne 3aca770040 Merge branch '0_15' into gif 2024-04-13 20:06:08 +02:00
Christian Schwinne 95b25ce526 Include gif library for all esp32 variants 2024-03-19 22:53:43 +01:00
Christian Schwinne 23f35a76ea Update pio version 2024-03-19 22:39:33 +01:00
Christian Schwinne 0481eb38ab Merge 0_15 2024-03-19 22:03:55 +01:00
Christian Schwinne 247de600af Fix missing GIF enable macros 2024-03-17 22:57:15 +01:00
Christian Schwinne 3e60d3d96e Working GIF support 2024-03-17 22:24:55 +01:00
Christian Schwinne b2afac8914 GIFs work again in principle 2024-03-10 21:36:13 +01:00
Christian Schwinne 3ad56ea103 GIF testing 2024-03-10 14:34:15 +01:00
Christian Schwinne 1f25edc737
Merge pull request #3805 from Aircoookie/0_15
update gif with new changes
2024-03-09 19:44:42 +01:00
10 zmienionych plików z 395 dodań i 208 usunięć

Wyświetl plik

@ -46,6 +46,10 @@
- ESPAsyncWebServer 2.2.0 (#3828 by @willmmiles)
- Bugfixes: #3843, #3844
#### Build 2403191
- Add Image effect (GIF playback from FS support)
#### Build 2403190
- limit max PWM frequency (fix incorrect PWM resolution)
- Segment UI bugfix

Wyświetl plik

@ -207,6 +207,12 @@ lib_deps =
ESPAsyncUDP
${env.lib_deps}
[esp32_all_variants]
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
bitbank2/AnimatedGIF@^1.4.7
https://github.com/Aircoookie/GifDecoder#bc3af18
[esp32]
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
platform = espressif32@3.5.0
@ -221,7 +227,7 @@ build_flags = -g
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
lib_deps =
https://github.com/lorol/LITTLEFS.git
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${esp32_all_variants.lib_deps}
${env.lib_deps}
# additional build flags for audioreactive
AR_build_flags = -D USERMOD_AUDIOREACTIVE
@ -242,7 +248,7 @@ build_flags = -g
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${esp32_all_variants.lib_deps}
${env.lib_deps}
[esp32s2]
@ -261,7 +267,7 @@ build_flags = -g
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
;; ARDUINO_USB_CDC_ON_BOOT
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${esp32_all_variants.lib_deps}
${env.lib_deps}
[esp32c3]
@ -278,7 +284,7 @@ build_flags = -g
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
;; ARDUINO_USB_CDC_ON_BOOT
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${esp32_all_variants.lib_deps}
${env.lib_deps}
[esp32s3]
@ -297,7 +303,7 @@ build_flags = -g
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
lib_deps =
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
${esp32_all_variants.lib_deps}
${env.lib_deps}

Wyświetl plik

@ -1,11 +1,9 @@
#
# This file is autogenerated by pip-compile with Python 3.12
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile
#
aiofiles==22.1.0
# via platformio
ajsonrpc==1.2.0
# via platformio
anyio==3.6.2

Wyświetl plik

@ -4474,6 +4474,24 @@ uint16_t mode_washing_machine(void) {
static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,!;;!";
/*
Image effect
Draws a .gif image from filesystem on the matrix/strip
*/
uint16_t mode_image(void) {
#ifdef WLED_DISABLE_GIF
return mode_static();
#else
renderImageToSegment(SEGMENT);
return FRAMETIME;
#endif
// if (status != 0 && status != 254 && status != 255) {
// Serial.print("GIF renderer return: ");
// Serial.println(status);
// }
}
static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128";
/*
Blends random colors across palette
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
@ -7977,7 +7995,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS);
addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE);
addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL);
addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE);
addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE);
addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE);
addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE);

Wyświetl plik

@ -175,7 +175,7 @@
#define FX_MODE_TWO_DOTS 50
#define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity)
#define FX_MODE_RUNNING_DUAL 52
// #define FX_MODE_HALLOWEEN 53 // removed in 0.14!
#define FX_MODE_IMAGE 53 // was Halloween before 0.14
#define FX_MODE_TRICOLOR_CHASE 54
#define FX_MODE_TRICOLOR_WIPE 55
#define FX_MODE_TRICOLOR_FADE 56

Wyświetl plik

@ -199,6 +199,9 @@ void Segment::resetIfRequired() {
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;
#ifndef WLED_DISABLE_GIF
endImagePlayback(this);
#endif
}
CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {

Wyświetl plik

@ -126,6 +126,19 @@ void onHueConnect(void* arg, AsyncClient* client);
void sendHuePoll();
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
#include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend)
//image_loader.cpp
#ifndef WLED_DISABLE_GIF
bool fileSeekCallback(unsigned long position);
unsigned long filePositionCallback(void);
int fileReadCallback(void);
int fileReadBlockCallback(void * buffer, int numberOfBytes);
int fileSizeCallback(void);
byte renderImageToSegment(Segment &seg);
void endImagePlayback(Segment* seg);
#endif
//improv.cpp
enum ImprovRPCType {
Command_Wifi = 0x01,
@ -163,7 +176,6 @@ void handleIR();
#include "ESPAsyncWebServer.h"
#include "src/dependencies/json/ArduinoJson-v6.h"
#include "src/dependencies/json/AsyncJson-v6.h"
#include "FX.h"
bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);

Wyświetl plik

@ -0,0 +1,144 @@
#include "wled.h"
#ifndef WLED_DISABLE_GIF
#include "GifDecoder.h"
/*
* Functions to render images from filesystem to segments, used by the "Image" effect
*/
File file;
char lastFilename[34] = "/";
GifDecoder<320,320,12,true> decoder;
bool gifDecodeFailed = false;
unsigned long lastFrameDisplayTime = 0, currentFrameDelay = 0;
bool fileSeekCallback(unsigned long position) {
return file.seek(position);
}
unsigned long filePositionCallback(void) {
return file.position();
}
int fileReadCallback(void) {
return file.read();
}
int fileReadBlockCallback(void * buffer, int numberOfBytes) {
return file.read((uint8_t*)buffer, numberOfBytes);
}
int fileSizeCallback(void) {
return file.size();
}
bool openGif(const char *filename) {
file = WLED_FS.open(filename, "r");
if (!file) return false;
return true;
}
Segment* activeSeg;
uint16_t gifWidth, gifHeight;
void screenClearCallback(void) {
activeSeg->fill(0);
}
void updateScreenCallback(void) {}
void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue) {
// simple nearest-neighbor scaling
int16_t outY = y * activeSeg->height() / gifHeight;
int16_t outX = x * activeSeg->width() / gifWidth;
// set multiple pixels if upscaling
for (int16_t i = 0; i < (activeSeg->width()+(gifWidth-1)) / gifWidth; i++) {
for (int16_t j = 0; j < (activeSeg->height()+(gifHeight-1)) / gifHeight; j++) {
activeSeg->setPixelColorXY(outX + i, outY + j, gamma8(red), gamma8(green), gamma8(blue));
}
}
}
#define IMAGE_ERROR_NONE 0
#define IMAGE_ERROR_NO_NAME 1
#define IMAGE_ERROR_SEG_LIMIT 2
#define IMAGE_ERROR_UNSUPPORTED_FORMAT 3
#define IMAGE_ERROR_FILE_MISSING 4
#define IMAGE_ERROR_DECODER_ALLOC 5
#define IMAGE_ERROR_GIF_DECODE 6
#define IMAGE_ERROR_FRAME_DECODE 7
#define IMAGE_ERROR_WAITING 254
#define IMAGE_ERROR_PREV 255
// renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment
byte renderImageToSegment(Segment &seg) {
if (!seg.name) return IMAGE_ERROR_NO_NAME;
// disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining
if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING;
if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time
activeSeg = &seg;
if (strncmp(lastFilename +1, seg.name, 32) != 0) { // segment name changed, load new image
strncpy(lastFilename +1, seg.name, 32);
gifDecodeFailed = false;
if (strcmp(lastFilename + strlen(lastFilename) - 4, ".gif") != 0) {
gifDecodeFailed = true;
return IMAGE_ERROR_UNSUPPORTED_FORMAT;
}
if (file) file.close();
openGif(lastFilename);
if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; }
decoder.setScreenClearCallback(screenClearCallback);
decoder.setUpdateScreenCallback(updateScreenCallback);
decoder.setDrawPixelCallback(drawPixelCallback);
decoder.setFileSeekCallback(fileSeekCallback);
decoder.setFilePositionCallback(filePositionCallback);
decoder.setFileReadCallback(fileReadCallback);
decoder.setFileReadBlockCallback(fileReadBlockCallback);
decoder.setFileSizeCallback(fileSizeCallback);
decoder.alloc();
DEBUG_PRINTLN(F("Starting decoding"));
if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; }
DEBUG_PRINTLN(F("Decoding started"));
}
if (gifDecodeFailed) return IMAGE_ERROR_PREV;
if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; }
//if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; }
// speed 0 = half speed, 128 = normal, 255 = full FX FPS
// TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast
uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128;
// TODO consider handling this on FX level with a different frametime, but that would cause slow gifs to speed up during transitions
if (millis() - lastFrameDisplayTime < wait) return IMAGE_ERROR_WAITING;
decoder.getSize(&gifWidth, &gifHeight);
int result = decoder.decodeFrame(false);
if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; }
currentFrameDelay = decoder.getFrameDelay_ms();
unsigned long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate
currentFrameDelay = tooSlowBy > currentFrameDelay ? 0 : currentFrameDelay - tooSlowBy;
lastFrameDisplayTime = millis();
return IMAGE_ERROR_NONE;
}
void endImagePlayback(Segment *seg) {
DEBUG_PRINTLN(F("Image playback end called"));
if (!activeSeg || activeSeg != seg) return;
if (file) file.close();
decoder.dealloc();
gifDecodeFailed = false;
activeSeg = nullptr;
lastFilename[1] = '\0';
DEBUG_PRINTLN(F("Image playback ended"));
}
#endif

Wyświetl plik

@ -81,6 +81,8 @@
#define WIFI_MODE_AP WIFI_AP
#include <QuickEspNow.h>
#endif
#undef WLED_DISABLE_GIF
#define WLED_DISABLE_GIF
#else // ESP32
#include <HardwareSerial.h> // ensure we have the correct "Serial" on new MCUs (depends on ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT)
#include <WiFi.h>