diff --git a/.github/workflows/arduino_library_lint.yml b/.github/workflows/arduino_library_lint.yml
index 282b565cec..ecc4d198ea 100644
--- a/.github/workflows/arduino_library_lint.yml
+++ b/.github/workflows/arduino_library_lint.yml
@@ -2,7 +2,7 @@
on:
push:
- pull_request:
+ pull_request_target:
name: Arduino Library Lint
jobs:
lint:
diff --git a/.github/workflows/build_adafruit_feather_nrf52840_sense.yml b/.github/workflows/build_adafruit_feather_nrf52840_sense.yml
index caa42d9e59..602f37f7c5 100644
--- a/.github/workflows/build_adafruit_feather_nrf52840_sense.yml
+++ b/.github/workflows/build_adafruit_feather_nrf52840_sense.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_adafruit_xiaoblesense.yml b/.github/workflows/build_adafruit_xiaoblesense.yml
index 7d15ae5670..dc39452cd9 100644
--- a/.github/workflows/build_adafruit_xiaoblesense.yml
+++ b/.github/workflows/build_adafruit_xiaoblesense.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_attiny1616.yml b/.github/workflows/build_attiny1616.yml
index cdf16101a4..8d03029f6a 100644
--- a/.github/workflows/build_attiny1616.yml
+++ b/.github/workflows/build_attiny1616.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_attiny85.yml b/.github/workflows/build_attiny85.yml
index e0b8afc777..b05e371fe5 100644
--- a/.github/workflows/build_attiny85.yml
+++ b/.github/workflows/build_attiny85.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_attiny88.yml b/.github/workflows/build_attiny88.yml
index c6964131b0..15b2e9d558 100644
--- a/.github/workflows/build_attiny88.yml
+++ b/.github/workflows/build_attiny88.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_bluepill.yml b/.github/workflows/build_bluepill.yml
index 695f75f2a6..41d3ba1342 100644
--- a/.github/workflows/build_bluepill.yml
+++ b/.github/workflows/build_bluepill.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_digix.yml b/.github/workflows/build_digix.yml
index c3048d283f..7bd13742e9 100644
--- a/.github/workflows/build_digix.yml
+++ b/.github/workflows/build_digix.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_due.yml b/.github/workflows/build_due.yml
new file mode 100644
index 0000000000..e55d3fd554
--- /dev/null
+++ b/.github/workflows/build_due.yml
@@ -0,0 +1,15 @@
+name: due
+
+on:
+ push:
+ branches:
+ - master
+ pull_request_target:
+ branches:
+ - master
+
+jobs:
+ build:
+ uses: ./.github/workflows/build_template.yml
+ with:
+ args: due
diff --git a/.github/workflows/build_esp32c3.yml b/.github/workflows/build_esp32c3.yml
index dd4d47d4a1..775acbaeac 100644
--- a/.github/workflows/build_esp32c3.yml
+++ b/.github/workflows/build_esp32c3.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32c6.yml b/.github/workflows/build_esp32c6.yml
index 50af0ce03d..ad58960c59 100644
--- a/.github/workflows/build_esp32c6.yml
+++ b/.github/workflows/build_esp32c6.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32dev.yml b/.github/workflows/build_esp32dev.yml
index 20ea6e067d..5964542fed 100644
--- a/.github/workflows/build_esp32dev.yml
+++ b/.github/workflows/build_esp32dev.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32dev_idf3.3.yml b/.github/workflows/build_esp32dev_idf3.3.yml
index 97d46a6035..57bd9d0472 100644
--- a/.github/workflows/build_esp32dev_idf3.3.yml
+++ b/.github/workflows/build_esp32dev_idf3.3.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32dev_idf4.4.yml b/.github/workflows/build_esp32dev_idf4.4.yml
index 43885e877a..485b163b36 100644
--- a/.github/workflows/build_esp32dev_idf4.4.yml
+++ b/.github/workflows/build_esp32dev_idf4.4.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32dev_namespace.yml b/.github/workflows/build_esp32dev_namespace.yml
new file mode 100644
index 0000000000..86f4d1e792
--- /dev/null
+++ b/.github/workflows/build_esp32dev_namespace.yml
@@ -0,0 +1,15 @@
+name: esp32dev_namespace
+
+on:
+ push:
+ branches:
+ - master
+ pull_request_target:
+ branches:
+ - master
+
+jobs:
+ build:
+ uses: ./.github/workflows/build_template.yml
+ with:
+ args: esp32dev --defines FASTLED_FORCE_NAMESPACE=1,FASTLED_FORCE_USE_NAMESPACE=1
diff --git a/.github/workflows/build_esp32s3.yml b/.github/workflows/build_esp32s3.yml
index 6decb7effd..501d830711 100644
--- a/.github/workflows/build_esp32s3.yml
+++ b/.github/workflows/build_esp32s3.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp32wroom.yml b/.github/workflows/build_esp32wroom.yml
index 5bc836f12a..7e7f5f1115 100644
--- a/.github/workflows/build_esp32wroom.yml
+++ b/.github/workflows/build_esp32wroom.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_esp8622.yml b/.github/workflows/build_esp8622.yml
index 20d9a56792..53e7650589 100644
--- a/.github/workflows/build_esp8622.yml
+++ b/.github/workflows/build_esp8622.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml
index 2f5346aaca..a4ff4b9c55 100644
--- a/.github/workflows/build_linux.yml
+++ b/.github/workflows/build_linux.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_maple_map.yml b/.github/workflows/build_maple_map.yml
index 2da84c9336..600ded6662 100644
--- a/.github/workflows/build_maple_map.yml
+++ b/.github/workflows/build_maple_map.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_nano_every.yml b/.github/workflows/build_nano_every.yml
index 9a8bc58381..7037f3f671 100644
--- a/.github/workflows/build_nano_every.yml
+++ b/.github/workflows/build_nano_every.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_nrf52840_dk.yml b/.github/workflows/build_nrf52840_dk.yml
index 63d348377b..65d9cbbd6a 100644
--- a/.github/workflows/build_nrf52840_dk.yml
+++ b/.github/workflows/build_nrf52840_dk.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_rp2040.yml b/.github/workflows/build_rp2040.yml
index 5937fd16c1..6207c97762 100644
--- a/.github/workflows/build_rp2040.yml
+++ b/.github/workflows/build_rp2040.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_rp2040_earle.yml b/.github/workflows/build_rp2040_earle.yml
index de1171984b..5d46e695f7 100644
--- a/.github/workflows/build_rp2040_earle.yml
+++ b/.github/workflows/build_rp2040_earle.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_rp2350.yml b/.github/workflows/build_rp2350.yml
index d2ce2d09b3..11eb03d28e 100644
--- a/.github/workflows/build_rp2350.yml
+++ b/.github/workflows/build_rp2350.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy30.yml b/.github/workflows/build_teensy30.yml
index 258dfcf677..fad87e8281 100644
--- a/.github/workflows/build_teensy30.yml
+++ b/.github/workflows/build_teensy30.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy31.yml b/.github/workflows/build_teensy31.yml
index 8e12d297c2..29959f7259 100644
--- a/.github/workflows/build_teensy31.yml
+++ b/.github/workflows/build_teensy31.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy40.yml b/.github/workflows/build_teensy40.yml
index 82d9bf5bf7..1d7164f71f 100644
--- a/.github/workflows/build_teensy40.yml
+++ b/.github/workflows/build_teensy40.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy41.yml b/.github/workflows/build_teensy41.yml
index 97c859b1bb..43298a5700 100644
--- a/.github/workflows/build_teensy41.yml
+++ b/.github/workflows/build_teensy41.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy41_ofled.yml b/.github/workflows/build_teensy41_ofled.yml
index 546ff42e6a..5beea758a7 100644
--- a/.github/workflows/build_teensy41_ofled.yml
+++ b/.github/workflows/build_teensy41_ofled.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensyLC.yml b/.github/workflows/build_teensyLC.yml
index 5c205be651..d78893b953 100644
--- a/.github/workflows/build_teensyLC.yml
+++ b/.github/workflows/build_teensyLC.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_teensy_octo.yml b/.github/workflows/build_teensy_octo.yml
index c346cf4c5e..8c20ef4f80 100644
--- a/.github/workflows/build_teensy_octo.yml
+++ b/.github/workflows/build_teensy_octo.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_template.yml b/.github/workflows/build_template.yml
index 2ef330f3ac..223db4968d 100644
--- a/.github/workflows/build_template.yml
+++ b/.github/workflows/build_template.yml
@@ -23,10 +23,6 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- - name: Install Python
- uses: actions/setup-python@v5
- with:
- python-version: '3.11'
# disabled for now.
@@ -38,8 +34,21 @@ jobs:
# restore-keys: |
# ${{ runner.os }}-build-
- - name: Install UV
- run: pip install uv
+ - name: Pin python version
+ run: |
+ echo "3.11" >> .python-version
+
+ - name: Install uv
+ uses: astral-sh/setup-uv@v5
+ with:
+ enable-cache: true
+ cache-dependency-glob: "**/pyproject.toml"
+
+ - name: "Set up Python"
+ uses: actions/setup-python@v5
+ with:
+ python-version-file: ".python-version"
+
- name: Install Platform
if: inputs.platform != ''
diff --git a/.github/workflows/build_unit_test.yml b/.github/workflows/build_unit_test.yml
index 5d33d2a5dc..61083ce601 100644
--- a/.github/workflows/build_unit_test.yml
+++ b/.github/workflows/build_unit_test.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_uno.yml b/.github/workflows/build_uno.yml
index 7307eecc96..0490d3d9e2 100644
--- a/.github/workflows/build_uno.yml
+++ b/.github/workflows/build_uno.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_uno_r4_wifif.yml b/.github/workflows/build_uno_r4_wifif.yml
index 022b609e7f..653bf18689 100644
--- a/.github/workflows/build_uno_r4_wifif.yml
+++ b/.github/workflows/build_uno_r4_wifif.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/build_wasm.yml b/.github/workflows/build_wasm.yml
index 61bc7b73a2..a274426292 100644
--- a/.github/workflows/build_wasm.yml
+++ b/.github/workflows/build_wasm.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
@@ -41,7 +41,7 @@ jobs:
- name: Install UV for python and npm packages
run: |
- pip install uv
+ pip install uv fastled
npm install -g live-server
- name: Verify live-server installation
@@ -51,7 +51,7 @@ jobs:
- name: Compile fastled.js, fastled.wasm, and index.html
run: |
- uv run ci/wasm_compile.py -b examples/wasm
+ fastled --just-compile examples/wasm
continue-on-error: ${{ matrix.os != 'ubuntu-latest' }}
shell: bash
diff --git a/.github/workflows/build_yun.yml b/.github/workflows/build_yun.yml
index aefb7cfbcf..e3be6d3cc1 100644
--- a/.github/workflows/build_yun.yml
+++ b/.github/workflows/build_yun.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/check_attiny85.yml b/.github/workflows/check_attiny85.yml
index f1d0c785ba..3ce42c465a 100644
--- a/.github/workflows/check_attiny85.yml
+++ b/.github/workflows/check_attiny85.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/check_esp32_size.yml b/.github/workflows/check_esp32_size.yml
index b25a021cbd..d130c83841 100644
--- a/.github/workflows/check_esp32_size.yml
+++ b/.github/workflows/check_esp32_size.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/check_teensy41_size.yml b/.github/workflows/check_teensy41_size.yml
index d67d45c28d..7db9a9b1e3 100644
--- a/.github/workflows/check_teensy41_size.yml
+++ b/.github/workflows/check_teensy41_size.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/.github/workflows/check_uno_size.yml b/.github/workflows/check_uno_size.yml
index e903f92b0e..0d02ce75cc 100644
--- a/.github/workflows/check_uno_size.yml
+++ b/.github/workflows/check_uno_size.yml
@@ -4,7 +4,7 @@ on:
push:
branches:
- master
- pull_request:
+ pull_request_target:
branches:
- master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 34d3423eb6..25f37ed481 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,18 +4,22 @@
cmake_minimum_required(VERSION 3.5)
+# Collect all source files
file(GLOB FastLED_SRCS "src/*.cpp")
-file(GLOB FastLED_SRCS "src/fl/**/*.cpp")
-file(GLOB FastLED_SRCS "src/sensors/**/*.cpp")
-file(GLOB FastLED_SRCS "src/fx/**/*.cpp")
+file(GLOB FastLED_FL_SRCS "src/fl/*.cpp")
+file(GLOB FastLED_SENSORS_SRCS "src/sensors/*.cpp")
+file(GLOB FastLED_FX_SRCS "src/fx/*.cpp" "src/fx/**/*.cpp")
-file(GLOB ESP32_SRCS "src/platforms/esp/32/*.cpp")
-file(GLOB ESP32_THIRD_PARTY "src/third_party/*.c")
-file(GLOB ESP32_THIRD_PARTY "src/third_party/*.cpp")
-list(APPEND FastLED_SRCS ${ESP32_SRCS})
+file(GLOB ESP32_SRCS "src/platforms/esp/32/*.cpp" "src/platforms/esp/32/rmt_5/*.cpp")
+file(GLOB ESP32_THIRD_PARTY_SRCS "src/third_party/**/src/*.c" "src/third_party/**/src/*.cpp")
+file(GLOB ESP32_LED_STRIP_SRCS "src/third_party/espressif/led_strip/src/*.c")
-idf_component_register(SRCS ${FastLED_SRCS} ${ESP32_LED_STRIP_COMPONENT_SRCS}
- INCLUDE_DIRS "src"
+# Combine all source files into a single list
+list(APPEND FastLED_SRCS ${FastLED_FL_SRCS} ${FastLED_SENSORS_SRCS} ${FastLED_FX_SRCS} ${ESP32_SRCS} ${ESP32_THIRD_PARTY_SRCS} ${ESP32_LED_STRIP_SRCS})
+
+# Register the component with ESP-IDF
+idf_component_register(SRCS ${FastLED_SRCS}
+ INCLUDE_DIRS "src" "src/third_party/espressif/led_strip/src"
REQUIRES arduino-esp32 esp_driver_rmt driver)
project(FastLED)
diff --git a/README.md b/README.md
index 21555eb03c..0c9820cbb9 100644
--- a/README.md
+++ b/README.md
@@ -25,8 +25,6 @@ FastLED is a robust and massively parallel-led driver for Arduino, Esp32, Raspbe
-*Hey everyone, Zach here. If you use or like this library then give us a star. I'm trying to make FastLED the #2 most popular library for Arduino. It's just one click, and you'll benefit from continued updates to FastLED.*
-
## About
@@ -85,6 +83,7 @@ For more examples see this [link](examples). Web compiled [examples](https://zac

+*Note some users find that newer versions of the ESP32 arduino core (3.10) don't work very well, but older versions do, see [issue 1903](https://github.com/FastLED/FastLED/issues/1903)
## New in 3.9.8 - Massive Teensy 4.1 & 4.0 LED output

@@ -121,7 +120,7 @@ Update: max overclock has been reported at +70%: https://www.reddit.com/r/FastLE
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny4313.yml)
-*Now compiles in the upcoming FastLED 3.9.14! - Very memory limited, so only tested against examples WS2812 Blink and APA102*
+*New FastLED 3.9.14! - Very memory limited, so only tested against examples WS2812 Blink and APA102*
[](https://github.com/FastLED/FastLED/actions/workflows/build_yun.yml)
@@ -136,7 +135,7 @@ Update: max overclock has been reported at +70%: https://www.reddit.com/r/FastLE
[](https://github.com/FastLED/FastLED/actions/workflows/build_nano_every.yml)
[](https://github.com/FastLED/FastLED/actions/workflows/build_giga_r1.yml)
-*Multiple issues with this board. Pins aren't defined, F_CPU is not defined nor is it constant. And lots of other issues. Help wanted!*
+*Now works in 3.9.14!*
### Teensy
@@ -175,7 +174,7 @@ Update: max overclock has been reported at +70%: https://www.reddit.com/r/FastLE
[](https://github.com/FastLED/FastLED/actions/workflows/build_apollo3_red.yml) *Board needs pin definitions.*
-[](https://github.com/FastLED/FastLED/actions/workflows/build_apollo3_thing_explorable.yml) *Now Supported in the upcoming FastLED 3.9.12!*
+[](https://github.com/FastLED/FastLED/actions/workflows/build_apollo3_thing_explorable.yml)
### STM
@@ -227,6 +226,8 @@ Update: max overclock has been reported at +70%: https://www.reddit.com/r/FastLE
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp_extra_libs.yml)
+[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32dev_namespace.yml)
+
*Legacy Toolchains*
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32dev_idf3.3.yml)
@@ -295,6 +296,8 @@ I2S needs special setup as of 3.9.11 and earlier (current version of this writin
The S3 is a CPU beast, but has half the RMT tx channels (4) and 2/3rds the I2S channels (16) of ESPDev. The S3 requires a special driver for I2S which you can find in this [example](https://github.com/FastLED/FastLED/blob/master/examples/Esp32S3I2SDemo/Esp32S3I2SDemo.ino)
+*Note some users find that newer versions of the ESP32 arduino core (3.10) don't work very well, but older versions do, see [issue 1903](https://github.com/FastLED/FastLED/issues/1903)
+
### RaspberriPi
I (Zach Vorhies) don't use this platform. Help wanted on what the limits of this chip is.
@@ -361,6 +364,7 @@ If you are looking for documentation on how something in the library works, plea
If you run into bugs with the library, or if you'd like to request support for a particular platform or LED chipset, please submit an issue at http://fastled.io/issues.
+
## Supported LED Chipsets
Here's a list of all the LED chipsets are supported. More details on the LED chipsets are included [on our wiki page](https://github.com/FastLED/FastLED/wiki/Chipset-reference)
@@ -457,6 +461,7 @@ Zach has this to say about FastLED:
*"The true power of FastLED lies in its ability to transform programmers into LED artists. Free space becomes their canvas; bending light is their medium. FastLED is a collective effort by programmers who want to manifest the world that science fiction writers promised us. -- To contribute code to FastLED is to leave behind a piece of something immortal."*
+
## Contributing
See our easy to use guide here:
diff --git a/RELEASE.md b/RELEASE.md
index 179033aa6e..4998ba6af4 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -24,10 +24,10 @@ Release notes should list highlight changes (not necessarily all minor bug fixes
Git commands to commit and tag release'
```bash
-$ git commit -m "Rev 3.9.13 - HD107 turbo LED support"
-$ git tag 3.9.13 master
+$ git commit -am "Rev 3.9.14 - Fixes for mqtt, Giga R1, Sin32 interpretation"
+$ git tag 3.9.14 master
$ git push
-$ git push origin 3.9.13
+$ git push origin 3.9.14
```
Then use the GitHub UI to make a new “Release”:
diff --git a/ci/ci/boards.py b/ci/ci/boards.py
index f6c44842fb..abb417e80d 100644
--- a/ci/ci/boards.py
+++ b/ci/ci/boards.py
@@ -83,6 +83,11 @@ def __hash__(self) -> int:
board_name="web",
)
+DUE = Board(
+ board_name="due",
+ platform="atmelsam",
+)
+
APOLLO3_RED_BOARD = Board(
board_name="apollo3_red",
real_board_name="SparkFun_RedBoard_Artemis_ATP",
@@ -271,6 +276,7 @@ def __hash__(self) -> int:
ALL: list[Board] = [
+ DUE,
WEBTARGET,
APOLLO3_RED_BOARD,
APOLLO3_SPARKFUN_THING_PLUS_EXPLORERABLE,
diff --git a/ci/run_test_wasm_local_compile.py b/ci/run_test_wasm_local_compile.py
index f19a34aca4..7a7c41f680 100644
--- a/ci/run_test_wasm_local_compile.py
+++ b/ci/run_test_wasm_local_compile.py
@@ -13,8 +13,16 @@ def test_build_all_examples(self) -> None:
from fastled import Api, Test # type: ignore
with Api.server(auto_updates=True) as server:
- out = Test.test_examples(host=server)
- self.assertEqual(0, len(out), f"Failed tests: {out}")
+
+ exception_map = Test.test_examples(host=server)
+ if len(exception_map) > 0:
+ exception: Exception
+ msg: str = ""
+ for example, exception in exception_map.items():
+ msg += f"Failed to compile example: {example}, error: {exception}\n"
+ self.fail(msg)
+
+ # self.assertEqual(0, len(out), f"Failed tests: {out}")
if __name__ == "__main__":
diff --git a/ci/tests/test_no_using_namespace_fl_in_headers.py b/ci/tests/test_no_using_namespace_fl_in_headers.py
index b73c8f5364..a782541982 100644
--- a/ci/tests/test_no_using_namespace_fl_in_headers.py
+++ b/ci/tests/test_no_using_namespace_fl_in_headers.py
@@ -13,6 +13,8 @@
class NoUsingNamespaceFlInHeaderTester(unittest.TestCase):
def check_file(self, file_path) -> list[str]:
+ if "FastLED.h" in file_path:
+ return []
failings: list[str] = []
with open(file_path, "r", encoding="utf-8") as f:
for line_number, line in enumerate(f, 1):
diff --git a/ci/wasm_compile.py b/ci/wasm_compile.py
index 1abd82c247..7028ebefba 100644
--- a/ci/wasm_compile.py
+++ b/ci/wasm_compile.py
@@ -1,8 +1,10 @@
import argparse
import subprocess
+import sys
+from typing import List, Tuple
-def parse_args() -> tuple[argparse.Namespace, list]:
+def parse_args() -> Tuple[argparse.Namespace, list[str]]:
parser = argparse.ArgumentParser(description="Compile wasm")
parser.add_argument(
"sketch_dir",
@@ -15,12 +17,30 @@ def parse_args() -> tuple[argparse.Namespace, list]:
return known_args, unknown_args
-def main() -> None:
+def run_command(cmd_list: List[str]) -> int:
+ """Run a command and return its exit code."""
+ cmd_str = subprocess.list2cmdline(cmd_list)
+ print(f"Running command: {cmd_str}")
+ rtn = subprocess.call(cmd_list)
+ if rtn != 0:
+ print(f"ERROR: Command {cmd_str} failed with return code {rtn}")
+ return rtn
+
+
+def main() -> int:
args, unknown_args = parse_args()
- cmd_list = ["fastled", args.sketch_dir, "--build", "--just-compile"]
- cmd_list.extend(unknown_args)
- subprocess.check_call(cmd_list)
+
+ # First run the build command
+ build_cmd = ["fastled", args.sketch_dir, "--build"] + unknown_args
+ build_result = run_command(build_cmd)
+
+ # Then run the compile command
+ compile_cmd = ["fastled", args.sketch_dir, "--just-compile"] + unknown_args
+ compile_result = run_command(compile_cmd)
+
+ # Return non-zero if either command failed
+ return build_result if build_result != 0 else compile_result
if __name__ == "__main__":
- main()
+ sys.exit(main())
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 3457a7f54c..e0832c2055 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = FastLED
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.9.13
+PROJECT_NUMBER = 3.9.14
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/examples/Apa102HDOverride/Apa102HDOverride.ino b/examples/Apa102HDOverride/Apa102HDOverride.ino
index f649dcc1a1..4b43aa9158 100644
--- a/examples/Apa102HDOverride/Apa102HDOverride.ino
+++ b/examples/Apa102HDOverride/Apa102HDOverride.ino
@@ -15,11 +15,11 @@
#define STRIP_1_DATA_PIN 3
#define STRIP_1_CLOCK_PIN 4
-void five_bit_hd_gamma_bitshift(CRGB colors,
- CRGB scale,
- uint8_t global_brightness,
- CRGB* out_colors,
- uint8_t *out_power_5bit) {
+void fl::five_bit_hd_gamma_bitshift(CRGB colors,
+ CRGB scale,
+ uint8_t global_brightness,
+ CRGB* out_colors,
+ uint8_t *out_power_5bit) {
// all 0 values for output
*out_colors = CRGB(0, 0, 0);
*out_power_5bit = 0;
diff --git a/examples/Fire2023/Fire2023.ino b/examples/Fire2023/Fire2023.ino
new file mode 100644
index 0000000000..04681e99cb
--- /dev/null
+++ b/examples/Fire2023/Fire2023.ino
@@ -0,0 +1,250 @@
+/*This is a fire effect based on the famous Fire2012; but with various small improvements.
+Perlin noise is being used to make a fire layer and a smoke layer;
+and the overlay of both can make a quite realistic effect.
+
+The speed of both need to be adapted to the matrix size and width:
+* Super small matrices (like 3x3 led) don't need the smoke
+* medium sized matrices (8x8 for example) profit from fine tuning both Fire Speed/scale as well as Smoke speed/scale
+
+This code was adapted for a matrix with just four LED columns in 90° around a core and a height of 28.
+
+Right at the bottom of the code, you find a translation matrix that needs to be adapted to your set up. I included
+a link to a helpful page for this.
+
+@repo https://github.com/Anderas2/Fire2023
+@author https://github.com/Anderas2
+*/
+
+
+#include "FastLED.h"
+#include "fl/xymap.h"
+#include "fl/screenmap.h"
+#include "fl/vector.h"
+
+using namespace fl;
+
+
+// matrix size
+#define WIDTH 4
+#define HEIGHT 28
+#define CentreX (WIDTH / 2) - 1
+#define CentreY (HEIGHT / 2) - 1
+
+// NUM_LEDS = WIDTH * HEIGHT
+#define PIXELPIN 18
+#define NUM_LEDS 120
+#define LAST_VISIBLE_LED 119
+
+
+// Fire properties
+#define BRIGHTNESS 255
+#define FIRESPEED 17
+#define FLAMEHEIGHT 3.8 // the higher the value, the higher the flame
+#define FIRENOISESCALE 125 // small values, softer fire. Big values, blink fire. 0-255
+
+// Smoke screen properties
+// The smoke screen works best for big fire effects. It effectively cuts of a part of the flames
+// from the rest, sometimes; which looks very much fire-like. For small fire effects with low
+// LED count in the height, it doesn't help
+// speed must be a little different and faster from Firespeed, to be visible.
+// Dimmer should be somewhere in the middle for big fires, and low for small fires.
+#define SMOKESPEED 25 // how fast the perlin noise is parsed for the smoke
+#define SMOKENOISE_DIMMER 250 // thickness of smoke: the lower the value, the brighter the flames. 0-255
+#define SMOKENOISESCALE 125 // small values, softer smoke. Big values, blink smoke. 0-255
+
+CRGB leds[NUM_LEDS];
+
+// fire palette roughly like matlab "hot" colormap
+// This was one of the most important parts to improve - fire color makes fire impression.
+// position, r, g, b value.
+// max value for "position" is BRIGHTNESS
+DEFINE_GRADIENT_PALETTE(hot_gp) {
+ 27, 0, 0, 0, // black
+ 28, 140, 40, 0, // red
+ 30, 205, 80, 0, // orange
+ 155, 255, 100, 0,
+ 210, 255, 200, 0, // yellow
+ 255, 255, 255, 255 // white
+};
+CRGBPalette32 hotPalette = hot_gp;
+
+// Map XY coordinates to numbers on the LED strip
+uint8_t XY (uint8_t x, uint8_t y);
+
+
+// parameters and buffer for the noise array
+#define NUM_LAYERS 2
+// two layers of perlin noise make the fire effect
+#define FIRENOISE 0
+#define SMOKENOISE 1
+uint32_t x[NUM_LAYERS];
+uint32_t y[NUM_LAYERS];
+uint32_t z[NUM_LAYERS];
+uint32_t scale_x[NUM_LAYERS];
+uint32_t scale_y[NUM_LAYERS];
+
+uint8_t noise[NUM_LAYERS][WIDTH][HEIGHT];
+uint8_t noise2[NUM_LAYERS][WIDTH][HEIGHT];
+
+uint8_t heat[NUM_LEDS];
+
+
+ScreenMap makeScreenMap();
+
+void setup() {
+
+ //Serial.begin(115200);
+ // Adjust this for you own setup. Use the hardware SPI pins if possible.
+ // On Teensy 3.1/3.2 the pins are 11 & 13
+ // Details here: https://github.com/FastLED/FastLED/wiki/SPI-Hardware-or-Bit-banging
+ // In case you see flickering / glitching leds, reduce the data rate to 12 MHZ or less
+ auto screenMap = makeScreenMap();
+ FastLED.addLeds(leds, NUM_LEDS).setScreenMap(screenMap); // Pin für Neopixel
+ FastLED.setBrightness(BRIGHTNESS);
+ FastLED.setDither(DISABLE_DITHER);
+}
+
+void Fire2023(uint32_t now);
+
+void loop() {
+ EVERY_N_MILLISECONDS(8) {
+ Fire2023(millis());
+ }
+ FastLED.show();
+}
+
+ScreenMap makeScreenMap() {
+ fl::HeapVector lut;
+ for (uint16_t y = 0; y < WIDTH; y++) {
+ for (uint16_t x = 0; x < HEIGHT; x++) {
+ pair_xy_float xy = {float(x) * 3, float(y) * 20};
+ lut.push_back(xy);
+ }
+ }
+ return ScreenMap(lut.data(), lut.size(), 1);
+}
+
+void Fire2023(uint32_t now) {
+ // some changing values
+ // these values are produced by perlin noise to add randomness and smooth transitions
+ uint16_t ctrl1 = inoise16(11 * now, 0, 0);
+ uint16_t ctrl2 = inoise16(13 * now, 100000, 100000);
+ uint16_t ctrl = ((ctrl1 + ctrl2) >> 1);
+
+ // parameters for the fire heat map
+ x[FIRENOISE] = 3 * ctrl * FIRESPEED;
+ y[FIRENOISE] = 20 * now * FIRESPEED;
+ z[FIRENOISE] = 5 * now * FIRESPEED;
+ scale_x[FIRENOISE] = scale8(ctrl1, FIRENOISESCALE);
+ scale_y[FIRENOISE] = scale8(ctrl2, FIRENOISESCALE);
+
+ //calculate the perlin noise data for the fire
+ for (uint8_t x_count = 0; x_count < WIDTH; x_count++) {
+ uint32_t xoffset = scale_x[FIRENOISE] * (x_count - CentreX);
+ for (uint8_t y_count = 0; y_count < HEIGHT; y_count++) {
+ uint32_t yoffset = scale_y[FIRENOISE] * (y_count - CentreY);
+ uint16_t data = ((inoise16(x[FIRENOISE] + xoffset, y[FIRENOISE] + yoffset, z[FIRENOISE])) + 1);
+ noise[FIRENOISE][x_count][y_count] = data >> 8;
+ }
+ }
+
+ // parameters for the smoke map
+ x[SMOKENOISE] = 3 * ctrl * SMOKESPEED;
+ y[SMOKENOISE] = 20 * now * SMOKESPEED;
+ z[SMOKENOISE] = 5 * now * SMOKESPEED;
+ scale_x[SMOKENOISE] = scale8(ctrl1, SMOKENOISESCALE);
+ scale_y[SMOKENOISE] = scale8(ctrl2, SMOKENOISESCALE);
+
+ //calculate the perlin noise data for the smoke
+ for (uint8_t x_count = 0; x_count < WIDTH; x_count++) {
+ uint32_t xoffset = scale_x[SMOKENOISE] * (x_count - CentreX);
+ for (uint8_t y_count = 0; y_count < HEIGHT; y_count++) {
+ uint32_t yoffset = scale_y[SMOKENOISE] * (y_count - CentreY);
+ uint16_t data = ((inoise16(x[SMOKENOISE] + xoffset, y[SMOKENOISE] + yoffset, z[SMOKENOISE])) + 1);
+ noise[SMOKENOISE][x_count][y_count] = data / SMOKENOISE_DIMMER;
+ }
+ }
+
+ //copy everything one line up
+ for (uint8_t y = 0; y < HEIGHT - 1; y++) {
+ for (uint8_t x = 0; x < WIDTH; x++) {
+ heat[XY(x, y)] = heat[XY(x, y + 1)];
+ }
+ }
+
+ // draw lowest line - seed the fire where it is brightest and hottest
+ for (uint8_t x = 0; x < WIDTH; x++) {
+ heat[XY(x, HEIGHT-1)] = noise[FIRENOISE][WIDTH - x][CentreX];
+ //if (heat[XY(x, HEIGHT-1)] < 200) heat[XY(x, HEIGHT-1)] = 150;
+ }
+
+ // dim the flames based on FIRENOISE noise.
+ // if the FIRENOISE noise is strong, the led goes out fast
+ // if the FIRENOISE noise is weak, the led stays on stronger.
+ // once the heat is gone, it stays dark.
+ for (uint8_t y = 0; y < HEIGHT - 1; y++) {
+ for (uint8_t x = 0; x < WIDTH; x++) {
+ uint8_t dim = noise[FIRENOISE][x][y];
+ // high value in FLAMEHEIGHT = less dimming = high flames
+ dim = dim / FLAMEHEIGHT;
+ dim = 255 - dim;
+ heat[XY(x, y)] = scale8(heat[XY(x, y)] , dim);
+
+ // map the colors based on heatmap
+ // use the heat map to set the color of the LED from the "hot" palette
+ // whichpalette position brightness blend or not
+ leds[XY(x, y)] = ColorFromPalette(hotPalette, heat[XY(x, y)], heat[XY(x, y)], LINEARBLEND);
+
+ // dim the result based on SMOKENOISE noise
+ // this is not saved in the heat map - the flame may dim away and come back
+ // next iteration.
+ leds[XY(x, y)].nscale8(noise[SMOKENOISE][x][y]);
+
+ }
+ }
+}
+
+/* Physical layout of LED strip ****************************/
+uint8_t XY (uint8_t x, uint8_t y) {
+ // any out of bounds address maps to the first hidden pixel
+ // https://macetech.github.io/FastLED-XY-Map-Generator/
+ if ( (x >= WIDTH) || (y >= HEIGHT) ) {
+ return (LAST_VISIBLE_LED + 1);
+ }
+ const uint8_t XYTable[] = {
+ 25, 26, 81, 82,
+ 25, 27, 81, 83,
+ 25, 28, 80, 84,
+ 24, 29, 79, 85,
+ 23, 30, 78, 86,
+ 22, 31, 77, 87,
+ 21, 32, 76, 88,
+ 20, 33, 75, 89,
+ 19, 34, 74, 90,
+ 18, 35, 73, 91,
+ 17, 36, 72, 92,
+ 16, 37, 71, 93,
+ 15, 38, 70, 94,
+ 14, 39, 69, 95,
+ 13, 40, 68, 96,
+ 12, 41, 67, 97,
+ 11, 42, 66, 98,
+ 10, 43, 65, 99,
+ 9, 44, 64, 100,
+ 8, 45, 63, 101,
+ 7, 46, 62, 102,
+ 6, 47, 61, 103,
+ 5, 48, 60, 104,
+ 4, 49, 59, 105,
+ 3, 50, 58, 106,
+ 2, 51, 57, 107,
+ 1, 52, 56, 108,
+ 0, 53, 55, 109
+ };
+
+ uint8_t i = (y * WIDTH) + x;
+ uint8_t j = XYTable[i];
+ return j;
+}
+
+
diff --git a/examples/LuminescentGrand/arduino/LedRopeTCL.h b/examples/LuminescentGrand/arduino/LedRopeTCL.h
index 156f16f020..d8016f5842 100644
--- a/examples/LuminescentGrand/arduino/LedRopeTCL.h
+++ b/examples/LuminescentGrand/arduino/LedRopeTCL.h
@@ -15,6 +15,8 @@
#include "crgb.h"
#include "fl/screenmap.h"
+using namespace fl;
+
// LedRopeTCL is a C++ wrapper around the Total Control Lighting LED rope
// device driver (TCL.h). This wrapper includes automatic setup of the LED
// rope and allows the user to use a graphics-state like interface for
diff --git a/library.json b/library.json
index 788f4a06cf..d1cae870f6 100644
--- a/library.json
+++ b/library.json
@@ -38,7 +38,7 @@
"type": "git",
"url": "https://github.com/FastLED/FastLED.git"
},
- "version": "3.9.13",
+ "version": "3.9.14",
"license": "MIT",
"homepage": "http://fastled.io",
"frameworks": "arduino",
diff --git a/library.properties b/library.properties
index 481e667a21..8946e86999 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=FastLED
-version=3.9.13
+version=3.9.14
author=Daniel Garcia
maintainer=Daniel Garcia
sentence=Multi-platform library for controlling dozens of different types of LEDs along with optimized math, effect, and noise functions.
diff --git a/lint b/lint
index d0412e163f..0dc7fdb14b 100755
--- a/lint
+++ b/lint
@@ -50,24 +50,16 @@ EOL
# Linting the Python code.
echo "Running ruff check"
uvx ruff check --fix ci --exclude ci/tmp/ --exclude ci/wasm/
-uvx ruff check --fix src/platforms/wasm/compiler/compile.py
-uvx ruff check --fix src/platforms/wasm/compiler/server.py
UV run ruff check --fix dev/dev.py
echo Running black
uvx black ci --exclude ci/tmp/ --exclude ci/wasm/
-uvx black src/platforms/wasm/compiler/compile.py
-uvx black src/platforms/wasm/compiler/server.py
uvx black dev/dev.py
uvx echo Running isort
uvx isort --profile black ci --skip ci/tmp/ --skip ci/wasm/
-uvx isort --profile black src/platforms/wasm/compiler/compile.py
-uvx isort --profile black src/platforms/wasm/compiler/server.py
uvx isort --profile black dev/dev.py
echo "Running mypy"
uvx echo yes | mypy --install-type
uvx mypy ci --exclude ci/tmp/ --exclude ci/wasm/
-uvx mypy src/platforms/wasm/compiler/compile.py
-uvx mypy src/platforms/wasm/compiler/server.py
uvx mypy dev/dev.py
diff --git a/platformio.ini b/platformio.ini
index b1f91f682a..fe41597145 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -31,6 +31,11 @@ platform = atmelavr
board = uno
framework = arduino
+[env:giga_r1_m7]
+platform = ststm32
+board = giga_r1_m7
+framework = arduino
+
[env:esp32s3]
extends = env:generic-esp
board = seeed_xiao_esp32s3
@@ -59,7 +64,7 @@ build_flags = ${env:generic-esp.build_flags}
[env:esp32c2]
extends = env:generic-esp
platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF5
-board = esp32-c2-devkitm-1
+board = esp32-c2-devkitm-1bjec
build_flags =
${env:generic-esp.build_flags}
diff --git a/pyproject.toml b/pyproject.toml
index 5aa8e29682..7cd63e37e5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
- "platformio==6.1.16",
+ "platformio==6.1.17",
"fastled-wasm",
"python-dateutil",
"ruff",
diff --git a/release_notes.md b/release_notes.md
index 172b6aadc5..8a111483c5 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,8 +1,15 @@
+FastLED 3.9.15
+==============
+* ESP32 series now supports FORCE_FASTLED_NAMESPACE=1
+
FastLED 3.9.14
==============
-* Attiny13 and Attiny4343 now works
+* Attiny4343 now works
* https://github.com/FastLED/FastLED/pull/1874
* Thanks https://github.com/sutaburosu!
+* Arduino GIGA Now working
+ * Thank you [@RubixCubix!](https://github.com/RubiCubix)
+* Fix for mqtt build modes: https://github.com/FastLED/FastLED/issues/1884
FastLED 3.9.13
==============
diff --git a/src/FastLED.cpp b/src/FastLED.cpp
index d4471b0f77..0372b3d169 100644
--- a/src/FastLED.cpp
+++ b/src/FastLED.cpp
@@ -23,14 +23,15 @@
volatile uint32_t fuckit;
#endif
-#ifndef FASTLED_DEFINE_WEAK_YEILD_FUNCTION
-#if defined(__AVR_ATtiny13__)
-// Arduino.h also defines this as a weak function on this platform.
-#define FASTLED_DEFINE_WEAK_YEILD_FUNCTION 0
-#else
-#define FASTLED_DEFINE_WEAK_YEILD_FUNCTION 1
-#endif
-#endif
+// Disable to fix build breakage.
+// #ifndef FASTLED_DEFINE_WEAK_YEILD_FUNCTION
+// #if defined(__AVR_ATtiny13__)
+// // Arduino.h also defines this as a weak function on this platform.
+// #define FASTLED_DEFINE_WEAK_YEILD_FUNCTION 0
+// #else
+// #define FASTLED_DEFINE_WEAK_YEILD_FUNCTION 1
+// #endif
+// #endif
/// Has to be declared outside of any namespaces.
/// Called at program exit when run in a desktop environment.
@@ -38,8 +39,8 @@ volatile uint32_t fuckit;
/// @returns 0 to indicate success
extern "C" __attribute__((weak)) int atexit(void (* /*func*/ )()) { return 0; }
-#if FASTLED_DEFINE_WEAK_YEILD_FUNCTION
-extern "C" __attribute__((weak)) void yield(void) { }
+#ifdef FASTLED_NEEDS_YIELD
+extern "C" void yield(void) { }
#endif
FASTLED_NAMESPACE_BEGIN
diff --git a/src/FastLED.h b/src/FastLED.h
index 2ebb6d4f27..3ef72518fb 100644
--- a/src/FastLED.h
+++ b/src/FastLED.h
@@ -16,13 +16,13 @@
/// * 1 digit for the major version
/// * 3 digits for the minor version
/// * 3 digits for the patch version
-#define FASTLED_VERSION 3009013
+#define FASTLED_VERSION 3009014
#ifndef FASTLED_INTERNAL
# ifdef FASTLED_SHOW_VERSION
# ifdef FASTLED_HAS_PRAGMA_MESSAGE
-# pragma message "FastLED version 3.009.013"
+# pragma message "FastLED version 3.009.014"
# else
-# warning FastLED version 3.009.013 (Not really a warning, just telling you here.)
+# warning FastLED version 3.009.014 (Not really a warning, just telling you here.)
# endif
# endif
#endif
@@ -846,11 +846,18 @@ FASTLED_NAMESPACE_END
#ifdef FASTLED_UI
// As a convenience, include the UI headers and bring them into the global namespace
#include "fl/ui.h"
+#include "fl/xymap.h"
using fl::UIButton;
using fl::UICheckbox;
using fl::UINumberField;
using fl::UISlider;
+using fl::XYMap;
#define FASTLED_TITLE(text) fl::UITitle g_title(text)
#define FASTLED_DESCRIPTION(text) fl::UIDescription g_description(text)
#endif // FASTLED_UI
+#if defined(FASTLED_FORCE_USE_NAMESPACE) && FASTLED_FORCE_USE_NAMESPACE==1
+using namespace fl;
+#endif
+
+
diff --git a/src/chipsets.h b/src/chipsets.h
index 7ad834518d..42210406be 100644
--- a/src/chipsets.h
+++ b/src/chipsets.h
@@ -2,11 +2,12 @@
#define __INC_CHIPSETS_H
#include "pixeltypes.h"
-#include "five_bit_hd_gamma.h"
+#include "fl/five_bit_hd_gamma.h"
#include "fl/force_inline.h"
#include "pixel_iterator.h"
#include "crgb.h"
#include "eorder.h"
+#include "fl/namespace.h"
@@ -103,6 +104,7 @@ FASTLED_NAMESPACE_END
// a side buffer dedicated for the RGBW data. The RGB data is then converted to RGBW
// and sent to the delegate controller for rendering as if it were RGB data.
FASTLED_NAMESPACE_BEGIN
+
template <
typename CONTROLLER,
EOrder RGB_ORDER = GRB> // Default on WS2812>
@@ -364,7 +366,7 @@ template <
// "just works" over "fastest possible" here.
// https://www.pjrc.com/why-apa102-leds-have-trouble-at-24-mhz/
uint32_t SPI_SPEED = DATA_RATE_MHZ(6),
- FiveBitGammaCorrectionMode GAMMA_CORRECTION_MODE = kFiveBitGammaCorrectionMode_Null,
+ fl::FiveBitGammaCorrectionMode GAMMA_CORRECTION_MODE = fl::kFiveBitGammaCorrectionMode_Null,
uint32_t START_FRAME = 0x00000000,
uint32_t END_FRAME = 0xFF000000
>
@@ -425,11 +427,11 @@ class APA102Controller : public CPixelLEDController {
/// @copydoc CPixelLEDController::showPixels()
virtual void showPixels(PixelController & pixels) override {
switch (GAMMA_CORRECTION_MODE) {
- case kFiveBitGammaCorrectionMode_Null: {
+ case fl::kFiveBitGammaCorrectionMode_Null: {
showPixelsDefault(pixels);
break;
}
- case kFiveBitGammaCorrectionMode_BitShift: {
+ case fl::kFiveBitGammaCorrectionMode_BitShift: {
showPixelsGammaBitShift(pixels);
break;
}
@@ -531,7 +533,7 @@ class APA102ControllerHD : public APA102Controller<
CLOCK_PIN,
RGB_ORDER,
SPI_SPEED,
- kFiveBitGammaCorrectionMode_BitShift,
+ fl::kFiveBitGammaCorrectionMode_BitShift,
uint32_t(0x00000000),
uint32_t(0x00000000)> {
public:
@@ -555,7 +557,7 @@ class SK9822Controller : public APA102Controller<
CLOCK_PIN,
RGB_ORDER,
SPI_SPEED,
- kFiveBitGammaCorrectionMode_Null,
+ fl::kFiveBitGammaCorrectionMode_Null,
0x00000000,
0x00000000
> {
@@ -577,7 +579,7 @@ class SK9822ControllerHD : public APA102Controller<
CLOCK_PIN,
RGB_ORDER,
SPI_SPEED,
- kFiveBitGammaCorrectionMode_BitShift,
+ fl::kFiveBitGammaCorrectionMode_BitShift,
0x00000000,
0x00000000
> {
@@ -596,7 +598,7 @@ class HD107Controller : public APA102Controller<
CLOCK_PIN,
RGB_ORDER,
SPI_SPEED,
- kFiveBitGammaCorrectionMode_Null,
+ fl::kFiveBitGammaCorrectionMode_Null,
0x00000000,
0x00000000
> {};
diff --git a/src/five_bit_hd_gamma.cpp b/src/fl/five_bit_hd_gamma.cpp
similarity index 99%
rename from src/five_bit_hd_gamma.cpp
rename to src/fl/five_bit_hd_gamma.cpp
index 72092c622e..f7f7917119 100644
--- a/src/five_bit_hd_gamma.cpp
+++ b/src/fl/five_bit_hd_gamma.cpp
@@ -14,8 +14,7 @@
// Author: Zach Vorhies
-
-FASTLED_NAMESPACE_BEGIN
+namespace fl {
namespace {
template T mymax(T a, T b) { return (a > b) ? a : b; }
@@ -159,4 +158,4 @@ void __builtin_five_bit_hd_gamma_bitshift(CRGB colors, CRGB colors_scale,
out_power_5bit);
}
-FASTLED_NAMESPACE_END
+} // namespace fl
diff --git a/src/five_bit_hd_gamma.h b/src/fl/five_bit_hd_gamma.h
similarity index 98%
rename from src/five_bit_hd_gamma.h
rename to src/fl/five_bit_hd_gamma.h
index 59e2679611..4c4174e607 100644
--- a/src/five_bit_hd_gamma.h
+++ b/src/fl/five_bit_hd_gamma.h
@@ -9,7 +9,7 @@
#include "fl/force_inline.h"
#include "crgb.h"
-FASTLED_NAMESPACE_BEGIN
+namespace fl {
enum FiveBitGammaCorrectionMode {
kFiveBitGammaCorrectionMode_Null = 0,
@@ -90,5 +90,5 @@ void five_bit_hd_gamma_function(CRGB color,
uint16_t *r16, uint16_t *g16, uint16_t *b16);
#endif // FASTLED_FIVE_BIT_HD_GAMMA_FUNCTION_OVERRIDE
-FASTLED_NAMESPACE_END
+} // namespace fl
diff --git a/src/fl/sin32.cpp b/src/fl/sin32.cpp
new file mode 100644
index 0000000000..ad83fac112
--- /dev/null
+++ b/src/fl/sin32.cpp
@@ -0,0 +1,35 @@
+
+
+#include
+
+namespace fl {
+
+const int16_t sinLut[] =
+{
+ 0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179, 7962, 8739, 9512, 10278, 11039, 11793,
+ 12539, 13279, 14010, 14732, 15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403, 22005, 22594,
+ 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790, 27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956,
+ 30273, 30571, 30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521, 32609, 32678, 32728, 32757,
+ 32767, 32757, 32728, 32678, 32609, 32521, 32412, 32285, 32137, 31971, 31785, 31580, 31356, 31113, 30852, 30571,
+ 30273, 29956, 29621, 29268, 28898, 28510, 28105, 27683, 27245, 26790, 26319, 25832, 25329, 24811, 24279, 23731,
+ 23170, 22594, 22005, 21403, 20787, 20159, 19519, 18868, 18204, 17530, 16846, 16151, 15446, 14732, 14010, 13279,
+ 12539, 11793, 11039, 10278, 9512, 8739, 7962, 7179, 6393, 5602, 4808, 4011, 3212, 2410, 1608, 804,
+ 0, -804, -1608, -2410, -3212, -4011, -4808, -5602, -6393, -7179, -7962, -8739, -9512, -10278, -11039, -11793,
+-12539, -13279, -14010, -14732, -15446, -16151, -16846, -17530, -18204, -18868, -19519, -20159, -20787, -21403, -22005, -22594,
+-23170, -23731, -24279, -24811, -25329, -25832, -26319, -26790, -27245, -27683, -28105, -28510, -28898, -29268, -29621, -29956,
+-30273, -30571, -30852, -31113, -31356, -31580, -31785, -31971, -32137, -32285, -32412, -32521, -32609, -32678, -32728, -32757,
+-32767, -32757, -32728, -32678, -32609, -32521, -32412, -32285, -32137, -31971, -31785, -31580, -31356, -31113, -30852, -30571,
+-30273, -29956, -29621, -29268, -28898, -28510, -28105, -27683, -27245, -26790, -26319, -25832, -25329, -24811, -24279, -23731,
+-23170, -22594, -22005, -21403, -20787, -20159, -19519, -18868, -18204, -17530, -16846, -16151, -15446, -14732, -14010, -13279,
+-12539, -11793, -11039, -10278, -9512, -8739, -7962, -7179, -6393, -5602, -4808, -4011, -3212, -2410, -1608, -804,
+ 0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179, 7962, 8739, 9512, 10278, 11039, 11793,
+ 12539, 13279, 14010, 14732, 15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403, 22005, 22594,
+ 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790, 27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956,
+ 30273, 30571, 30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521, 32609, 32678, 32728, 32757,
+ 32767};
+
+const int16_t *sinArray = &sinLut[0];
+
+const int16_t *cosArray = &sinLut[64];
+
+} // namespace fl
diff --git a/src/fl/sin32.h b/src/fl/sin32.h
new file mode 100644
index 0000000000..d877a03338
--- /dev/null
+++ b/src/fl/sin32.h
@@ -0,0 +1,70 @@
+#pragma once
+
+
+#include
+
+#include "namespace.h"
+#include "force_inline.h"
+
+namespace fl {
+
+// fast and accurate sin and cos approximations
+// they differ only 0.01 % from actual sinf and cosf funtions
+// sin32 and cos32 use 24 bit unsigned integer arguments
+// 0 to 16777216 is one cycle
+// they output an integer between -2147418112 and 2147418112
+// that's 32767 * 65536
+// this is because I use int16_t look up table to interpolate the results
+//
+// sin16 and cos16 are faster and more accurate funtions that take uint16_t as arguments
+// and return int16_t as output
+// they can replace the older implementation and are 62 times more accurate and twice as fast
+// the downside with these funtions is that they use 640 bytes for the look up table
+// thats a lot for old microcontrollers but nothing for modern ones
+//
+// sin32 and cos32 take about 13 cyces to execute on an esp32
+// they're 32 times faster than sinf and cosf
+// you can use choose to use these new by writing
+// #define USE_SIN_32 before #include "FastLED.h"
+
+extern const int16_t *sinArray;
+
+extern const int16_t *cosArray;
+
+// 0 to 16777216 is a full circle
+// output is between -2147418112 and 2147418112
+FASTLED_FORCE_INLINE static int32_t sin32(uint32_t angle)
+{
+ uint8_t angle256 = angle / 65536;
+ int32_t subAngle = angle % 65536;
+ return sinArray[angle256] * (65536 - subAngle) + sinArray[angle256 + 1] * subAngle;
+}
+
+// 0 to 16777216 is a full circle
+// output is between -2147418112 and 2147418112
+FASTLED_FORCE_INLINE static int32_t cos32(uint32_t angle)
+{
+ uint8_t angle256 = angle / 65536;
+ int32_t subAngle = angle % 65536;
+ return cosArray[angle256] * (65536 - subAngle) + cosArray[angle256 + 1] * subAngle;
+}
+
+// 0 to 65536 is a full circle
+// output is between -32767 and 32767
+FASTLED_FORCE_INLINE static int16_t sin16lut(uint16_t angle)
+{
+ uint8_t angle256 = angle / 256;
+ int32_t subAngle = angle % 256;
+ return (sinArray[angle256] * (256 - subAngle) + sinArray[angle256 + 1] * subAngle) / 256;
+}
+
+// 0 to 65536 is a full circle
+// output is between -32767 and 32767
+FASTLED_FORCE_INLINE static int16_t cos16lut(uint16_t angle)
+{
+ uint8_t angle256 = angle / 256;
+ int32_t subAngle = angle % 256;
+ return (cosArray[angle256] * (256 - subAngle) + cosArray[angle256 + 1] * subAngle) / 256;
+}
+
+} // namespace fl
diff --git a/src/fx/2d/noisepalette.cpp b/src/fx/2d/noisepalette.cpp
index e2bdf02fd0..450239e61e 100644
--- a/src/fx/2d/noisepalette.cpp
+++ b/src/fx/2d/noisepalette.cpp
@@ -33,10 +33,10 @@ NoisePalette::NoisePalette(XYMap xyMap, float fps)
setPalettePreset(0);
// Allocate memory for the noise array using scoped_ptr
- noise = scoped_ptr(new uint8_t[width * height]);
+ noise = scoped_array(new uint8_t[width * height]);
}
-void NoisePalette::setPalettePreset(int paletteIndex) {
+void NoisePalette::setPalettePreset(int paletteIndex) {
currentPaletteIndex = paletteIndex % 12; // Ensure the index wraps around
switch (currentPaletteIndex) {
case 0:
diff --git a/src/fx/2d/noisepalette.h b/src/fx/2d/noisepalette.h
index 150215162f..5ff6dc6b9b 100644
--- a/src/fx/2d/noisepalette.h
+++ b/src/fx/2d/noisepalette.h
@@ -60,7 +60,7 @@ class NoisePalette : public Fx2d {
uint16_t width, height;
uint16_t speed = 0;
uint16_t scale = 0;
- fl::scoped_ptr noise;
+ fl::scoped_array noise;
CRGBPalette16 currentPalette;
bool colorLoop = 0;
int currentPaletteIndex = 0;
diff --git a/src/fx/readme b/src/fx/readme
index 5025438146..30d5b11a89 100644
--- a/src/fx/readme
+++ b/src/fx/readme
@@ -15,18 +15,15 @@ As a result, FX components can be "heavyweight," meaning they may include a larg
*.hpp are somewhere between a standard header and a *.cpp file. While a standard header typically only attempts to declare data layout, functions and
classes, *.hpp files are typically much more heavy weight and will happy inject global data into your compilation unit. Because of this, *.hpp files should only ever be included once.
-Another reason is licensing. Starting with FastLED 4.0, we now distribute some amazing code that has restrictive commercial licensing requirements. If
-we included these by default into the core driver then that would be problematic for the user. Therefore such files are NOT compiled by default and
-must be included by the user explicitly as an *.hpp file.
## Licensing
-Some FX components are public domain and can be freely used or copied in commercial applications without the need for a license or permission.
+Everything in this library is under FastLED standard license except the following:
-However, not all FX components come with permissive licenses for commercial use. If you include an FX component with restrictions, you will see a compilation warning indicating its non-commercial license. It is your responsibility to contact the creator for proper licensing if used in commercial products.
+ * Animartrix
-For non-commercial, artistic projects where no financial transactions are involved, you generally don't need to worry about these restrictions.
+Animartrix is free for non commercial use, paid license otherwise.
-Certain higher-end FX components, such as the fx component "animatrix," have more restrictive licensing, but they remain free for non-commercial use.
+Optional code modules are tagged as *.hpp.
-Happy coding!
\ No newline at end of file
+Happy coding!
diff --git a/src/hsv2rgb.cpp b/src/hsv2rgb.cpp
index 9799137c7c..a4cf5a521f 100644
--- a/src/hsv2rgb.cpp
+++ b/src/hsv2rgb.cpp
@@ -422,8 +422,11 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
//nscale8x3_video( r, g, b, sat);
#if (FASTLED_SCALE8_FIXED==1)
r = scale8_LEAVING_R1_DIRTY( r, satscale);
+ asm volatile(""); // Fixes jumping red pixel: https://github.com/FastLED/FastLED/pull/943
g = scale8_LEAVING_R1_DIRTY( g, satscale);
+ asm volatile("");
b = scale8_LEAVING_R1_DIRTY( b, satscale);
+ asm volatile("");
cleanup_R1();
#else
if( r ) r = scale8( r, satscale) + 1;
@@ -447,8 +450,11 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
// nscale8x3_video( r, g, b, val);
#if (FASTLED_SCALE8_FIXED==1)
r = scale8_LEAVING_R1_DIRTY( r, val);
+ asm volatile(""); // Fixes jumping red pixel: https://github.com/FastLED/FastLED/pull/943
g = scale8_LEAVING_R1_DIRTY( g, val);
+ asm volatile("");
b = scale8_LEAVING_R1_DIRTY( b, val);
+ asm volatile("");
cleanup_R1();
#else
if( r ) r = scale8( r, val) + 1;
diff --git a/src/led_sysdefs.h b/src/led_sysdefs.h
index 9d245accb2..b7528f5468 100644
--- a/src/led_sysdefs.h
+++ b/src/led_sysdefs.h
@@ -32,7 +32,7 @@
#elif defined(__SAM3X8E__)
// Include sam/due headers
#include "platforms/arm/sam/led_sysdefs_arm_sam.h"
-#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX) || defined(STM32F1)
+#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX) || defined(STM32F1) || defined(STM32F407xx)
#include "platforms/arm/stm32/led_sysdefs_arm_stm32.h"
#elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__)
#include "platforms/arm/d21/led_sysdefs_arm_d21.h"
@@ -53,6 +53,8 @@
#include "platforms/apollo3/led_sysdefs_apollo3.h"
#elif defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_RENESAS_UNO) || defined(ARDUINO_ARCH_RENESAS_PORTENTA)
#include "platforms/arm/renesas/led_sysdef_arm_renesas.h"
+#elif defined(ARDUINO_GIGA)|| defined(ARDUINO_GIGA_M7)
+#include "platforms/arm/giga/led_sysdef_arm_giga.h"
#elif defined(__x86_64__) || defined(FASTLED_STUB_IMPL) || defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(__EMSCRIPTEN__)
// Not on a microcontroller
//# ifdef FASTLED_HAS_PRAGMA_MESSAGE
diff --git a/src/lib8tion/trig8.h b/src/lib8tion/trig8.h
index 8af033369e..fe42dbfa5f 100644
--- a/src/lib8tion/trig8.h
+++ b/src/lib8tion/trig8.h
@@ -20,7 +20,14 @@
/// the 8-bit approximation is more than 20X faster.
/// @{
-#if defined(__AVR__)
+#if defined(USE_SIN_32)
+
+#define sin16 fl::sin16lut
+#define cos16 fl::cos16lut
+
+#include "fl/sin32.h"
+
+#elif defined(__AVR__)
/// Platform-independent alias of the fast sin implementation
#define sin16 sin16_avr
@@ -132,7 +139,9 @@ LIB8STATIC int16_t sin16_C(uint16_t theta) {
///
/// @param theta input angle from 0-65535
/// @returns cos of theta, value between -32767 to 32767.
+#ifndef USE_SIN_32
LIB8STATIC int16_t cos16(uint16_t theta) { return sin16(theta + 16384); }
+#endif
///////////////////////////////////////////////////////////////////////
// sin8() and cos8()
diff --git a/src/pixel_controller.h b/src/pixel_controller.h
index ee8cbce6ef..8c5d49553f 100644
--- a/src/pixel_controller.h
+++ b/src/pixel_controller.h
@@ -13,7 +13,7 @@
#include "FastLED.h"
#include "rgbw.h"
-#include "five_bit_hd_gamma.h"
+#include "fl/five_bit_hd_gamma.h"
#include "fl/force_inline.h"
#include "fl/namespace.h"
#include "eorder.h"
@@ -493,7 +493,7 @@ struct PixelController {
brightness = 255;
CRGB scale = mColorAdjustment.premixed;
#endif
- five_bit_hd_gamma_bitshift(
+ fl::five_bit_hd_gamma_bitshift(
rgb,
scale,
brightness,
diff --git a/src/platforms.h b/src/platforms.h
index 87f651fb0c..f77aaa3781 100644
--- a/src/platforms.h
+++ b/src/platforms.h
@@ -29,7 +29,7 @@
#elif defined(__SAM3X8E__)
// Include sam/due headers
#include "platforms/arm/sam/fastled_arm_sam.h"
-#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX) || defined(STM32F1)
+#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX) || defined(STM32F1) || defined(STM32F407xx)
#include "platforms/arm/stm32/fastled_arm_stm32.h"
#elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__)
#include "platforms/arm/d21/fastled_arm_d21.h"
@@ -46,6 +46,8 @@
#include "platforms/apollo3/fastled_apollo3.h"
#elif defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_RENESAS_UNO) || defined(ARDUINO_ARCH_RENESAS_PORTENTA)
#include "platforms/arm/renesas/fastled_arm_renesas.h"
+#elif defined(ARDUINO_GIGA) || defined(ARDUINO_GIGA_M7)
+#include "platforms/arm/giga/fastled_arm_giga.h"
#elif defined(__x86_64__) || defined(FASTLED_STUB_IMPL)
// stub platform for testing (on cpu)
diff --git a/src/platforms/arm/giga/armpin.h b/src/platforms/arm/giga/armpin.h
new file mode 100644
index 0000000000..b36931902e
--- /dev/null
+++ b/src/platforms/arm/giga/armpin.h
@@ -0,0 +1,50 @@
+#pragma once
+#include
+
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
+
+#define _R(T) struct __gen_struct_ ## T
+#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin : public _ARMPIN {};
+
+/// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this
+/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
+/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
+/// The registers are data output, set output, clear output, toggle output, input, and direction
+
+template class _ARMPIN {
+
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
+ inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+
+ inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = (_MASK<<16); }
+
+ inline static void set(FASTLED_REGISTER port_t val) __attribute__ ((always_inline)) { _GPIO::r()->ODR = val; }
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { if(_GPIO::r()->ODR & _MASK) { lo(); } else { hi(); } }
+
+ inline static void hi(FASTLED_REGISTER port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(FASTLED_REGISTER port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(FASTLED_REGISTER port_ptr_t port, FASTLED_REGISTER port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { return _GPIO::r()->ODR | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO::r()->ODR & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO::r()->ODR; }
+
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR = (_MASK<<16); }
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR = _MASK; }
+
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+};
+
+
+
+FASTLED_NAMESPACE_END
diff --git a/src/platforms/arm/giga/clockless_arm_giga.h b/src/platforms/arm/giga/clockless_arm_giga.h
new file mode 100644
index 0000000000..a8c5b81aea
--- /dev/null
+++ b/src/platforms/arm/giga/clockless_arm_giga.h
@@ -0,0 +1,128 @@
+#ifndef __INC_CLOCKLESS_ARM_GIGA
+#define __INC_CLOCKLESS_ARM_GIGA
+
+FASTLED_NAMESPACE_BEGIN
+
+// Definition for a single channel clockless controller for GIGA M7
+// See clockless.h for detailed info on how the template parameters are used.
+#define ARM_DEMCR (*(volatile uint32_t *)0xE000EDFC) // Debug Exception and Monitor Control
+#define ARM_DEMCR_TRCENA (1 << 24) // Enable debugging & monitoring blocks
+#define ARM_DWT_CTRL (*(volatile uint32_t *)0xE0001000) // DWT control register
+#define ARM_DWT_CTRL_CYCCNTENA (1 << 0) // Enable cycle count
+#define ARM_DWT_CYCCNT (*(volatile uint32_t *)0xE0001004) // Cycle count register
+
+
+#define FASTLED_HAS_CLOCKLESS 1
+
+template
+class ClocklessController : public CPixelLEDController {
+ typedef typename FastPin::port_ptr_t data_ptr_t;
+ typedef typename FastPin::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait mWait;
+
+public:
+ virtual void init() {
+ FastPin::setOutput();
+ mPinMask = FastPin::mask();
+ mPort = FastPin::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+protected:
+ virtual void showPixels(PixelController & pixels) {
+ mWait.wait();
+ if(!showRGBInternal(pixels)) {
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
+
+ template __attribute__ ((always_inline)) inline static void writeBits(FASTLED_REGISTER uint32_t & next_mark, FASTLED_REGISTER data_ptr_t port, FASTLED_REGISTER data_t hi, FASTLED_REGISTER data_t lo, FASTLED_REGISTER uint8_t & b) {
+ for(FASTLED_REGISTER uint32_t i = BITS-1; i > 0; --i) {
+ while(ARM_DWT_CYCCNT < next_mark);
+ next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
+ FastPin::fastset(port, hi);
+ if(b&0x80) {
+ while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
+ FastPin::fastset(port, lo);
+ } else {
+ while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
+ FastPin::fastset(port, lo);
+ }
+ b <<= 1;
+ }
+
+ while(ARM_DWT_CYCCNT < next_mark);
+ next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
+ FastPin::fastset(port, hi);
+
+ if(b&0x80) {
+ while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
+ FastPin::fastset(port, lo);
+ } else {
+ while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
+ FastPin::fastset(port, lo);
+ }
+ }
+
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
+ static uint32_t showRGBInternal(PixelController pixels) {
+ // Get access to the clock
+ ARM_DEMCR |= ARM_DEMCR_TRCENA;
+ ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
+ ARM_DWT_CYCCNT = 0;
+
+ FASTLED_REGISTER data_ptr_t port = FastPin::port();
+ FASTLED_REGISTER data_t hi = *port | FastPin::mask();
+ FASTLED_REGISTER data_t lo = *port & ~FastPin::mask();
+ *port = lo;
+
+ // Setup the pixel controller and load/scale the first byte
+ pixels.preStepFirstByteDithering();
+ FASTLED_REGISTER uint8_t b = pixels.loadAndScale0();
+
+ cli();
+ uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
+
+ while(pixels.has(1)) {
+ pixels.stepDithering();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ cli();
+ // if interrupts took longer than 45µs, punt on the current frame
+ if(ARM_DWT_CYCCNT > next_mark) {
+ if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
+ }
+
+ hi = *port | FastPin::mask();
+ lo = *port & ~FastPin::mask();
+ #endif
+ // Write first byte, read next byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale1();
+
+ // Write second byte, read 3rd byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale2();
+
+ // Write third byte, read 1st byte of next pixel
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.advanceAndLoadAndScale0();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ sei();
+ #endif
+ };
+
+ sei();
+ return ARM_DWT_CYCCNT;
+ }
+};
+
+FASTLED_NAMESPACE_END
+
+#endif
diff --git a/src/platforms/arm/giga/fastled_arm_giga.h b/src/platforms/arm/giga/fastled_arm_giga.h
new file mode 100644
index 0000000000..a6d4753db8
--- /dev/null
+++ b/src/platforms/arm/giga/fastled_arm_giga.h
@@ -0,0 +1,8 @@
+#ifndef __INC_FASTLED_ARM_GIGA_H
+#define __INC_FASTLED_ARM_GIGA_H
+
+#include "fastpin_arm_giga.h"
+#include "../../fastspi_ardunio_core.h"
+#include "clockless_arm_giga.h"
+
+#endif
diff --git a/src/platforms/arm/giga/fastpin_arm_giga.h b/src/platforms/arm/giga/fastpin_arm_giga.h
new file mode 100644
index 0000000000..b4ee357d88
--- /dev/null
+++ b/src/platforms/arm/giga/fastpin_arm_giga.h
@@ -0,0 +1,208 @@
+#ifndef __FASTPIN_ARM_GIGA_H
+#define __FASTPIN_ARM_GIGA_H
+
+#include "fl/force_inline.h"
+#include "fl/namespace.h"
+#include "armpin.h"
+
+FASTLED_NAMESPACE_BEGIN
+
+#if defined(ARDUINO_GIGA) || defined(ARDUINO_GIGA_M7)
+#define _RD32(T) struct __gen_struct_ ## T { static FASTLED_FORCE_INLINE volatile GPIO_TypeDef * r() { return T; } };
+#define _FL_IO(L,C) _RD32(GPIO ## L);
+
+#else
+#error "Platform not supported"
+#endif
+
+_FL_IO(A,0);
+_FL_IO(B,1);
+_FL_IO(C,2);
+_FL_IO(D,3);
+_FL_IO(E,4);
+_FL_IO(F,5);
+_FL_IO(G,6);
+_FL_IO(H,7);
+_FL_IO(I,8);
+_FL_IO(J,9);
+_FL_IO(K,10);
+
+// Actual pin definitions
+#if defined(ARDUINO_GIGA) || defined(ARDUINO_GIGA_M7)
+#define MAX_PIN 102
+
+// PA0-PA15
+_FL_DEFPIN(83, 0, A);
+_FL_DEFPIN(66, 1, A);
+_FL_DEFPIN(3, 2, A);
+_FL_DEFPIN(2, 3, A);
+_FL_DEFPIN(84, 4, A);
+_FL_DEFPIN(85, 5, A);
+_FL_DEFPIN(56, 6, A);
+_FL_DEFPIN(5, 7, A);
+//_FL_DEFPIN(UART7_RX, 8, A);
+_FL_DEFPIN(1, 9, A);
+//_FL_DEFPIN(BT_ON, 10, A);
+//_FL_DEFPIN(USB-OTG-FS_DM, 11, A);
+//_FL_DEFPIN(USB-OTG-FS_DP, 12, A);
+//_FL_DEFPIN(SWDIO, 13, A);
+//_FL_DEFPIN(SWCLK, 14, A);
+//_FL_DEFPIN(U9 Power Switch, 15, A);
+
+// PB0-PB13
+_FL_DEFPIN(78, 0, B);
+_FL_DEFPIN(79, 1, B);
+_FL_DEFPIN(47, 2, B);
+_FL_DEFPIN(91, 3, B);
+_FL_DEFPIN(7, 4, B);
+_FL_DEFPIN(93, 5, B);
+_FL_DEFPIN(101, 6, B);
+_FL_DEFPIN(0, 7, B);
+_FL_DEFPIN(8, 8, B);
+_FL_DEFPIN(9, 9, B);
+//_FL_DEFPIN(WL_ON, 10, B);
+_FL_DEFPIN(20, 11, B);
+_FL_DEFPIN(74, 12, B);
+_FL_DEFPIN(94, 13, B);
+
+// PC0-PC15
+_FL_DEFPIN(82, 0, C);
+_FL_DEFPIN(73, 1, C);
+_FL_DEFPIN(81, 2, C);
+_FL_DEFPIN(80, 3, C);
+_FL_DEFPIN(76, 4, C);
+_FL_DEFPIN(77, 5, C);
+_FL_DEFPIN(68, 6, C);
+_FL_DEFPIN(15, 7, C);
+//_FL_DEFPIN(D0, 8, C);
+//_FL_DEFPIN(D1, 9, C);
+//_FL_DEFPIN(D2, 10, C);
+//_FL_DEFPIN(D3, 11, C);
+//_FL_DEFPIN(CLK, 12, C);
+//_FL_DEFPIN(BOOT0_BUTTON, 13, C);
+
+// PD0-PD13
+//_FL_DEFPIN(FMC_D3, 0, D);
+//_FL_DEFPIN(FMC_D2, 1, D);
+//_FL_DEFPIN(SDMMC1_CMD, 2, D);
+_FL_DEFPIN(75, 3, D);
+_FL_DEFPIN(67, 4, D);
+_FL_DEFPIN(18, 5, D);
+_FL_DEFPIN(19, 6, D);
+_FL_DEFPIN(90, 7, D);
+//_FL_DEFPIN(FMC_DQ13, 8, D);
+//_FL_DEFPIN(FMC_DQ14, 9, D);
+//_FL_DEFPIN(FMC_DQ15, 10, D);
+//_FL_DEFPIN(SI/IO0, 11, D);
+//_FL_DEFPIN(SO/IO1, 12, D);
+_FL_DEFPIN(6, 13, D);
+//_FL_DEFPIN(FMC_D0, 14, D);
+//_FL_DEFPIN(FMC_D1, 14, D);
+
+// PE0-PE15
+//_FL_DEFPIN(FMC_DQML, 0, E);
+//_FL_DEFPIN(FMC_DQMH, 1, E);
+//_FL_DEFPIN(QUADSPI_BK2-IO1, 2, E);
+_FL_DEFPIN(88, 3, E);
+_FL_DEFPIN(49, 4, E);
+_FL_DEFPIN(51, 5, E);
+_FL_DEFPIN(40, 6, E);
+//_FL_DEFPIN(FMC_DQ4, 7, E);
+//_FL_DEFPIN(FMC_DQ5, 8, E);
+//_FL_DEFPIN(FMC_DQ6, 9, E);
+//_FL_DEFPIN(FMC_DQ7, 10, E);
+//_FL_DEFPIN(FMC_DQ8, 11, E);
+//_FL_DEFPIN(FMC_DQ9, 12, E);
+//_FL_DEFPIN(FMC_DQ10, 13, E);
+//_FL_DEFPIN(FMC_DQ11, 14, E);
+//_FL_DEFPIN(FMC_DQ2, 15, E);
+
+// PG0-PG15
+//_FL_DEFPIN(FMC_A10, 0, G);
+//_FL_DEFPIN(FMC_A11, 1, G);
+//_FL_DEFPIN(FMC_A12, 2, G);
+//_FL_DEFPIN(BT_WAKE_H, 3, G);
+//_FL_DEFPIN(FMC_BA0, 4, G);
+//_FL_DEFPIN(FMC_BA1, 5, G);
+//_FL_DEFPIN(CS, 6, G);
+_FL_DEFPIN(53, 7, G);
+_FL_DEFPIN(89, 9, G);
+_FL_DEFPIN(44, 10, G);
+_FL_DEFPIN(62, 11, G);
+_FL_DEFPIN(24, 12, G);
+_FL_DEFPIN(14, 14, G);
+//_FL_DEFPIN(FMC_SDNCAS, 15, G);
+
+// PH3-PH15
+//_FL_DEFPIN(FMC_SDCKE0, 2, H);
+//_FL_DEFPIN(FMC_SDNCS, 3, H);
+_FL_DEFPIN(21, 4, H);
+//_FL_DEFPIN(FMC_SDNWE, 5, H);
+_FL_DEFPIN(13, 6, H);
+//_FL_DEFPIN(BT_WAKE_D, 7, H);
+_FL_DEFPIN(55, 8, H);
+_FL_DEFPIN(65, 9, H);
+_FL_DEFPIN(64, 10, H);
+_FL_DEFPIN(63, 11, H);
+_FL_DEFPIN(102, 12, H);
+_FL_DEFPIN(16, 13, H);
+_FL_DEFPIN(61, 14, H);
+_FL_DEFPIN(46, 15, H);
+
+// PI0-PI15
+_FL_DEFPIN(69, 0, I);
+_FL_DEFPIN(70, 1, I);
+_FL_DEFPIN(71, 2, I);
+_FL_DEFPIN(72, 3, I);
+_FL_DEFPIN(60, 4, I);
+_FL_DEFPIN(54, 5, I);
+_FL_DEFPIN(59, 6, I);
+_FL_DEFPIN(58, 7, I);
+_FL_DEFPIN(17, 9, I);
+_FL_DEFPIN(43, 10, I);
+_FL_DEFPIN(50, 11, I);
+_FL_DEFPIN(86, 12, I);
+_FL_DEFPIN(45, 13, I);
+_FL_DEFPIN(39, 14, I);
+_FL_DEFPIN(42, 15, I);
+
+// PJ0-PJ15
+_FL_DEFPIN(25, 0, J);
+_FL_DEFPIN(27, 1, J);
+_FL_DEFPIN(29, 2, J);
+_FL_DEFPIN(31, 3, J);
+_FL_DEFPIN(33, 4, J);
+_FL_DEFPIN(35, 5, J);
+_FL_DEFPIN(37, 6, J);
+_FL_DEFPIN(38, 7, J);
+_FL_DEFPIN(4, 8, J);
+_FL_DEFPIN(57, 9, J);
+_FL_DEFPIN(11, 10, J);
+_FL_DEFPIN(12, 11, J);
+_FL_DEFPIN(22, 12, J);
+_FL_DEFPIN(87, 13, J);
+_FL_DEFPIN(26, 14, J);
+_FL_DEFPIN(28, 15, J);
+
+// PK0-PK7
+_FL_DEFPIN(48, 0, K);
+_FL_DEFPIN(10, 1, K);
+_FL_DEFPIN(52, 2, K);
+_FL_DEFPIN(30, 3, K);
+_FL_DEFPIN(32, 4, K);
+_FL_DEFPIN(34, 5, K);
+_FL_DEFPIN(36, 6, K);
+_FL_DEFPIN(41, 7, K);
+
+// SPI2 MOSI
+#define SPI_DATA 90
+// SPI2 SCK
+#define SPI_CLOCK 91
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#endif // ARDUINO_GIGA || ARDUINO_GIGA_M7
+
+FASTLED_NAMESPACE_END
+
+#endif // __INC_FASTPIN_ARM_STM32
diff --git a/src/platforms/arm/giga/led_sysdef_arm_giga.h b/src/platforms/arm/giga/led_sysdef_arm_giga.h
new file mode 100644
index 0000000000..6c0e2b426f
--- /dev/null
+++ b/src/platforms/arm/giga/led_sysdef_arm_giga.h
@@ -0,0 +1,31 @@
+#ifndef __INC_LED_SYSDEFS_ARM_GIGA_H
+#define __INC_LED_SYSDEFS_ARM_GIGA_H
+
+#define FASTLED_ARM
+
+#ifndef INTERRUPT_THRESHOLD
+#define INTERRUPT_THRESHOLD 1
+#endif
+
+// Default to allowing interrupts
+#ifndef FASTLED_ALLOW_INTERRUPTS
+#define FASTLED_ALLOW_INTERRUPTS 1
+#endif
+
+#if FASTLED_ALLOW_INTERRUPTS == 1
+#define FASTLED_ACCURATE_CLOCK
+#endif
+
+// reusing/abusing cli/sei defs for due
+#define cli() __disable_irq();
+#define sei() __enable_irq();
+
+#define FASTLED_NO_PINMAP
+
+typedef volatile uint32_t RoReg;
+typedef volatile uint32_t RwReg;
+
+#define F_CPU 480000000
+
+#endif
+
diff --git a/src/platforms/arm/k20/clockless_block_arm_k20.h b/src/platforms/arm/k20/clockless_block_arm_k20.h
index d6e35e08b5..44176229a6 100644
--- a/src/platforms/arm/k20/clockless_block_arm_k20.h
+++ b/src/platforms/arm/k20/clockless_block_arm_k20.h
@@ -14,7 +14,6 @@
#define PORT_MASK (((1<
diff --git a/src/platforms/arm/k20/fastspi_arm_k20.h b/src/platforms/arm/k20/fastspi_arm_k20.h
index b860bf78bc..5c6d6407a9 100644
--- a/src/platforms/arm/k20/fastspi_arm_k20.h
+++ b/src/platforms/arm/k20/fastspi_arm_k20.h
@@ -37,8 +37,6 @@ template class BitWork {
static int highestBit() __attribute__((always_inline)) { return 0; }
};
-#define MAX(A, B) (( (A) > (B) ) ? (A) : (B))
-
#define USE_CONT 0
// intra-frame backup data
struct SPIState {
diff --git a/src/platforms/arm/stm32/fastpin_arm_stm32.h b/src/platforms/arm/stm32/fastpin_arm_stm32.h
index c5a4f1b8e7..a013969564 100644
--- a/src/platforms/arm/stm32/fastpin_arm_stm32.h
+++ b/src/platforms/arm/stm32/fastpin_arm_stm32.h
@@ -7,7 +7,7 @@
#else
#ifndef USE_NEW_STM32_PIN_DEFINITIONS
-#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_MAPLE_MINI)
+#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_MAPLE_MINI) //|| defined(STM32F407xx)
#define USE_NEW_STM32_PIN_DEFINITIONS
#endif
#endif
diff --git a/src/platforms/arm/stm32/fastpin_arm_stm_legacy.h b/src/platforms/arm/stm32/fastpin_arm_stm_legacy.h
index 65965f5718..831338e0b8 100644
--- a/src/platforms/arm/stm32/fastpin_arm_stm_legacy.h
+++ b/src/platforms/arm/stm32/fastpin_arm_stm_legacy.h
@@ -15,7 +15,7 @@ FASTLED_NAMESPACE_BEGIN
#define _RD32(T) struct __gen_struct_ ## T { static FASTLED_FORCE_INLINE gpio_reg_map* r() { return T->regs; } };
#define _FL_IO(L,C) _RD32(GPIO ## L); _FL_DEFINE_PORT3(L, C, _R(GPIO ## L));
-#elif defined(STM32F2XX)
+#elif defined(STM32F2XX) || defined(STM32F407xx)
#define _RD32(T) struct __gen_struct_ ## T { static FASTLED_FORCE_INLINE volatile GPIO_TypeDef * r() { return T; } };
#define _FL_IO(L,C) _RD32(GPIO ## L);
@@ -153,7 +153,7 @@ _FL_DEFPIN(4, 15, C);
#define HAS_HARDWARE_PIN_SUPPORT
-#elif defined(ARDUINO_GENERIC_F103C8TX) // stm32duino generic STM32F103C8TX
+#elif defined(ARDUINO_GENERIC_F103C8TX) || defined(STM32F407xx) // stm32duino generic STM32F103C8TX
#define MAX_PIN 36
// PA0-PA15
diff --git a/src/platforms/arm/stm32/fastpin_arm_stm_new.h b/src/platforms/arm/stm32/fastpin_arm_stm_new.h
index 22a2bae555..16707f660d 100644
--- a/src/platforms/arm/stm32/fastpin_arm_stm_new.h
+++ b/src/platforms/arm/stm32/fastpin_arm_stm_new.h
@@ -152,6 +152,73 @@ _DEFPIN_ARM(PB1, 1, B);
#define HAS_HARDWARE_PIN_SUPPORT
+
+#elif defined(STM32F407xx)
+//intended for OpenFFBoard-main board that uses STM32F407VGT6 MCU
+// Only using one output for LED strip support for now.
+//https://github.com/Ultrawipf/OpenFFBoard/wiki/
+
+//Register mapping
+#define _RD32_GPIO_MAP(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) FASTLED_FORCE_INLINE volatile GPIO_TypeDef* r() { return T; } };
+#define _RD32 _RD32_GPIO_MAP
+#define _IO32(L) _RD32(GPIO ## L)
+
+_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E);
+
+#define MAX_PIN PB1
+ _DEFPIN_ARM(PE2, 2, E); // DIN 8
+ _DEFPIN_ARM(PE3, 3, E); // DIN 7
+ _DEFPIN_ARM(PE4, 4, E); // DIN 6
+ _DEFPIN_ARM(PE5, 5, E); // DIN 5
+ _DEFPIN_ARM(PE6, 6, E); // DIN 4
+ _DEFPIN_ARM(PC13, 13, C); // DIN 3
+ _DEFPIN_ARM(PC14, 14, C); // DIN 2
+ _DEFPIN_ARM(PC15, 15, C); // DIN 1
+ //INSERT OTHERS HERE
+
+
+// _DEFPIN_ARM(PB11, 11, B);
+// _DEFPIN_ARM(PB10, 10, B);
+// _DEFPIN_ARM(PB2, 2, B);
+// _DEFPIN_ARM(PB0, 0, B);
+// _DEFPIN_ARM(PA7, 7, A);
+// _DEFPIN_ARM(PA6, 6, A);
+// _DEFPIN_ARM(PA5, 5, A);
+// _DEFPIN_ARM(PA4, 4, A);
+// _DEFPIN_ARM(PA3, 3, A);
+// _DEFPIN_ARM(PA2, 2, A);
+// _DEFPIN_ARM(PA1, 1, A);
+// _DEFPIN_ARM(PA0, 0, A);
+// _DEFPIN_ARM(PC15, 15, C);
+// _DEFPIN_ARM(PC14, 14, C);
+// _DEFPIN_ARM(PC13, 13, C);
+// _DEFPIN_ARM(PB7, 7, B);
+// _DEFPIN_ARM(PB6, 6, B);
+// _DEFPIN_ARM(PB5, 5, B);
+// _DEFPIN_ARM(PB4, 4, B);
+// _DEFPIN_ARM(PB3, 3, B);
+// _DEFPIN_ARM(PA15, 15, A);
+// _DEFPIN_ARM(PA14, 14, A);
+// _DEFPIN_ARM(PA13, 13, A);
+// _DEFPIN_ARM(PA12, 12, A);
+// _DEFPIN_ARM(PA11, 11, A);
+// _DEFPIN_ARM(PA10, 10, A);
+// _DEFPIN_ARM(PA9, 9, A);
+// _DEFPIN_ARM(PA8, 8, A);
+ _DEFPIN_ARM(PB15, 15, B);
+// _DEFPIN_ARM(PB14, 14, B);
+// _DEFPIN_ARM(PB13, 13, B);
+// _DEFPIN_ARM(PB12, 12, B);
+// _DEFPIN_ARM(PB8, 8, B);
+ _DEFPIN_ARM(PB1, 1, B);
+
+// SPI2 MOSI
+#define SPI_DATA PB15
+// SPI2 SCK
+#define SPI_CLOCK PB13
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
#else
#error "Please define pin map for this board"
diff --git a/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
index 90cef900a0..b556bdac81 100644
--- a/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
+++ b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
@@ -3,7 +3,8 @@
#if defined(STM32F10X_MD) || defined(STM32F2XX)
-#include
+//#include
+
#include
#include "fl/namespace.h"
@@ -33,6 +34,13 @@ FASTLED_USING_NAMESPACE
#define cli() noInterrupts()
#define sei() interrupts()
+#elif defined(STM32F407xx)
+// stm32duino
+
+#define cli() noInterrupts()
+#define sei() interrupts()
+
+
#else
#error "Platform not supported"
#endif
@@ -55,7 +63,7 @@ FASTLED_USING_NAMESPACE
// pgmspace definitions
#define PROGMEM
-#if !defined(STM32F1)
+#if !defined(STM32F1) && !defined(STM32F407xx)
// The stm32duino core already defines these
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
@@ -78,6 +86,9 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u
// F_CPU is already defined on stm32duino, but it's not constant.
#undef F_CPU
#define F_CPU 72000000
+#elif defined(STM32F407xx)
+#undef F_CPU
+#define F_CPU 168000000
#else
#define F_CPU 72000000
#endif
diff --git a/src/platforms/esp/32/rmt_5/idf5_clockless_rmt_esp32.h b/src/platforms/esp/32/rmt_5/idf5_clockless_rmt_esp32.h
index efdf431b0e..e179c7efbd 100644
--- a/src/platforms/esp/32/rmt_5/idf5_clockless_rmt_esp32.h
+++ b/src/platforms/esp/32/rmt_5/idf5_clockless_rmt_esp32.h
@@ -9,7 +9,9 @@
#include "eorder.h"
#include "pixel_iterator.h"
#include "idf5_rmt.h"
+#include "fl/namespace.h"
+FASTLED_NAMESPACE_BEGIN
template
class ClocklessController : public CPixelLEDController
@@ -53,4 +55,6 @@ class ClocklessController : public CPixelLEDController
CPixelLEDController::endShowLeds(data);
mRMTController.showPixels();
}
-};
\ No newline at end of file
+};
+
+FASTLED_NAMESPACE_END
diff --git a/src/platforms/esp/32/rmt_5/idf5_rmt.cpp b/src/platforms/esp/32/rmt_5/idf5_rmt.cpp
index 2a7b1617c3..633fe0fddb 100644
--- a/src/platforms/esp/32/rmt_5/idf5_rmt.cpp
+++ b/src/platforms/esp/32/rmt_5/idf5_rmt.cpp
@@ -17,10 +17,14 @@
#include "fl/assert.h"
#include "fl/convert.h" // for convert_fastled_timings_to_timedeltas(...)
+#include "fl/namespace.h"
#include "strip_rmt.h"
+
#define TAG "idf5_rmt.cpp"
+FASTLED_NAMESPACE_BEGIN
+
RmtController5::RmtController5(int DATA_PIN, int T1, int T2, int T3, RmtController5::DmaMode dma_mode)
: mPin(DATA_PIN), mT1(T1), mT2(T2), mT3(T3), mDmaMode(dma_mode) {
@@ -68,6 +72,8 @@ void RmtController5::showPixels() {
mLedStrip->drawAsync();
}
+FASTLED_NAMESPACE_END
+
#endif // FASTLED_RMT5
#endif // ESP32
diff --git a/src/platforms/esp/32/rmt_5/idf5_rmt.h b/src/platforms/esp/32/rmt_5/idf5_rmt.h
index 5671aa3396..eaa4a9173c 100644
--- a/src/platforms/esp/32/rmt_5/idf5_rmt.h
+++ b/src/platforms/esp/32/rmt_5/idf5_rmt.h
@@ -6,6 +6,9 @@
#include "pixel_iterator.h"
#include
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
class IRmtStrip;
@@ -40,6 +43,8 @@ class RmtController5
DmaMode mDmaMode;
};
+FASTLED_NAMESPACE_END
+
#endif // FASTLED_RMT5
diff --git a/src/platforms/esp/32/rmt_5/strip_rmt.cpp b/src/platforms/esp/32/rmt_5/strip_rmt.cpp
index 57cbe2bc21..77b833cde4 100644
--- a/src/platforms/esp/32/rmt_5/strip_rmt.cpp
+++ b/src/platforms/esp/32/rmt_5/strip_rmt.cpp
@@ -13,6 +13,9 @@
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
namespace { // anonymous namespace
@@ -169,6 +172,7 @@ IRmtStrip *IRmtStrip::Create(
);
}
+FASTLED_NAMESPACE_END
#endif // FASTLED_RMT5
diff --git a/src/platforms/esp/32/rmt_5/strip_rmt.h b/src/platforms/esp/32/rmt_5/strip_rmt.h
index 76b3a93694..97b2a52fbb 100644
--- a/src/platforms/esp/32/rmt_5/strip_rmt.h
+++ b/src/platforms/esp/32/rmt_5/strip_rmt.h
@@ -2,6 +2,9 @@
#pragma once
#include
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
class IRmtStrip
{
@@ -32,3 +35,5 @@ class IRmtStrip
virtual void fillRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) = 0;
virtual uint32_t numPixels() = 0;
};
+
+FASTLED_NAMESPACE_END
diff --git a/src/platforms/esp/32/spi_ws2812/strip_spi.cpp b/src/platforms/esp/32/spi_ws2812/strip_spi.cpp
index 2f7ccf1db2..efc1bbda51 100644
--- a/src/platforms/esp/32/spi_ws2812/strip_spi.cpp
+++ b/src/platforms/esp/32/spi_ws2812/strip_spi.cpp
@@ -21,6 +21,9 @@
#include "rgbw.h"
#include "fl/warn.h"
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
static const char *TAG = "strip_spi";
@@ -262,6 +265,8 @@ ISpiStripWs2812* ISpiStripWs2812::Create(int pin, uint32_t led_count, bool is_rg
return new SpiStripWs2812(pin, size_as_rgb, spi_bus, dma_mode);
}
+FASTLED_NAMESPACE_END
+
#endif // FASTLED_ESP32_HAS_CLOCKLESS_SPI
#endif // ESP32
diff --git a/src/platforms/esp/32/spi_ws2812/strip_spi.h b/src/platforms/esp/32/spi_ws2812/strip_spi.h
index dbed977739..e45b5e6e52 100644
--- a/src/platforms/esp/32/spi_ws2812/strip_spi.h
+++ b/src/platforms/esp/32/spi_ws2812/strip_spi.h
@@ -1,6 +1,9 @@
#pragma once
#include
+#include "fl/namespace.h"
+
+FASTLED_NAMESPACE_BEGIN
class ISpiStripWs2812 {
public:
@@ -62,3 +65,5 @@ class ISpiStripWs2812 {
virtual void setPixel(uint32_t index, uint8_t red, uint8_t green,
uint8_t blue) = 0;
};
+
+FASTLED_NAMESPACE_END
diff --git a/src/platforms/wasm/compiler/.dockerignore b/src/platforms/wasm/compiler/.dockerignore
deleted file mode 100644
index e81dc79c32..0000000000
--- a/src/platforms/wasm/compiler/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-**/.mypy_cache/
-**/.ruff_cache/
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/CMakeLists.txt b/src/platforms/wasm/compiler/CMakeLists.txt
deleted file mode 100644
index 84ed7cce5c..0000000000
--- a/src/platforms/wasm/compiler/CMakeLists.txt
+++ /dev/null
@@ -1,139 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(FastLED_WASM)
-
-# Enable verbose makefile output for all compiled sources
-set(CMAKE_VERBOSE_MAKEFILE ON)
-
-# --- Set Emscripten as the Compiler ---
-set(CMAKE_C_COMPILER "emcc")
-set(CMAKE_CXX_COMPILER "em++")
-set(CMAKE_AR "emar")
-set(CMAKE_RANLIB "emranlib")
-
-# Use ccache as a compiler launcher (requires CMake 3.4 or newer)
-set(CMAKE_C_COMPILER_LAUNCHER "ccache")
-set(CMAKE_CXX_COMPILER_LAUNCHER "ccache")
-
-# --- Build Mode and Optimization Level ---
-if(NOT DEFINED ENV{BUILD_MODE})
- set(BUILD_MODE "QUICK")
-else()
- set(BUILD_MODE $ENV{BUILD_MODE})
-endif()
-
-if(BUILD_MODE STREQUAL "QUICK")
- set(OPT_LEVEL "-O0")
-elseif(BUILD_MODE STREQUAL "DEBUG")
- set(OPT_LEVEL "-Og")
-else() # RELEASE
- set(OPT_LEVEL "-Oz")
-endif()
-
-# --- Common Compiler and Linker Flags ---
-set(COMMON_COMPILE_FLAGS
- -DFASTLED_ENGINE_EVENTS_MAX_LISTENERS=50
- -DFASTLED_FORCE_NAMESPACE=1
- -DFASTLED_NO_FORCE_INLINE
- -DFASTLED_USE_PROGMEM=0
- -DDISABLE_EXCEPTION_CATCHING=1
- -fno-exceptions
- -fno-rtti
- -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0
- -std=gnu++17
- -fpermissive
- -fno-inline
- -Wno-constant-logical-operand
- -Wnon-c-typedef-for-linkage
- -Werror=bad-function-cast
- -Werror=cast-function-type
- -sUSE_PTHREADS=0 # Disable threading support
- ${OPT_LEVEL}
-)
-
-# (Optional: PROFILE flags can be added here if needed)
-
-set(COMMON_LINK_FLAGS
- -sALLOW_MEMORY_GROWTH=0
- -sDISABLE_EXCEPTION_CATCHING=1
- -sDISABLE_EXCEPTION_THROWING=0
- -sWASM_BIGINT
- --bind
- -DUSE_OFFSET_CONVERTER=0
- -sINITIAL_MEMORY=134217728
- -fuse-ld=lld
- --no-entry
- -sMODULARIZE=1
-)
-
-set(LIBRARY_LINK_FLAGS
- ${COMMON_LINK_FLAGS}
-)
-
-set(SKETCH_LINK_FLAGS
- ${COMMON_LINK_FLAGS}
- -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','stringToUTF8','lengthBytesUTF8']
- -sEXPORTED_FUNCTIONS=['_malloc','_free','_extern_setup','_extern_loop','_fastled_declare_files']
- -sEXPORT_NAME=fastled
- -o fastled.js
-)
-
-if(BUILD_MODE STREQUAL "DEBUG")
- list(APPEND COMMON_COMPILE_FLAGS
- -g3
- -fsanitize=address
- -fsanitize=undefined
- )
- set(DEBUG_LINK_FLAGS
- -gsource-map
- --emit-symbol-map
- -sSTACK_OVERFLOW_CHECK=2
- -ASSERTIONS=1
- )
- list(APPEND LIBRARY_LINK_FLAGS ${DEBUG_LINK_FLAGS})
- list(APPEND SKETCH_LINK_FLAGS ${DEBUG_LINK_FLAGS})
-endif()
-
-# --- FASTLED LIBRARY SETUP ---
-set(LIBFASTLED_PATH /precompiled/libfastled.a)
-
-if(EXISTS ${LIBFASTLED_PATH})
- message(STATUS "Found prebuilt libfastled.a at ${LIBFASTLED_PATH}, skipping build of FastLED library.")
- add_library(fastled STATIC IMPORTED)
- set_target_properties(fastled PROPERTIES IMPORTED_LOCATION ${LIBFASTLED_PATH})
-else()
- message(FATAL_ERROR "Did not find precompiled libfastled.a at ${LIBFASTLED_PATH}. Please build the library first.")
-endif()
-
-if(TARGET fastled)
- set_target_properties(fastled PROPERTIES
- CXX_STANDARD 17
- CXX_STANDARD_REQUIRED ON
- POSITION_INDEPENDENT_CODE ON
- )
-endif()
-
-# --- LIBRARY TARGET: sketch_lib ---
-file(GLOB_RECURSE ALL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
-message(STATUS "All sources: ${ALL_SOURCES}")
-
-add_library(sketch_lib STATIC ${ALL_SOURCES})
-
-target_compile_options(sketch_lib PRIVATE ${COMMON_COMPILE_FLAGS})
-target_compile_definitions(sketch_lib PRIVATE SKETCH_COMPILE)
-target_include_directories(sketch_lib PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- "/precompiled/include"
-)
-set_target_properties(sketch_lib PROPERTIES
- CXX_STANDARD 17
- CXX_STANDARD_REQUIRED ON
-)
-
-# ── FINAL LINKING STEP: Produce fastled.js ──
-# This custom target invokes em++ to link the static library (sketch_lib)
-# with the precompiled libfastled.a into the final binary fastled.js.
-add_custom_target(final_wasm ALL
- COMMAND em++ ${SKETCH_LINK_FLAGS} -Wl,--whole-archive $ -Wl,--no-whole-archive /precompiled/libfastled.a
- DEPENDS sketch_lib fastled
- COMMENT "Linking final wasm binary to fastled.js"
-)
diff --git a/src/platforms/wasm/compiler/Dockerfile b/src/platforms/wasm/compiler/Dockerfile
deleted file mode 100644
index e3188a2682..0000000000
--- a/src/platforms/wasm/compiler/Dockerfile
+++ /dev/null
@@ -1,197 +0,0 @@
-# Overview of this docker file
-# This is a emscripten docker file that is used to compile FastLED for the web assembly platform.
-# The goals of this docker are:
-# * Compile the inputs as quickly as possible.
-# * Be very fast to rebuild
-# Container size is important, but not the primary goal.
-#
-# The emscripten build is based on emscripten. We create a custom `wasm_compiler_flags.py``
-# that performs the necessary transformations to make this work.
-#
-# Maximizing compiler speed
-# First let's talk about why platformio is typically slow
-# * Network checking to see if the repo's are up to date
-# * Unnecessary recompilation of cpp files that haven't changed.
-#
-# We address these slow compiler speeds via a few tricks
-# * The emscripten compiler is wrapped in ccache so that identical compilations are cached.
-# * We prewarm the ccache with a pre-compile of an example
-# * This will generate the initial cache and also install the necessary tools.
-#
-# Pre-warming the cache
-# * We have two pre-warm cycles. We do this for speed reasons.
-# * The first pre-warm is done with a copy of fastled downloaded from the github repo
-# * Docker is very relaxed on invalidating a cache layer for statements cloning a github repo. We want this.
-# * So we clone the repo early in the docker image build cycle. Then we run a pre-warm compile.
-# * This is the slowest pre-warm, and once built, tends to always be cached. However, it tends to go out of date
-# quickly, which will make the cache be less effective.
-# * The second pre-warm is done with a fresh copy of the fastled repo from the host machine that is copied over the
-# git hub repo. We copy directories piece by piece to maximize the cache hit rate. Core files then platform files.
-# * During developement when many files are changed, this second pre-warm will almost always be invalidated, however
-# it is very fast to rebuild because the initial tool download of platformio has already been done with the first pre-warm.
-# * After this second pre-warm, the ccache will have the exact state of the repo in it's cache.
-#
-# Final state
-# * The final state of the docker image is a pre-warmed cached with the entire instance ready to compile.
-# * The calling code is expected to provide volume mapped directory that will be inserted into the docker image when it runs.
-# * However, this is not true when using this in server mode (see server.py) where the code to be compiled is injected into the
-# container instance via a FastAPI route, the compilation is performed. Typically the web compiler is much better at holding
-# on the cached files. Server.py will also periodically git pull the fastled repo to keep in sync with the latest changes.
-
-
-# This will be set to arm64 to support MacOS M1+ devices (and Linux-based arm64 devices)
-ARG PLATFORM_TAG=""
-
-# Use only Emscripten base image
-FROM emscripten/emsdk:3.1.70${PLATFORM_TAG}
-
-
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Update the apt-get package list. This takes a long time, so we do it first to maximize cache hits.
-# Also install apt-fast first
-RUN apt-get update
-
-RUN apt-get install -y software-properties-common
-
-RUN add-apt-repository ppa:apt-fast/stable -y && \
- apt-get update && \
- apt-get -y install apt-fast
-
-# Update apt and install required packages
-RUN apt-fast install -y \
- git \
- gawk \
- nano \
- ca-certificates \
- python3 \
- python3-pip \
- dos2unix \
- tar \
- wget \
- unzip \
- make \
- cmake \
- ninja-build \
- ccache \
- zlib1g \
- zlib1g-dev \
- gcc \
- g++ \
- rsync \
- && rm -rf /var/lib/apt/lists/*
-
-
-# /container/bin contains symbolic links to python3 and pip3 as python and pip that we use for the compiler.
-RUN mkdir -p /container/bin && \
- ln -s /usr/bin/python3 /container/bin/python && \
- ln -s /usr/bin/pip3 /container/bin/pip
-
-
-# Add Python and Emscripten to PATH
-ENV PATH="/container/bin:/usr/local/bin:/usr/bin:/emsdk:/emsdk/upstream/emscripten:${PATH}"
-ENV CCACHE_DIR=/ccache
-ENV CCACHE_MAXSIZE=1G
-
-# Create a custom print script
-RUN echo '#!/bin/sh' > /usr/bin/print && \
- echo 'echo "$@"' >> /usr/bin/print && \
- chmod +x /usr/bin/print
-
-# Add print function (which seems to be missing, strangly) and PATH modifications to /etc/profile
-RUN echo 'print() { echo "$@"; }' >> /etc/profile && \
- echo 'export -f print' >> /etc/profile && \
- echo 'export PATH="/container/bin:/usr/bin:/emsdk:/emsdk/upstream/emscripten:$PATH"' >> /etc/profile && \
- echo 'source /emsdk/emsdk_env.sh' >> /etc/profile
-
-# This was added to try and fix formatting issues. It didn't fix it but it's better to force everything to use
-# utf-8, as god intended it.
-ENV LANG=en_US.UTF-8
-ENV LC_CTYPE=UTF-8
-RUN echo 'export LANG=en_US.UTF-8' >> /etc/profile && \
- echo 'export LC_CTYPE=UTF-8' >> /etc/profile
-
-# This is disabled code to try and use the arduino-cli to transform an *.ino file into a cpp file
-# to enable the auto-predeclaration of missing functions. However, Arduino-cli is absolutely gigantic
-# and requires that we compile it against one of the platforms. This doesn't work for us because
-# we don't want a compile failure because of something weird in the platform we are compiling against, which
-# isn't wasm.
-#COPY src/platforms/wasm/compiler/install-arduino-cli.sh /install-arduino-cli.sh
-#RUN chmod +x /install-arduino-cli.sh && /install-arduino-cli.sh || echo "Failed to install Arduino CLI"
-
-RUN pip install uv==0.5.6
-
-# Get the compiler requirements and install them.
-COPY src/platforms/wasm/compiler/requirements.txt /install/requirements.txt
-RUN uv pip install --system -r /install/requirements.txt
-
-RUN pio settings set check_platformio_interval 9999
-RUN pio settings set enable_telemetry 0
-
-# FIRST PRE-WARM CYCLE and initial setup: Download the fastled repo from the github and pre-warm the cache with a compilation.
-# This is by far the most expensive part of the build, because platformio needs to download initial tools. This
-# pre-warm cycle is "sticky" and tends to stay in the cache for a long time since docker is very relaxed about
-# invalidating cache layers that clone a github repo.
-
-ARG FASTLED_VERSION=master
-ENV FASTLED_VERSION=${FASTLED_VERSION}
-RUN git clone -b ${FASTLED_VERSION} https://github.com/fastled/FastLED.git --depth 1 /git/fastled && \
- mkdir -p /js/fastled && \
- rsync -a /git/fastled/ /js/fastled/ --exclude='.git'
-
-# Create symlinks for wasm platform files.
-COPY src/platforms/wasm/compiler/init_runtime.py /js/init_runtime.py
-COPY src/platforms/wasm/compiler/prewarm.sh /js/prewarm.sh
-
-WORKDIR /js
-
-ARG NO_PREWARM=0
-ENV NO_PREWARM=${NO_PREWARM}
-
-RUN python /js/init_runtime.py || true
-
-
-# First pre-warm cycle - always do it as part of the build.
-RUN mkdir -p /logs
-
-# Force a build if the compiler flags change.
-COPY src/platforms/wasm/compiler/wasm_compiler_flags.py /trash/wasm_compiler_flags.py
-COPY src/platforms/wasm/compiler/CMakeLists.txt /trash/CMakeLists.txt
-RUN rm -rf /trash
-
-RUN chmod +x /js/prewarm.sh && \
- cat /js/prewarm.sh >> /logs/prewarm.log.0
-RUN /js/prewarm.sh --force >> /logs/prewarm.log.1 || true
-
-
-# Copy the fastled repo from the host machine and prepare for pre-warm
-# Make sure and delete files that have been removed so that we don't get
-# duplicate symbols from stale files.
-COPY *.json /host/fastled/
-COPY src/*.* /host/fastled/src/
-COPY examples /host/fastled/examples
-COPY src/fx /host/fastled/src/fx
-COPY src/fl /host/fastled/src/fl
-COPY src/lib8tion /host/fastled/src/lib8tion
-COPY src/third_party /host/fastled/src/third_party
-COPY src/sensors /host/fastled/src/sensors
-COPY src/platforms /host/fastled/src/platforms
-
-COPY src/platforms/wasm/compiler/entrypoint.sh /entrypoint.sh
-RUN chmod +x /entrypoint.sh && dos2unix /entrypoint.sh
-
-# now sync local to the source directory.
-RUN rsync -av /host/fastled/ /js/fastled/ && rm -rf /host/fastled
-
-RUN python /js/init_runtime.py || true
-
-
-# SECOND PRE-WARM CYCLE: Copy the fastled repo from the host machine and pre-warm the cache with that compilation. This will
-# be much quicker than the first pre-warm cycle.
-RUN /js/prewarm.sh --force > /logs/prewarm.log.2 || true
-
-# Now timestamp the image and store it at the end of the build.
-RUN date > /image_timestamp.txt
-
-ENTRYPOINT ["/entrypoint.sh"]
-CMD ["python", "/js/run.py", "server"]
diff --git a/src/platforms/wasm/compiler/__init__.py b/src/platforms/wasm/compiler/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/platforms/wasm/compiler/arduino-pre-process.sh b/src/platforms/wasm/compiler/arduino-pre-process.sh
deleted file mode 100755
index eccd60056d..0000000000
--- a/src/platforms/wasm/compiler/arduino-pre-process.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-arduino-cli compile --preprocess --fqbn arduino:avr:uno /pre-warm/Blink/Blink.ino
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/build.sh b/src/platforms/wasm/compiler/build.sh
deleted file mode 100644
index bea9d5f1c1..0000000000
--- a/src/platforms/wasm/compiler/build.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-python compile.py --no-platformio
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/build_archive.sh b/src/platforms/wasm/compiler/build_archive.sh
deleted file mode 100755
index 9556a504d9..0000000000
--- a/src/platforms/wasm/compiler/build_archive.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-set -e # Exit immediately if a command exits with a non-zero status
-set -x
-
-# if /include does not exist
-if [ ! -d "/precompiled/include" ]; then
- echo "include directory does not exist, copying header include tree"
- # echo "include directory does not exist, copying header include tree"
- # copy *.h,*.hpp files from fastled/src/** to /include
- mkdir -p /precompiled/include
- cd fastled/src
- find . -name "*.h*" -exec cp --parents {} /precompiled/include \;
- cd ../../
-fi
-
-# if /precompiled/libfastled.a does not exist
-if [ ! -f "/precompiled/libfastled.a" ]; then
- # echo "libfastled.a does not exist, compiling static library"
- echo "libfastled.a does not exist, compiling static library"
- cd fastled/src/platforms/wasm/compiler/lib
- mkdir -p build
- cd build
- emcmake cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..
- emmake cmake --build . -v -j
- cp fastled/libfastled.a /precompiled/libfastled.a
- cd ../../../../../
-fi
-
diff --git a/src/platforms/wasm/compiler/build_fast.sh b/src/platforms/wasm/compiler/build_fast.sh
deleted file mode 100644
index ff37208684..0000000000
--- a/src/platforms/wasm/compiler/build_fast.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-set -e # Exit immediately if a command exits with a non-zero status
-set -x
-
-#################################
-# Compile fastled lib
-#################################
-
-
-./build_archive.sh
-
-# first compile if build doesn't exist
-first_compile=false
-
-# if build directory doesn't exist
-if [ ! -d "build" ]; then
- # Create the build directory if it doesn't exist and mark as first compile.
- mkdir -p build
- # if /js/src/CMakeCache.txt exists then delete it
-
- first_compile=true
-fi
-
-cd build
-
-# Set build mode: QUICK, DEBUG, or RELEASE (default is QUICK)
-export BUILD_MODE=${1:-QUICK}
-
-# Check for an optional second parameter to activate PROFILE
-# PROFILE_FLAG="-DPROFILE=ON"
-
-# touch CMakeLists.txt to force reconfigure
-touch /js/CMakeLists.txt
-
-
-# always delete CMakeCache.txt
-if [ -f "/js/fastled/src/CMakeCache.txt" ]; then
- rm -rf /js/fastled/src/CMakeCache.txt
-fi
-
-
-if [ "$first_compile" = true ]; then
- # Configure with CMake
- # If you want verbose build output, you can enable CMAKE_VERBOSE_MAKEFILE.
- echo "Configuring build with CMake..."
- emcmake cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..
-else
- # If the build directory already exists, reconfigure with CMake.
- echo "Skipping CMake configuration as build directory already exists."
-fi
-
-# Build the project using CMake
-emmake cmake --build . -v -j
-
diff --git a/src/platforms/wasm/compiler/code_sync.py b/src/platforms/wasm/compiler/code_sync.py
deleted file mode 100644
index 9aacb60c25..0000000000
--- a/src/platforms/wasm/compiler/code_sync.py
+++ /dev/null
@@ -1,76 +0,0 @@
-
-import os
-from pathlib import Path
-from typing import Callable
-import subprocess
-import time
-
-from compile_lock import COMPILE_LOCK
-
-VOLUME_MAPPED_SRC = Path("/host/fastled/src")
-RSYNC_DEST = Path("/js/fastled/src")
-TIME_START = time.time()
-
-def sync_src_to_target(
- src: Path, dst: Path, callback: Callable[[], None] | None = None
-) -> bool:
- """Sync the volume mapped source directory to the FastLED source directory."""
- suppress_print = (
- TIME_START + 30 > time.time()
- ) # Don't print during initial volume map.
- if not src.exists():
- # Volume is not mapped in so we don't rsync it.
- print(f"Skipping rsync, as fastled src at {src} doesn't exist")
- return False
- try:
- exclude_hidden = "--exclude=.*/" # suppresses folders like .mypy_cache/
- print("\nSyncing source directories...")
- with COMPILE_LOCK:
- # Use rsync to copy files, preserving timestamps and deleting removed files
- cp: subprocess.CompletedProcess = subprocess.run(
- ["rsync", "-av", "--info=NAME", "--delete", f"{src}/", f"{dst}/", exclude_hidden],
- check=True,
- text=True,
- capture_output=True,
- )
- if cp.returncode == 0:
- changed = False
- changed_lines: list[str] = []
- lines = cp.stdout.split("\n")
- for line in lines:
- suffix = line.strip().split(".")[-1]
- if suffix in ["cpp", "h", "hpp", "ino", "py", "js", "html", "css"]:
- if not suppress_print:
- print(f"Changed file: {line}")
- changed = True
- changed_lines.append(line)
- if changed:
- if not suppress_print:
- print(f"FastLED code had updates: {changed_lines}")
- if callback:
- callback()
- return True
- print("Source directory synced successfully with no changes")
- return False
- else:
- print(f"Error syncing directories: {cp.stdout}\n\n{cp.stderr}")
- return False
-
- except subprocess.CalledProcessError as e:
- print(f"Error syncing directories: {e.stdout}\n\n{e.stderr}")
- except Exception as e:
- print(f"Error syncing directories: {e}")
- return False
-
-
-
-def sync_source_directory_if_volume_is_mapped(
- callback: Callable[[], None] | None = None
-) -> bool:
- """Sync the volume mapped source directory to the FastLED source directory."""
- if not VOLUME_MAPPED_SRC.exists():
- # Volume is not mapped in so we don't rsync it.
- print("Skipping rsync, as fastled src volume not mapped")
- return False
- print("Syncing source directories because host is mapped in")
- return sync_src_to_target(VOLUME_MAPPED_SRC, RSYNC_DEST, callback=callback)
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/compile.py b/src/platforms/wasm/compiler/compile.py
deleted file mode 100644
index b618a47af8..0000000000
--- a/src/platforms/wasm/compiler/compile.py
+++ /dev/null
@@ -1,659 +0,0 @@
-# A compilation script specific to fastled's docker compiler.
-# This script will pull the users code from a mapped directory,
-# then do some processing to convert the *.ino files to *.cpp and
-# insert certain headers like "Arduino.h" (pointing to a fake implementation).
-# After this, the code is compiled, and the output files are copied back
-# to the users mapped directory in the fastled_js folder.
-# There are a few assumptions for this script:
-# 1. The mapped directory will contain only one directory with the users code, this is
-# enforced by the script that sets up the docker container.
-# 2. The docker container has installed compiler dependencies in the /js directory.
-
-import argparse
-import hashlib
-import json
-import os
-import re
-import shutil
-import subprocess
-import sys
-from dataclasses import dataclass
-from datetime import datetime
-from enum import Enum
-from pathlib import Path
-from typing import List
-
-
-@dataclass
-class DateLine:
- dt: datetime
- line: str
-
-
-class BuildMode(Enum):
- DEBUG = "DEBUG"
- QUICK = "QUICK"
- RELEASE = "RELEASE"
-
- @classmethod
- def from_string(cls, mode_str: str) -> "BuildMode":
- try:
- return cls[mode_str.upper()]
- except KeyError:
- valid_modes = [mode.name for mode in cls]
- raise ValueError(f"BUILD_MODE must be one of {valid_modes}, got {mode_str}")
-
-
-@dataclass
-class SyntaxCheckResult:
- file_path: Path
- is_valid: bool
- message: str
-
-
-_CHECK_SYNTAX = False
-_COMPILER_PATH = "em++"
-
-JS_DIR = Path("/js")
-FASTLED_DIR = JS_DIR / "fastled"
-FASTLED_SRC = FASTLED_DIR / "src"
-FASTLED_SRC_PLATFORMS = FASTLED_SRC / "platforms"
-FASTLED_SRC_PLATFORMS_WASM = FASTLED_SRC_PLATFORMS / "wasm"
-FASTLED_SRC_PLATFORMS_WASM_COMPILER = FASTLED_SRC_PLATFORMS_WASM / "compiler"
-
-
-JS_SRC = JS_DIR / "src"
-
-FASTLED_DIR = JS_DIR / "fastled"
-FASTLED_SRC_DIR = FASTLED_DIR / "src"
-FASTLED_PLATFORMS_DIR = FASTLED_SRC_DIR / "platforms"
-FASTLED_WASM_DIR = FASTLED_PLATFORMS_DIR / "wasm"
-FASTLED_COMPILER_DIR = FASTLED_WASM_DIR / "compiler"
-FASTLED_MODULES_DIR = FASTLED_COMPILER_DIR / "modules"
-
-PIO_BUILD_DIR = JS_DIR / ".pio/build"
-ARDUINO_H_SRC = JS_DIR / "Arduino.h"
-INDEX_HTML_SRC = FASTLED_COMPILER_DIR / "index.html"
-INDEX_CSS_SRC = FASTLED_COMPILER_DIR / "index.css"
-INDEX_JS_SRC = FASTLED_COMPILER_DIR / "index.js"
-
-
-WASM_COMPILER_SETTTINGS = JS_DIR / "wasm_compiler_flags.py"
-OUTPUT_FILES = ["fastled.js", "fastled.wasm"]
-HEADERS_TO_INSERT = ["#include ", '#include "platforms/wasm/js.h"']
-FILE_EXTENSIONS = [".ino", ".h", ".hpp", ".cpp"]
-MAX_COMPILE_ATTEMPTS = 1 # Occasionally the compiler fails for unknown reasons, but disabled because it increases the build time on failure.
-FASTLED_OUTPUT_DIR_NAME = "fastled_js"
-
-assert JS_DIR.exists()
-assert ARDUINO_H_SRC.exists()
-assert INDEX_HTML_SRC.exists()
-assert INDEX_CSS_SRC.exists(), f"Index CSS not found at {INDEX_CSS_SRC}"
-assert INDEX_JS_SRC.exists()
-assert WASM_COMPILER_SETTTINGS.exists()
-assert FASTLED_SRC_PLATFORMS_WASM_COMPILER.exists()
-assert JS_DIR.exists(), f"JS_DIR does not exist: {JS_DIR}"
-assert ARDUINO_H_SRC.exists(), f"ARDUINO_H_SRC does not exist: {ARDUINO_H_SRC}"
-assert INDEX_HTML_SRC.exists(), f"INDEX_HTML_SRC does not exist: {INDEX_HTML_SRC}"
-assert INDEX_CSS_SRC.exists(), f"INDEX_CSS_SRC does not exist: {INDEX_CSS_SRC}"
-assert INDEX_JS_SRC.exists(), f"INDEX_JS_SRC does not exist: {INDEX_JS_SRC}"
-assert (
- WASM_COMPILER_SETTTINGS.exists()
-), f"WASM_COMPILER_SETTTINGS does not exist: {WASM_COMPILER_SETTTINGS}"
-
-
-def copy_files(src_dir: Path, js_src: Path) -> None:
- print("Copying files from mapped directory to container...")
- for item in src_dir.iterdir():
- if item.is_dir():
- print(f"Copying directory: {item}")
- shutil.copytree(item, js_src / item.name, dirs_exist_ok=True)
- else:
- print(f"Copying file: {item}")
- shutil.copy2(item, js_src / item.name)
-
-
-def compile(
- js_dir: Path, build_mode: BuildMode, auto_clean: bool, no_platformio: bool
-) -> int:
- print("Starting compilation process...")
- max_attempts = 1
- env = os.environ.copy()
- env["BUILD_MODE"] = build_mode.name
- print(f"Build mode: {build_mode.name}")
- cmd_list: list[str] = []
- if no_platformio:
- # execute build_archive.syh
- cmd_list = [
- "/bin/bash",
- "-c",
- "/js/build_fast.sh",
- ]
- else:
- cmd_list.extend(["pio", "run"])
- if not auto_clean:
- cmd_list.append("--disable-auto-clean")
-
- def _open_process(cmd_list: list[str] = cmd_list) -> subprocess.Popen:
- out = subprocess.Popen(
- cmd_list,
- cwd=js_dir,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True,
- env=env,
- )
- return out
-
- output_lines = []
- for attempt in range(1, max_attempts + 1):
- try:
- print(f"Attempting compilation (attempt {attempt}/{max_attempts})...")
- process = _open_process()
- assert process.stdout is not None
- for line in process.stdout:
- processed_line = line.replace("fastled/src", "src")
- timestamped_line = _timestamp_output(processed_line)
- output_lines.append(timestamped_line)
- process.wait()
- relative_output = _make_timestamps_relative("\n".join(output_lines))
- print(relative_output)
- if process.returncode == 0:
- print(f"Compilation successful on attempt {attempt}")
- return 0
- else:
- raise subprocess.CalledProcessError(process.returncode, ["pio", "run"])
- except subprocess.CalledProcessError:
- print(f"Compilation failed on attempt {attempt}")
- if attempt == max_attempts:
- print("Max attempts reached. Compilation failed.")
- return 1
- print("Retrying...")
- return 1
-
-
-def insert_header(file: Path) -> None:
- print(f"Inserting header in file: {file}")
- with open(file, "r") as f:
- content = f.read()
-
- # Remove existing includes
- for header in HEADERS_TO_INSERT:
- content = re.sub(
- rf"^.*{re.escape(header)}.*\n", "", content, flags=re.MULTILINE
- )
-
- # Remove both versions of Arduino.h include
- arduino_pattern = r'^\s*#\s*include\s*[<"]Arduino\.h[>"]\s*.*\n'
- content = re.sub(arduino_pattern, "", content, flags=re.MULTILINE)
-
- # Add new headers at the beginning
- content = "\n".join(HEADERS_TO_INSERT) + "\n" + content
-
- with open(file, "w") as f:
- f.write(content)
- print(f"Processed: {file}")
-
-
-def transform_to_cpp(src_dir: Path) -> None:
- print("Transforming files to cpp...")
- ino_files = list(src_dir.glob("*.ino"))
-
- if ino_files:
- ino_file = ino_files[0]
- print(f"Found .ino file: {ino_file}")
- main_cpp = src_dir / "main.cpp"
- if main_cpp.exists():
- print("main.cpp already exists, renaming to main2.hpp")
- main_cpp.rename(src_dir / "main2.hpp")
-
- new_cpp_file = ino_file.with_suffix(".ino.cpp")
- print(f"Renaming {ino_file} to {new_cpp_file.name}")
- ino_file.rename(new_cpp_file)
-
- if (src_dir / "main2.hpp").exists():
- print(f"Including main2.hpp in {new_cpp_file.name}")
- with open(new_cpp_file, "a") as f:
- f.write('#include "main2.hpp"\n')
-
-
-def insert_headers(
- src_dir: Path, exclusion_folders: List[Path], file_extensions: List[str]
-) -> None:
- print("Inserting headers in source files...")
- for file in src_dir.rglob("*"):
- if (
- file.suffix in file_extensions
- and not any(folder in file.parents for folder in exclusion_folders)
- and file.name != "Arduino.h"
- ):
- insert_header(file)
-
-
-def process_ino_files(src_dir: Path) -> None:
- transform_to_cpp(src_dir)
- exclusion_folders: List[Path] = []
- insert_headers(src_dir, exclusion_folders, FILE_EXTENSIONS)
- print("Transform to cpp and insert header operations completed.")
-
-
-def check_syntax_with_gcc(file_path, gcc_path="gcc"):
- """
- Perform syntax checking on a C or C++ source file using GCC.
-
- Parameters:
- file_path (str): Path to the source file to check.
- gcc_path (str): Path to the GCC executable (default is 'gcc').
-
- Returns:
- bool: True if syntax is correct, False otherwise.
- str: Output or error message from GCC.
- """
- try:
- # Run GCC with -fsyntax-only flag for syntax checking
- cmd_list = [
- gcc_path,
- "-fsyntax-only",
- "-std=gnu++20",
- "-fpermissive",
- "-Wno-everything", # Suppress all warnings
- "-I",
- "/js/src/", # Add /js/src/ to the include path
- "-I",
- "/js/fastled/src/", # Add /js/fastled/src/ to the include path
- "-I",
- "/emsdk/upstream/emscripten/system/include",
- file_path,
- ]
- cmd_str = subprocess.list2cmdline(cmd_list)
- print(f"Running command: {cmd_str}")
- result = subprocess.run(
- cmd_list,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- text=True,
- )
-
- # Check the return code to determine if syntax is valid
- if result.returncode == 0:
- return True, "Syntax check passed successfully."
- else:
- return False, result.stderr
- except FileNotFoundError:
- return False, f"GCC not found at {gcc_path}."
- except Exception as e:
- return False, str(e)
-
-
-def check_syntax(
- directory_path: Path, gcc_path: str = "gcc"
-) -> list[SyntaxCheckResult]:
- # os walk
- out: list[SyntaxCheckResult] = []
- exclusion_list = set("fastled_js")
- for root, dirs, files in os.walk(directory_path):
- # if sub directory is in exclusion list, skip
- dirs[:] = [d for d in dirs if d not in exclusion_list]
- for file in files:
- if file.endswith(".cpp") or file.endswith(".ino"):
- file_path = os.path.join(root, file)
- is_valid, message = check_syntax_with_gcc(file_path, gcc_path)
- if not is_valid:
- print(f"Syntax check failed for file: {file_path}")
- print(f"Error message: {message}")
- out.append(
- SyntaxCheckResult(
- file_path=Path(file_path), is_valid=False, message=message
- )
- )
- else:
- print(f"Syntax check passed for file: {file_path}")
- out.append(
- SyntaxCheckResult(
- file_path=Path(file_path),
- is_valid=True,
- message="Syntax check passed successfully.",
- )
- )
- return out
-
-
-def _make_timestamps_relative(stdout: str) -> str:
- def parse(line: str) -> DateLine:
- parts = line.split(" ")
- if len(parts) < 2:
- raise ValueError(f"Invalid line: {line}")
-
- date_str, time_str = parts[:2]
- rest = " ".join(parts[2:])
- # Parse with microsecond precision
- dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M:%S.%f")
- return DateLine(dt, rest)
-
- lines = stdout.split("\n")
- if not lines:
- return stdout
- parsed: list[DateLine] = []
- for line in lines:
- if not line.strip(): # Skip empty lines
- continue
- try:
- parsed.append(parse(line))
- except ValueError:
- print(f"Failed to parse line: {line}")
- continue
-
- if not parsed:
- return stdout
-
- outlines: list[str] = []
- start_time = parsed[0].dt
-
- # Calculate relative times with
- for p in parsed:
- delta = p.dt - start_time
- seconds = delta.total_seconds()
- line_str = f"{seconds:3.2f} {p.line}"
- outlines.append(line_str)
-
- return "\n".join(outlines)
-
-
-def _timestamp_output(line: str) -> str:
- now = datetime.now()
- timestamp = now.strftime("%Y-%m-%d %H:%M:%S.%f")
- return f"{timestamp} {line.rstrip()}"
-
-
-def parse_args() -> argparse.Namespace:
- parser = argparse.ArgumentParser(description="Compile FastLED for WASM")
- parser.add_argument(
- "--mapped-dir",
- type=Path,
- default="/mapped",
- help="Directory containing source files (default: /mapped)",
- )
- parser.add_argument(
- "--keep-files", action="store_true", help="Keep source files after compilation"
- )
- parser.add_argument(
- "--only-copy",
- action="store_true",
- help="Only copy files from mapped directory to container",
- )
- parser.add_argument(
- "--only-insert-header",
- action="store_true",
- help="Only insert headers in source files",
- )
- parser.add_argument(
- "--only-compile", action="store_true", help="Only compile the project"
- )
- parser.add_argument(
- "--profile",
- action="store_true",
- help="Enable profiling for compilation to see what's taking so long.",
- )
-
- parser.add_argument(
- "--disable-auto-clean",
- action="store_true",
- help="Massaive speed improvement to not have to rebuild everything, but flakes out sometimes.",
- default=os.getenv("DISABLE_AUTO_CLEAN", "0") == "1",
- )
- parser.add_argument(
- "--no-platformio",
- action="store_true",
- help="Don't use platformio to compile the project, use the new system of direct emcc calls.",
- )
- # Add mutually exclusive build mode group
- build_mode = parser.add_mutually_exclusive_group()
- build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
- build_mode.add_argument(
- "--quick",
- action="store_true",
- default=True,
- help="Build in quick mode (default)",
- )
- build_mode.add_argument(
- "--release", action="store_true", help="Build in release mode"
- )
-
- return parser.parse_args()
-
-
-def find_project_dir(mapped_dir: Path) -> Path:
- mapped_dirs: List[Path] = list(mapped_dir.iterdir())
- if len(mapped_dirs) > 1:
- raise ValueError(
- f"Error: More than one directory found in {mapped_dir}, which are {mapped_dirs}"
- )
-
- src_dir: Path = mapped_dirs[0]
- return src_dir
-
-
-def process_compile(
- js_dir: Path, build_mode: BuildMode, auto_clean: bool, no_platformio: bool
-) -> None:
- print("Starting compilation...")
- rtn = compile(js_dir, build_mode, auto_clean, no_platformio=no_platformio)
- print(f"Compilation return code: {rtn}")
- if rtn != 0:
- print("Compilation failed.")
- raise RuntimeError("Compilation failed.")
- print("Compilation successful.")
-
-
-def cleanup(args: argparse.Namespace, js_src: Path) -> None:
- if not args.keep_files and not (args.only_copy or args.only_insert_header):
- print("Removing temporary source files")
- shutil.rmtree(js_src)
- else:
- print("Keeping temporary source files")
-
-
-def hash_file(file_path: Path) -> str:
- hasher = hashlib.md5()
- with open(file_path, "rb") as f:
- for chunk in iter(lambda: f.read(4096), b""):
- hasher.update(chunk)
- return hasher.hexdigest()
-
-
-def main() -> int:
- print("Starting FastLED WASM compilation script...")
- args = parse_args()
- print(f"Keep files flag: {args.keep_files}")
- print(f"Using mapped directory: {args.mapped_dir}")
-
- if args.profile:
- print("Enabling profiling for compilation.")
- # Profile linking
- os.environ["EMPROFILE"] = "2"
-
- try:
- if JS_SRC.exists():
- shutil.rmtree(JS_SRC)
- JS_SRC.mkdir(parents=True, exist_ok=True)
- src_dir = find_project_dir(args.mapped_dir)
-
- any_only_flags = args.only_copy or args.only_insert_header or args.only_compile
-
- do_copy = not any_only_flags or args.only_copy
- do_insert_header = not any_only_flags or args.only_insert_header
- do_compile = not any_only_flags or args.only_compile
-
- if do_copy:
- copy_files(src_dir, JS_SRC)
- print("Copying Arduino.h to src/Arduino.h")
- shutil.copy(ARDUINO_H_SRC, JS_SRC / "Arduino.h")
- if args.only_copy:
- return 0
-
- if do_insert_header:
- process_ino_files(JS_SRC)
- if args.only_insert_header:
- print("Transform to cpp and insert header operations completed.")
- return 0
-
- if _CHECK_SYNTAX:
- print("Performing syntax check...")
- syntax_results = check_syntax(
- directory_path=JS_SRC, gcc_path=_COMPILER_PATH
- )
- failed_checks = [r for r in syntax_results if not r.is_valid]
- if failed_checks:
- print("\nSyntax check failed!")
- for result in failed_checks:
- print(f"\nFile: {result.file_path}")
- print(f"Error: {result.message}")
- return 1
- print("Syntax check passed for all files.")
-
- no_platformio: bool = args.no_platformio
-
- if do_compile:
- try:
- # Determine build mode from args
- if args.debug:
- build_mode = BuildMode.DEBUG
- elif args.release:
- build_mode = BuildMode.RELEASE
- else:
- # Default to QUICK mode if neither debug nor release specified
- build_mode = BuildMode.QUICK
-
- process_compile(
- js_dir=JS_DIR,
- build_mode=build_mode,
- auto_clean=not args.disable_auto_clean,
- no_platformio=no_platformio,
- )
- except Exception as e:
- print(f"Error: {str(e)}")
- return 1
-
- def _get_build_dir_platformio() -> Path:
- build_dirs = [d for d in PIO_BUILD_DIR.iterdir() if d.is_dir()]
- if len(build_dirs) != 1:
- raise RuntimeError(
- f"Expected exactly one build directory in {PIO_BUILD_DIR}, found {len(build_dirs)}: {build_dirs}"
- )
- build_dir: Path = build_dirs[0]
- return build_dir
-
- def _get_build_dir_cmake() -> Path:
- return JS_DIR / "build"
-
- if no_platformio:
- build_dir = _get_build_dir_cmake()
- else:
- build_dir = _get_build_dir_platformio()
-
- print("Copying output files...")
- fastled_js_dir: Path = src_dir / FASTLED_OUTPUT_DIR_NAME
- fastled_js_dir.mkdir(parents=True, exist_ok=True)
-
- for file in ["fastled.js", "fastled.wasm"]:
- _src = build_dir / file
- _dst = fastled_js_dir / file
- print(f"Copying {_src} to {_dst}")
- shutil.copy2(_src, _dst)
-
- print(f"Copying {INDEX_HTML_SRC} to output directory")
- shutil.copy2(INDEX_HTML_SRC, fastled_js_dir / "index.html")
- print(f"Copying {INDEX_CSS_SRC} to output directory")
- shutil.copy2(INDEX_CSS_SRC, fastled_js_dir / "index.css")
-
- # copy all js files in FASTLED_COMPILER_DIR to output directory
- Path(fastled_js_dir / "modules").mkdir(parents=True, exist_ok=True)
- for _file in FASTLED_MODULES_DIR.iterdir():
- if _file.suffix == ".js":
- print(f"Copying {_file} to output directory")
- shutil.copy2(_file, fastled_js_dir / "modules" / _file.name)
-
- fastled_js_mem = build_dir / "fastled.js.mem"
- fastled_wasm_map = build_dir / "fastled.wasm.map"
- fastled_js_symbols = build_dir / "fastled.js.symbols"
- if fastled_js_mem.exists():
- print(f"Copying {fastled_js_mem} to output directory")
- shutil.copy2(fastled_js_mem, fastled_js_dir / fastled_js_mem.name)
- if fastled_wasm_map.exists():
- print(f"Copying {fastled_wasm_map} to output directory")
- shutil.copy2(fastled_wasm_map, fastled_js_dir / fastled_wasm_map.name)
- if fastled_js_symbols.exists():
- print(f"Copying {fastled_js_symbols} to output directory")
- shutil.copy2(
- fastled_js_symbols, fastled_js_dir / fastled_js_symbols.name
- )
- print("Copying index.js to output directory")
- shutil.copy2(INDEX_JS_SRC, fastled_js_dir / "index.js")
- optional_input_data_dir = src_dir / "data"
- output_data_dir = fastled_js_dir / optional_input_data_dir.name
-
- # Handle data directory if it exists
- manifest: list[dict] = []
- if optional_input_data_dir.exists():
- # Clean up existing output data directory
- if output_data_dir.exists():
- for _file in output_data_dir.iterdir():
- _file.unlink()
-
- # Create output data directory and copy files
- output_data_dir.mkdir(parents=True, exist_ok=True)
- for _file in optional_input_data_dir.iterdir():
- if _file.is_file(): # Only copy files, not directories
- filename: str = _file.name
- if filename.endswith(".embedded.json"):
- print("Embedding data file")
- filename_no_embedded = filename.replace(
- ".embedded.json", ""
- )
- # read json file
- with open(_file, "r") as f:
- data = json.load(f)
- hash_value = data["hash"]
- size = data["size"]
- manifest.append(
- {
- "name": filename_no_embedded,
- "path": f"data/{filename_no_embedded}",
- "size": size,
- "hash": hash_value,
- }
- )
- else:
- print(f"Copying {_file.name} -> {output_data_dir}")
- shutil.copy2(_file, output_data_dir / _file.name)
- hash = hash_file(_file)
- manifest.append(
- {
- "name": _file.name,
- "path": f"data/{_file.name}",
- "size": _file.stat().st_size,
- "hash": hash,
- }
- )
-
- # Write manifest file even if empty
- print("Writing manifest files.json")
- manifest_json_str = json.dumps(manifest, indent=2, sort_keys=True)
- with open(fastled_js_dir / "files.json", "w") as f:
- f.write(manifest_json_str)
- cleanup(args, JS_SRC)
-
- print("Compilation process completed successfully")
- return 0
-
- except Exception as e:
- import traceback
-
- stacktrace = traceback.format_exc()
- print(stacktrace)
- print(f"Error: {str(e)}")
- return 1
-
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/src/platforms/wasm/compiler/compile_lock.py b/src/platforms/wasm/compiler/compile_lock.py
deleted file mode 100644
index 637c02b0e7..0000000000
--- a/src/platforms/wasm/compiler/compile_lock.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import threading
-
-COMPILE_LOCK = threading.Lock()
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/entrypoint.sh b/src/platforms/wasm/compiler/entrypoint.sh
deleted file mode 100644
index 82defab844..0000000000
--- a/src/platforms/wasm/compiler/entrypoint.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-source /emsdk/emsdk_env.sh
-export PATH=$PATH:/emsdk/upstream/bin
-python init_runtime.py
-./final_prewarm.sh
-exec "$@"
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/extra/100dots.html b/src/platforms/wasm/compiler/extra/100dots.html
deleted file mode 100644
index 384393ed02..0000000000
--- a/src/platforms/wasm/compiler/extra/100dots.html
+++ /dev/null
@@ -1,186 +0,0 @@
-
-
-
-
-
- LED Grid Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/platforms/wasm/compiler/extra/demo_threejs.html b/src/platforms/wasm/compiler/extra/demo_threejs.html
deleted file mode 100644
index 3f074f77b0..0000000000
--- a/src/platforms/wasm/compiler/extra/demo_threejs.html
+++ /dev/null
@@ -1,216 +0,0 @@
-
-
-
- three.js webgl - framebuffer - texture
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/platforms/wasm/compiler/extra/webgl_postprocessing_unreal_bloom.html b/src/platforms/wasm/compiler/extra/webgl_postprocessing_unreal_bloom.html
deleted file mode 100644
index 0e94132f40..0000000000
--- a/src/platforms/wasm/compiler/extra/webgl_postprocessing_unreal_bloom.html
+++ /dev/null
@@ -1,191 +0,0 @@
-
-
-
- three.js webgl - postprocessing - unreal bloom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/platforms/wasm/compiler/final_prewarm.sh b/src/platforms/wasm/compiler/final_prewarm.sh
deleted file mode 100755
index 8feb7caea4..0000000000
--- a/src/platforms/wasm/compiler/final_prewarm.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-if [ "$RENDER" != "true" ]; then
- echo "Skipping finalprewarm..."
- exit 0
-fi
-
-git_path=/git/fastled
-fastled_path=/js/fastled
-
-# update the fastled git repo
-cd $git_path
-
-git fetch origin
-git reset --hard origin/master
-# ["rsync", "-av", "--info=NAME", "--delete", f"{src}/", f"{dst}/"],
-
-cd /js
-
-rsync -av --info=NAME --delete "$git_path/" "$fastled_path/" --exclude ".git"
-# rsync -av --info=NAME --delete "$git_path/examples" "$fastled_path/src"
-
-# now print out all the files in the current directory
-ls -la
-
-
diff --git a/src/platforms/wasm/compiler/init_runtime.py b/src/platforms/wasm/compiler/init_runtime.py
deleted file mode 100644
index 96b9d8265d..0000000000
--- a/src/platforms/wasm/compiler/init_runtime.py
+++ /dev/null
@@ -1,63 +0,0 @@
-
-import os
-from pathlib import Path
-import glob
-import warnings
-from concurrent.futures import ThreadPoolExecutor
-
-HERE = Path(__file__).parent
-
-
-_COMPILER_DIR = Path("/js/fastled/src/platforms/wasm/compiler")
-
-
-def task(src: str | Path) -> None:
- src = Path(src)
- if "entrypoint.sh" in str(src):
- return
- link_dst = Path("/js") / src.name
-
- # Handle shell scripts
- if src.suffix == '.sh':
- os.system(f"dos2unix {src} && chmod +x {src}")
-
- # if link exists, remove it
- if link_dst.exists():
- print(f"Removing existing link {link_dst}")
- try:
- os.remove(link_dst)
- except Exception as e:
- warnings.warn(f"Failed to remove {link_dst}: {e}")
-
-
- if not link_dst.exists():
- print(f"Linking {src} to {link_dst}")
- try:
- os.symlink(str(src), str(link_dst))
- except FileExistsError:
- print(f"Target {link_dst} already exists")
- else:
- print(f"Target {link_dst} already exists")
-
-
-def make_links() -> None:
- # Define file patterns to include
- patterns = ['*.h', '*.py', '*.css', '*.sh', "*.ino", "*.hpp", "*.cpp", "*.ini", "*.txt"]
-
- # Get all matching files in compiler directory
- files = []
- for pattern in patterns:
- files.extend(glob.glob(str(_COMPILER_DIR / pattern)))
-
- # Process files in parallel using ThreadPoolExecutor
- with ThreadPoolExecutor(max_workers=16) as executor:
- executor.map(task, files)
-
-
-def init_runtime() -> None:
- os.chdir(str(HERE))
- make_links()
-
-
-if __name__ == "__main__":
- init_runtime()
diff --git a/src/platforms/wasm/compiler/install-arduino-cli.sh b/src/platforms/wasm/compiler/install-arduino-cli.sh
deleted file mode 100755
index 7bd1bbb3d2..0000000000
--- a/src/platforms/wasm/compiler/install-arduino-cli.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-# this is a work in progress for install the arduino-cli tool so that
-# ino sketches can be converted into cpp code in preparation for the
-# wasm compilation.
-
-wget https://github.com/arduino/arduino-cli/releases/download/v1.0.4/arduino-cli_1.0.4_Linux_64bit.tar.gz && \
- tar -xvf arduino-cli_1.0.4_Linux_64bit.tar.gz && \
- mv arduino-cli /usr/bin/arduino-cli && \
- rm -rf arduino-cli_1.0.4_Linux_64bit*
-
-# COPY examples/Blink/Blink.ino /pre-warm/Blink/Blink.ino
-arduino-cli core update-index
-arduino-cli core install arduino:avr
-
-mkdir -p /pre-warm/Blink && \
- cat < /pre-warm/Blink/Blink.ino
-void setup() {
- // initialize digital pin LED_BUILTIN as an output.
- pinMode(LED_BUILTIN, OUTPUT);
-}
-
-void loop() {
- do_it();
- // turn the LED on (HIGH is the voltage level)
- digitalWrite(LED_BUILTIN, HIGH);
- // wait for a second
- delay(1000);
- // turn the LED off by making the voltage LOW
- digitalWrite(LED_BUILTIN, LOW);
- // wait for a second
- delay(1000);
-}
-
-void do_it() {
- int i = 0;
- i++;
-}
-EOF
-
-arduino-cli compile --preprocess --fqbn arduino:avr:uno /pre-warm/Blink/Blink.ino
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/lib/CMakeLists.txt b/src/platforms/wasm/compiler/lib/CMakeLists.txt
deleted file mode 100644
index 6462526d0e..0000000000
--- a/src/platforms/wasm/compiler/lib/CMakeLists.txt
+++ /dev/null
@@ -1,152 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(FastLED_WASM)
-
-# Enable verbose makefile output for all compiled sources
-set(CMAKE_VERBOSE_MAKEFILE ON)
-
-
-# projenv.Replace(CC=CC, CXX=CXX, LINK=LINK, AR="emar", RANLIB="emranlib")
-# env.Replace(CC=CC, CXX=CXX, LINK=LINK, AR="emar", RANLIB="emranlib")
-
-# --- Set Emscripten as the Compiler ---
-set(CMAKE_C_COMPILER "emcc")
-set(CMAKE_CXX_COMPILER "em++")
-set(CMAKE_AR "emar")
-set(CMAKE_RANLIB "emranlib")
-
-# Use ccache as a compiler launcher (requires CMake 3.4 or newer)
-set(CMAKE_C_COMPILER_LAUNCHER "ccache")
-set(CMAKE_CXX_COMPILER_LAUNCHER "ccache")
-
-
-# --- Build Mode and Optimization Level ---
-if(NOT DEFINED ENV{BUILD_MODE})
- set(BUILD_MODE "QUICK")
-else()
- set(BUILD_MODE $ENV{BUILD_MODE})
-endif()
-
-# if(BUILD_MODE STREQUAL "QUICK")
-# set(OPT_LEVEL "-O1")
-# elseif(BUILD_MODE STREQUAL "DEBUG")
-# set(OPT_LEVEL "-Og")
-# else() # RELEASE
-# set(OPT_LEVEL "-Oz")
-# endif()
-
-
-set(OPT_LEVEL "-Oz")
-
-# --- Common Compiler and Linker Flags ---
-set(COMMON_COMPILE_FLAGS
- -DFASTLED_ENGINE_EVENTS_MAX_LISTENERS=50
- -DFASTLED_FORCE_NAMESPACE=1
- -DFASTLED_USE_PROGMEM=0
- -DDISABLE_EXCEPTION_CATCHING=1
- -fno-exceptions
- -fno-rtti
- -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0
- -std=gnu++17
- -fpermissive
- ${OPT_LEVEL}
-)
-
-# If PROFILE flag is passed (e.g. via -DPROFILE), add Clang statistics flags.
-# if(DEFINED PROFILE)
-# message(STATUS "PROFILE flag passed: enabling Clang compiler stats output")
-# list(APPEND COMMON_COMPILE_FLAGS -Xclang -print-stats -mllvm -stats -DLLVM_FORCE_ENABLE_STATS=1)
-# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLLVM_FORCE_ENABLE_STATS")
-# else()
-# message(STATUS "PROFILE flag not passed: skipping Clang compiler stats output")
-# endif()
-
-set(COMMON_LINK_FLAGS
- -sALLOW_MEMORY_GROWTH=0
- -sDISABLE_EXCEPTION_CATCHING=1
- -sDISABLE_EXCEPTION_THROWING=0
- --bind
- -DUSE_OFFSET_CONVERTER=0
- -sINITIAL_MEMORY=134217728
- -fuse-ld=lld
- --no-entry
- -sMODULARIZE=1
- -sUSE_PTHREADS=0 # Disable threading support
-)
-
-set(LIBRARY_LINK_FLAGS
- ${COMMON_LINK_FLAGS}
-
-)
-
-
-if(BUILD_MODE STREQUAL "DEBUG")
- list(APPEND COMMON_COMPILE_FLAGS
- -g3
- -fsanitize=address
- -fsanitize=undefined
- )
- set(DEBUG_LINK_FLAGS
- -gsource-map
- --emit-symbol-map
- -sSTACK_OVERFLOW_CHECK=2
- -ASSERTIONS=1
- )
- list(APPEND LIBRARY_LINK_FLAGS ${DEBUG_LINK_FLAGS})
-endif()
-
-# src\platforms\wasm\compiler\lib\CMakeLists.txt
-
-# --- FASTLED LIBRARY SETUP ---
-# Set the FastLED source directory (assumes your FastLED sources are in fastled/src)
-set(FASTLED_SOURCE_DIR ../../../../)
-# set(FASTLED_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/fastled/src)
-message(STATUS "fastled source directory: ${FASTLED_SOURCE_DIR}")
-
-
-# Enable header copying mode.
-set(FASTLED_COPY_HEADERS ON CACHE BOOL "Copy FastLED headers to the include path")
-set(FASTLED_INCLUDE_DEST /include CACHE PATH "Destination path for FastLED headers")
-
-# (Optional) Add the FastLED headers to the global include path.
-include_directories(${FASTLED_SOURCE_DIR})
-
-# Delegate building the FastLED library (and header copying) to the subdirectory.
-add_subdirectory(${FASTLED_SOURCE_DIR} ${CMAKE_BINARY_DIR}/fastled)
-# Add FastLED headers to the global include path.
-
-
-
-
-
-
-
-
-# Set target properties for fastled (if it exists)
-if(TARGET fastled)
- set_target_properties(fastled PROPERTIES
- CXX_STANDARD 17
- CXX_STANDARD_REQUIRED ON
- POSITION_INDEPENDENT_CODE ON
- )
-endif()
-
-# # --- EXECUTABLE (SKETCH) SETUP ---
-# # Instead of using the FastLED sources directly, we build an executable from local sketch sources.
-# file(GLOB_RECURSE EXECUTABLE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
-# message(STATUS "Executable sources: ${EXECUTABLE_SOURCES}")
-
-# add_executable(sketch ${EXECUTABLE_SOURCES})
-
-# # Set compile options and definitions for the sketch executable.
-# target_compile_options(sketch PRIVATE ${COMMON_COMPILE_FLAGS})
-# target_compile_definitions(sketch PRIVATE SKETCH_COMPILE)
-# target_include_directories(sketch PRIVATE
-# ${CMAKE_CURRENT_SOURCE_DIR}/fastled/src
-# ${CMAKE_CURRENT_SOURCE_DIR}/src
-# )
-# target_link_options(sketch PRIVATE ${SKETCH_LINK_FLAGS})
-# set_target_properties(sketch PROPERTIES
-# CXX_STANDARD 17
-# CXX_STANDARD_REQUIRED ON
-# )
-# target_link_libraries(sketch PRIVATE fastled)
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/modules/graphics_manager_threejs.js b/src/platforms/wasm/compiler/modules/graphics_manager_threejs.js
index a8c02dac8a..0aa26c114d 100644
--- a/src/platforms/wasm/compiler/modules/graphics_manager_threejs.js
+++ b/src/platforms/wasm/compiler/modules/graphics_manager_threejs.js
@@ -63,6 +63,7 @@ export class GraphicsManagerThreeJS {
this.previousTotalLeds = 0;
this.bloom_stength = 1;
this.bloom_radius = 16;
+ this.outside_bounds_warning_count = 0;
}
reset() {
@@ -307,8 +308,17 @@ export class GraphicsManagerThreeJS {
const y_array = stripData.map.y;
const length = Math.min(x_array.length, y_array.length);
+ const WARNING_COUNT = 10;
+
for (let j = 0; j < pixelCount; j++) {
if (j >= length) {
+ this.outside_bounds_warning_count++;
+ if (this.outside_bounds_warning_count < WARNING_COUNT) {
+ console.warn(`Strip ${strip_id}: Pixel ${j} is outside the screen map ${map.length}, skipping update`);
+ if (this.outside_bounds_warning_count === WARNING_COUNT) {
+ console.warn('Suppressing further warnings about pixels outside the screen map');
+ }
+ }
console.warn(`Strip ${strip_id}: Pixel ${j} is outside the screen map ${map.length}, skipping update`);
continue;
}
diff --git a/src/platforms/wasm/compiler/platformio.ini b/src/platforms/wasm/compiler/platformio.ini
index f0d042323b..f004978955 100644
--- a/src/platforms/wasm/compiler/platformio.ini
+++ b/src/platforms/wasm/compiler/platformio.ini
@@ -11,9 +11,11 @@ build_flags =
-DFASTLED_NO_PINMAP
-DHAS_HARDWARE_PIN_SUPPORT
-DFASTLED_FORCE_SOFTWARE_SPI
+ -I/js/fastled/src/platforms/wasm/compiler
custom_wasm_export_name = fastled
lib_deps =
FastLED=symlink://fastled
-build_dir=build/wasm
\ No newline at end of file
+build_dir=build/wasm
+force_verbose=yes
\ No newline at end of file
diff --git a/src/platforms/wasm/compiler/pre-process.sh b/src/platforms/wasm/compiler/pre-process.sh
deleted file mode 100755
index 2de77b51ac..0000000000
--- a/src/platforms/wasm/compiler/pre-process.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-
-set -e
-set -x
-
-python compile.py --only-copy
-
-# Find the .ino file in the src directory
-ino_file=$(find src -name "*.ino" -type f)
-
-if [ -z "$ino_file" ]; then
- echo "Error: No .ino file found in the src directory"
- exit 1
-fi
-
-# Extract the filename without extension
-ino_filename=$(basename "$ino_file")
-ino_name="${ino_filename%.*}"
-
-# Copy and process the .ino file
-cp "$ino_file" "src/${ino_name}.ino.cpp"
-python process-ino.py "src/${ino_name}.ino.cpp"
-
-# Remove the original .ino file
-rm "$ino_file"
-
-python compile.py --only-compile
diff --git a/src/platforms/wasm/compiler/prewarm.sh b/src/platforms/wasm/compiler/prewarm.sh
deleted file mode 100755
index c55fe20881..0000000000
--- a/src/platforms/wasm/compiler/prewarm.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-set -x
-set -e
-
-# --force flag to force prewarm
-#test to see if --force flag is set
-forced=0
-if [ "$1" == "--force" ]; then
- forced=1
-fi
-
-echo "Forced: $forced"
-echo "NO_PREWARM: $NO_PREWARM"
-
-# if os env has PREWARM == "true"
-if [ "$forced" == "0" ]; then
- if [ "$NO_PREWARM" != "1" ]; then
- echo "Prewarming..."
- else
- echo "Skipping prewarm..."
- exit 0
- fi
-fi
-
-rm -rf /prewarm
-mkdir -p /prewarm && cp -r /js/fastled/examples/wasm /prewarm/wasm
-python /js/compile.py --debug --mapped-dir /prewarm && rm -rf /js/.pio/build/wasm/src/wasm.ino.o || echo "failed to delete wasm.ino.o"
-rm -rf /prewarm
-
-mkdir -p /prewarm && cp -r /js/fastled/examples/wasm /prewarm/wasm
-python /js/compile.py --quick --mapped-dir /prewarm && rm -rf /js/.pio/build/wasm/src/wasm.ino.o || echo "failed to delete wasm.ino.o"
-rm -rf /prewarm
-
-mkdir -p /prewarm && cp -r /js/fastled/examples/wasm /prewarm/wasm
-python /js/compile.py --release --mapped-dir /prewarm && rm -rf /js/.pio/build/wasm/src/wasm.ino.o || echo "failed to delete wasm.ino.o"
-rm -rf /prewarm
-
-mkdir -p /prewarm && cp -r /js/fastled/examples/wasm /prewarm/wasm
-cd /js
-python compile.py --no-platformio --mapped-dir /prewarm # 60 seconds -> 5 seconds
-python compile.py --no-platformio --mapped-dir /prewarm # 5 seconds -> 0.5 seconds
-rm -rf /prewarm
diff --git a/src/platforms/wasm/compiler/process-ino.py b/src/platforms/wasm/compiler/process-ino.py
deleted file mode 100644
index 21e4be2e14..0000000000
--- a/src/platforms/wasm/compiler/process-ino.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env python3
-
-# This is experimental code to process an INO file and output
-# a C++ version like the arduino IDE does, where all the declarations
-# of function prototypes are at the top of the file.
-# However, clang ast dump will not correctly identify the integer types
-# of the arguments. For examples, uint8_t was being identified as "int".
-# This could be because we are using clang 11 from emscripten and this
-# might have been fixed in a newer version version of clang. However,
-# the amount of work to get this to work is massive so I'm stopping here.
-
-import os
-import sys
-import subprocess
-import argparse
-import re
-from dataclasses import dataclass
-
-@dataclass
-class FunctionPrototype:
- return_type: str
- name: str
- args: list[str]
-
- def __repr__(self) -> str:
- return f"{self.return_type} {self.name}({', '.join(self.args)})"
-
-def parse_arguments() -> argparse.Namespace:
- parser = argparse.ArgumentParser(description="Process INO file and dump AST.")
- parser.add_argument("input_file", help="Input source file (.cpp)")
- return parser.parse_args()
-
-def run_command(command):
- result = subprocess.run(command, capture_output=True, text=True)
- return result.stdout, result.stderr, result.returncode
-
-def parse_ast_output(ast_output):
- function_pattern = re.compile(r'FunctionDecl.*?line:\d+:\d+\s+(.*?)\s+\'(.*?)\'')
- functions = function_pattern.findall(ast_output)
- return [f"{name} {prototype}" for name, prototype in functions]
-
-def main() -> None:
- # Parse command-line arguments
- args = parse_arguments()
-
-
- # Ensure the file exists
- if not os.path.isfile(args.input_file):
- print(f"Error: File '{args.input_file}' not found!")
- sys.exit(1)
-
- # Add Emscripten's Clang to PATH
- os.environ['PATH'] = "/emsdk_portable/upstream/bin:" + os.environ['PATH']
-
- # Print Clang version
- stdout, stderr, returncode = run_command(["clang", "--version"])
- print(stdout)
- if returncode != 0:
- print(f"Error: {stderr}", file=sys.stderr)
- sys.exit(returncode)
-
- # Dump the AST
- stdout, stderr, returncode = run_command(["clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-nostdinc", args.input_file])
-
- # Parse the AST output, even if there was an error
- function_prototypes = parse_ast_output(stdout)
-
- # Print warning if there was an error, but continue processing
- if returncode != 0:
- print("Warning: Clang reported an error (possibly due to missing stdio.h), but continuing to process output.", file=sys.stderr)
- print(f"Clang error: {stderr}", file=sys.stderr)
-
- # Read the contents of the input file
- with open(args.input_file, 'r') as f:
- file_contents = f.read()
-
- # Find the position of setup() function
- setup_pos = file_contents.find('void setup()')
- if setup_pos == -1:
- print("Error: setup() function not found in the file.")
- sys.exit(1)
-
- def predicate(name: str) -> bool:
- if name.startswith('loop ') or name.startswith('setup '):
- return False
- return True
-
-
-
- def parse(name: str) -> FunctionPrototype | None:
- if name.startswith('invalid '):
- name = name[len('invalid '):]
- parts = name.split()
- if len(parts) < 2:
- return None
- name, type, *rest = parts
- args = " ".join(rest)
- return FunctionPrototype(type, name, args.split(','))
-
-
- prototypes = [parse(name) for name in function_prototypes if predicate(name)]
- prototypes = [str(proto) for proto in prototypes if proto]
-
- # Insert the prototypes before setup()
- prototypes_text = "\n".join(prototypes)
- prototypes_text_cleaned = prototypes_text.replace('\n', '\n') # This line effectively does nothing, but ensures prototypes_text_cleaned is a string
- new_contents = file_contents[:setup_pos] + prototypes_text_cleaned + "\n\n" + file_contents[setup_pos:]
-
- # Write the modified contents back to the file
- with open(args.input_file, 'w') as f:
- f.write(new_contents)
-
- print(f"Function prototypes have been inserted into {args.input_file}")
-
- # Write the function prototypes to protos.txt as well
- with open('protos.txt', 'w') as f:
- f.write("Function Prototypes:\n")
- for prototype in function_prototypes:
- f.write(f"{prototype}\n")
-
- print("Function prototypes have also been written to protos.txt")
-
-if __name__ == "__main__":
- main()
diff --git a/src/platforms/wasm/compiler/requirements.txt b/src/platforms/wasm/compiler/requirements.txt
deleted file mode 100644
index 553bdf042f..0000000000
--- a/src/platforms/wasm/compiler/requirements.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-platformio==6.1.16
-
-# API dependencies
-fastapi==0.109.2
-uvicorn[standard]==0.30.6
-python-multipart==0.0.19
-disklru==2.0.0
-psutil==6.1.1
-
-# File transfer utility
-# https://github.com/zackees/tx
-wormhole-tx
diff --git a/src/platforms/wasm/compiler/run.py b/src/platforms/wasm/compiler/run.py
deleted file mode 100644
index eadf4b96b9..0000000000
--- a/src/platforms/wasm/compiler/run.py
+++ /dev/null
@@ -1,125 +0,0 @@
-import argparse
-import subprocess
-import os
-import sys
-from typing import Tuple
-import warnings
-from pathlib import Path
-
-from code_sync import sync_source_directory_if_volume_is_mapped
-
-_PORT = os.environ.get("PORT", 80)
-
-_CHOICES = [
- "compile",
- "server"
-]
-
-HERE = Path(__file__).parent
-
-# if [ "$RENDER" != "true" ]; then
-# echo "Skipping finalprewarm..."
-# exit 0
-# fi
-
-# git_path=/git/fastled
-# fastled_path=/js/fastled
-
-# # update the fastled git repo
-# cd $git_path
-
-# git fetch origin
-# git reset --hard origin/master
-# # ["rsync", "-av", "--info=NAME", "--delete", f"{src}/", f"{dst}/"],
-
-# cd /js
-
-# rsync -av --info=NAME --delete "$git_path/" "$fastled_path/" --exclude ".git"
-
-def _update_fastled() -> None:
- # NOT ENABLED YET
- if True:
- return
- is_render = os.environ.get("RENDER", "false") == "true"
- if not is_render:
- print("Skipping finalprewarm...")
- return
- git_path = "/git/fastled"
- fastled_path = "/js/fastled"
- subprocess.run(["git", "fetch", "origin"], cwd=git_path)
- subprocess.run(["git", "reset", "--hard", "origin/master"], cwd=git_path)
- subprocess.run(["rsync", "-av", "--info=NAME", "--delete", f"{git_path}/", f"{fastled_path}/", "--exclude", ".git"], cwd="/js")
-
-
-
-
-def _parse_args() -> Tuple[argparse.Namespace, list[str]]:
- parser = argparse.ArgumentParser(description="Run compile.py with additional arguments")
- parser.add_argument("mode", help="Which mode does this script run in", choices=_CHOICES)
- return parser.parse_known_args()
-
-def _run_server(unknown_args: list[str]) -> int:
- env = os.environ.copy()
- if "--disable-auto-clean" in unknown_args:
- env["DISABLE_AUTO_CLEAN"] = "1"
- unknown_args.remove("--disable-auto-clean")
- if "--allow-shutdown" in unknown_args:
- env["ALLOW_SHUTDOWN"] = "1"
- unknown_args.remove("--allow-shutdown")
- if "--no-auto-update" in unknown_args:
- env["NO_AUTO_UPDATE"] = "1"
- unknown_args.remove("--no-auto-update")
- if "--no-sketch-cache" in unknown_args:
- env["NO_SKETCH_CACHE"] = "1"
- unknown_args.remove("--no-sketch-cache")
- if unknown_args:
- warnings.warn(f"Unknown arguments: {unknown_args}")
- unknown_args = []
- cmd_list = [
- "uvicorn",
- "server:app",
- "--host",
- "0.0.0.0",
- "--workers",
- "1",
- "--port",
- f"{_PORT}"
- ]
- cp: subprocess.CompletedProcess = subprocess.run(cmd_list, cwd=str(HERE), env=env)
- return cp.returncode
-
-def _run_compile(unknown_args: list[str]) -> int:
-
- # Construct the command to call compile.py with unknown arguments
- command = [sys.executable, 'compile.py'] + unknown_args
-
- # Call compile.py with the unknown arguments
- result = subprocess.run(command, text=True, cwd=str(HERE))
-
- # Print the output from compile.py
- #print(result.stdout)
- #if result.stderr:
- # print(result.stderr, file=sys.stderr)
- return result.returncode
-
-def main() -> int:
- print("Running...")
- args, unknown_args = _parse_args()
- _update_fastled()
- sync_source_directory_if_volume_is_mapped()
-
- try:
- if args.mode == "compile":
- rtn = _run_compile(unknown_args)
- return rtn
- elif args.mode == "server":
- rtn = _run_server(unknown_args)
- return rtn
- raise ValueError(f"Unknown mode: {args.mode}")
- except KeyboardInterrupt:
- print("Exiting...")
- return 1
-
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/src/platforms/wasm/compiler/server.py b/src/platforms/wasm/compiler/server.py
deleted file mode 100644
index c8cf70c6d9..0000000000
--- a/src/platforms/wasm/compiler/server.py
+++ /dev/null
@@ -1,775 +0,0 @@
-import json
-import os
-import shutil
-import subprocess
-import tempfile
-import threading
-import time
-import warnings
-import zipfile
-import zlib
-from contextlib import asynccontextmanager
-from pathlib import Path
-from tempfile import NamedTemporaryFile
-from threading import Timer
-
-import psutil # type: ignore
-from code_sync import ( # type: ignore
- sync_source_directory_if_volume_is_mapped,
- sync_src_to_target,
-)
-from compile_lock import COMPILE_LOCK # type: ignore
-from disklru import DiskLRUCache # type: ignore
-from fastapi import ( # type: ignore
- BackgroundTasks,
- Body,
- FastAPI,
- File,
- Header,
- HTTPException,
- UploadFile,
-)
-from fastapi.responses import FileResponse, RedirectResponse, Response # type: ignore
-from sketch_hasher import generate_hash_of_project_files # type: ignore
-from starlette.middleware.base import BaseHTTPMiddleware # type: ignore
-from starlette.requests import Request # type: ignore
-
-_EXAMPLES: list[str] = [
- "Chromancer",
- "LuminescentGrand",
- "wasm",
- "FxAnimartrix",
- "FxCylon",
- "FxDemoReel100",
- "FxFire2012",
- "FxEngine",
- "FxGfx2Video",
- "FxNoisePlusPalette",
- "FxNoiseRing",
- "FxSdCard",
- "FxWater",
-]
-_VOLUME_MAPPED_SRC = Path("/host/fastled/src")
-_RSYNC_DEST = Path("/js/fastled/src")
-
-_TEMP_DIR = Path("/tmp")
-
-_TEST = False
-_UPLOAD_LIMIT = 10 * 1024 * 1024
-_MEMORY_LIMIT_MB = int(os.environ.get("MEMORY_LIMIT_MB", "0")) # 0 means disabled
-_MEMORY_CHECK_INTERVAL = 0.1 # Check every 100ms
-_MEMORY_EXCEEDED_EXIT_CODE = 137 # Standard OOM kill code
-# Protect the endpoints from random bots.
-# Note that that the wasm_compiler.py greps for this string to get the URL of the server.
-# Changing the name could break the compiler.
-_AUTH_TOKEN = "oBOT5jbsO4ztgrpNsQwlmFLIKB"
-
-_LIVE_GIT_UPDATES_INTERVAL = int(
- os.environ.get("LIVE_GIT_UPDATE_INTERVAL", 60 * 60 * 24)
-) # Update every 24 hours
-_ALLOW_SHUTDOWN = os.environ.get("ALLOW_SHUTDOWN", "false").lower() in ["true", "1"]
-_NO_SKETCH_CACHE = os.environ.get("NO_SKETCH_CACHE", "false").lower() in ["true", "1"]
-_LIVE_GIT_FASTLED_DIR = Path("/git/fastled")
-
-# TODO - cleanup
-_NO_AUTO_UPDATE = (
- os.environ.get("NO_AUTO_UPDATE", "0") in ["1", "true"]
- or _VOLUME_MAPPED_SRC.exists()
-)
-# This feature is broken. To fix, issue a git update, THEN invoke the compiler command to re-warm the cache.
-# otherwise you get worst case scenario on a new compile.
-# _LIVE_GIT_UPDATES_ENABLED = (not _NO_AUTO_UPDATE) or (
-# os.environ.get("LIVE_GIT_UPDATES", "0") in ["1", "true"]
-# )
-_LIVE_GIT_UPDATES_ENABLED = False
-
-
-if _NO_SKETCH_CACHE:
- print("Sketch caching disabled")
-
-UPLOAD_DIR = Path("/uploads")
-UPLOAD_DIR.mkdir(exist_ok=True)
-COMPILE_COUNT = 0
-COMPILE_FAILURES = 0
-COMPILE_SUCCESSES = 0
-START_TIME = time.time()
-
-OUTPUT_DIR = Path("/output")
-OUTPUT_DIR.mkdir(exist_ok=True)
-
-# Initialize disk cache
-SKETCH_CACHE_FILE = OUTPUT_DIR / "compile_cache.db"
-SKETCH_CACHE_MAX_ENTRIES = 50
-SKETCH_CACHE = DiskLRUCache(str(SKETCH_CACHE_FILE), SKETCH_CACHE_MAX_ENTRIES)
-
-
-class UploadSizeMiddleware(BaseHTTPMiddleware):
- def __init__(self, app, max_upload_size: int):
- super().__init__(app)
- self.max_upload_size = max_upload_size
-
- async def dispatch(self, request: Request, call_next):
- if request.method == "POST" and "/compile/wasm" in request.url.path:
- print(
- f"Upload request with content-length: {request.headers.get('content-length')}"
- )
- content_length = request.headers.get("content-length")
- if content_length:
- content_length = int(content_length) # type: ignore
- if content_length > self.max_upload_size: # type: ignore
- return Response(
- status_code=413,
- content=f"File size exceeds {self.max_upload_size} byte limit, for large assets please put them in data/ directory to avoid uploading them to the server.",
- )
- return await call_next(request)
-
-
-@asynccontextmanager # type: ignore
-async def lifespan(app: FastAPI): # type: ignore
- print("Starting FastLED wasm compiler server...")
- try:
- print(f"Settings: {json.dumps(get_settings(), indent=2)}")
- except Exception as e:
- print(f"Error getting settings: {e}")
-
- if _MEMORY_LIMIT_MB > 0:
- print(f"Starting memory watchdog (limit: {_MEMORY_LIMIT_MB}MB)")
- memory_watchdog()
-
- sync_source_directory_if_volume_is_mapped()
- if _LIVE_GIT_UPDATES_ENABLED:
- Timer(
- _LIVE_GIT_UPDATES_INTERVAL, sync_live_git_to_target
- ).start() # Start the periodic git update
- else:
- print("Auto updates disabled")
- yield # end startup
- return # end shutdown
-
-
-app = FastAPI(lifespan=lifespan)
-
-app.add_middleware(UploadSizeMiddleware, max_upload_size=_UPLOAD_LIMIT)
-
-
-def update_live_git_repo() -> None:
- if not _LIVE_GIT_UPDATES_ENABLED:
- return
- try:
- if not _LIVE_GIT_FASTLED_DIR.exists():
- subprocess.run(
- [
- "git",
- "clone",
- "https://github.com/fastled/fastled.git",
- str(_LIVE_GIT_FASTLED_DIR),
- "--depth=1",
- ],
- check=True,
- )
- print("Cloned live FastLED repository")
- else:
- print("Updating live FastLED repository")
- subprocess.run(
- ["git", "fetch", "origin"],
- check=True,
- capture_output=True,
- cwd=_LIVE_GIT_FASTLED_DIR,
- )
- subprocess.run(
- ["git", "reset", "--hard", "origin/master"],
- check=True,
- capture_output=True,
- cwd=_LIVE_GIT_FASTLED_DIR,
- )
- print("Live FastLED repository updated successfully")
- except subprocess.CalledProcessError as e:
- warnings.warn(
- f"Error updating live FastLED repository: {e.stdout}\n\n{e.stderr}"
- )
-
-
-def try_get_cached_zip(hash: str) -> bytes | None:
- if _NO_SKETCH_CACHE:
- print("Sketch caching disabled, skipping cache get")
- return None
- return SKETCH_CACHE.get_bytes(hash)
-
-
-def cache_put(hash: str, data: bytes) -> None:
- if _NO_SKETCH_CACHE:
- print("Sketch caching disabled, skipping cache put")
- return
- SKETCH_CACHE.put_bytes(hash, data)
-
-
-def sync_live_git_to_target() -> None:
- if not _LIVE_GIT_UPDATES_ENABLED:
- return
- update_live_git_repo() # no lock
-
- def on_files_changed() -> None:
- print("FastLED source changed from github repo, clearing disk cache.")
- SKETCH_CACHE.clear()
-
- sync_src_to_target(
- _LIVE_GIT_FASTLED_DIR / "src", _RSYNC_DEST, callback=on_files_changed
- )
- sync_src_to_target(
- _LIVE_GIT_FASTLED_DIR / "examples",
- _RSYNC_DEST.parent / "examples",
- callback=on_files_changed,
- )
- # Basically a setTimeout() in JS.
- Timer(
- _LIVE_GIT_UPDATES_INTERVAL, sync_live_git_to_target
- ).start() # Start the periodic git update
-
-
-def compile_source(
- temp_src_dir: Path,
- file_path: Path,
- background_tasks: BackgroundTasks,
- build_mode: str,
- profile: bool,
- hash_value: str | None = None,
-) -> FileResponse | HTTPException:
- """Compile source code and return compiled artifacts as a zip file."""
- epoch = time.time()
-
- def _print(msg) -> None:
- diff = time.time() - epoch
- print(f" = SERVER {diff:.2f}s = {msg}")
-
- _print("Starting compile_source")
- global COMPILE_COUNT
- global COMPILE_FAILURES
- global COMPILE_SUCCESSES
- COMPILE_COUNT += 1
- temp_zip_dir = None
- try:
- # Find the first directory in temp_src_dir
- src_dir = next(Path(temp_src_dir).iterdir())
- _print(f"\nFound source directory: {src_dir}")
- except StopIteration:
- return HTTPException(
- status_code=500,
- detail=f"No files found in extracted directory: {temp_src_dir}",
- )
-
- _print("Files are ready, waiting for compile lock...")
- COMPILE_LOCK_start = time.time()
-
- with COMPILE_LOCK:
- COMPILE_LOCK_end = time.time()
-
- is_debug = build_mode.lower() == "debug"
-
- _print("\nRunning compiler...")
- cmd = [
- "python",
- "run.py",
- "compile",
- f"--mapped-dir={temp_src_dir}",
- ]
- if is_debug:
- cmd += ["--no-platformio"] # fast path that doesn't need a lock.
- cmd.append(f"--{build_mode.lower()}")
- if profile:
- cmd.append("--profile")
- # cp = subprocess.run(cmd, cwd="/js", capture_output=True, text=True)
- # cp = subprocess.run(cmd, cwd="/js", stdout=subprocess.STDOUT, stderr=subprocess.STDOUT, text=True)
- proc = subprocess.Popen(
- cmd,
- cwd="/js",
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- text=True,
- )
- assert proc.stdout is not None
- stdout_lines: list[str] = []
-
- for line in iter(proc.stdout.readline, ""):
- print(line, end="")
- stdout_lines.append(line)
- _print("Compiler finished.")
- stdout = "".join(stdout_lines)
- proc.stdout.close()
- return_code = proc.wait()
- if return_code != 0:
- COMPILE_FAILURES += 1
- print(f"Compilation failed with return code {return_code}:\n{stdout}")
- return HTTPException(
- status_code=400,
- detail=f"Compilation failed with return code {return_code}:\n{stdout}",
- )
- COMPILE_SUCCESSES += 1
- compile_time = time.time() - COMPILE_LOCK_end
- COMPILE_LOCK_time = COMPILE_LOCK_end - COMPILE_LOCK_start
-
- print(f"\nCompiler output:\nstdout:\n{stdout}")
- print(f"Compile lock time: {COMPILE_LOCK_time:.2f}s")
- print(f"Compile time: {compile_time:.2f}s")
-
- # Find the fastled_js directory
- fastled_js_dir = src_dir / "fastled_js"
- print(f"\nLooking for fastled_js directory at: {fastled_js_dir}")
-
- _print("Looking for fastled_js directory...")
- if not fastled_js_dir.exists():
- print(f"Directory contents of {src_dir}:")
- for path in src_dir.rglob("*"):
- print(f" {path}")
- return HTTPException(
- status_code=500,
- detail=f"Compilation artifacts not found at {fastled_js_dir}",
- )
- _print("Found fastled_js directory, zipping...")
-
- # Replace separate stdout/stderr files with single out.txt
- out_txt = fastled_js_dir / "out.txt"
- perf_txt = fastled_js_dir / "perf.txt"
- hash_txt = fastled_js_dir / "hash.txt"
- print(f"\nSaving combined output to: {out_txt}")
- out_txt.write_text(stdout)
- perf_txt.write_text(
- f"Compile lock time: {COMPILE_LOCK_time:.2f}s\nCompile time: {compile_time:.2f}s"
- )
- if hash_value is not None:
- hash_txt.write_text(hash_value)
-
- OUTPUT_DIR.mkdir(exist_ok=True) # Ensure output directory exists
- output_zip_path = OUTPUT_DIR / f"fastled_output_{hash(str(file_path))}.zip"
- _print(f"\nCreating output zip at: {output_zip_path}")
-
- start_zip = time.time()
- try:
- with zipfile.ZipFile(
- output_zip_path, "w", zipfile.ZIP_DEFLATED, compresslevel=1
- ) as zip_out:
- _print("\nAdding files to output zip:")
- for file_path in fastled_js_dir.rglob("*"):
- if file_path.is_file():
- arc_path = file_path.relative_to(fastled_js_dir)
- _print(f" Adding: {arc_path}")
- zip_out.write(file_path, arc_path)
- except zipfile.BadZipFile as e:
- _print(f"Error creating zip file: {e}")
- return HTTPException(status_code=500, detail=f"Failed to create zip file: {e}")
- except zlib.error as e:
- _print(f"Compression error: {e}")
- return HTTPException(
- status_code=500, detail=f"Zip compression failed - zlib error: {e}"
- )
- except Exception as e:
- _print(f"Unexpected error creating zip: {e}")
- return HTTPException(status_code=500, detail=f"Failed to create zip file: {e}")
- zip_time = time.time() - start_zip
- print(f"Zip file created in {zip_time:.2f}s")
-
- def cleanup_files():
- if output_zip_path.exists():
- output_zip_path.unlink()
- if temp_zip_dir:
- shutil.rmtree(temp_zip_dir, ignore_errors=True)
- if temp_src_dir:
- shutil.rmtree(temp_src_dir, ignore_errors=True)
-
- background_tasks.add_task(cleanup_files)
- _print(f"\nReturning output zip: {output_zip_path}")
- return FileResponse(
- path=output_zip_path,
- media_type="application/zip",
- filename="fastled_output.zip",
- background=background_tasks,
- )
-
-
-def memory_watchdog() -> None:
- """Monitor memory usage and kill process if it exceeds limit."""
- if _MEMORY_LIMIT_MB <= 0:
- return
-
- def check_memory() -> None:
- while True:
- process = psutil.Process(os.getpid())
- memory_mb = process.memory_info().rss / 1024 / 1024
- if memory_mb > _MEMORY_LIMIT_MB:
- print(
- f"Memory limit exceeded! Using {memory_mb:.1f}MB > {_MEMORY_LIMIT_MB}MB limit"
- )
- os._exit(_MEMORY_EXCEEDED_EXIT_CODE)
- time.sleep(_MEMORY_CHECK_INTERVAL)
-
- watchdog_thread = threading.Thread(target=check_memory, daemon=True)
- watchdog_thread.start()
-
-
-def get_settings() -> dict:
- settings = {
- "ALLOW_SHUTDOWN": _ALLOW_SHUTDOWN,
- "NO_AUTO_UPDATE": os.environ.get("NO_AUTO_UPDATE", "0"),
- "NO_SKETCH_CACHE": _NO_SKETCH_CACHE,
- "LIVE_GIT_UPDATES_ENABLED": _LIVE_GIT_UPDATES_ENABLED,
- "LIVE_GIT_UPDATES_INTERVAL": _LIVE_GIT_UPDATES_INTERVAL,
- "UPLOAD_LIMIT": _UPLOAD_LIMIT,
- "VOLUME_MAPPED_SRC": str(_VOLUME_MAPPED_SRC),
- "VOLUME_MAPPED_SRC_EXISTS": _VOLUME_MAPPED_SRC.exists(),
- }
- return settings
-
-
-def startup() -> None:
- print("Starting FastLED wasm compiler server...")
- try:
- print(f"Settings: {json.dumps(get_settings(), indent=2)}")
- except Exception as e:
- print(f"Error getting settings: {e}")
-
- if _MEMORY_LIMIT_MB > 0:
- print(f"Starting memory watchdog (limit: {_MEMORY_LIMIT_MB}MB)")
- memory_watchdog()
-
- sync_source_directory_if_volume_is_mapped()
- if _LIVE_GIT_UPDATES_ENABLED:
- Timer(
- _LIVE_GIT_UPDATES_INTERVAL, sync_live_git_to_target
- ).start() # Start the periodic git update
- else:
- print("Auto updates disabled")
-
-
-@app.get("/", include_in_schema=False)
-async def read_root() -> RedirectResponse:
- """Redirect to the /docs endpoint."""
-
- print("Endpoint accessed: / (root redirect to docs)")
- return RedirectResponse(url="/docs")
-
-
-@app.get("/healthz")
-async def healthz() -> dict:
- """Health check endpoint."""
- print("Endpoint accessed: /healthz")
- return {"status": "ok"}
-
-
-if _ALLOW_SHUTDOWN:
-
- @app.get("/shutdown")
- async def shutdown() -> dict:
- """Shutdown the server."""
- print("Endpoint accessed: /shutdown")
- print("Shutting down server...")
- SKETCH_CACHE.close()
- os._exit(0)
- return {"status": "ok"}
-
-
-@app.get("/settings")
-async def settings() -> dict:
- """Get the current settings."""
- print("Endpoint accessed: /settings")
- settings = {
- "ALLOW_SHUTDOWN": _ALLOW_SHUTDOWN,
- "NO_AUTO_UPDATE": os.environ.get("NO_AUTO_UPDATE", "0"),
- "NO_SKETCH_CACHE": _NO_SKETCH_CACHE,
- "LIVE_GIT_UPDATES_ENABLED": _LIVE_GIT_UPDATES_ENABLED,
- "LIVE_GIT_UPDATES_INTERVAL": _LIVE_GIT_UPDATES_INTERVAL,
- "UPLOAD_LIMIT": _UPLOAD_LIMIT,
- "VOLUME_MAPPED_SRC": str(_VOLUME_MAPPED_SRC),
- "VOLUME_MAPPED_SRC_EXISTS": _VOLUME_MAPPED_SRC.exists(),
- }
- return settings
-
-
-@app.get("/compile/wasm/inuse")
-async def compiler_in_use() -> dict:
- """Check if the compiler is in use."""
- print("Endpoint accessed: /compile/wasm/inuse")
- return {"in_use": COMPILE_LOCK.locked()}
-
-
-def zip_example_to_file(example: str, dst_zip_file: Path) -> None:
- examples_dir = Path(f"/js/fastled/examples/{example}")
- if not examples_dir.exists():
- raise HTTPException(
- status_code=404, detail=f"Example {example} not found at {examples_dir}"
- )
-
- try:
- print(f"Creating zip file at: {dst_zip_file}")
- with zipfile.ZipFile(str(dst_zip_file), "w", zipfile.ZIP_DEFLATED) as zip_out:
- for file_path in examples_dir.rglob("*"):
- if file_path.is_file():
- if "fastled_js" in file_path.parts:
- continue
- arc_path = file_path.relative_to(Path("/js/fastled/examples"))
- zip_out.write(file_path, arc_path)
- print(f"Zip file created at: {dst_zip_file}")
- except Exception as e:
- warnings.warn(f"Error: {e}")
- raise
-
-
-def make_random_path_string(digits: int) -> str:
- """Generate a random number."""
- import random
- import string
-
- return "".join(random.choices(string.ascii_lowercase + string.digits, k=digits))
-
-
-@app.get("/project/init")
-def project_init(background_tasks: BackgroundTasks) -> FileResponse:
- """Archive /js/fastled/examples/wasm into a zip file and return it."""
- print("Endpoint accessed: /project/init")
- # tmp_zip_file = NamedTemporaryFile(delete=False)
- # tmp_zip_path = Path(tmp_zip_file.name)
-
- tmp_zip_path = _TEMP_DIR / f"wasm-{make_random_path_string(16)}.zip"
- zip_example_to_file("wasm", tmp_zip_path)
-
- # assert tmp_zip_path.exists()
- if not tmp_zip_path.exists():
- warnings.warn("Failed to create zip file for wasm example.")
- raise HTTPException(
- status_code=500, detail="Failed to create zip file for wasm example."
- )
-
- def cleanup() -> None:
- try:
- os.unlink(tmp_zip_path)
- except Exception as e:
- warnings.warn(f"Error cleaning up: {e}")
-
- background_tasks.add_task(cleanup)
- return FileResponse(
- path=tmp_zip_path,
- media_type="application/zip",
- filename="fastled_example.zip",
- background=background_tasks,
- )
-
-
-@app.post("/project/init")
-def project_init_example(
- background_tasks: BackgroundTasks, example: str = Body(...)
-) -> FileResponse:
- """Archive /js/fastled/examples/{example} into a zip file and return it."""
- print(f"Endpoint accessed: /project/init/example with example: {example}")
- if ".." in example:
- raise HTTPException(status_code=400, detail="Invalid example name.")
- name = Path("example").name
- tmp_file_path = _TEMP_DIR / f"{name}-{make_random_path_string(16)}.zip"
- zip_example_to_file(example, Path(tmp_file_path))
-
- if not tmp_file_path.exists():
- warnings.warn(f"Failed to create zip file for {example} example.")
- raise HTTPException(
- status_code=500, detail=f"Failed to create zip file for {example} example."
- )
-
- def cleanup() -> None:
- try:
- os.unlink(tmp_file_path)
- except Exception as e:
- warnings.warn(f"Error cleaning up: {e}")
- raise
-
- background_tasks.add_task(cleanup)
- return FileResponse(
- path=tmp_file_path,
- media_type="application/zip",
- filename="fastled_example.zip",
- background=background_tasks,
- )
-
-
-@app.get("/info")
-def info_examples() -> dict:
- """Get a list of examples."""
- print("Endpoint accessed: /info")
- uptime = time.time() - START_TIME
- uptime_fmtd = time.strftime("%H:%M:%S", time.gmtime(uptime))
- try:
- build_timestamp = (
- Path("/image_timestamp.txt").read_text(encoding="utf-8").strip()
- )
- except Exception as e:
- import warnings
-
- warnings.warn(f"Error reading build timestamp: {e}")
- build_timestamp = "unknown"
-
- # ARG FASTLED_VERSION=3.9.11
- # ENV FASTLED_VERSION=${FASTLED_VERSION}
-
- fastled_version = os.environ.get("FASTLED_VERSION", "unknown")
- out = {
- "examples": _EXAMPLES,
- "compile_count": COMPILE_COUNT,
- "compile_failures": COMPILE_FAILURES,
- "compile_successes": COMPILE_SUCCESSES,
- "uptime": uptime_fmtd,
- "build_timestamp": build_timestamp,
- "fastled_version": fastled_version,
- }
- return out
-
-
-# THIS MUST NOT BE ASYNC!!!!
-@app.post("/compile/wasm")
-def compile_wasm(
- file: UploadFile = File(...),
- authorization: str = Header(None),
- build: str = Header(None),
- profile: str = Header(None),
- background_tasks: BackgroundTasks = BackgroundTasks(),
-) -> FileResponse:
- """Upload a file into a temporary directory."""
- print(f"Endpoint accessed: /compile/wasm with file: {file.filename}")
- if build is not None:
- build = build.lower()
-
- if build not in ["quick", "release", "debug", None]:
- raise HTTPException(
- status_code=400,
- detail="Invalid build mode. Must be one of 'quick', 'release', or 'debug' or omitted",
- )
- do_profile: bool = False
- if profile is not None:
- do_profile = profile.lower() == "true" or profile.lower() == "1"
- print(f"Build mode is {build}")
- build = build or "quick"
- print(f"Starting upload process for file: {file.filename}")
-
- if not _TEST and authorization != _AUTH_TOKEN:
- raise HTTPException(status_code=401, detail="Unauthorized")
-
- if file is None:
- raise HTTPException(status_code=400, detail="No file uploaded.")
-
- if file.filename is None:
- raise HTTPException(status_code=400, detail="No filename provided.")
-
- if not file.filename.endswith(".zip"):
- raise HTTPException(
- status_code=400, detail="Uploaded file must be a zip archive."
- )
-
- temp_zip_dir = None
- temp_src_dir = None
-
- try:
- # Create temporary directories - one for zip, one for source
- temp_zip_dir = tempfile.mkdtemp()
- temp_src_dir = tempfile.mkdtemp()
- print(
- f"Created temporary directories:\nzip_dir: {temp_zip_dir}\nsrc_dir: {temp_src_dir}"
- )
-
- file_path = Path(temp_zip_dir) / file.filename
- print(f"Saving uploaded file to: {file_path}")
-
- # Simple file save since size is already checked by middleware
- with open(file_path, "wb") as f:
- shutil.copyfileobj(file.file, f)
-
- print("extracting zip file...")
- hash_value: str | None = None
- with zipfile.ZipFile(file_path, "r") as zip_ref:
- # Extract everything first
- zip_ref.extractall(temp_src_dir)
-
- # Then find and remove any platformio.ini files
- platform_files = list(Path(temp_src_dir).rglob("*platformio.ini"))
- if platform_files:
- warnings.warn(f"Removing platformio.ini files: {platform_files}")
- for p in platform_files:
- p.unlink()
-
- try:
- hash_value = generate_hash_of_project_files(Path(temp_src_dir))
- except Exception as e:
- warnings.warn(
- f"Error generating hash: {e}, fast cache access is disabled for this build."
- )
-
- def on_files_changed() -> None:
- print("Source files changed, clearing cache")
- SKETCH_CACHE.clear()
-
- sync_source_directory_if_volume_is_mapped(callback=on_files_changed)
-
- entry: bytes | None = None
- if hash_value is not None:
- print(f"Hash of source files: {hash_value}")
- entry = try_get_cached_zip(hash_value)
- if entry is not None:
- print("Returning cached zip file")
- # Create a temporary file for the cached data
- tmp_file = NamedTemporaryFile(delete=False)
- tmp_file.write(entry)
- tmp_file.close()
-
- def cleanup_temp():
- try:
- os.unlink(tmp_file.name)
- except: # noqa: E722
- pass
-
- background_tasks.add_task(cleanup_temp)
-
- return FileResponse(
- path=tmp_file.name,
- media_type="application/zip",
- filename="fastled_output.zip",
- background=background_tasks,
- )
-
- print("\nContents of source directory:")
- for path in Path(temp_src_dir).rglob("*"):
- print(f" {path}")
- out = compile_source(
- Path(temp_src_dir),
- file_path,
- background_tasks,
- build,
- do_profile,
- hash_value,
- )
- if isinstance(out, HTTPException):
- print("Raising HTTPException")
- txt = out.detail
- json_str = json.dumps(txt)
- warnings.warn(f"Error compiling source: {json_str}")
- raise out
- # Cache the compiled zip file
- out_path = Path(out.path)
- data = out_path.read_bytes()
- if hash_value is not None:
- cache_put(hash_value, data)
- return out
- except HTTPException as e:
- import traceback
-
- stacktrace = traceback.format_exc()
- print(f"HTTPException in upload process: {str(e)}\n{stacktrace}")
- raise e
-
- except Exception as e:
- import traceback
-
- stack_trace = traceback.format_exc()
- print(f"Error in upload process: {stack_trace}")
- raise HTTPException(
- status_code=500,
- detail=f"Upload process failed: {str(e)}\nTrace: {e.__traceback__}",
- )
- finally:
- # Clean up in case of error
- if temp_zip_dir:
- shutil.rmtree(temp_zip_dir, ignore_errors=True)
- if temp_src_dir:
- shutil.rmtree(temp_src_dir, ignore_errors=True)
diff --git a/src/platforms/wasm/compiler/sketch_hasher.py b/src/platforms/wasm/compiler/sketch_hasher.py
deleted file mode 100644
index 7befbf3b25..0000000000
--- a/src/platforms/wasm/compiler/sketch_hasher.py
+++ /dev/null
@@ -1,254 +0,0 @@
-
-"""
-This module provides functions to generate a hash of all files in a directory.
-Source files like ino,cpp,h,hpp are concatenated and preprocessed with GCC.
-Data date files are hashed as is.
-"""
-
-
-__all__ = ["generate_hash_of_project_files"]
-
-from dataclasses import dataclass
-from pathlib import Path
-from tempfile import TemporaryDirectory
-from typing import List
-import hashlib
-import os
-import re
-import subprocess
-import warnings
-
-_SOURCE_EXTENSIONS = [".cpp", ".hpp", ".h", ".ino"]
-
-@dataclass
-class ProjectFiles:
- """A class to represent the project files."""
-
- src_files: list[Path]
- other_files: list[Path]
-
-
-@dataclass
-class SrcFileHashResult:
- hash: str
- stdout: str
- error: bool
-
-
-def hash_string(s: str) -> str:
- return hashlib.sha256(s.encode()).hexdigest()
-
-
-def collect_files(directory: Path, src_file_extensions: list[str] | None = None) -> ProjectFiles:
- """Collect files from a directory and separate them into source and other files.
-
- Args:
- directory (Path): The directory to scan for files.
-
- Returns:
- ProjectFiles: Object containing lists of source and other files.
- """
- src_file_extensions = src_file_extensions or _SOURCE_EXTENSIONS
- print(f"Collecting files from {directory}")
-
- src_files: list[Path] = []
- other_files: list[Path] = []
-
- def is_source_file(filename: str) -> bool:
- return any(filename.endswith(ext) for ext in src_file_extensions)
-
- for root, _, filenames in os.walk(str(directory)):
- for filename in filenames:
- print(f"Checking file: {filename}")
- file_path = Path(os.path.join(root, filename))
-
- if is_source_file(filename):
- src_files.append(file_path)
- else:
- other_files.append(file_path)
-
- return ProjectFiles(src_files=src_files, other_files=other_files)
-
-
-def concatenate_files(file_list: List[Path], output_file: Path) -> None:
- """Concatenate files into a single output file.
-
- Args:
- file_list (List[str]): List of file paths to concatenate.
- output_file (str): Path to the output file.
- """
- with open(str(output_file), "w", encoding="utf-8") as outfile:
- for file_path in file_list:
- outfile.write(f"// File: {file_path}\n")
- with open(file_path, "r", encoding="utf-8") as infile:
- outfile.write(infile.read())
- outfile.write("\n\n")
-
-
-def collapse_spaces_preserve_cstrings(line: str):
- def replace_outside_cstrings(match):
- # This function processes the part outside of C strings
- content = match.group(0)
- if content.startswith('"') or content.startswith("'"):
- return content # It's inside a C string, keep as is
- else:
- # Collapse spaces outside of C strings
- return " ".join(content.split())
-
- # Regular expression to match C strings and non-C string parts
- pattern = r'\"(?:\\.|[^\"])*\"|\'.*?\'|[^"\']+'
- processed_line = "".join(
- replace_outside_cstrings(match) for match in re.finditer(pattern, line)
- )
- return processed_line
-
-
-# return a hash
-def preprocess_with_gcc(input_file: Path, output_file: Path) -> None:
- """Preprocess a file with GCC, leaving #include directives intact.
-
- Args:
- input_file (str): Path to the input file.
- output_file (str): Path to the preprocessed output file.
- """
- # Convert paths to absolute paths
- # input_file = os.path.abspath(str(input_file))
- input_file = input_file.absolute()
- output_file = output_file.absolute()
- temp_input = str(input_file) + ".tmp"
-
- try:
- # Create modified version of input that comments out includes
- with open(str(input_file), "r") as fin, open(str(temp_input), "w") as fout:
- for line in fin:
- if line.strip().startswith("#include"):
- fout.write(f"// PRESERVED: {line}")
- else:
- fout.write(line)
-
- # Run GCC preprocessor with explicit output path in order to remove
- # comments. This is necessary to ensure that the hash
- # of the preprocessed file is consistent without respect to formatting
- # and whitespace.
- gcc_command: list[str] = [
- "gcc",
- "-E", # Preprocess only
- "-P", # No line markers
- "-fdirectives-only",
- "-fpreprocessed", # Handle preprocessed input
- "-x",
- "c++", # Explicitly treat input as C++ source
- "-o",
- str(output_file), # Explicit output file
- temp_input,
- ]
-
- result = subprocess.run(gcc_command, check=True, capture_output=True, text=True)
-
- if not os.path.exists(output_file):
- raise FileNotFoundError(
- f"GCC failed to create output file. stderr: {result.stderr}"
- )
-
- # Restore include lines
- with open(output_file, "r") as f:
- content = f.read()
-
- content = content.replace("// PRESERVED: #include", "#include")
- out_lines: list[str] = []
- # now preform minification to further strip out horizontal whitespace and // File: comments.
- for line in content.split("\n"):
- # Skip file marker comments and empty lines
- line = line.strip()
- if not line: # skip empty line
- continue
- if line.startswith(
- "// File:"
- ): # these change because of the temp file, so need to be removed.
- continue
- # Collapse multiple spaces into single space and strip whitespace
- # line = ' '.join(line.split())
- line = collapse_spaces_preserve_cstrings(line)
- out_lines.append(line)
- # Join with new lines
- content = "\n".join(out_lines)
- with open(output_file, "w") as f:
- f.write(content)
-
- print(f"Preprocessed file saved to {output_file}")
-
- except subprocess.CalledProcessError as e:
- print(f"GCC preprocessing failed: {e.stderr}")
- raise
- except Exception as e:
- print(f"Preprocessing error: {str(e)}")
- raise
- finally:
- # Clean up temporary file
- try:
- if os.path.exists(temp_input):
- os.remove(temp_input)
- except: # noqa: E722
- warnings.warn(f"Failed to remove temporary file: {temp_input}")
- pass
-
-
-def generate_hash_of_src_files(src_files: list[Path]) -> SrcFileHashResult:
- """Generate a hash of all source files in a directory.
-
- Args:
- src_files (list[Path]): List of source files to hash.
-
- Returns:
- SrcFileHashResult: Object containing hash, stdout and error status.
- """
- try:
- with TemporaryDirectory() as temp_dir:
- temp_file = Path(temp_dir) / "concatenated_output.cpp"
- preprocessed_file = Path(temp_dir) / "preprocessed_output.cpp"
- concatenate_files(src_files, Path(temp_file))
- preprocess_with_gcc(temp_file, preprocessed_file)
- contents = preprocessed_file.read_text()
-
- # strip the last line in it:
- parts = contents.split("\n")
- out_lines: list[str] = []
- for line in parts:
- if "concatenated_output.cpp" not in line:
- out_lines.append(line)
-
- contents = "\n".join(out_lines)
- return SrcFileHashResult(
- hash=hash_string(contents),
- stdout="", # No stdout in success case
- error=False,
- )
- except Exception:
- import traceback
-
- stack_trace = traceback.format_exc()
- print(stack_trace)
- return SrcFileHashResult(hash="", stdout=stack_trace, error=True)
-
-
-def generate_hash_of_project_files(root_dir: Path) -> str:
- """Generate a hash of all files in a directory.
-
- Args:
- root_dir (Path): The root directory to hash.
-
- Returns:
- str: The hash of all files in the directory.
- """
- project_files = collect_files(root_dir)
- src_result = generate_hash_of_src_files(project_files.src_files)
- if src_result.error:
- raise Exception(f"Error hashing source files: {src_result.stdout}")
-
- other_files = project_files.other_files
- # for all other files, don't pre-process them, just hash them
- hash_object = hashlib.sha256()
- for file in other_files:
- hash_object.update(file.read_bytes())
- other_files_hash = hash_object.hexdigest()
- return hash_string(src_result.hash + other_files_hash)
diff --git a/src/platforms/wasm/compiler/wasm_compiler_flags.py b/src/platforms/wasm/compiler/wasm_compiler_flags.py
index 4c2d2ea459..1aff6b9234 100644
--- a/src/platforms/wasm/compiler/wasm_compiler_flags.py
+++ b/src/platforms/wasm/compiler/wasm_compiler_flags.py
@@ -1,3 +1,7 @@
+# pylint: skip-file
+# flake8: noqa
+# type: ignore
+
import os
USE_CCACHE = True if "NO_CCACHE" not in os.environ else False
@@ -12,7 +16,7 @@
# Set flags based on build mode
DEBUG = BUILD_MODE == "DEBUG"
-QUICK_BUILD = BUILD_MODE == "QUICK"
+QUICK_BUILD = BUILD_MODE == "QUICK"
OPTIMIZED = BUILD_MODE == "RELEASE"
# Global variable to control WASM output (0 for asm.js, 1 for WebAssembly)
@@ -21,7 +25,7 @@
USE_WASM = 2
if DEBUG or QUICK_BUILD:
- USE_WASM=1 # disable wasm2js on these builds.
+ USE_WASM = 1 # disable wasm2js on these builds.
build_mode = "-O1" if QUICK_BUILD else "-Oz"
@@ -49,13 +53,13 @@
"-DFASTLED_ENGINE_EVENTS_MAX_LISTENERS=50",
"-DFASTLED_FORCE_NAMESPACE=1",
"-DFASTLED_USE_PROGMEM=0",
- #"-DDISABLE_EXCEPTION_CATCHING=1",
+ # "-DDISABLE_EXCEPTION_CATCHING=1",
"-sALLOW_MEMORY_GROWTH=0",
- #"-fno-exceptions",
- #"-fno-rtti",
- #"-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
- #"-sDISABLE_EXCEPTION_CATCHING=1",
- #"-sDISABLE_EXCEPTION_THROWING=0",
+ # "-fno-exceptions",
+ # "-fno-rtti",
+ # "-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
+ # "-sDISABLE_EXCEPTION_CATCHING=1",
+ # "-sDISABLE_EXCEPTION_THROWING=0",
build_mode,
"--bind",
"-DUSE_OFFSET_CONVERTER=0",
@@ -66,12 +70,14 @@
"-Wnon-c-typedef-for-linkage",
f"-sWASM={USE_WASM}",
"-fuse-ld=lld",
- #-Wbad-function-cast -Wcast-function
+ # -Wbad-function-cast -Wcast-function
"-Werror=bad-function-cast",
"-Werror=cast-function-type",
# add /js/src/ to the include path
"-I",
"src",
+ # add /js/fastled/src/platforms/wasm/compiler to the include path
+ "-I/js/fastled/src/platforms/wasm/compiler",
]
if QUICK_BUILD:
@@ -83,13 +89,13 @@
if opt in sketch_flags:
sketch_flags.remove(opt)
sketch_flags += [
- '-g3',
- '-gsource-map',
- '--emit-symbol-map',
- '-sSTACK_OVERFLOW_CHECK=2',
- '-ASSERTIONS=1',
- '-fsanitize=address',
- '-fsanitize=undefined',
+ "-g3",
+ "-gsource-map",
+ "--emit-symbol-map",
+ "-sSTACK_OVERFLOW_CHECK=2",
+ "-ASSERTIONS=1",
+ "-fsanitize=address",
+ "-fsanitize=undefined",
]
@@ -97,11 +103,11 @@
"-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','stringToUTF8','lengthBytesUTF8']",
"-sEXPORTED_FUNCTIONS=['_malloc','_free','_extern_setup','_extern_loop','_fastled_declare_files']",
"--no-entry",
- #"-fno-exceptions",
- #"-fno-rtti",
- #"-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
- #"-sDISABLE_EXCEPTION_CATCHING=1",
- #"-sDISABLE_EXCEPTION_THROWING=0",
+ # "-fno-exceptions",
+ # "-fno-rtti",
+ # "-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
+ # "-sDISABLE_EXCEPTION_CATCHING=1",
+ # "-sDISABLE_EXCEPTION_THROWING=0",
]
if OPTIMIZED:
@@ -124,18 +130,17 @@
fastled_compile_cc_flags = [
"-Werror=bad-function-cast",
"-Werror=cast-function-type",
- #"-fno-exceptions",
- #"-fno-rtti",
+ # "-fno-exceptions",
+ # "-fno-rtti",
build_mode,
- #"-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
- #"-fno-exceptions",
- #"-sDISABLE_EXCEPTION_CATCHING=1",
- #"-sDISABLE_EXCEPTION_THROWING=0",
+ # "-DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0",
+ # "-fno-exceptions",
+ # "-sDISABLE_EXCEPTION_CATCHING=1",
+ # "-sDISABLE_EXCEPTION_THROWING=0",
+ "-I/js/fastled/src/platforms/wasm/compiler",
]
-
-
fastled_compile_link_flags = [
"-Wl,--whole-archive,-fuse-ld=lld",
"-Werror=bad-function-cast",
@@ -150,5 +155,3 @@
# for final linking.
lb.env.Append(CCFLAGS=fastled_compile_cc_flags)
lb.env.Append(LINKFLAGS=fastled_compile_link_flags)
-
-
diff --git a/src/platforms/wasm/timer.cpp b/src/platforms/wasm/timer.cpp
index d9d7f68586..c895df8939 100644
--- a/src/platforms/wasm/timer.cpp
+++ b/src/platforms/wasm/timer.cpp
@@ -36,6 +36,7 @@ extern "C" {
return uint32_t(out & 0xFFFFFFFF);
}
+
// Replacement for 'delay' in WebAssembly context
EMSCRIPTEN_KEEPALIVE void delay(int ms) {
// Keep in mind this is NOT ASYNC as of 2024-12, and will block the main thread.
@@ -47,6 +48,12 @@ extern "C" {
// upload times back to the client.
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
+
+ // Replacement for 'yield' in WebAssembly context
+ EMSCRIPTEN_KEEPALIVE void yield() {
+ // Use emscripten_yield to allow the browser to perform other tasks
+ delay(0);
+ }
}
#endif // __EMSCRIPTEN__
diff --git a/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c b/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c
index 346a5b5065..2bdc51547f 100644
--- a/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c
+++ b/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c
@@ -6,6 +6,8 @@
#if FASTLED_RMT5
+#include "fl/unused.h"
+
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
@@ -142,6 +144,7 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
{
led_strip_rmt_obj *rmt_strip = NULL;
esp_err_t ret = ESP_OK;
+ FASTLED_UNUSED(ret);
ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_color_component_format_t component_fmt = led_config->color_component_format;
// If R/G/B order is not specified, set default GRB order as fallback
diff --git a/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c b/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c
index f6fb226d3b..e5c1fc540b 100644
--- a/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c
+++ b/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c
@@ -5,6 +5,8 @@
#if FASTLED_RMT5
+#include "fl/unused.h"
+
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
@@ -83,6 +85,7 @@ static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
+ FASTLED_UNUSED(ret);
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(config->led_model < LED_MODEL_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led model");
// Create a temporary config with the same base values
@@ -131,6 +134,7 @@ esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rm
esp_err_t rmt_new_led_strip_encoder_with_timings(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) {
esp_err_t ret = ESP_OK;
+ FASTLED_UNUSED(ret);
rmt_led_strip_encoder_t *led_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
diff --git a/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c b/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c
index 3df6094351..bdba37474f 100644
--- a/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c
+++ b/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
+
#include
#include
#include
@@ -17,6 +18,7 @@
#include "soc/spi_periph.h"
#include "led_strip.h"
#include "led_strip_interface.h"
+#include "fl/unused.h"
#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
@@ -151,6 +153,7 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l
{
led_strip_spi_obj *spi_strip = NULL;
esp_err_t ret = ESP_OK;
+ FASTLED_UNUSED(ret);
ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_color_component_format_t component_fmt = led_config->color_component_format;
// If R/G/B order is not specified, set default GRB order as fallback
diff --git a/tests/test_apa102_hd.cpp b/tests/test_apa102_hd.cpp
index 000b7964d0..2af05dcb3b 100644
--- a/tests/test_apa102_hd.cpp
+++ b/tests/test_apa102_hd.cpp
@@ -5,7 +5,7 @@
#include "test.h"
#include "FastLED.h"
-#include "five_bit_hd_gamma.h"
+#include "fl/five_bit_hd_gamma.h"
#include "assert.h"
#include "math.h"
#include
diff --git a/tests/test_arduino_wasm.cpp b/tests/test_arduino_wasm.cpp
deleted file mode 100644
index 3bd516c1f2..0000000000
--- a/tests/test_arduino_wasm.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-
-// g++ --std=c++11 test.cpp
-
-#include "test.h"
-
-#include "test.h"
-#include "platforms/wasm/compiler/Arduino.h"
-
-#include "fl/namespace.h"
-FASTLED_USING_NAMESPACE
-
-TEST_CASE("arduino_wasm") {
- SUBCASE("random") {
- for (int i = 0; i < 100; i++) {
- long r = random(0, 1);
- CHECK_EQ(0, r);
- }
- }
-}
-
diff --git a/tests/test_sin32.cpp b/tests/test_sin32.cpp
new file mode 100644
index 0000000000..489080c5fb
--- /dev/null
+++ b/tests/test_sin32.cpp
@@ -0,0 +1,33 @@
+
+// g++ --std=c++11 test.cpp
+
+#include "test.h"
+
+#include "test.h"
+#include "fl/sin32.h"
+
+#include "fl/namespace.h"
+FASTLED_USING_NAMESPACE
+
+// 16777216 is 1 cycle
+const uint32_t _360 = 16777216;
+const uint32_t _ONE = 2147418112;
+const uint32_t _NEG_ONE = -2147418112;
+
+TEST_CASE("compile test") {
+ int32_t result = sin32(0);
+ REQUIRE(result == 0);
+
+ result = sin32(_360);
+ REQUIRE(result == 0);
+
+ result = sin32(_360 / 4);
+ REQUIRE(result == _ONE);
+
+ result = sin32(_360 / 2);
+ REQUIRE(result == 0);
+
+ result = sin32(_360 / 4 * 3);
+ REQUIRE(result == _NEG_ONE);
+
+}