Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
11b0b75e26 | ||
|
214d4364f1 | ||
|
7c3b96c0e1 | ||
|
82faa46531 | ||
|
63acddf1a5 | ||
|
a84e242a37 | ||
|
148de04e6f | ||
|
4f4b6ca253 | ||
|
776971db2c | ||
|
301cacc91d |
@ -158,6 +158,7 @@ lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.4.0
|
||||
IRremoteESP8266 @ 2.7.18
|
||||
wasm3/Wasm3 @ 0.5.0
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.2
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
|
@ -38,6 +38,32 @@ uint16_t WS2812FX::mode_static(void) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Custom mode. Executes WebAssembly fx() function
|
||||
*/
|
||||
uint16_t WS2812FX::mode_custom(void) {
|
||||
if (SEGENV.call == 0) wasmfx.init();
|
||||
wasmfx.run();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//testing TEMP
|
||||
uint16_t WS2812FX::mode_benchmark(void) {
|
||||
uint32_t i=(now/4);
|
||||
uint32_t c=0;
|
||||
while(c<SEGLEN){
|
||||
uint32_t v=i%256;
|
||||
setPixelColor(c,v,v/2,0);
|
||||
c++;
|
||||
i=(i+SEGMENT.speed/16+1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Blink/strobe function
|
||||
* Alternate between color1 and color2
|
||||
|
25
wled00/FX.h
25
wled00/FX.h
@ -69,7 +69,7 @@
|
||||
#endif
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
#define MIN_SHOW_DELAY 15
|
||||
#define MIN_SHOW_DELAY 1
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT _segments[_segment_index]
|
||||
@ -113,7 +113,7 @@
|
||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||
|
||||
#define MODE_COUNT 118
|
||||
#define MODE_COUNT 120
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@ -233,6 +233,8 @@
|
||||
#define FX_MODE_BLENDS 115
|
||||
#define FX_MODE_TV_SIMULATOR 116
|
||||
#define FX_MODE_DYNAMIC_SMOOTH 117
|
||||
#define FX_MODE_CUSTOM 118
|
||||
#define FX_MODE_BENCHMARK 119
|
||||
|
||||
|
||||
class WS2812FX {
|
||||
@ -378,12 +380,16 @@ class WS2812FX {
|
||||
*/
|
||||
void resetIfRequired() {
|
||||
if (_requiresReset) {
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
deallocateData();
|
||||
_requiresReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isResetRequired() {
|
||||
return _requiresReset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
@ -594,6 +600,8 @@ class WS2812FX {
|
||||
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
|
||||
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
|
||||
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
|
||||
_mode[FX_MODE_CUSTOM] = &WS2812FX::mode_custom;
|
||||
_mode[FX_MODE_BENCHMARK] = &WS2812FX::mode_benchmark;
|
||||
|
||||
_brightness = DEFAULT_BRIGHTNESS;
|
||||
currentPalette = CRGBPalette16(CRGB::Black);
|
||||
@ -816,7 +824,9 @@ class WS2812FX {
|
||||
mode_candy_cane(void),
|
||||
mode_blends(void),
|
||||
mode_tv_simulator(void),
|
||||
mode_dynamic_smooth(void);
|
||||
mode_dynamic_smooth(void),
|
||||
mode_custom(void),
|
||||
mode_benchmark(void);
|
||||
|
||||
private:
|
||||
uint32_t crgb_to_col(CRGB fastled);
|
||||
@ -892,6 +902,7 @@ class WS2812FX {
|
||||
|
||||
ColorTransition transitions[MAX_NUM_TRANSITIONS]; //12 bytes per element
|
||||
friend class ColorTransition;
|
||||
friend class WASMFX;
|
||||
|
||||
uint16_t
|
||||
realPixelIndex(uint16_t i),
|
||||
@ -903,15 +914,15 @@ const char JSON_mode_names[] PROGMEM = R"=====([
|
||||
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
|
||||
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
|
||||
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Chase 2","Aurora","Stream",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Tetrix","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Two Dots","Two Areas","Running Dual","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||
"Two Dots","Two Areas","Running Dual","Halloween","Chase 3","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
||||
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
|
||||
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth"
|
||||
"Flow","Chunchun","Dancing Shadows","Washing Machine","Candy Cane","Blends","TV Simulator","Dynamic Smooth","Custom","Benchmark"
|
||||
])=====";
|
||||
|
||||
|
||||
|
@ -144,6 +144,7 @@ void WS2812FX::service() {
|
||||
|
||||
// reset the segment runtime data if needed, called before isActive to ensure deleted
|
||||
// segment's buffers are cleared
|
||||
if (SEGENV.isResetRequired()) wasmfx.end();
|
||||
SEGENV.resetIfRequired();
|
||||
|
||||
if (!SEGMENT.isActive()) continue;
|
||||
|
@ -249,6 +249,15 @@
|
||||
#define MAX_LEDS_PER_BUS 4096
|
||||
#endif
|
||||
|
||||
#ifndef MAX_WASM_BIN_SIZE
|
||||
#define MAX_WASM_BIN_SIZE 8192
|
||||
#endif
|
||||
|
||||
#define WASM_STATE_UNLOADED 0
|
||||
#define WASM_STATE_READY 1 //wasm runtime allocated
|
||||
#define WASM_STATE_STALE 2 //inited, but wasm_buffer has updated. Runtime re-init required.
|
||||
#define WASM_STATE_ERROR 3 //runtime wasm error
|
||||
|
||||
// string temp buffer (now stored in stack locally)
|
||||
#define OMAX 2048
|
||||
|
||||
|
@ -82,6 +82,7 @@ bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* conte
|
||||
bool writeObjectToFile(const char* file, const char* key, JsonDocument* content);
|
||||
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest);
|
||||
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest);
|
||||
bool readToBuffer(const char* file, uint8_t** buf, uint32_t* len);
|
||||
void updateFSInfo();
|
||||
void closeFile();
|
||||
|
||||
@ -249,6 +250,32 @@ void userSetup();
|
||||
void userConnected();
|
||||
void userLoop();
|
||||
|
||||
//wasm.cpp
|
||||
void wasmInit();
|
||||
void wasmRunTask();
|
||||
void wasmEnd();
|
||||
|
||||
class WASMFX {
|
||||
public:
|
||||
void init() {
|
||||
wasmInit();
|
||||
}
|
||||
|
||||
void run() {
|
||||
wasmRunTask();
|
||||
}
|
||||
|
||||
void end() {
|
||||
wasmEnd();
|
||||
}
|
||||
|
||||
uint32_t now();
|
||||
uint32_t speed();
|
||||
uint32_t intensity();
|
||||
uint32_t len();
|
||||
void set(uint32_t i, uint32_t r, uint32_t g, uint32_t b);
|
||||
};
|
||||
|
||||
//wled_eeprom.cpp
|
||||
void applyMacro(byte index);
|
||||
void deEEP();
|
||||
|
@ -409,3 +409,21 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//provide maximum buffer size in len variable
|
||||
//if this returns true, the buffer array must be deleted by the caller
|
||||
bool readToBuffer(const char* file, uint8_t** buf, uint32_t* len) {
|
||||
Serial.println("opening file");
|
||||
File f = WLED_FS.open(file,"r");
|
||||
if (!f) return false;
|
||||
uint32_t sz = f.size();
|
||||
Serial.println(sz);
|
||||
if (!sz || sz > *len) {f.close(); return false;}
|
||||
*buf = new uint8_t[sz];
|
||||
if (!*buf) {f.close(); return false;}
|
||||
*len = sz;
|
||||
f.read(*buf, sz);
|
||||
f.close();
|
||||
Serial.println("done");
|
||||
return true;
|
||||
}
|
319
wled00/wasm.cpp
Normal file
319
wled00/wasm.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
#include <wasm3.h>
|
||||
#include <m3_env.h>
|
||||
#include "wled.h"
|
||||
|
||||
#define WASM_STACK_SLOTS 1024
|
||||
#define NATIVE_STACK_SIZE (32*1024)
|
||||
|
||||
// For (most) devices that cannot allocate a 64KiB wasm page
|
||||
#define WASM_MEMORY_LIMIT 4096
|
||||
|
||||
/*unsigned char app_wasm[] = {
|
||||
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x03, 0x60,
|
||||
0x00, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x60, 0x00,
|
||||
0x00, 0x02, 0x2b, 0x04, 0x03, 0x6c, 0x65, 0x64, 0x03, 0x6e, 0x6f, 0x77,
|
||||
0x00, 0x00, 0x03, 0x6c, 0x65, 0x64, 0x03, 0x6c, 0x65, 0x6e, 0x00, 0x00,
|
||||
0x03, 0x6c, 0x65, 0x64, 0x03, 0x73, 0x65, 0x74, 0x00, 0x01, 0x03, 0x6c,
|
||||
0x65, 0x64, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x00, 0x00, 0x03, 0x02,
|
||||
0x01, 0x02, 0x05, 0x03, 0x01, 0x00, 0x00, 0x07, 0x0f, 0x02, 0x02, 0x66,
|
||||
0x78, 0x00, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
|
||||
0x0a, 0x45, 0x01, 0x43, 0x01, 0x04, 0x7f, 0x10, 0x00, 0x41, 0x02, 0x76,
|
||||
0x21, 0x00, 0x10, 0x01, 0x21, 0x02, 0x03, 0x40, 0x20, 0x01, 0x20, 0x02,
|
||||
0x49, 0x04, 0x40, 0x20, 0x01, 0x20, 0x00, 0x41, 0xff, 0x01, 0x71, 0x22,
|
||||
0x03, 0x20, 0x03, 0x41, 0x01, 0x76, 0x41, 0x00, 0x10, 0x02, 0x20, 0x00,
|
||||
0x10, 0x03, 0x41, 0x04, 0x76, 0x41, 0x01, 0x6a, 0x6a, 0x21, 0x00, 0x20,
|
||||
0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x01, 0x0b, 0x0b, 0x0b, 0x00,
|
||||
0x20, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x61, 0x70, 0x70,
|
||||
0x69, 0x6e, 0x67, 0x55, 0x52, 0x4c, 0x0e, 0x2e, 0x2f, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x77, 0x61, 0x73, 0x6d, 0x2e, 0x6d, 0x61, 0x70
|
||||
};*/
|
||||
//unsigned int app_wasm_len = 201;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* API bindings
|
||||
*
|
||||
* Note: each RawFunction should complete with one of these calls:
|
||||
* m3ApiReturn(val) - Returns a value
|
||||
* m3ApiSuccess() - Returns void (and no traps)
|
||||
* m3ApiTrap(trap) - Returns a trap
|
||||
*/
|
||||
|
||||
m3ApiRawFunction(m3_arduino_millis)
|
||||
{
|
||||
m3ApiReturnType (uint32_t)
|
||||
|
||||
m3ApiReturn(millis());
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_arduino_delay)
|
||||
{
|
||||
m3ApiGetArg (uint32_t, ms)
|
||||
|
||||
// You can also trace API calls
|
||||
Serial.print("api: delay "); Serial.println(ms);
|
||||
|
||||
//delay(ms);
|
||||
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
// This maps pin modes from arduino_wasm_api.h
|
||||
// to actual platform-specific values
|
||||
uint8_t mapPinMode(uint8_t mode)
|
||||
{
|
||||
switch(mode) {
|
||||
case 0: return INPUT;
|
||||
case 1: return OUTPUT;
|
||||
case 2: return INPUT_PULLUP;
|
||||
}
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_arduino_pinMode)
|
||||
{
|
||||
m3ApiGetArg (uint32_t, pin)
|
||||
m3ApiGetArg (uint32_t, mode)
|
||||
|
||||
pinMode(pin, (uint8_t)mapPinMode(mode));
|
||||
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_arduino_digitalWrite)
|
||||
{
|
||||
m3ApiGetArg (uint32_t, pin)
|
||||
m3ApiGetArg (uint32_t, value)
|
||||
|
||||
digitalWrite(pin, value);
|
||||
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_arduino_getPinLED)
|
||||
{
|
||||
m3ApiReturnType (uint32_t)
|
||||
|
||||
m3ApiReturn(2);
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_arduino_print)
|
||||
{
|
||||
m3ApiGetArgMem (const uint8_t *, buf)
|
||||
m3ApiGetArg (uint32_t, len)
|
||||
|
||||
Serial.write(buf, len);
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_now) {
|
||||
m3ApiReturnType(uint32_t)
|
||||
m3ApiReturn(wasmfx.now());
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_speed) {
|
||||
m3ApiReturnType(uint32_t)
|
||||
m3ApiReturn(wasmfx.speed());//strip._segments[strip._segment_index].speed);
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_intensity) {
|
||||
m3ApiReturnType(uint32_t)
|
||||
m3ApiReturn(wasmfx.intensity());//strip._segments[strip._segment_index].intensity);
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_len) {
|
||||
m3ApiReturnType(uint32_t)
|
||||
m3ApiReturn(wasmfx.len());//strip._virtualSegmentLength);
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_fill) {
|
||||
m3ApiGetArg (uint32_t, color)
|
||||
|
||||
strip.fill(color);
|
||||
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_set) {
|
||||
m3ApiGetArg (uint32_t, index)
|
||||
m3ApiGetArg (uint32_t, r)
|
||||
m3ApiGetArg (uint32_t, g)
|
||||
m3ApiGetArg (uint32_t, b)
|
||||
|
||||
strip.setPixelColor(index, r,g,b);
|
||||
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
m3ApiRawFunction(m3_led_rgb) {
|
||||
m3ApiGetArg (uint32_t, r)
|
||||
m3ApiGetArg (uint32_t, g)
|
||||
m3ApiGetArg (uint32_t, b)
|
||||
|
||||
m3ApiReturnType(uint32_t)
|
||||
uint32_t c = (r << 16) + (g << 8) + b;
|
||||
m3ApiReturn(c);
|
||||
}
|
||||
|
||||
M3Result LinkArduino (IM3Runtime runtime)
|
||||
{
|
||||
IM3Module module = runtime->modules;
|
||||
const char* arduino = "arduino";
|
||||
const char* led = "led";
|
||||
|
||||
m3_LinkRawFunction (module, arduino, "millis", "i()", &m3_arduino_millis);
|
||||
m3_LinkRawFunction (module, arduino, "delay", "v(i)", &m3_arduino_delay); //temp
|
||||
m3_LinkRawFunction (module, arduino, "pinMode", "v(ii)", &m3_arduino_pinMode); //temp
|
||||
m3_LinkRawFunction (module, arduino, "digitalWrite", "v(ii)", &m3_arduino_digitalWrite); //temp
|
||||
|
||||
// Test functions
|
||||
m3_LinkRawFunction (module, arduino, "getPinLED", "i()", &m3_arduino_getPinLED); //temp
|
||||
m3_LinkRawFunction (module, arduino, "print", "v(*i)", &m3_arduino_print);
|
||||
|
||||
//WLED functions
|
||||
m3_LinkRawFunction (module, led, "now", "i()", &m3_led_now);
|
||||
m3_LinkRawFunction (module, led, "speed", "i()", &m3_led_speed);
|
||||
m3_LinkRawFunction (module, led, "intensity", "i()", &m3_led_intensity);
|
||||
m3_LinkRawFunction (module, led, "len", "i()", &m3_led_len);
|
||||
m3_LinkRawFunction (module, led, "fill", "v(i)", &m3_led_fill);
|
||||
m3_LinkRawFunction (module, led, "set", "v(iiii)",&m3_led_set);
|
||||
m3_LinkRawFunction (module, led, "rgb", "i(iii)", &m3_led_rgb);
|
||||
|
||||
return m3Err_none;
|
||||
}
|
||||
|
||||
/*
|
||||
* Engine start, liftoff!
|
||||
*/
|
||||
|
||||
#define FATAL(func, msg) { Serial.print("Fatal: " func " "); Serial.println(msg); return; }
|
||||
|
||||
M3Result result;
|
||||
IM3Environment env;
|
||||
IM3Runtime runtime;
|
||||
IM3Module module;
|
||||
IM3Function fu;
|
||||
|
||||
//uint32_t app_wasm_len = MAX_WASM_BIN_SIZE;
|
||||
//uint8_t* app_wasm = nullptr;
|
||||
|
||||
void wasm_task(void*)
|
||||
{
|
||||
result = m3Err_none;
|
||||
|
||||
env = m3_NewEnvironment ();
|
||||
if (!env) FATAL("NewEnv", "failed");
|
||||
|
||||
runtime = m3_NewRuntime (env, WASM_STACK_SLOTS, NULL);
|
||||
if (!runtime) FATAL("NewRt", "failed");
|
||||
|
||||
#ifdef WASM_MEMORY_LIMIT
|
||||
runtime->memoryLimit = WASM_MEMORY_LIMIT;
|
||||
#endif
|
||||
|
||||
if (!wasm_buffer) { //from filesystem (fx.wasm)
|
||||
wasm_buffer_len = MAX_WASM_BIN_SIZE;
|
||||
if (!readToBuffer("/fx.wasm", &wasm_buffer, &wasm_buffer_len)) {
|
||||
result = "fload";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Serial.println(app_wasm_len);
|
||||
//Serial.println((uint32_t)app_wasm);
|
||||
|
||||
if (wasm_buffer == nullptr) {
|
||||
result = "npr";
|
||||
return;
|
||||
}
|
||||
|
||||
result = m3_ParseModule (env, &module, wasm_buffer, wasm_buffer_len);
|
||||
if (result) FATAL("Prs", result);
|
||||
|
||||
delete[] wasm_buffer; wasm_buffer = nullptr; wasm_buffer_len = 0;
|
||||
|
||||
result = m3_LoadModule (runtime, module);
|
||||
if (result) FATAL("Load", result);
|
||||
|
||||
result = LinkArduino (runtime);
|
||||
if (result) FATAL("Lnk", result);
|
||||
|
||||
result = m3_FindFunction (&fu, runtime, "fx");
|
||||
if (result) FATAL("Func", result);
|
||||
|
||||
Serial.println(F("WASM init success!"));
|
||||
wasm_state = WASM_STATE_READY;
|
||||
}
|
||||
|
||||
void wasmInit()
|
||||
{
|
||||
if (runtime || env) wasmEnd();
|
||||
wasm_task(NULL);
|
||||
}
|
||||
|
||||
volatile bool wasmRunning = false;
|
||||
|
||||
void wasmRun(void * parameter) {
|
||||
result = m3_CallV(fu);
|
||||
|
||||
if (result) {
|
||||
M3ErrorInfo info;
|
||||
m3_GetErrorInfo (runtime, &info);
|
||||
Serial.print("Err: ");
|
||||
Serial.print(result);
|
||||
Serial.print(" (");
|
||||
Serial.print(info.message);
|
||||
Serial.println(")");
|
||||
if (info.file && strlen(info.file) && info.line) {
|
||||
Serial.print("At ");
|
||||
Serial.print(info.file);
|
||||
Serial.print(":");
|
||||
Serial.println(info.line);
|
||||
}
|
||||
wasm_state = WASM_STATE_ERROR;
|
||||
}
|
||||
wasmRunning = false;
|
||||
#ifdef ESP32
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wasmRunTask() {
|
||||
//re-init after wasm_buffer refresh
|
||||
if (wasm_state == WASM_STATE_STALE) wasmInit();
|
||||
|
||||
if (wasm_state != WASM_STATE_READY) return;
|
||||
|
||||
if (result) {
|
||||
Serial.print("WASM run error");
|
||||
Serial.println(result);
|
||||
wasm_state = WASM_STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
// On ESP32, we can launch in a separate thread
|
||||
wasmRunning = true;
|
||||
unsigned long startTime = millis();
|
||||
TaskHandle_t xHandle = NULL;
|
||||
xTaskCreate(&wasmRun, "wasm3", 8096, NULL, 1, &xHandle);
|
||||
while (wasmRunning) {
|
||||
if (millis() - startTime > 250) { //bail
|
||||
if (xHandle != NULL) vTaskDelete(xHandle);
|
||||
wasmRunning = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
wasmRun(nullptr); //no hang protection (e.g. "while (true);")
|
||||
#endif
|
||||
}
|
||||
|
||||
void wasmEnd() {
|
||||
//if (module) m3_FreeModule(module); module = nullptr;
|
||||
Serial.println("F");
|
||||
if (runtime) m3_FreeRuntime(runtime); runtime = nullptr;
|
||||
if (env) m3_FreeEnvironment(env); env = nullptr;
|
||||
Serial.println("F later");
|
||||
wasm_state = WASM_STATE_UNLOADED;
|
||||
}
|
17
wled00/wasmfx.cpp
Normal file
17
wled00/wasmfx.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "wled.h"
|
||||
|
||||
uint32_t WASMFX::now() {
|
||||
return strip.now;
|
||||
}
|
||||
|
||||
uint32_t WASMFX::speed() {
|
||||
return strip._segments[strip._segment_index].speed;
|
||||
}
|
||||
|
||||
uint32_t WASMFX::intensity() {
|
||||
return strip._segments[strip._segment_index].intensity;
|
||||
}
|
||||
|
||||
uint32_t WASMFX::len() {
|
||||
return strip._virtualSegmentLength;
|
||||
}
|
@ -588,6 +588,12 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after
|
||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||
|
||||
// WASM
|
||||
WLED_GLOBAL WASMFX wasmfx _INIT(WASMFX());
|
||||
WLED_GLOBAL uint8_t* wasm_buffer _INIT(nullptr);
|
||||
WLED_GLOBAL uint32_t wasm_buffer_len _INIT(0);
|
||||
WLED_GLOBAL byte wasm_state _INIT(WASM_STATE_UNLOADED);
|
||||
|
||||
// Usermod manager
|
||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
|
||||
|
@ -19,12 +19,12 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
} else if(type == WS_EVT_DISCONNECT){
|
||||
//client disconnected
|
||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||
} else if(type == WS_EVT_DATA){
|
||||
} else if(type == WS_EVT_DATA) {
|
||||
//data packet
|
||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||
if(info->final && info->index == 0 && info->len == len){
|
||||
if(info->opcode == WS_TEXT) {
|
||||
//the whole message is in a single frame and we got all of its data (max. 1450byte)
|
||||
if(info->opcode == WS_TEXT)
|
||||
if(info->final && info->index == 0 && info->len == len)
|
||||
{
|
||||
bool verboseResponse = false;
|
||||
{ //scope JsonDocument so it releases its buffer
|
||||
@ -51,8 +51,29 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
//update if it takes longer than 300ms until next "broadcast"
|
||||
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client);
|
||||
} else {
|
||||
if((info->index + len) == info->len){
|
||||
if(info->final){
|
||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (info->opcode == WS_BINARY){ //wasm custom FX binary
|
||||
if (len > MAX_WASM_BIN_SIZE) return;
|
||||
if(info->index == 0){
|
||||
delete[] wasm_buffer;
|
||||
wasm_buffer = new uint8_t[len];
|
||||
wasm_buffer_len = len;
|
||||
}
|
||||
|
||||
if (info->index + info->len <= len) {
|
||||
memcpy(wasm_buffer + info->index, data, info->len);
|
||||
}
|
||||
|
||||
if (info->final) {
|
||||
//reload WASM on the next frame
|
||||
wasm_state = WASM_STATE_STALE;
|
||||
}
|
||||
} else {
|
||||
//message is comprised of multiple frames or the frame is split into multiple packets
|
||||
//if(info->index == 0){
|
||||
//if (!wsFrameBuffer && len < 4096) wsFrameBuffer = new uint8_t[4096];
|
||||
@ -63,13 +84,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
|
||||
//}
|
||||
|
||||
if((info->index + len) == info->len){
|
||||
if(info->final){
|
||||
if(info->message_opcode == WS_TEXT) {
|
||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if(type == WS_EVT_ERROR){
|
||||
//error was received from the other end
|
||||
|
Loading…
Reference in New Issue
Block a user