From b1ce744383c7f3ff9adc91f268f02eb098e4f4c7 Mon Sep 17 00:00:00 2001 From: Tom Lauwaerts Date: Mon, 27 Oct 2025 17:35:34 +0100 Subject: [PATCH 1/5] Add `rand()` primitive --- src/Primitives/arduino.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index f66ed4d8..1e04393c 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -132,7 +132,7 @@ int resolve_isr(int pin) { // Primitives #define NUM_PRIMITIVES 0 -#define NUM_PRIMITIVES_ARDUINO 38 +#define NUM_PRIMITIVES_ARDUINO 39 #define ALL_PRIMITIVES (NUM_PRIMITIVES + NUM_PRIMITIVES_ARDUINO) @@ -353,6 +353,11 @@ def_prim(micros, NoneToOneU64) { return true; } +def_prim(rand, NoneToOneU32) { + pushInt32(rand()); + return true; +} + def_prim(print_int, oneToNoneU32) { uint32_t integer = arg0.uint32; Serial.print(integer); @@ -988,6 +993,7 @@ void install_primitives() { install_primitive(abort); install_primitive(millis); install_primitive(micros); + install_primitive(rand); install_primitive(print_int); install_primitive(print_string); From 181a4696acbdf7c97fc224f9906f659fef946007 Mon Sep 17 00:00:00 2001 From: Tom Lauwaerts Date: Mon, 27 Oct 2025 17:36:46 +0100 Subject: [PATCH 2/5] Add M5stack display primitives --- src/Primitives/arduino.cpp | 58 +++++++++++++++++++++++- src/Primitives/emulated.cpp | 1 + src/Primitives/m5stack/display.cpp | 23 ++++++++++ src/Primitives/m5stack/display.h | 14 ++++++ tutorials/wat/main/cardputer.wat | 73 ++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/Primitives/m5stack/display.cpp create mode 100644 src/Primitives/m5stack/display.h create mode 100644 tutorials/wat/main/cardputer.wat diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index 1e04393c..73620416 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -25,6 +25,9 @@ #include "../WARDuino/CallbackHandler.h" #include "primitives.h" +// M5stack +#include "m5stack/display.h" + // NEOPIXEL #include #define PIN 33 @@ -132,7 +135,7 @@ int resolve_isr(int pin) { // Primitives #define NUM_PRIMITIVES 0 -#define NUM_PRIMITIVES_ARDUINO 39 +#define NUM_PRIMITIVES_ARDUINO 44 #define ALL_PRIMITIVES (NUM_PRIMITIVES + NUM_PRIMITIVES_ARDUINO) @@ -247,6 +250,15 @@ Type fourToNoneU32 = { 0x8001111 /* 0x800 = no return ; 1 = I32; 1 = I32; 1 = I32; 1 = I32*/ }; +Type fiveToNoneI32 = { + .form = FUNC, + .param_count = 5, + .params = param_I32_arr_len5, + .result_count = 0, + .results = nullptr, + .mask = 0x80011111 +}; + Type oneToOneU32 = { .form = FUNC, .param_count = 1, @@ -956,6 +968,44 @@ int32_t http_post_request(Module *m, const String url, const String body, return httpResponseCode; } +// Cardputer display +def_prim(display_setup, NoneToNoneU32) { + setup(); + return true; +} + +def_prim(display_width, NoneToOneU32) { + pushInt32(width()); + return true; +} + +def_prim(display_height, NoneToOneU32) { + pushInt32(height()); + return true; +} + + +def_prim(display_fillrect, fiveToNoneI32) { + uint32_t color = arg4.uint32; + int32_t height = arg3.int32; + int32_t width = arg2.int32; + int32_t y = arg1.int32; + int32_t x = arg0.int32; + fillRect(x, y, width, height, color); + pop_args(5); + return true; +} + +def_prim(display_fillcircle, fourToNoneI32) { + uint32_t color = arg3.uint32; + int32_t radius = arg2.int32; + int32_t y = arg1.int32; + int32_t x = arg0.int32; + fillCircle(x, y, radius, color); + pop_args(5); + return true; +} + //------------------------------------------------------ // Installing all the primitives & ISRs //------------------------------------------------------ @@ -1040,6 +1090,12 @@ void install_primitives() { install_primitive(chip_ledc_attach); install_primitive(chip_ledc_set_duty); + install_primitive(display_setup); + install_primitive(display_width); + install_primitive(display_height); + install_primitive(display_fillrect); + install_primitive(display_fillcircle); + dbg_info("INSTALLING ISRs\n"); install_isrs(); } diff --git a/src/Primitives/emulated.cpp b/src/Primitives/emulated.cpp index cfcd171b..b1409674 100644 --- a/src/Primitives/emulated.cpp +++ b/src/Primitives/emulated.cpp @@ -103,6 +103,7 @@ uint32_t param_I32_arr_len1[1] = {I32}; uint32_t param_I32_arr_len2[2] = {I32, I32}; uint32_t param_I32_arr_len3[3] = {I32, I32, I32}; uint32_t param_I32_arr_len4[4] = {I32, I32, I32, I32}; +uint32_t param_I32_arr_len5[5] = {I32, I32, I32, I32, I32}; uint32_t param_I32_arr_len10[10] = {I32, I32, I32, I32, I32, I32, I32, I32, I32, I32}; diff --git a/src/Primitives/m5stack/display.cpp b/src/Primitives/m5stack/display.cpp new file mode 100644 index 00000000..62e59358 --- /dev/null +++ b/src/Primitives/m5stack/display.cpp @@ -0,0 +1,23 @@ +#include "display.h" +#include "M5Cardputer.h" + +void setup() { + auto cfg = M5.config(); + M5Cardputer.begin(cfg); +} + +int width() { + return M5Cardputer.Display.width(); +} + +int height() { + return M5Cardputer.Display.height(); +} + +void fillRect(int x, int y, int w, int h, uint32_t color) { + M5Cardputer.Display.fillRect(x, y, w, h, color); +} + +void fillCircle(int x, int y, int radius, uint32_t color) { + M5Cardputer.Display.fillCircle(x, y, radius, color); +} \ No newline at end of file diff --git a/src/Primitives/m5stack/display.h b/src/Primitives/m5stack/display.h new file mode 100644 index 00000000..5ceafef3 --- /dev/null +++ b/src/Primitives/m5stack/display.h @@ -0,0 +1,14 @@ +#pragma once + +// port of the Graphics library for M5Stack series +// https://github.com/m5stack/M5GFX + +void setup(); + +int width(); + +int height(); + +void fillRect(int x, int y, int w, int h, uint32_t color); + +void fillCircle(int x, int y, int radius, uint32_t color); diff --git a/tutorials/wat/main/cardputer.wat b/tutorials/wat/main/cardputer.wat new file mode 100644 index 00000000..3c284f80 --- /dev/null +++ b/tutorials/wat/main/cardputer.wat @@ -0,0 +1,73 @@ +;; WARDuino port of M5stack cardputer Basic Display example +;; https://github.com/m5stack/M5Cardputer/blob/master/examples/Basic/display/display.ino +(module + ;; Type declarations + (type $int32->int32->i32->i32->void (func (param i32 i32 i32 i32))) + (type $int32->i32->i32->i32->i32->void (func (param i32 i32 i32 i32 i32))) + (type $void->int32 (func (result i32))) + (type $void->void (func)) + + ;; Imports from the WARDuino VM + (import "env" "display_setup" (func $env.setup (type $void->void))) + (import "env" "display_width" (func $env.width (type $void->int32))) + (import "env" "rand" (func $env.rand (type $void->int32))) + (import "env" "display_height" (func $env.height (type $void->int32))) + (import "env" "display_fillrect" (func $env.fillrect (type $int32->i32->i32->i32->i32->void))) + (import "env" "display_fillcircle" (func $env.fillcircle (type $int32->int32->i32->i32->void))) + + ;; chaos function (public) + (func $chaos (type $void->void) + (local $x i32) + (local $y i32) + (local $r i32) + + ;; Initialise + call $env.setup + + ;; Update display in infinite loop + loop $infinite + ;; int x = rand() % M5Cardputer.Display.width(); + call $env.rand + call $env.width + i32.rem_u + local.set $x + ;; int y = rand() % M5Cardputer.Display.height(); + call $env.rand + call $env.height + i32.rem_u + local.set $y + ;; int r = (M5Cardputer.Display.width() >> 4) + 2; + call $env.width + i32.const 4 + i32.shr_s + i32.const 2 + i32.add + local.set $r + ;; M5Cardputer.Display.fillCircle(x, y, r, c); + local.get $x + local.get $y + local.get $r + call $env.rand + call $env.fillcircle + ;; int x = rand() % M5Cardputer.Display.width(); + call $env.rand + call $env.width + i32.rem_u + local.set $x + ;; int y = rand() % M5Cardputer.Display.height(); + call $env.rand + call $env.height + i32.rem_u + local.set $y + ;; M5Cardputer.Display.fillRectangle(x, y, w, h, c); + local.get $x + local.get $y + local.get $r + local.get $r + call $env.rand + call $env.fillrect + br $infinite ;; jump back to start of loop + end) + + ;; Export chaos as function + (export "main" (func $chaos))) From 4df4a697ec4b127645235811e9d144eb270e90fd Mon Sep 17 00:00:00 2001 From: Tom Lauwaerts Date: Tue, 28 Oct 2025 07:16:45 +0100 Subject: [PATCH 3/5] Fix compilation --- src/Primitives/arduino.cpp | 5 +++-- src/Primitives/m5stack/display.cpp | 2 +- src/Primitives/m5stack/display.h | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index 73620416..f7473a50 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -208,6 +208,7 @@ uint32_t param_I32_arr_len1[1] = {I32}; uint32_t param_I32_arr_len2[2] = {I32, I32}; uint32_t param_I32_arr_len3[3] = {I32, I32, I32}; uint32_t param_I32_arr_len4[4] = {I32, I32, I32, I32}; +uint32_t param_I32_arr_len5[5] = {I32, I32, I32, I32, I32}; uint32_t param_I32_arr_len10[10] = {I32, I32, I32, I32, I32, I32, I32, I32, I32, I32}; @@ -970,7 +971,7 @@ int32_t http_post_request(Module *m, const String url, const String body, // Cardputer display def_prim(display_setup, NoneToNoneU32) { - setup(); + displaySetup(); return true; } @@ -996,7 +997,7 @@ def_prim(display_fillrect, fiveToNoneI32) { return true; } -def_prim(display_fillcircle, fourToNoneI32) { +def_prim(display_fillcircle, fourToNoneU32) { uint32_t color = arg3.uint32; int32_t radius = arg2.int32; int32_t y = arg1.int32; diff --git a/src/Primitives/m5stack/display.cpp b/src/Primitives/m5stack/display.cpp index 62e59358..9f037fd5 100644 --- a/src/Primitives/m5stack/display.cpp +++ b/src/Primitives/m5stack/display.cpp @@ -1,7 +1,7 @@ #include "display.h" #include "M5Cardputer.h" -void setup() { +void displaySetup() { auto cfg = M5.config(); M5Cardputer.begin(cfg); } diff --git a/src/Primitives/m5stack/display.h b/src/Primitives/m5stack/display.h index 5ceafef3..ee58a572 100644 --- a/src/Primitives/m5stack/display.h +++ b/src/Primitives/m5stack/display.h @@ -1,9 +1,11 @@ #pragma once +#include + // port of the Graphics library for M5Stack series // https://github.com/m5stack/M5GFX -void setup(); +void displaySetup(); int width(); From b9ac57410548ea7dce57db286d8837f9b52fe5d7 Mon Sep 17 00:00:00 2001 From: Tom Lauwaerts Date: Wed, 29 Oct 2025 12:52:40 +0100 Subject: [PATCH 4/5] Use Arduino random function --- src/Primitives/arduino.cpp | 6 +++--- tutorials/wat/main/cardputer.wat | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index f7473a50..2967b395 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -366,8 +366,8 @@ def_prim(micros, NoneToOneU64) { return true; } -def_prim(rand, NoneToOneU32) { - pushInt32(rand()); +def_prim(int_random, NoneToOneU32) { + pushInt32(random(6000)); return true; } @@ -1044,7 +1044,7 @@ void install_primitives() { install_primitive(abort); install_primitive(millis); install_primitive(micros); - install_primitive(rand); + install_primitive(int_random); install_primitive(print_int); install_primitive(print_string); diff --git a/tutorials/wat/main/cardputer.wat b/tutorials/wat/main/cardputer.wat index 3c284f80..b2ebf382 100644 --- a/tutorials/wat/main/cardputer.wat +++ b/tutorials/wat/main/cardputer.wat @@ -10,7 +10,7 @@ ;; Imports from the WARDuino VM (import "env" "display_setup" (func $env.setup (type $void->void))) (import "env" "display_width" (func $env.width (type $void->int32))) - (import "env" "rand" (func $env.rand (type $void->int32))) + (import "env" "int_random" (func $env.rand (type $void->int32))) (import "env" "display_height" (func $env.height (type $void->int32))) (import "env" "display_fillrect" (func $env.fillrect (type $int32->i32->i32->i32->i32->void))) (import "env" "display_fillcircle" (func $env.fillcircle (type $int32->int32->i32->i32->void))) From 8e27b03dd0e2be6fc6832168fab8fd06845e3110 Mon Sep 17 00:00:00 2001 From: Tom Lauwaerts Date: Wed, 29 Oct 2025 12:53:40 +0100 Subject: [PATCH 5/5] Reduce sketch size: delete primitives --- src/Primitives/arduino.cpp | 340 ------------------------------------- 1 file changed, 340 deletions(-) diff --git a/src/Primitives/arduino.cpp b/src/Primitives/arduino.cpp index 2967b395..21e6d853 100644 --- a/src/Primitives/arduino.cpp +++ b/src/Primitives/arduino.cpp @@ -28,13 +28,6 @@ // M5stack #include "m5stack/display.h" -// NEOPIXEL -#include -#define PIN 33 -#define NUMPIXELS 64 -Adafruit_NeoPixel pixels = - Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); - #define delay_us(ms) delayMicroseconds(ms) #include SPIClass *spi = new SPIClass(); @@ -391,122 +384,6 @@ def_prim(print_string, twoToNoneU32) { return true; } -def_prim(wifi_connect, fourToNoneU32) { - uint32_t ssid = arg3.uint32; - uint32_t len0 = arg2.uint32; - uint32_t pass = arg1.uint32; - uint32_t len1 = arg0.uint32; - - String ssid_str = parse_utf8_string(m->memory.bytes, len0, ssid).c_str(); - String pass_str = parse_utf8_string(m->memory.bytes, len1, pass).c_str(); - - connect(ssid_str, pass_str); - - pop_args(4); - return true; -} - -def_prim(wifi_status, NoneToOneU32) { - int32_t status = WiFi.status(); - pushInt32(status); - return true; -} - -def_prim(wifi_connected, NoneToOneU32) { - pushInt32(WiFi.status() == WL_CONNECTED ? 1 : 0); - return true; -} - -def_prim(wifi_localip, twoToOneU32) { - uint32_t buff = arg1.uint32; - IPAddress ip = WiFi.localIP(); - - String ipString = String(ip[0]); - for (byte octet = 1; octet < 4; ++octet) { - ipString += '.' + String(ip[octet]); - } - - // TODO handle too small buffer - for (unsigned long i = 0; i < ipString.length(); i++) { - m->memory.bytes[buff + i] = (uint32_t)ipString[i]; - } - pop_args(2); - pushInt32(buff); - return true; -} - -def_prim(http_get, fourToOneU32) { - int32_t return_value = -11; - - // Check WiFi connection status - if (WiFi.status() == WL_CONNECTED) { - uint32_t addr = arg3.uint32; - uint32_t length = arg2.uint32; - uint32_t response = arg1.uint32; - uint32_t size = arg0.uint32; - - String url = parse_utf8_string(m->memory.bytes, length, addr).c_str(); - Serial.print("GET "); - Serial.println(url); - - Serial.flush(); - // Send HTTP GET request - return_value = http_get_request(m, url, response, size); - } - - pop_args(4); - pushInt32(return_value); - return true; -} - -def_prim(http_post, tenToOneU32) { - int32_t status_code = -11; - - // Check WiFi connection status - if (WiFi.status() == WL_CONNECTED) { - uint32_t url = arg9.uint32; - uint32_t url_len = arg8.uint32; - uint32_t body = arg7.uint32; - uint32_t body_len = arg6.uint32; - uint32_t content_type = arg5.uint32; - uint32_t content_type_len = arg4.uint32; - uint32_t authorization = arg3.uint32; - uint32_t authorization_len = arg2.uint32; - uint32_t response = arg1.uint32; - uint32_t size = arg0.uint32; - - String url_parsed = - parse_utf8_string(m->memory.bytes, url_len, url).c_str(); - String body_parsed = - parse_utf8_string(m->memory.bytes, body_len, body).c_str(); - String content_type_parsed = - parse_utf8_string(m->memory.bytes, content_type_len, content_type) - .c_str(); - String authorization_parsed = - parse_utf8_string(m->memory.bytes, authorization_len, authorization) - .c_str(); - Serial.print("POST "); - Serial.print(url_parsed); - Serial.print("\n\t Content-type: '"); - Serial.print(content_type_parsed); - Serial.print("'\n\t Authorization: '"); - Serial.print(authorization_parsed); - Serial.print("'\n\t '"); - Serial.print(body_parsed); - Serial.print("'\n"); - - // Send HTTP POST request - status_code = - http_post_request(m, url_parsed, body_parsed, content_type_parsed, - authorization_parsed, response, size); - } - - pop_args(10); - pushInt32(status_code); - Serial.flush(); - return true; -} - // warning: undefined symbol: chip_pin_mode def_prim(chip_pin_mode, twoToNoneU32) { printf("chip_pin_mode \n"); @@ -615,32 +492,6 @@ def_prim(write_spi_bytes_16, twoToNoneU32) { return true; } -def_prim(init_pixels, NoneToNoneU32) { - pixels.begin(); - return true; -} - -def_prim(set_pixel_color, fourToOneU32) { - uint8_t blue = arg0.uint32; - uint8_t green = arg1.uint32; - uint8_t red = arg2.uint32; - uint8_t index = arg3.uint32; - - pixels.setPixelColor(index, pixels.Color(red, green, blue)); - pop_args(4); - return true; -} - -def_prim(show_pixels, NoneToNoneU32) { - pixels.show(); - return true; -} - -def_prim(clear_pixels, NoneToNoneU32) { - pixels.clear(); - return true; -} - // LED Control primitives def_prim(chip_ledc_set_duty, threeToNoneU32) { @@ -711,175 +562,6 @@ def_prim(unsubscribe_interrupt, oneToNoneU32) { return true; } -// MQTT MODULE - -#include - -WiFiClient wifiClient; -PubSubClient mqttClient(wifiClient); - -def_prim(mqtt_init, threeToNoneU32) { - WiFi.mode(WIFI_STA); - uint32_t server_param = arg2.uint32; - uint32_t length = arg1.uint32; - uint32_t port = arg0.uint32; - - const char *server = - parse_utf8_string(m->memory.bytes, length, server_param).c_str(); - mqttClient.setServer(server, port); - mqttClient.setCallback([](const char *topic, const unsigned char *payload, - unsigned int length) { - CallbackHandler::push_event(topic, (const char *)payload, length); - }); - -#if DEBUG - Serial.print("Set MQTT server to ["); - Serial.print(server); - Serial.print(":"); - Serial.print(port); - Serial.println("]"); - Serial.flush(); -#endif - - pop_args(3); - return true; -} - -def_prim(mqtt_connect, twoToOneU32) { - uint32_t client_id_param = arg1.uint32; - uint32_t length = arg0.uint32; - - String client_id = - parse_utf8_string(m->memory.bytes, length, client_id_param).c_str(); -#if DEBUG - Serial.print("Connecting to MQTT server as "); - Serial.print(client_id); -#endif - bool ret = mqttClient.connect(client_id.c_str()); - -#if DEBUG - Serial.print(": "); - Serial.print(mqttClient.state()); - Serial.print(", "); - Serial.println(ret); - Serial.flush(); -#endif - - pop_args(2); - pushInt32((int)ret); - return true; -} - -def_prim(mqtt_connected, NoneToOneU32) { - pushInt32((int)mqttClient.connected()); - return true; -} - -def_prim(mqtt_state, NoneToOneU32) { - pushInt32(mqttClient.state()); - return true; -} - -def_prim(mqtt_publish, fourToOneU32) { - uint32_t topic_param = arg3.uint32; - uint32_t topic_length = arg2.uint32; - uint32_t payload_param = arg1.uint32; - uint32_t payload_length = arg0.uint32; - - String topic = - parse_utf8_string(m->memory.bytes, topic_length, topic_param).c_str(); -#if DEBUG - Serial.println("MQTT Publish"); - Serial.print("("); - Serial.print(topic_param); - Serial.print(", "); - Serial.print(topic_length); - Serial.print(") "); - Serial.print(topic); - Serial.println(""); -#endif - String payload = - parse_utf8_string(m->memory.bytes, payload_length, payload_param) - .c_str(); -#if DEBUG - Serial.print("("); - Serial.print(payload_param); - Serial.print(", "); - Serial.print(payload_length); - Serial.print(") "); - Serial.print(payload); - Serial.println(""); -#endif - - bool ret = mqttClient.publish(topic.c_str(), payload.c_str()); - -#if DEBUG - Serial.print("Status code: "); - Serial.println(ret); - Serial.flush(); -#endif - - pop_args(4); - pushInt32((int)ret); - return true; -} - -def_prim(mqtt_subscribe, threeToOneU32) { - uint32_t topic_param = arg2.uint32; - uint32_t topic_length = arg1.uint32; - uint32_t fidx = arg0.uint32; - - const char *topic = - parse_utf8_string(m->memory.bytes, topic_length, topic_param).c_str(); - - Callback c = Callback(m, topic, fidx); - CallbackHandler::add_callback(c); - - bool ret = mqttClient.subscribe(topic); - -#if DEBUG - Serial.print("Subscribed to "); - Serial.println(topic); - Serial.flush(); -#endif - - pop_args(2); - pushInt32((int)ret); - return true; -} - -def_prim(mqtt_unsubscribe, threeToOneU32) { - uint32_t topic_param = arg2.uint32; - uint32_t topic_length = arg1.uint32; - uint32_t fidx = arg0.uint32; - - const char *topic = - parse_utf8_string(m->memory.bytes, topic_length, topic_param).c_str(); - - Callback c = Callback(m, topic, fidx); - CallbackHandler::remove_callback(c); - - bool ret = 1; - if (CallbackHandler::callback_count(topic) == 0) { - ret = mqttClient.unsubscribe(topic); - } - -#if DEBUG - Serial.print("Unsubscribed to "); - Serial.println(topic); - Serial.flush(); -#endif - - pop_args(2); - pushInt32((int)ret); - return true; -} - -def_prim(mqtt_loop, NoneToOneU32) { - pushInt32((int)mqttClient.loop()); - return true; -} - //------------------------------------------------------ // Util functions //------------------------------------------------------ @@ -1049,14 +731,6 @@ void install_primitives() { install_primitive(print_int); install_primitive(print_string); - install_primitive(wifi_connect); - install_primitive(wifi_connected); - install_primitive(wifi_status); - install_primitive(wifi_localip); - - install_primitive(http_get); - install_primitive(http_post); - install_primitive(chip_pin_mode); install_primitive(chip_digital_write); install_primitive_reverse(chip_digital_write); @@ -1072,20 +746,6 @@ void install_primitives() { install_primitive(subscribe_interrupt); install_primitive(unsubscribe_interrupt); - install_primitive(mqtt_init); - install_primitive(mqtt_connect); - install_primitive(mqtt_connected); - install_primitive(mqtt_state); - install_primitive(mqtt_publish); - install_primitive(mqtt_subscribe); - install_primitive(mqtt_unsubscribe); - install_primitive(mqtt_loop); - - install_primitive(init_pixels); - install_primitive(set_pixel_color); - install_primitive(clear_pixels); - install_primitive(show_pixels); - // temporary primitives needed for analogWrite in ESP32 install_primitive(chip_analog_write); install_primitive(chip_ledc_attach);