2121#include " ../MoonBase/Module.h"
2222
2323#if FT_LIVESCRIPT
24+ #define USE_FASTLED // as ESPLiveScript.h calls hsv ! one of the reserved functions!!
2425 #include " ESPLiveScript.h" // note: contains declarations AND definitions, therefore can only be included once!
25- #endif
26-
27- #include " Effect.h" // effect.h will include VirtualLayer.h which will include PhysicalLayer.h
26+ static bool waitingOnLiveScript = true ;
27+ static bool scriptsRunning = false ;
28+ #endif
29+
30+ #include " Nodes.h" // Nodes.h will include VirtualLayer.h which will include PhysicalLayer.h
2831
2932PhysicalLayer layerP; // global declaration of the physical layer
3033
3134// to do: move to virtual layer ...
32- void fadeToBlackBy_static (uint8_t fadeValue)
33- {
34- layerP.layerV [0 ]->fadeToBlackBy (fadeValue);
35- }
35+ void _fadeToBlackBy (uint8_t fadeValue) { layerP.layerV [0 ]->fadeToBlackBy (fadeValue);}
36+ static void sPCLive (uint16_t pixel, CRGB color) {layerP.layerV [0 ]->setPixelColor (pixel, color);} // setPixelColor with color
37+ static void sCFPLive (uint16_t pixel, uint8_t index, uint8_t brightness) { layerP.layerV [0 ]->setPixelColor (pixel, ColorFromPalette (PartyColors_p, index, brightness));} // setPixelColor within palette
3638
3739static void _addPin (uint8_t pinNr) {layerP.addPin (pinNr);}
3840static void _addPixelsPre () {layerP.addPixelsPre ();}
3941static void _addPixel (uint16_t x, uint16_t y, uint16_t z) {layerP.addPixel ({x, y, z});}
4042static void _addPixelsPost () {layerP.addPixelsPost ();}
4143
44+ static float _triangle (float j) {return 1.0 - fabs (fmod (2 * j, 2.0 ) - 1.0 );}
45+ static float _time (float j) {
46+ float myVal = millis ();;
47+ myVal = myVal / 65535 / j; // PixelBlaze uses 1000/65535 = .015259.
48+ myVal = fmod (myVal, 1.0 ); // ewowi: with 0.015 as input, you get fmod(millis/1000,1.0), which has a period of 1 second, sounds right
49+ return myVal;
50+ }
51+
4252class ModuleAnimations : public Module
4353{
4454public:
@@ -55,24 +65,53 @@ class ModuleAnimations : public Module
5565 ) : Module(" animations" , server, sveltekit, filesService) {
5666 ESP_LOGD (TAG, " constructor" );
5767
58- addExternalVariable (" leds" , " CRGB *" , " " , (void *)layerP.leds );
59- addExternalFunction (" fadeToBlackBy" , " void" , " uint8_t" , (void *)fadeToBlackBy_static);
68+ uint8_t (*_inoise8)(uint16_t , uint16_t , uint16_t )=inoise8;
6069 uint16_t (*_random16)(uint16_t )=random16; // enforce specific random16 function
61- addExternalFunction (" random16" , " uint16_t" , " uint16_t" , (void *)_random16);
62- addExternalFunction (" sin8" , " uint8_t" , " uint8_t" , (void *)sin8);
63- addExternalFunction (" cos8" , " uint8_t" , " uint8_t" , (void *)cos8);
64- addExternalFunction (" delay" , " void" , " uint8_t" , (void *)delay);
70+
71+ // default
72+ addExternalFun (" uint32_t" , " millis" , " " , (void *)millis);
73+ float (*_sin)(float ) = sin;
74+ addExternalFun (" float" , " sin" , " float" , (void *)_sin);
75+ float (*_cos)(float ) = cos;
76+ addExternalFun (" float" , " cos" , " float" , (void *)_cos);
77+ float (*_atan2)(float , float ) = atan2;
78+ addExternalFun (" float" , " atan2" , " float,float" ,(void *)_atan2);
79+ float (*_hypot)(float , float ) = hypot;
80+ addExternalFun (" float" , " hypot" , " float,float" ,(void *)_hypot);
81+ addExternalFun (" float" , " time" , " float" , (void *)_time);
82+ addExternalFun (" float" , " triangle" , " float" , (void *)_triangle);
83+
6584 addExternalFunction (" addPin" , " void" , " uint8_t" , (void *)_addPin);
6685 addExternalFunction (" addPixelsPre" , " void" , " " , (void *)_addPixelsPre);
6786 addExternalFunction (" addPixel" , " void" , " uint16_t,uint16_t,uint16_t" , (void *)_addPixel);
6887 addExternalFunction (" addPixelsPost" , " void" , " " , (void *)_addPixelsPost);
69-
88+ addExternalFunction (" cos8" , " uint8_t" , " uint8_t" , (void *)cos8);
89+ addExternalFunction (" delay" , " void" , " uint8_t" , (void *)delay);
90+ addExternalFunction (" fadeToBlackBy" , " void" , " uint8_t" , (void *)_fadeToBlackBy);
91+ addExternalFunction (" inoise8" , " uint8_t" , " uint16_t,uint16_t,uint16_t" , (void *)_inoise8);
92+ addExternalVariable (" leds" , " CRGB *" , " " , (void *)layerP.leds );
93+ addExternalVariable (" now" , " uint32_t" , " " , (void *)millis);
94+ addExternalFunction (" random16" , " uint16_t" , " uint16_t" , (void *)_random16);
95+ addExternalFunction (" sin8" , " uint8_t" , " uint8_t" , (void *)sin8);
96+ addExternalFunction (" sPC" , " void" , " uint16_t,CRGB" , (void *)sPCLive );
97+ addExternalFunction (" sCFP" , " void" , " uint16_t,uint8_t,uint8_t" , (void *)sCFPLive );
98+
7099 for (asm_external el: external_links) {
71100 ESP_LOGD (TAG, " elink %s %s %d" , el.shortname .c_str (), el.name .c_str (), el.type );
72101 }
73102 // ... send to client
74103 }
75104
105+ void addExternalVal (string result, string name, void * ptr) {
106+ if (findLink (name, externalType::value) == -1 ) // not allready added earlier
107+ addExternalVariable (name, result, " " , ptr);
108+ }
109+
110+ void addExternalFun (string result, string name, string parameters, void * ptr) {
111+ if (findLink (name, externalType::function) == -1 ) // not allready added earlier
112+ addExternalFunction (name, result, parameters, ptr);
113+ }
114+
76115 void begin () {
77116 Module::begin ();
78117
@@ -132,6 +171,8 @@ class ModuleAnimations : public Module
132171 values.add (" Sinus" );
133172 values.add (" Lissajous" );
134173 values.add (" Lines" );
174+ values.add (" Panel16" );
175+ values.add (" Multiply" );
135176 // find all the .sc files on FS
136177 File rootFolder = ESPFS.open (" /" );
137178 walkThroughFiles (rootFolder, [&](File folder, File file) {
@@ -226,14 +267,14 @@ class ModuleAnimations : public Module
226267 animationsChanged = false ;
227268
228269 // rebuild layerP->layerV->effects
229- for (Effect* effect : layerP.layerV [0 ]->effects ) {
230- ESP_LOGD (TAG, " delete effect %s" , effect ->name ());
231- delete effect ;
270+ for (Node* node : layerP.layerV [0 ]->nodes ) {
271+ ESP_LOGD (TAG, " delete effect %s" , node ->name ());
272+ delete node ;
232273 }
233- layerP.layerV [0 ]->effects .clear (); // remove all effects
274+ layerP.layerV [0 ]->nodes .clear (); // remove all effects
234275 for (JsonObject node: _state.data [" nodes" ].as <JsonArray>()) {
235276 ESP_LOGD (TAG, " create effect %s" , node[" animation" ].as <String>().c_str ());
236- layerP.addEffect (node[" animation" ]); // fill the layers and effects ...
277+ layerP.addNode (node[" animation" ]); // fill the layers and effects ...
237278 }
238279 }
239280
@@ -247,12 +288,29 @@ class ModuleAnimations : public Module
247288 layerP.leds [i] = CRGB (0 , 0 , 128 );
248289 }
249290
291+ if (scriptsRunning && !waitingOnLiveScript) {// show has been called (in other loop)
292+ waitingOnLiveScript = true ; // waiting on Live Script
293+ // ESP_LOGD(TAG, "waitingOnLiveScript %d %d", scriptsRunning, waitingOnLiveScript);
294+ while (waitingOnLiveScript) delay (1 ); // so live can continue
295+ }
296+
250297 // Serial.printf(" %s", animation.c_str());
251298 if (showLeds) driverShow ();
252299 }
253300
254301 // update scripts / read only values in the UI
255302 void loop1s () {
303+ bool isRunning = false ;
304+ for (Executable &exec: scriptRuntime._scExecutables ) {
305+ if (exec.isRunning ()) {
306+ isRunning = true ;
307+ break ;
308+ }
309+ }
310+ scriptsRunning = isRunning;
311+ if (!scriptsRunning) waitingOnLiveScript = true ; // reset to default
312+ // ESP_LOGD(TAG, "waitingOnLiveScript %d %d", scriptsRunning, waitingOnLiveScript);
313+
256314 if (!_socket->getConnectedClients ()) return ;
257315
258316 JsonDocument newData; // to only send updatedData
@@ -291,18 +349,23 @@ class ModuleAnimations : public Module
291349
292350 void driverShow ()
293351 {
294- if (_state.data [" driverOn" ])
352+ if (_state.data [" driverOn" ] && FastLED. count ()) {
295353 FastLED.show ();
354+ }
296355 }
297356
298357 // ESPLiveScript functions
299358 // =======================
300359
301- static void show ()
360+ static void sync ()
302361 {
303- delay ( 1 ); // to feed the watchdog (also if loopState == 0)
362+ // Serial.printf("±");
304363
305- // gAnimations->driverShow();
364+ delay (1 ); // to feed the watchdog (also if loopState == 0)
365+ // ESP_LOGD(TAG, "waitingOnLiveScript %d %d", scriptsRunning, waitingOnLiveScript);
366+ while (!waitingOnLiveScript) delay (1 ); // to feed the watchdog
367+ // do Live Script cycle
368+ waitingOnLiveScript = false ; // Live Script produced a frame, main loop will deal with it
306369 }
307370
308371 void compileAndRun (const char * animation, const char * type, JsonVariant error) {
@@ -324,21 +387,24 @@ class ModuleAnimations : public Module
324387
325388 // send UI spinner
326389
327- runningPrograms.setFunctionToSync (show );
390+ runningPrograms.setFunctionToSync (sync );
328391
329392 // run the recompile not in httpd but in main loopTask (otherwise we run out of stack space)
330393 // runInLoopTask.push_back([&, animation, type, error] {
331394 ESP_LOGD (TAG, " compileAndRun %s %s" , animation, type);
332395 File file = ESPFS.open (animation);
333396 if (file) {
334- std::string scScript = file.readString ().c_str ();
335- // scScript += "void main(){setup();sync();}";
397+ std::string scScript;
398+ scScript += " #define NUM_LEDS " + std::to_string (layerP.nrOfLeds ) + " \n " ; // NUM_LEDS is used in arrays -> must be define e.g. uint8_t rMapRadius[NUM_LEDS];
399+ scScript += " #define width " + std::to_string (layerP.layerV [0 ]->size .x ) + " \n " ;
400+ scScript += " #define height " + std::to_string (layerP.layerV [0 ]->size .y ) + " \n " ;
401+ scScript += " #define depth " + std::to_string (layerP.layerV [0 ]->size .z ) + " \n " ;
402+ scScript += file.readString ().c_str ();
336403 file.close ();
337404
338405 // gAnimations = this;
339406 if (equal (type, " Effect" )) {
340- scScript += " #define NUM_LEDS " + std::to_string (layerP.nrOfLeds ) + " \n " ; // NUM_LEDS is used in arrays -> must be define e.g. uint8_t rMapRadius[NUM_LEDS];
341- scScript += " void main(){setup();while(2>1){loop();delay(1);}}" ; // sync();
407+ scScript += " void main(){setup();while(2>1){loop();sync();}}" ; // ;
342408 } else if (equal (type, " Fixture definition" )) {
343409 scScript += " void main(){addPixelsPre();setup();addPixelsPost();}" ;
344410 }
@@ -348,15 +414,16 @@ class ModuleAnimations : public Module
348414
349415 // ESP_LOGD(TAG, "parsing %s", scScript.c_str());
350416
351- Executable executable = parser.parseScript (&scScript);
417+ Executable executable = parser.parseScript (&scScript); // note that this class will be deleted after the function call !!!
352418 executable.name = animation;
353419 ESP_LOGD (TAG, " parsing %s done\n " , animation);
354420 scriptRuntime.addExe (executable); // if already exists, delete it first
355421 ESP_LOGD (TAG, " addExe success %s\n " , executable.exeExist ?" true" :" false" );
356422
357423 if (executable.exeExist ) {
358424 if (equal (type, " Fixture definition" )) {
359- executable.execute (" main" ); // background task (async - vs sync)
425+ // executable.execute("main"); //background task (async - vs sync)
426+ scriptRuntime.execute (executable.name , " main" ); // background task (async - vs sync)
360427 // pass = 1;
361428 // liveM->executeTask(liveFixtureID, "c");
362429 // pass = 2;
@@ -366,7 +433,8 @@ class ModuleAnimations : public Module
366433 // setup : create controls
367434 // executable.execute("setup");
368435 // send controls to UI
369- executable.executeAsTask (" main" ); // background task (async - vs sync)
436+ // executable.executeAsTask("main"); //background task (async - vs sync)
437+ scriptRuntime.executeAsTask (executable.name , " main" ); // background task (async - vs sync)
370438 // assert failed: xEventGroupSync event_groups.c:228 (uxBitsToWaitFor != 0)
371439 }
372440 } else
@@ -386,10 +454,15 @@ class ModuleAnimations : public Module
386454 void kill (int index) {
387455 ESP_LOGD (TAG, " kill %d" , index);
388456 if (index < scriptRuntime._scExecutables .size ()) {
389- scriptRuntime.kill (scriptRuntime._scExecutables [index].name );
390- scriptRuntime.free (scriptRuntime._scExecutables [index].name );
457+ // scriptRuntime.kill(scriptRuntime._scExecutables[index].name);
458+ // scriptRuntime.free(scriptRuntime._scExecutables[index].name);
391459 scriptRuntime.deleteExe (scriptRuntime._scExecutables [index].name );
392460 }
461+
462+ if (waitingOnLiveScript) {
463+ waitingOnLiveScript = false ;
464+ // ESP_LOGD(TAG, "waitingOnLiveScript %d %d", scriptsRunning, waitingOnLiveScript);
465+ }
393466 }
394467}; // class ModuleAnimations
395468
0 commit comments