first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
66
libraries/FastLED/ADVANCED_DEVELOPMENT.md
Normal file
66
libraries/FastLED/ADVANCED_DEVELOPMENT.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Advanced Development with FastLED
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
## GDB On Unit Tests
|
||||
|
||||
Yes, we have step through debugging with FastLED.
|
||||
|
||||
* VSCode
|
||||
* Install Plugin: GDB Debugger - Beyond
|
||||
* Navigate to one of the tests in `tests/` and open in
|
||||
* Hit `F5`
|
||||
|
||||
If the Python Debugger pops up, then manually switch the VSCode debugger using `Launch(gdb)`
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## Enabling 3-second compile times using our `web-compiler`
|
||||
|
||||
* You must have `docker` installed for fastest compile times. It's free.
|
||||
* `cd <FASTLED FOLDER>`
|
||||
* `pip install fastled`
|
||||
* `fastled examples/Blink/Blink.ino`
|
||||
* Cpp changes to the fastled source can be compiled by the live fastled compiler.
|
||||
|
||||
## Testing your changes
|
||||
|
||||
Most of this is in the basic CONTRIBUTING.md guide. But as a reminder
|
||||
* Unit Testing: `./test`
|
||||
* Linting: `./lint`
|
||||
* Compiling on platforms `./compile uno,teensy41,esp32s3 --examples Blink,Apa102HD`
|
||||
|
||||
## Enabling AI coding
|
||||
|
||||
`aider.chat` is available for advanced and high velocity coding with FastLED. To use it, have your open-ai or Anthropic api key ready. It's recommended to use Anthropic as it's performance is much better than Open-AI for coding.
|
||||
|
||||
At the root of the project type:
|
||||
|
||||
`./ai` and follow the prompts. Once the key is installed you will get a prompt that looks like this:
|
||||
|
||||
```bash
|
||||
architect>
|
||||
```
|
||||
|
||||
There are two modes to use this AI, a watch mode which watches your files for changes and launches automatically, and a slow way which you add target files then instruct it to make changes:
|
||||
|
||||
* watch mode (best for implimenting a function or two)
|
||||
* Edit any file in the repo. Add a comment with `AI!` at the end. The ai will see this and start implementing what you just typed.
|
||||
* Example: Edit `src/fl/vector.h` and put in a comment `// Add more comments AI!`, then say yes to the changes in the prompt.
|
||||
* Slow mode (much better for bigger changes across the file or several)
|
||||
* While you are in the `architect> ` prompt you will add a file to the chat
|
||||
* `/add src/fl/vector.h`
|
||||
* Now tell the AI what you want it to do, and it will do it.
|
||||
* Making the AI fix it's own problems it introduced.
|
||||
* At the AI command prompt, have it run the following
|
||||
* Linux/Mac: `/run ./test`
|
||||
* On Windows: `/run uv run test.py`
|
||||
* After the test concludes, the AI will ask you if you want to add the output back into the chat, agree to it then let it try to correct it's mistakes.
|
||||
|
||||
Every single time you do a change, make sure and thoroughly check it. I recommend VSCodes built in git diff tool.
|
||||
|
||||
Although the AI is pretty amazing, it will inject entropy into your code and this is the source of a lot of problems. So watch all changes it makes very thoroughly. Under almost all circumstances you will have to revert unnecessary changes (like comments) line by line.
|
||||
49
libraries/FastLED/APA102.md
Normal file
49
libraries/FastLED/APA102.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Special Notes on APA102 and the 'High Definition' Mode in FastLED
|
||||
|
||||
The APA102 LED driver includes a 5-bit per-LED brightness component. Previously, this feature was not fully utilized, except through a workaround that defined a global brightness affecting all LEDs uniformly rather than individually.
|
||||
|
||||
In FastLED the APA102 chipset will have extra resolution in comparison to the WS2812 RGB8 mode.
|
||||
|
||||
There are two modes:
|
||||
* APA102 "Regular Mode"
|
||||
* Has enhanced color resolution when using the "global brightness" factor
|
||||
* APA102HD Mode
|
||||
* Applies automatic gamma correction at the driver level using "pseudo 13-bit" color mixing.
|
||||
|
||||
**APA102HD Mode**
|
||||
|
||||
[example: examples/APA102HD](examples/Apa102HD/)
|
||||
|
||||
By introducing a 5-bit gamma bit-shift algorithm, we now effectively leverage this per-LED brightness control. Faced with the decision to either rewrite the entire `CRGB` library to expose the 5-bit brightness—including adaptations for formats like RGBW—or to retain the existing RGB8 format used by FastLED and implement the enhancement at the driver level, the latter option was chosen. This approach avoids widespread changes and maintains compatibility; if RGB8 suffices for game development, it is adequate for LED development as well.
|
||||
|
||||
The term "Pseudo-13-bit" arises because the additional resolution becomes significant only when all color components are at low values. For example, colors like `CRGB(255, 255, 254)` or `CRGB(255, 1, 1)` do not benefit from increased resolution due to the dominance of the brighter components. However, in low-light conditions with colors such as `CRGB(8, 8, 8)`, where the maximum component value is low, the pseudo-13-bit algorithm significantly enhances resolution—precisely where increased resolution is most desired.
|
||||
|
||||
Gamma correction is applied to preserve the RGB8 format and because future LEDs are expected to support gamma correction inherently. In game development, the 0-255 color values are based on the gamma scale rather than the linear power scale. LEDs like the WS2812 operate on a linear power scale, which results in washed-out, undersaturated colors when displaying captured video directly. Implementing software gamma correction for RGB8 severely reduces color resolution.
|
||||
|
||||
To address this, an internal gamma scale mapping is applied:
|
||||
|
||||
```
|
||||
RGB8 → RGB16 + 5-bit gamma → RGB8 + 5-bit gamma
|
||||
```
|
||||
|
||||
During the conversion back to RGB8, the brightness from the 5-bit gamma is bit-shifted into the RGB components. Each time the 5-bit brightness is shifted right, the RGB components are shifted left. For example:
|
||||
|
||||
Starting with `RGB(4, 4, 4)` and a 5-bit brightness value of 31:
|
||||
|
||||
- Shift RGB components left, shift 5-bit brightness right:
|
||||
- `RGB(8, 8, 8)`, brightness 15
|
||||
- `RGB(16, 16, 16)`, brightness 7
|
||||
- `RGB(32, 32, 32)`, brightness 3
|
||||
- `RGB(64, 64, 64)`, brightness 1 (final state)
|
||||
|
||||
This simplified illustration omits that the actual processing occurs in 16-bit space rather than 8-bit, but the fundamental concept remains the same.
|
||||
|
||||
By truncating the gamma-corrected RGB16 values back to RGB8, the LEDs receive pre-boosted RGB components and pre-dimmed 5-bit brightness values. This method preserves minor color details over a greater range, offering a valuable trade-off and leading to the designation of this mode as "APA102HD."
|
||||
|
||||
In version 3.9.0, the algorithm was completely rewritten to function natively on 8-bit controllers like the `__AVR__` chipsets without significant performance loss. Previously, accumulating the numerator and denominator during the brightness bit-shifting process introduced extra bits that were ultimately truncated. Testing revealed that equivalent resolution could be achieved using straightforward bit-shifting, which also significantly reduced code size on AVR platforms with the new algorithm.
|
||||
|
||||
**Further Enhancements in Version 3.9.0**
|
||||
|
||||
Additionally, version 3.9.0 separated the color temperature from the global brightness scale. Before this update, global brightness was pre-mixed with the component scales—a method suitable for the WS2812's RGB8 format but not for the APA102's RGB8 plus 5-bit brightness. The update saw the global brightness and color scales separated for non-AVR chipsets. While the WS2812 continues to use pre-mixed values for performance reasons on AVR chipsets, the APA102 now performs component mixing within the "pseudo-13-bit space."
|
||||
|
||||
Although APA102HD mode offers the highest dynamic range, the standard APA102 mode also benefits from increased resolution when adjusting global brightness. In this mode, instead of pre-mixing scales and multiplying them against each `CRGB` value, the global brightness is applied to the 5-bit brightness component, and only the color scales are multiplied against the `CRGB` values. This approach is superior because each component of the color scale typically exceeds 127, providing ample high-order bits to preserve color information.
|
||||
25
libraries/FastLED/CMakeLists.txt
Normal file
25
libraries/FastLED/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# FastLED
|
||||
# https://github.com/FastLED/FastLED
|
||||
# MIT License
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Collect all source files
|
||||
file(GLOB FastLED_SRCS "src/*.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" "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")
|
||||
|
||||
# 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 esp_lcd driver)
|
||||
|
||||
project(FastLED)
|
||||
75
libraries/FastLED/CONTRIBUTING.md
Normal file
75
libraries/FastLED/CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
## Contributing
|
||||
|
||||
The most important part about contributing to FastLED is knowing how to test your changes.
|
||||
|
||||
The FastLED library includes a powerful cli that can compile to any device. It will run if you have either [python](https://www.python.org/downloads/) or [uv](https://github.com/astral-sh/uv) installed on the system.
|
||||
|
||||
## FastLED compiler cli
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_clone_and_compile.yml)
|
||||
|
||||
The FastLED compiler cli can be invoked at the project root.
|
||||
|
||||
```bash (MacOS/Linux, windows us git-bsh or compile.bat)
|
||||
git clone https://github.com/fastled/fastled
|
||||
cd fastled
|
||||
./compile uno --examples Blink # linux/macos/git-bash
|
||||
# compile.bat # Windows.
|
||||
```
|
||||
|
||||
## Linting and Unit Testing
|
||||
|
||||
```bash
|
||||
./lint
|
||||
./test # runs unit tests
|
||||
# Note that you do NOT need to install the C++ compiler toolchain
|
||||
# for compiling + running unit tests via ./test. If `gcc` is not
|
||||
# found in your system `PATH` then the `ziglang` clang compiler
|
||||
# will be swapped in automatically.
|
||||
````
|
||||
|
||||
|
||||
### Testing a bunch of platforms at once.
|
||||
|
||||
```
|
||||
./compile teensy41,teensy40 --examples Blink
|
||||
./compile esp32dev,esp32s3,esp32c3,esp32c6,esp32s2 --examples Blink,Apa102HD
|
||||
./compiles uno,digix,attiny85 --examples Blink,Apa102HD
|
||||
```
|
||||
|
||||
## Unit Tests
|
||||
|
||||
Shared code is unit-tested on the host machine. They can be found at `tests/` at the root of the repo. Unit testing only requires either `python` or `uv` to be installed. The C++ compiler toolchain will be installed automatically.
|
||||
|
||||
The easiest way to run the tests is just use `./test`
|
||||
|
||||
Alternatively, tests can be built and run for your development machine with CMake:
|
||||
|
||||
```bash
|
||||
cmake -S tests -B tests/.build
|
||||
ctest --test-dir tests/.build --output-on-failure
|
||||
# Not that this will fail if you do not have gcc installed. When in doubt
|
||||
# use ./test to compile the unit tests, as a compiler is guaranteed to be
|
||||
# available via this tool.
|
||||
```
|
||||
|
||||
## VSCode
|
||||
|
||||
We also support VSCode and IntelliSense auto-completion when the free [platformio](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide) extension is installed. The development sketch to test library changes can be found at [dev/dev.ino](dev/dev.ino).
|
||||
|
||||
* Make sure you have [platformio](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide) installed.
|
||||
* Click the compile button.
|
||||
|
||||

|
||||
*Changes in non platform specific code can be tested quickly in our webcompiler by invoking the script `./wasm` at the project root*
|
||||
|
||||
|
||||
## Once you are done
|
||||
* run `./test`
|
||||
* run `./lint`
|
||||
* Then submit your code via a git pull request.
|
||||
|
||||
|
||||
## Going deeper
|
||||
|
||||
[ADVANCED_DEVELOPMENT.md](https://github.com/FastLED/FastLED/blob/master/ADVANCED_DEVELOPMENT.md)
|
||||
20
libraries/FastLED/LICENSE
Normal file
20
libraries/FastLED/LICENSE
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 FastLED
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
56
libraries/FastLED/PORTING.md
Normal file
56
libraries/FastLED/PORTING.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Platform Porting Guide
|
||||
==========================
|
||||
|
||||
# Fast porting for a new board on existing hardware
|
||||
|
||||
Sometimes "porting" FastLED simply consists of supplying new pin definitions for the given platform. For example, platforms/avr/fastpin_avr.h contains various pin definitions for all the AVR variant chipsets/boards that FastLED supports. Defining a set of pins involves setting up a set of definitions - for example here's one full set from the avr fastpin file:
|
||||
|
||||
```
|
||||
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
|
||||
_FL_IO(A); _FL_IO(B); _FL_IO(C); _FL_IO(D);
|
||||
|
||||
#define MAX_PIN 31
|
||||
_FL_DEFPIN(0, 0, B); _FL_DEFPIN(1, 1, B); _FL_DEFPIN(2, 2, B); _FL_DEFPIN(3, 3, B);
|
||||
_FL_DEFPIN(4, 4, B); _FL_DEFPIN(5, 5, B); _FL_DEFPIN(6, 6, B); _FL_DEFPIN(7, 7, B);
|
||||
_FL_DEFPIN(8, 0, D); _FL_DEFPIN(9, 1, D); _FL_DEFPIN(10, 2, D); _FL_DEFPIN(11, 3, D);
|
||||
_FL_DEFPIN(12, 4, D); _FL_DEFPIN(13, 5, D); _FL_DEFPIN(14, 6, D); _FL_DEFPIN(15, 7, D);
|
||||
_FL_DEFPIN(16, 0, C); _FL_DEFPIN(17, 1, C); _FL_DEFPIN(18, 2, C); _FL_DEFPIN(19, 3, C);
|
||||
_FL_DEFPIN(20, 4, C); _FL_DEFPIN(21, 5, C); _FL_DEFPIN(22, 6, C); _FL_DEFPIN(23, 7, C);
|
||||
_FL_DEFPIN(24, 0, A); _FL_DEFPIN(25, 1, A); _FL_DEFPIN(26, 2, A); _FL_DEFPIN(27, 3, A);
|
||||
_FL_DEFPIN(28, 4, A); _FL_DEFPIN(29, 5, A); _FL_DEFPIN(30, 6, A); _FL_DEFPIN(31, 7, A);
|
||||
|
||||
#define HAS_HARDWARE_PIN_SUPPORT 1
|
||||
```
|
||||
|
||||
The ```_FL_IO``` macro is used to define the port registers for the platform while the ```_FL_DEFPIN``` macro is used to define pins. The parameters to the macro are the pin number, the bit on the port that represents that pin, and the port identifier itself. On some platforms, like the AVR, ports are identified by letter. On other platforms, like arm, ports are identified by number.
|
||||
|
||||
The ```HAS_HARDWARE_PIN_SUPPORT``` define tells the rest of the FastLED library that there is hardware pin support available. There may be other platform specific defines for things like hardware SPI ports and such.
|
||||
|
||||
## Setting up the basic files/folders
|
||||
|
||||
* Create platform directory (e.g. platforms/arm/kl26)
|
||||
* Create configuration header led_sysdefs_arm_kl26.h:
|
||||
* Define platform flags (like FASTLED_ARM/FASTLED_TEENSY)
|
||||
* Define configuration parameters re: interrupts, or clock doubling
|
||||
* Include extar system header files if needed
|
||||
* Create main platform include, fastled_arm_kl26.h
|
||||
* Include the various other header files as needed
|
||||
* Modify led_sysdefs.h to conditionally include platform sysdefs header file
|
||||
* Modify platforms.h to conditionally include platform fastled header
|
||||
|
||||
## Porting fastpin.h
|
||||
|
||||
The heart of the FastLED library is the fast pin access. This is a templated class that provides 1-2 cycle pin access, bypassing digital write and other such things. As such, this will usually be the first bit of the library that you will want to port when moving to a new platform. Once you have FastPIN up and running then you can do some basic work like testing toggles or running bit-bang'd SPI output.
|
||||
|
||||
There's two low level FastPin classes. There's the base FastPIN template class, and then there is FastPinBB which is for bit-banded access on those MCUs that support bitbanding. Note that the bitband class is optional and primarily useful in the implementation of other functionality internal to the platform. This file is also where you would do the pin to port/bit mapping defines.
|
||||
|
||||
Explaining how the macros work and should be used is currently beyond the scope of this document.
|
||||
|
||||
## Porting fastspi.h
|
||||
|
||||
This is where you define the low level interface to the hardware SPI system (including a writePixels method that does a bunch of housekeeping for writing led data). Use the fastspi_nop.h file as a reference for the methods that need to be implemented. There are ofteh other useful methods that can help with the internals of the SPI code, I recommend taking a look at how the various platforms implement their SPI classes.
|
||||
|
||||
## Porting clockless.h
|
||||
|
||||
This is where you define the code for the clockless controllers. Across ARM platforms this will usually be fairly similar - though different arm platforms will have different clock sources that you can/should use.
|
||||
499
libraries/FastLED/README.md
Normal file
499
libraries/FastLED/README.md
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
FastLED Library
|
||||
===========
|
||||
|
||||
[](https://www.ardu-badge.com/FastLED)
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build.yml)
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_unit_test.yml)
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/arduino_library_lint.yml)
|
||||
[](http://fastled.io/docs)
|
||||
[](https://www.reddit.com/r/FastLED/)
|
||||
|
||||
Want to control a strip of leds? Or control 10's of thousands? FastLED has your back.
|
||||
|
||||
FastLED is a robust and massively parallel-led driver for Arduino, Esp32, RaspberryPi, Atmega, Teensy, Uno, Apollo3 Arm and more. Also runs on dirt cheap sub $1 devices, due to it's incredibly small compile size. High end devices can drive upto ~30k LEDS (Teensy) and ~20k on ESP32. Supports nearly every single LED chipset in existence. Background rendering (ESP32/Teensy/RaspberriPi) means you can respond to user input while the leds render. FastLED is the third [most popular library on Arduino](https://docs.arduino.cc/libraries/).
|
||||
|
||||
FastLED has recently begun to evolve. While before the FastLED codebase was just a highly compatible cross platform LED driver, now it is becoming a cross platform way to generate visualizers that run on AVR, esp32, teensy, Rasperri PI etc
|
||||
|
||||
## Documentation
|
||||
|
||||
Can be found [here](https://fastled.io/docs/files.html)
|
||||
|
||||
## Star History
|
||||
|
||||
<a href="https://star-history.com/#fastled/fastled&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=fastled/fastled&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=fastled/fastled&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=fastled/fastled&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
|
||||
## About
|
||||
|
||||
This is a driver library for easily & efficiently controlling a wide variety of LED chipsets, like the ones
|
||||
sold by Adafruit (NeoPixel, DotStar, LPD8806), Sparkfun (WS2801), and AliExpress.
|
||||
|
||||
The 3.9.x series introduced:
|
||||
* Massive parallel rendering to drive thousands of LEDs.
|
||||
* Background rendering of LEDs so that your program/sketch can prepare the next frame and respond to user input without affect frame rate.
|
||||
|
||||
In addition to writing to the LEDs, this library also includes a number of functions for high-performing 8-bit math for manipulating
|
||||
your RGB values, as well as low level classes for abstracting out access to pins and SPI hardware, while
|
||||
still keeping things as fast as possible.
|
||||
|
||||
We have multiple goals with this library:
|
||||
|
||||
* Quick start for new developers - hook up your LEDs and go, no need to think about specifics of the LED chipsets being used
|
||||
* Zero pain switching LED chipsets - you get some new LEDs that the library supports, just change the definition of LEDs you're using, et. voila! Your code is running with the new LEDs.
|
||||
* High performance - with features like zero cost global brightness scaling, high performance 8-bit math for RGB manipulation, and some of the fastest bit-bang'd SPI support around, FastLED wants to keep as many CPU cycles available for your LED patterns as possible
|
||||
|
||||
## Example
|
||||
|
||||
*This is an Arduino Sketch that will run on Arduino Uno/Esp32/Raspberri Pi*
|
||||
```C++
|
||||
// New feature! Overclocking WS2812
|
||||
// #define FASTLED_OVERCLOCK 1.2 // 20% overclock ~ 960 khz.
|
||||
#include <FastLED.h>
|
||||
#define NUM_LEDS 60
|
||||
#define DATA_PIN 6
|
||||
CRGB leds[NUM_LEDS];
|
||||
void setup() { FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); }
|
||||
void loop() {
|
||||
leds[0] = CRGB::White; FastLED.show(); delay(30);
|
||||
leds[0] = CRGB::Black; FastLED.show(); delay(30);
|
||||
}
|
||||
```
|
||||
|
||||
For more examples, see this [link](examples). Web compiled [examples](https://zackees.github.io/fastled-wasm/).
|
||||
|
||||
|
||||
# New Feature Announcements
|
||||
|
||||
|
||||
## New in 3.9.16: WaveFx / Multi Layer Compositing / Time-based animation control
|
||||
|
||||
Video:
|
||||
|
||||
https://github.com/user-attachments/assets/9155124b-a93e-4317-b272-8bacc1b9c3a8
|
||||
|
||||
#### Major release for tech-artists!
|
||||
|
||||
Lots of improvements in this release, read the full [change list here](https://github.com/FastLED/FastLED/releases/tag/3.9.16)
|
||||
|
||||
#### Links
|
||||
|
||||
* This demo -> [FxWave2d](https://github.com/FastLED/FastLED/blob/master/examples/FxWave2d/FxWave2d.ino)
|
||||
* [Wave Simulation Library](https://github.com/FastLED/FastLED/blob/master/src/fl/wave_simulation.h)
|
||||
* [FireCylinder](https://github.com/FastLED/FastLED/blob/master/examples/FireCylinder/FireCylinder.ino)
|
||||
* Wraps around so that (0,y) ~= (width-1,y)
|
||||
* [TimeAlpha](https://github.com/FastLED/FastLED/blob/master/src/fl/time_alpha.h)
|
||||
* Precision control of animations with time-based alpha transition.
|
||||
|
||||
|
||||
|
||||
## New in 3.9.13: HD107 "Turbo" 40Mhz LED Support
|
||||
|
||||

|
||||
|
||||
## New in 3.9.12: WS2816 "HD" LED support
|
||||
|
||||

|
||||
|
||||
## New in 3.9.10: Super Stable WS2812 SPI driver for ESP32
|
||||
|
||||

|
||||
|
||||
## New in 3.9.9: 16-way Yves I2S parallel driver for the ESP32-S3
|
||||
|
||||

|
||||
|
||||
*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 WS2812 LED output
|
||||
|
||||
* *Teensy 4.1: 50 parallel pins*
|
||||
* *Teensy 4.0: 42 parallel pins*
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## New in 3.9.2 - Overclocking of WS2812
|
||||

|
||||
Update: max overclock has been reported at +70%: https://www.reddit.com/r/FastLED/comments/1gkcb6m/fastled_FASTLED_OVERCLOCK_17/
|
||||
|
||||
## New in 3.7.7 - RGBW LED Strip Support
|
||||
|
||||

|
||||
|
||||
|
||||
## Supported Platforms
|
||||
### Arduino
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_uno.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny85.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny88.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny1604.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny1616.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_attiny4313.yml)
|
||||
*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)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_digix.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_due.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_uno_r4_wifif.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_nano_every.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_giga_r1.yml)
|
||||
*Now works in 3.9.14!*
|
||||
|
||||
|
||||
### Teensy
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy30.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy31.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensyLC.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy40.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy41.yml)
|
||||
|
||||
*Specific Features*
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy_octo.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_teensy41_ofled.yml)
|
||||
|
||||
### NRF
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_adafruit_feather_nrf52840_sense.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_nrf52840_dk.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_adafruit_xiaoblesense.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_nrf52_xiaoblesense.yml)
|
||||
(This board has mbed engine but doesn't compile against Arduino.h right now for some unknown reason.)
|
||||
|
||||
### Apollo3
|
||||
|
||||
[](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)
|
||||
|
||||
### STM
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_bluepill.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_maple_map.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_stm103tb.yml)
|
||||
(PlatformIO doesn't support this board yet and we don't know what the build info is to support this is yet)
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_rp2040.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_rp2350.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_rp2350B.yml)
|
||||
|
||||
|
||||
### Esp
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp8622.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32dev.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32wroom.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32c2.yml)
|
||||
*Now supported as of FastLED 3.9.10!*
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32c3.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32s2.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32s3.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32c6.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32h2.yml)
|
||||
|
||||
*Specific features*
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_esp32_i2s_ws2812.yml)
|
||||
|
||||
[](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)
|
||||
|
||||
Espressif's current evaluation of FastLED's compatibility with their product sheet can be found [here](https://github.com/espressif/arduino-esp32/blob/gh-pages/LIBRARIES_TEST.md)
|
||||
|
||||
|
||||
### x86
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_linux.yml)
|
||||
|
||||
### Wasm
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_wasm.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_wasm_compilers.yml)
|
||||
|
||||
## Compiled Library Size Check
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/check_attiny85.yml)
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/check_uno_size.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/check_esp32_size.yml)
|
||||
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/check_teensy41_size.yml)
|
||||
|
||||
# Install
|
||||
|
||||
## Arduino IDE
|
||||
|
||||
After the ArduinoIDE is installed then add the library to your IDE
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## PlatformIO
|
||||
|
||||
PlatformIO offers an incredible IDE experience. Setup is easier than you think. Follow our guide here. Our template will allow your project to be compiled by both PlatformIO and ArduinoIDE
|
||||
|
||||
https://github.com/FastLED/PlatformIO-Starter
|
||||
|
||||
|
||||
# How to maximize the number of parallel WS2812 outputs
|
||||
|
||||
Some of the new processors can drive many many WS2812 strips in parallel.
|
||||
|
||||
# Leader Boards: Stock Setups
|
||||
|
||||
### Teensy 4.0/4.1
|
||||
|
||||
This chipset holds the current record for parallel output in a stock configuration. The theoretical output is 50 strips at a time with Teensy 4.1 and 42 strips with Teensy 4.2.
|
||||
|
||||
See this [example](https://github.com/FastLED/FastLED/blob/master/examples/TeensyMassiveParallel/TeensyMassiveParallel.ino) on how to enable.
|
||||
|
||||
### ESP32DEV
|
||||
|
||||
Surprisingly it's the good old ESP32Dev and not the ESP32S3, which holds the esp record for the amount of parallel outputs at 24 through I2S, and 8 via RMT.
|
||||
|
||||
I2S needs special setup as of 3.9.11 and earlier (current version of this writing is 3.9.11) see the [example](https://github.com/FastLED/FastLED/blob/master/examples/EspI2SDemo/EspI2SDemo.ino) here.
|
||||
|
||||
### ESP32-S3
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Exotic Setups
|
||||
|
||||
If you are willing to make a custom board with shift registers, then the ESp32S3 and ESP32Dev have special "virtual pin" libraries. These libraries will allow you to drive 120 parallel WS2812 outputs. However these are not included in FastLED but are compatible with it.
|
||||
|
||||
* Esp32DEV: https://github.com/hpwit/I2SClocklessVirtualLedDriver
|
||||
* Esp32-S3: https://github.com/hpwit/I2SClockLessLedVirtualDriveresp32s3
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
[](https://github.com/FastLED/FastLED/actions/workflows/build_clone_and_compile.yml)
|
||||
|
||||
Zero pain setup and install/test/run. Can be done from the command line in seconds if `uv` or `python` are installed. See our [contributing guide](https://github.com/FastLED/FastLED/blob/master/CONTRIBUTING.md) guide for more information.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
When changes are made then push to your fork to your repo and git will give you a url to trigger a pull request into the master repo.
|
||||
|
||||
### Testing other devices
|
||||
|
||||
* run [compile](compile) and then select your board
|
||||
|
||||
```bash
|
||||
Available boards:
|
||||
[0]: ATtiny1616
|
||||
[1]: adafruit_feather_nrf52840_sense
|
||||
[2]: attiny85
|
||||
[3]: bluepill
|
||||
[4]: digix
|
||||
[5]: esp01
|
||||
[6]: esp32c2
|
||||
[7]: esp32c3
|
||||
[8]: esp32c6
|
||||
[9]: esp32s3
|
||||
[10]: esp32dev
|
||||
[11]: esp32dev_i2s
|
||||
[12]: esp32dev_idf44
|
||||
[13]: esp32rmt_51
|
||||
[14]: nano_every
|
||||
[15]: rpipico
|
||||
[16]: rpipico2
|
||||
[17]: teensy30
|
||||
[18]: teensy41
|
||||
[19]: uno
|
||||
[20]: uno_r4_wifi
|
||||
[21]: xiaoblesense_adafruit
|
||||
[22]: yun
|
||||
[all]: All boards
|
||||
Enter the number of the board you want to use: 0
|
||||
```
|
||||
|
||||
## Help and Support
|
||||
|
||||
If you need help with using the library, please consider visiting the Reddit community at https://reddit.com/r/FastLED. There are thousands of knowledgeable FastLED users in that group and a plethora of solutions in the post history.
|
||||
|
||||
If you are looking for documentation on how something in the library works, please see the Doxygen documentation online at http://fastled.io/docs.
|
||||
|
||||
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)
|
||||
|
||||
* WS281x Clockless family
|
||||
* WS2811 (Old style 400khz & 800khz)
|
||||
* WS2812 (NeoPixel)
|
||||
* WS2812-V5B (250 uS reset)
|
||||
* WS2815
|
||||
* APA102 / SK9822 / HD107s (turbo->40mhz) / Adafruit DotStars (SPI)
|
||||
* HD107s, same thing as the APA102, but runs at turbo 40 Mhz
|
||||
* SmartMatrix panels - needs the SmartMatrix library (https://github.com/pixelmatix/SmartMatrix)
|
||||
* TM1809/4 - 3 wire chipset, cheaply available on aliexpress.com
|
||||
* TM1803 - 3 wire chipset, sold by RadioShack
|
||||
* UCS1903 - another 3-wire LED chipset, cheap
|
||||
* GW6205 - another 3-wire LED chipset
|
||||
* LPD8806 - SPI-based chipset, very high speed
|
||||
* WS2801 - SPI-based chipset, cheap and widely available
|
||||
* SM16716 - SPI-based chipset
|
||||
* APA102 - SPI-based chipset
|
||||
* APA102HD - Same as APA102 but with a high-definition gamma correction function applied at the driver level.
|
||||
* P9813 - aka Cool Neon's Total Control Lighting
|
||||
* DMX - send rgb data out over DMX using Arduino DMX libraries
|
||||
* LPD6803 - SPI-based chipset, chip CMODE pin must be set to 1 (inside oscillator mode)
|
||||
|
||||
## APA102 and the 'High Definition' Mode in FastLED
|
||||
|
||||
FastLED features driver-level gamma correction for the APA102 and SK9822 chipsets, using our "pseudo-13-bit mixing" algorithm.
|
||||
|
||||
Read about it here: https://github.com/FastLED/FastLED/blob/master/APA102.md
|
||||
|
||||
Enable it like by using the `APA102HD` type. Example:
|
||||
|
||||
```C++
|
||||
#define LED_TYPE APA102HD // "HD" suffix for APA102 family enables hardware gamma correction
|
||||
void setup() {
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, RGB>(leds_hd, NUM_LEDS);
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
Check out thr rust port of this algorithm:
|
||||
|
||||
https://docs.rs/apa102-spi/latest/apa102_spi/
|
||||
|
||||
# Getting Started
|
||||
|
||||
### Arduino IDE / PlatformIO Dual Repo
|
||||
|
||||
We've created a custom repo you can try to start your projects. This repo is designed to be used with VSCode + PlatformIO but is also *backwards compatible with the Arduino IDE*.
|
||||
|
||||
PlatformIO is an extension to VSCode and is generally viewed as a much better experience than the Arduino IDE. You get auto completion tools like intellisense and CoPilot and the ability to install tools like crash decoding. Anything you can do in Arduino IDE you can do with PlatformIO.
|
||||
|
||||
Get started here:
|
||||
|
||||
https://github.com/FastLED/PlatformIO-Starter
|
||||
|
||||
### ArduinoIDE
|
||||
|
||||
When running the Arduino IDE you need to do the additional installation step of installing FastLED in the global Arduino IDE package manager.
|
||||
|
||||
Install the library using either [the .zip file from the latest release](https://github.com/FastLED/FastLED/releases/latest/) or by searching for "FastLED" in the libraries manager of the Arduino IDE. [See the Arduino documentation on how to install libraries for more information.](https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries)
|
||||
|
||||
|
||||
## Porting FastLED to a new platform
|
||||
|
||||
Information on porting FastLED can be found in the file [PORTING.md](PORTING.md).
|
||||
|
||||
## What about that name?
|
||||
|
||||
Wait, what happened to FastSPI_LED and FastSPI_LED2? The library was initially named FastSPI_LED because it was focused on very fast and efficient SPI access. However, since then, the library has expanded to support a number of LED chipsets that don't use SPI, as well as a number of math and utility functions for LED processing across the board. We decided that the name FastLED more accurately represents the totality of what the library provides, everything fast, for LEDs.
|
||||
|
||||
## For more information
|
||||
|
||||
Check out the official site http://fastled.io for links to documentation, issues, and news.
|
||||
|
||||
## Daniel Garcia, Founder of FastLED
|
||||
|
||||
In Memory of Daniel Garcia
|
||||
Daniel Garcia, the brilliant founder of FastLED, tragically passed away in September 2019 in the Conception dive boat fire alongside his partner, Yulia. This heartbreaking loss was felt deeply by the maker and developer community, where Daniel's contributions had left an indelible mark.
|
||||
|
||||
Daniel was more than just a talented programmer; he was a passionate innovator who transformed the way creators interacted with LED technology. His work on FastLED brought high-performance LED control to countless projects, empowering developers to craft breathtaking installations.
|
||||
|
||||
In his personal life, Daniel was known for his kindness and creativity. His pride in FastLED and the vibrant community it fostered was a testament to his dedication to open-source development and his commitment to helping others bring light into the world.
|
||||
|
||||
While Daniel is no longer with us, his legacy continues through the FastLED library and the countless makers who use it. The community he built serves as a living tribute to his ingenuity, generosity, and the joy he found in sharing his work with the world.
|
||||
|
||||
## About the Current Contributor
|
||||
|
||||
Zach Vorhies, the current main contributor to FastLED, briefly worked with Dan in 2014 in San Francisco and was an avid user of the FastLED library for over 13 years. After Daniel Garcia’s untimely passing, Zach stepped up to ensure FastLED’s continued growth and development.
|
||||
|
||||
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:
|
||||
|
||||
https://github.com/FastLED/FastLED/blob/master/CONTRIBUTING.md
|
||||
|
||||
*To stay updated on the latest feature releases, please click the `Watch` button in the upper right*
|
||||
39
libraries/FastLED/RELEASE.md
Normal file
39
libraries/FastLED/RELEASE.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# FastLED Release howto
|
||||
|
||||
*Pushing a fastled release, the short version, last updated May 2024*
|
||||
|
||||
## Example
|
||||
|
||||
https://github.com/FastLED/FastLED/commit/4444758ffaf853ba4f8deb973532548c9c1ee231
|
||||
|
||||
## How to
|
||||
|
||||
Edit these files to update the version number
|
||||
* library.json
|
||||
* library.properties
|
||||
* src/FastLED.h
|
||||
* docs/Doxyfile
|
||||
* RELEASE.md
|
||||
* This file: update instructions with the current release.
|
||||
|
||||
|
||||
Edit this file with release notes and version number.
|
||||
* release_notes.md
|
||||
|
||||
Release notes should list highlight changes (not necessarily all minor bug fixes) and thank people for their help.
|
||||
|
||||
Git commands to commit and tag release'
|
||||
```bash
|
||||
$ git commit -am "Rev 3.9.20 - Misc fixes"
|
||||
$ git tag 3.9.20 master
|
||||
$ git push
|
||||
$ git push origin 3.9.20
|
||||
```
|
||||
|
||||
Then use the GitHub UI to make a new “Release”:
|
||||
|
||||
https://github.com/FastLED/FastLED/releases/new
|
||||
|
||||
Announce new version on subreddit, highlighting major changes and thanking people for helping.
|
||||
|
||||
That’s it.
|
||||
37
libraries/FastLED/TODO.md
Normal file
37
libraries/FastLED/TODO.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Testing
|
||||
|
||||
* Esp32 testing
|
||||
* https://github.com/marketplace/actions/esp32-qemu-runner will run a sketch for X seconds and see's if it crashes
|
||||
* There's specific tests we'd like to run with this including the WS2812 and APA102 tests to test the clockless and clocked drivers
|
||||
|
||||
# Feature Enhancements
|
||||
|
||||
* I2S driver for ESP32 WS2812
|
||||
* https://github.com/hpwit/I2SClocklessLedDriver
|
||||
* Our copy is here: https://github.com/FastLED/FastLED/blob/master/src/platforms/esp/32/clockless_i2s_esp32.h
|
||||
* S3:
|
||||
* https://github.com/hpwit/I2SClockLessLedDriveresp32s3
|
||||
* Apparently, this driver allows MASSIVE parallelization for WS2812
|
||||
* Timing guide for reducing RMT frequency https://github.com/Makuna/NeoPixelBus/pull/795
|
||||
* ESp32 LED guide
|
||||
* web: https://components.espressif.com/components/espressif/led_strip
|
||||
* repo: https://github.com/espressif/idf-extra-components/tree/60c14263f3b69ac6e98ecae79beecbe5c18d5596/led_strip
|
||||
* adafruit conversation on RMT progress: https://github.com/adafruit/Adafruit_NeoPixel/issues/375
|
||||
|
||||
|
||||
* MIT Licensed SdFat library
|
||||
* https://github.com/greiman/SdFat
|
||||
* YVes LittleFS implementation for ESP
|
||||
* https://github.com/hpwit/ledOS/blob/main/src/fileSystem.h
|
||||
|
||||
* NimBLE for Arduino
|
||||
* https://github.com/h2zero/NimBLE-Arduino?tab=readme-ov-file
|
||||
|
||||
* Arduino test compile
|
||||
* https://github.com/hpwit/arduino-test-compile/blob/master/arduino-test-compile.sh
|
||||
|
||||
|
||||
# Misc:
|
||||
|
||||
* sutaburosu's guide to playing around with FastLED 4
|
||||
* https://github.com/sutaburosu/FastLED4-ESP32-playpen
|
||||
3
libraries/FastLED/ai
Executable file
3
libraries/FastLED/ai
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
uv run aicode
|
||||
11
libraries/FastLED/ci/README.md
Normal file
11
libraries/FastLED/ci/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
This is the Continuous Integration tool that builds the product in various configurations.
|
||||
|
||||
Running
|
||||
|
||||
Install the python `uv` tool.
|
||||
|
||||
`pip install uv`
|
||||
|
||||
Now run the python in this directory
|
||||
|
||||
`uv run ci-compile.py`
|
||||
30
libraries/FastLED/ci/boards/esp32-c2-devkitm-1.json
Normal file
30
libraries/FastLED/ci/boards/esp32-c2-devkitm-1.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"build": {
|
||||
"core": "esp32",
|
||||
"f_cpu": "120000000L",
|
||||
"f_flash": "60000000L",
|
||||
"flash_mode": "qio",
|
||||
"mcu": "esp32c2",
|
||||
"variant": "esp32c2"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32c2.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32-C2-DevKitM-1",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 278528,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp8684/esp8684-devkitm-1/user_guide.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
31
libraries/FastLED/ci/boards/esp32-c6-devkitc-1.json
Normal file
31
libraries/FastLED/ci/boards/esp32-c6-devkitc-1.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"build": {
|
||||
"core": "esp32",
|
||||
"f_cpu": "160000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"mcu": "esp32c6",
|
||||
"variant": "esp32c6"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32c6.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32-C6-DevKitC-1",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
31
libraries/FastLED/ci/boards/esp32-h2-devkitm-1.json
Normal file
31
libraries/FastLED/ci/boards/esp32-h2-devkitm-1.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"build": {
|
||||
"core": "esp32",
|
||||
"f_cpu": "96000000L",
|
||||
"f_flash": "64000000L",
|
||||
"f_image": "48000000L",
|
||||
"flash_mode": "qio",
|
||||
"mcu": "esp32h2",
|
||||
"variant": "esp32h2"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32h2.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "Espressif ESP32-H2-DevKit",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32h2/esp32-h2-devkitm-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
61
libraries/FastLED/ci/boards/giga.json
Normal file
61
libraries/FastLED/ci/boards/giga.json
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "linker_script.ld",
|
||||
"flash_layout": "100_0"
|
||||
},
|
||||
"extra_flags": "-DARDUINO_GIGA -DARDUINO_GIGA_PINS -DGIGA_PINS -DGIGA -DCM4_BINARY_START=0x60000000 -DCM4_BINARY_END=0x60040000 -DCM4_RAM_END=0x60080000",
|
||||
"core": "arduino",
|
||||
"cpu": "cortex-m7",
|
||||
"f_cpu": "480000000L",
|
||||
"mcu": "stm32h747xih6",
|
||||
"variant": "GIGA",
|
||||
"product_line": "STM32H747xx",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2341",
|
||||
"0x0266"
|
||||
],
|
||||
[
|
||||
"0x2341",
|
||||
"0x0366"
|
||||
],
|
||||
[
|
||||
"0x2341",
|
||||
"0x0466"
|
||||
]
|
||||
]
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"jlink_device": "STM32H747XI_M7",
|
||||
"openocd_target": "stm32h7x_dual_bank"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Arduino Giga R1 Wifi",
|
||||
"upload": {
|
||||
"_maximum_ram_size": 294248,
|
||||
"_maximum_size": 1048576,
|
||||
"maximum_ram_size": 523624,
|
||||
"maximum_size": 1966080,
|
||||
"protocol": "dfu",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"dfu",
|
||||
"jlink",
|
||||
"stlink",
|
||||
"mbed"
|
||||
],
|
||||
"require_upload_port": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"offset_address": "0x08100000"
|
||||
},
|
||||
"url": "https://docs.arduino.cc/hardware/giga-r1-wifi",
|
||||
"vendor": "Arduino"
|
||||
}
|
||||
51
libraries/FastLED/ci/boards/nrf52840_dk.json
Normal file
51
libraries/FastLED/ci/boards/nrf52840_dk.json
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "nrf52_xxaa.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52_DK",
|
||||
"f_cpu": "64000000L",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "nRF52DK",
|
||||
"zephyr": {
|
||||
"variant": "nrf52840dk_nrf52840"
|
||||
}
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth"
|
||||
],
|
||||
"debug": {
|
||||
"default_tools": [
|
||||
"jlink"
|
||||
],
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": [
|
||||
"cmsis-dap",
|
||||
"jlink"
|
||||
],
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"mbed",
|
||||
"zephyr"
|
||||
],
|
||||
"name": "Nordic nRF52840-DK",
|
||||
"upload": {
|
||||
"maximum_ram_size": 262144,
|
||||
"maximum_size": 1048576,
|
||||
"protocol": "jlink",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"stlink",
|
||||
"blackmagic",
|
||||
"cmsis-dap",
|
||||
"mbed"
|
||||
]
|
||||
},
|
||||
"url": "https://os.mbed.com/platforms/Nordic-nRF52840-DK/",
|
||||
"vendor": "Nordic"
|
||||
}
|
||||
56
libraries/FastLED/ci/boards/rpipico.json
Normal file
56
libraries/FastLED/ci/boards/rpipico.json
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x000A"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-DARDUINO_RASPBERRY_PI_PICO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250 ",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x000A"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "rpipico"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Pico",
|
||||
"upload": {
|
||||
"maximum_ram_size": 262144,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"blackmagic",
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe",
|
||||
"pico-debug"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Raspberry Pi"
|
||||
}
|
||||
56
libraries/FastLED/ci/boards/rpipico2.json
Normal file
56
libraries/FastLED/ci/boards/rpipico2.json
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_generic_03h_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x000B"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m33",
|
||||
"extra_flags": "-D ARDUINO_RASPBERRY_PI_PICO_2 -DARDUINO_ARCH_RP2350 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x000B"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2350",
|
||||
"variant": "rpipico2"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2350_0",
|
||||
"openocd_target": "rp2350.cfg",
|
||||
"svd_path": "rp2350.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Pico 2",
|
||||
"upload": {
|
||||
"maximum_ram_size": 524288,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"blackmagic",
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe",
|
||||
"pico-debug"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Raspberry Pi"
|
||||
}
|
||||
56
libraries/FastLED/ci/boards/rpipicow.json
Normal file
56
libraries/FastLED/ci/boards/rpipicow.json
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0xF00A"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-DARDUINO_RASPBERRY_PI_PICO_W -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250 ",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0xF00A"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "rpipicow"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Pico W",
|
||||
"upload": {
|
||||
"maximum_ram_size": 262144,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"blackmagic",
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe",
|
||||
"pico-debug"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Raspberry Pi"
|
||||
}
|
||||
33
libraries/FastLED/ci/boards/sparkfun_thingplusmatter.json
Normal file
33
libraries/FastLED/ci/boards/sparkfun_thingplusmatter.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"build": {
|
||||
"core": "silabs",
|
||||
"f_cpu": "39000000L",
|
||||
"mcu": "cortex-m33",
|
||||
"variant": "thingplusmatter"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"thread",
|
||||
"wifi",
|
||||
"zigbee"
|
||||
],
|
||||
"debug": {
|
||||
"jlink_device": "EFR32MG24B020F1536IM40",
|
||||
"onboard_tools": [
|
||||
"jlink"
|
||||
],
|
||||
"svd_path": "EFR32MG24B020F1536IM40.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Sparkfun Thing Plus Matter",
|
||||
"upload": {
|
||||
"flash_size": "1536kB",
|
||||
"maximum_ram_size": 262144,
|
||||
"maximum_size": 1572864,
|
||||
"protocol": "jlink"
|
||||
},
|
||||
"url": "https://www.sparkfun.com/products/20270",
|
||||
"vendor": "Sparkfun"
|
||||
}
|
||||
108
libraries/FastLED/ci/ci-check-compiled-size.py
Normal file
108
libraries/FastLED/ci/ci-check-compiled-size.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
PROJECT_ROOT = HERE.parent
|
||||
|
||||
IS_GITHUB = "GITHUB_ACTIONS" in os.environ
|
||||
|
||||
|
||||
def run_command(
|
||||
cmd_list: list[str], shell: bool = False, check=False, capture_output: bool = False
|
||||
) -> str | None:
|
||||
check = check if check is not None else check
|
||||
cmd = cmd_list if not shell else subprocess.list2cmdline(cmd_list)
|
||||
|
||||
result: subprocess.CompletedProcess = subprocess.run(
|
||||
cmd, capture_output=capture_output, text=True, shell=shell, check=check
|
||||
)
|
||||
|
||||
if not capture_output:
|
||||
return None
|
||||
|
||||
stdout: str = result.stdout
|
||||
stdout = stdout.strip()
|
||||
return stdout
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check compiled program size for a board"
|
||||
)
|
||||
parser.add_argument("board", help="Board name")
|
||||
parser.add_argument(
|
||||
"--max-size", type=int, required=False, help="Maximum allowed size"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-build",
|
||||
action="store_true",
|
||||
help="Skip compilation and check existing build",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--example",
|
||||
default="Blink",
|
||||
help="Example to compile (default: Blink)",
|
||||
)
|
||||
|
||||
# Parse known args first
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
# Add remaining arguments as extra_args
|
||||
args.extra_args = unknown
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(str(PROJECT_ROOT))
|
||||
args = parse_args()
|
||||
|
||||
if not args.no_build:
|
||||
cmd_list = [
|
||||
"uv",
|
||||
"run",
|
||||
"ci/ci-compile.py",
|
||||
args.board,
|
||||
"--examples",
|
||||
args.example,
|
||||
] + args.extra_args
|
||||
try:
|
||||
run_command(cmd_list, shell=True, capture_output=IS_GITHUB, check=True)
|
||||
except subprocess.CalledProcessError:
|
||||
run_command(cmd_list, shell=True, capture_output=False, check=True)
|
||||
|
||||
output = run_command(
|
||||
["uv", "run", "ci/compiled_size.py", "--board", args.board],
|
||||
capture_output=True,
|
||||
)
|
||||
size_match = re.search(r": *(\d+)", output) # type: ignore
|
||||
|
||||
if not size_match:
|
||||
print("Error: Unable to extract size from output")
|
||||
print(f"Output: {output}")
|
||||
sys.exit(1)
|
||||
|
||||
size = int(size_match.group(1))
|
||||
|
||||
if args.max_size is not None and args.max_size > 0:
|
||||
max_size = args.max_size
|
||||
if size > max_size:
|
||||
print(f"{args.board} size {size} is greater than max size {max_size}")
|
||||
print("::error::Compiled size exceeds maximum allowed size")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"{args.board} size {size} is within the limit of {max_size}")
|
||||
else:
|
||||
if not args.max_size:
|
||||
print("Warning: No max size specified")
|
||||
elif args.max_size <= 0:
|
||||
print("Warning: max size was <= 0 so no check was performed")
|
||||
print(f"{args.board} size: {size}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
5
libraries/FastLED/ci/ci-compile
Executable file
5
libraries/FastLED/ci/ci-compile
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
# cd to the directory of the script
|
||||
cd "$(dirname "$0")"
|
||||
uv run ci-compile.py "$@"
|
||||
21
libraries/FastLED/ci/ci-compile-native.py
Normal file
21
libraries/FastLED/ci/ci-compile-native.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
# Change to the directory of the script
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Change to the 'native' directory and run 'pio run'
|
||||
os.chdir("native")
|
||||
result = subprocess.run(["pio", "run"], check=True)
|
||||
|
||||
# Exit with the same status as the pio run command
|
||||
sys.exit(result.returncode)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
317
libraries/FastLED/ci/ci-compile.py
Normal file
317
libraries/FastLED/ci/ci-compile.py
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
"""
|
||||
Runs the compilation process for all examples on all boards in parallel.
|
||||
Build artifacts are recycled within a board group so that subsequent ino
|
||||
files are built faster.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
from ci.boards import Board, get_board # type: ignore
|
||||
from ci.concurrent_run import ConcurrentRunArgs, concurrent_run
|
||||
from ci.locked_print import locked_print
|
||||
|
||||
HERE = Path(__file__).parent.resolve()
|
||||
|
||||
LIBS = ["src", "ci"]
|
||||
EXTRA_LIBS = [
|
||||
"https://github.com/me-no-dev/ESPAsyncWebServer.git",
|
||||
"ArduinoOTA",
|
||||
"SD",
|
||||
"FS",
|
||||
"ESPmDNS",
|
||||
"WiFi",
|
||||
"WebSockets",
|
||||
]
|
||||
BUILD_FLAGS = ["-Wl,-Map,firmware.map", "-fopt-info-all=optimization_report.txt"]
|
||||
|
||||
# Default boards to compile for. You can use boards not defined here but
|
||||
# if the board isn't part of the officially supported platformio boards then
|
||||
# you will need to add the board to the ~/.platformio/platforms directory.
|
||||
# prior to running this script. This happens automatically as of 2024-08-20
|
||||
# with the github workflow scripts.
|
||||
DEFAULT_BOARDS_NAMES = [
|
||||
"apollo3_red",
|
||||
"apollo3_thing_explorable",
|
||||
"web", # work in progress
|
||||
"uno", # Build is faster if this is first, because it's used for global init.
|
||||
"esp32dev",
|
||||
"esp01", # ESP8266
|
||||
"esp32c3",
|
||||
"attiny85",
|
||||
"ATtiny1616",
|
||||
"esp32c6",
|
||||
"esp32s3",
|
||||
"yun",
|
||||
"digix",
|
||||
"teensy30",
|
||||
"teensy41",
|
||||
"adafruit_feather_nrf52840_sense",
|
||||
"xiaoblesense_adafruit",
|
||||
"rpipico",
|
||||
"rpipico2",
|
||||
"uno_r4_wifi",
|
||||
"esp32rmt_51",
|
||||
"esp32dev_idf44",
|
||||
"bluepill",
|
||||
"esp32rmt_51",
|
||||
"giga_r1",
|
||||
"sparkfun_xrp_controller",
|
||||
]
|
||||
|
||||
OTHER_BOARDS_NAMES = [
|
||||
"nano_every",
|
||||
"esp32-c2-devkitm-1",
|
||||
]
|
||||
|
||||
# Examples to compile.
|
||||
DEFAULT_EXAMPLES = [
|
||||
"Apa102",
|
||||
"Apa102HD",
|
||||
"Apa102HDOverride",
|
||||
"Blink",
|
||||
"Blur",
|
||||
"Chromancer",
|
||||
"ColorPalette",
|
||||
"ColorTemperature",
|
||||
"Cylon",
|
||||
"DemoReel100",
|
||||
"FirstLight",
|
||||
"Fire2012",
|
||||
"Multiple/MultipleStripsInOneArray",
|
||||
"Multiple/ArrayOfLedArrays",
|
||||
"Noise",
|
||||
"NoisePlayground",
|
||||
"NoisePlusPalette",
|
||||
"LuminescentGrand",
|
||||
"Pacifica",
|
||||
"Pride2015",
|
||||
"RGBCalibrate",
|
||||
"RGBSetDemo",
|
||||
"RGBW",
|
||||
"Overclock",
|
||||
"RGBWEmulated",
|
||||
"TwinkleFox",
|
||||
"XYMatrix",
|
||||
"FxGfx2Video",
|
||||
"FxSdCard",
|
||||
"FxCylon",
|
||||
"FxDemoReel100",
|
||||
"FxTwinkleFox",
|
||||
"FxFire2012",
|
||||
"FxNoisePlusPalette",
|
||||
"FxPacifica",
|
||||
"FxEngine",
|
||||
"WS2816",
|
||||
]
|
||||
|
||||
EXTRA_EXAMPLES: dict[Board, list[str]] = {
|
||||
# ESP32DEV: ["EspI2SDemo"],
|
||||
# ESP32_S3_DEVKITC_1: ["EspS3I2SDemo"],
|
||||
}
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Compile FastLED examples for various boards."
|
||||
)
|
||||
# parser.add_argument(
|
||||
# "--boards", type=str, help="Comma-separated list of boards to compile for"
|
||||
# )
|
||||
# needs to be a positional argument instead
|
||||
parser.add_argument(
|
||||
"boards",
|
||||
type=str,
|
||||
help="Comma-separated list of boards to compile for",
|
||||
nargs="?",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--examples", type=str, help="Comma-separated list of examples to compile"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--exclude-examples", type=str, help="Examples that should be excluded"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-init", action="store_true", help="Skip the initialization step"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--defines", type=str, help="Comma-separated list of compiler definitions"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extra-packages",
|
||||
type=str,
|
||||
help="Comma-separated list of extra packages to install",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--add-extra-esp32-libs",
|
||||
action="store_true",
|
||||
help="Add extra libraries to the libraries list to check against compiler errors.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--build-dir", type=str, help="Override the default build directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-project-options",
|
||||
action="store_true",
|
||||
help="Don't use custom project options",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--interactive",
|
||||
action="store_true",
|
||||
help="Enable interactive mode to choose a board",
|
||||
)
|
||||
# Passed by the github action to disable interactive mode.
|
||||
parser.add_argument(
|
||||
"--no-interactive", action="store_true", help="Disable interactive mode"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="store_true", help="Enable verbose output"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--supported-boards",
|
||||
action="store_true",
|
||||
help="Print the list of supported boards and exit",
|
||||
)
|
||||
args, unknown = parser.parse_known_args()
|
||||
if unknown:
|
||||
warnings.warn(f"Unknown arguments: {unknown}")
|
||||
# if --interactive and --no-interative are both passed, --no-interactive takes precedence.
|
||||
if args.interactive and args.no_interactive:
|
||||
warnings.warn(
|
||||
"Both --interactive and --no-interactive were passed, --no-interactive takes precedence."
|
||||
)
|
||||
args.interactive = False
|
||||
return args
|
||||
|
||||
|
||||
def remove_duplicates(items: list[str]) -> list[str]:
|
||||
seen = set()
|
||||
out = []
|
||||
for item in items:
|
||||
if item not in seen:
|
||||
seen.add(item)
|
||||
out.append(item)
|
||||
return out
|
||||
|
||||
|
||||
def choose_board_interactively(boards: list[str]) -> list[str]:
|
||||
print("Available boards:")
|
||||
boards = remove_duplicates(sorted(boards))
|
||||
for i, board in enumerate(boards):
|
||||
print(f"[{i}]: {board}")
|
||||
print("[all]: All boards")
|
||||
out: list[str] = []
|
||||
while True:
|
||||
try:
|
||||
# choice = int(input("Enter the number of the board(s) you want to compile to: "))
|
||||
input_str = input(
|
||||
"Enter the number of the board(s) you want to compile to, or it's name(s): "
|
||||
)
|
||||
if "all" in input_str:
|
||||
return boards
|
||||
for board in input_str.split(","):
|
||||
if board == "":
|
||||
continue
|
||||
if not board.isdigit():
|
||||
out.append(board) # Assume it's a board name.
|
||||
else:
|
||||
index = int(board) # Find the board from the index.
|
||||
if 0 <= index < len(boards):
|
||||
out.append(boards[index])
|
||||
else:
|
||||
warnings.warn(f"invalid board index: {index}, skipping")
|
||||
if not out:
|
||||
print("Please try again.")
|
||||
continue
|
||||
return out
|
||||
except ValueError:
|
||||
print("Invalid input. Please enter a number.")
|
||||
|
||||
|
||||
def resolve_example_path(example: str) -> Path:
|
||||
example_path = HERE.parent / "examples" / example
|
||||
if not example_path.exists():
|
||||
raise FileNotFoundError(f"Example '{example}' not found at '{example_path}'")
|
||||
return example_path
|
||||
|
||||
|
||||
def create_concurrent_run_args(args: argparse.Namespace) -> ConcurrentRunArgs:
|
||||
skip_init = args.skip_init
|
||||
if args.interactive:
|
||||
boards = choose_board_interactively(DEFAULT_BOARDS_NAMES + OTHER_BOARDS_NAMES)
|
||||
else:
|
||||
boards = args.boards.split(",") if args.boards else DEFAULT_BOARDS_NAMES
|
||||
projects: list[Board] = []
|
||||
for board in boards:
|
||||
projects.append(get_board(board, no_project_options=args.no_project_options))
|
||||
extra_examples: dict[Board, list[Path]] = {}
|
||||
if args.examples is None:
|
||||
for b, _examples in EXTRA_EXAMPLES.items():
|
||||
resolved_examples = [resolve_example_path(example) for example in _examples]
|
||||
extra_examples[b] = resolved_examples
|
||||
examples = args.examples.split(",") if args.examples else DEFAULT_EXAMPLES
|
||||
examples_paths = [resolve_example_path(example) for example in examples]
|
||||
# now process example exclusions.
|
||||
if args.exclude_examples:
|
||||
exclude_examples = args.exclude_examples.split(",")
|
||||
examples_paths = [
|
||||
example
|
||||
for example in examples_paths
|
||||
if example.name not in exclude_examples
|
||||
]
|
||||
for exclude in exclude_examples:
|
||||
examples.remove(exclude)
|
||||
defines: list[str] = []
|
||||
if args.defines:
|
||||
defines.extend(args.defines.split(","))
|
||||
extra_packages: list[str] = []
|
||||
if args.extra_packages:
|
||||
extra_packages.extend(args.extra_packages.split(","))
|
||||
build_dir = args.build_dir
|
||||
extra_scripts = "pre:lib/ci/ci-flags.py"
|
||||
verbose = args.verbose
|
||||
|
||||
out: ConcurrentRunArgs = ConcurrentRunArgs(
|
||||
projects=projects,
|
||||
examples=examples_paths,
|
||||
skip_init=skip_init,
|
||||
defines=defines,
|
||||
extra_packages=extra_packages,
|
||||
libs=LIBS,
|
||||
build_dir=build_dir,
|
||||
extra_scripts=extra_scripts,
|
||||
cwd=str(HERE.parent),
|
||||
board_dir=(HERE / "boards").absolute().as_posix(),
|
||||
build_flags=BUILD_FLAGS,
|
||||
verbose=verbose,
|
||||
extra_examples=extra_examples,
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Main function."""
|
||||
args = parse_args()
|
||||
if args.supported_boards:
|
||||
print(",".join(DEFAULT_BOARDS_NAMES))
|
||||
return 0
|
||||
if args.add_extra_esp32_libs:
|
||||
LIBS.extend(EXTRA_LIBS)
|
||||
|
||||
# Set the working directory to the script's parent directory.
|
||||
run_args = create_concurrent_run_args(args)
|
||||
start_time = time.time()
|
||||
rtn = concurrent_run(args=run_args)
|
||||
time_taken = time.strftime("%Mm:%Ss", time.gmtime(time.time() - start_time))
|
||||
locked_print(f"Compilation finished in {time_taken}.")
|
||||
return rtn
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main())
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
56
libraries/FastLED/ci/ci-cppcheck.py
Normal file
56
libraries/FastLED/ci/ci-cppcheck.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MINIMUM_REPORT_SEVERTIY = "medium"
|
||||
MINIMUM_FAIL_SEVERTIY = "high"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Run cppcheck on the project")
|
||||
parser.add_argument("board", nargs="?", help="Board to check, optional")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
here = Path(__file__).parent
|
||||
project_root = here.parent
|
||||
build = project_root / ".build"
|
||||
os.chdir(str(build))
|
||||
|
||||
if args.board:
|
||||
build = build / args.board
|
||||
if not build.exists():
|
||||
print(f"Board {args.board} not found")
|
||||
return 1
|
||||
os.chdir(str(build))
|
||||
else:
|
||||
# Change to the first subdirectory in .build
|
||||
subdirs = [d for d in os.listdir() if os.path.isdir(d)]
|
||||
assert (
|
||||
len(subdirs) == 1
|
||||
), f"Expected exactly one subdirectory in {build}, instead got {subdirs}"
|
||||
if subdirs:
|
||||
os.chdir(subdirs[0])
|
||||
|
||||
# Run pio check command
|
||||
cp = subprocess.run(
|
||||
[
|
||||
"pio",
|
||||
"check",
|
||||
"--skip-packages",
|
||||
"--src-filters=+<lib/src/>",
|
||||
f"--severity={MINIMUM_REPORT_SEVERTIY}",
|
||||
f"--fail-on-defect={MINIMUM_FAIL_SEVERTIY}",
|
||||
"--flags",
|
||||
"--inline-suppr",
|
||||
],
|
||||
)
|
||||
return cp.returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
7
libraries/FastLED/ci/ci-flags.py
Normal file
7
libraries/FastLED/ci/ci-flags.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# mypy: ignore-errors
|
||||
# flake8: noqa
|
||||
# ruff: skip
|
||||
|
||||
Import("env") # type: ignore
|
||||
|
||||
env.Append(CXXFLAGS=["-Wno-register"]) # type: ignore
|
||||
0
libraries/FastLED/ci/ci/__init__.py
Normal file
0
libraries/FastLED/ci/ci/__init__.py
Normal file
175
libraries/FastLED/ci/ci/bin_2_elf.py
Normal file
175
libraries/FastLED/ci/ci/bin_2_elf.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _run_command(command: list, show_output=False):
|
||||
"""
|
||||
Run a command using subprocess and capture the output.
|
||||
|
||||
Args:
|
||||
command (list): Command to run.
|
||||
show_output (bool): Print command and its output if True.
|
||||
|
||||
Returns:
|
||||
str: Standard output of the command.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the command fails.
|
||||
"""
|
||||
if show_output:
|
||||
print(f"Running command: {' '.join(command)}")
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"Command failed: {' '.join(command)}\n{result.stderr}")
|
||||
if show_output and result.stdout:
|
||||
print(f"Command output: {result.stdout}")
|
||||
return result.stdout
|
||||
|
||||
|
||||
def _generate_linker_script(map_file: Path) -> Path:
|
||||
"""
|
||||
Generate a linker script based on map file information.
|
||||
|
||||
Args:
|
||||
map_file (Path): Path to the map file.
|
||||
|
||||
Returns:
|
||||
Path: Path to the generated linker script.
|
||||
"""
|
||||
linker_script_content = """
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x00000000 :
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
.bss :
|
||||
{
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
"""
|
||||
linker_script_path = map_file.with_suffix(".ld")
|
||||
linker_script_path.write_text(linker_script_content)
|
||||
print(f"Generated linker script at: {linker_script_path}")
|
||||
return linker_script_path
|
||||
|
||||
|
||||
def _create_dummy_object_file(as_path: Path, dummy_obj_path: Path):
|
||||
"""
|
||||
Create a minimal dummy object file using the specified assembler.
|
||||
|
||||
Args:
|
||||
as_path (Path): Path to the assembler executable.
|
||||
dummy_obj_path (Path): Path to the dummy object file to be created.
|
||||
"""
|
||||
assembly_code = """
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
nop
|
||||
"""
|
||||
asm_file = dummy_obj_path.with_suffix(".s")
|
||||
asm_file.write_text(assembly_code)
|
||||
|
||||
command = [str(as_path), "-o", str(dummy_obj_path), str(asm_file)]
|
||||
print(f"Creating dummy object file: {dummy_obj_path}")
|
||||
_run_command(command, show_output=True)
|
||||
asm_file.unlink() # Clean up the temporary assembly file
|
||||
|
||||
|
||||
def _create_dummy_elf(
|
||||
ld_path: Path, linker_script: Path, dummy_obj: Path, output_elf: Path
|
||||
):
|
||||
"""
|
||||
Create a dummy ELF file using the specified linker script and dummy object file.
|
||||
|
||||
Args:
|
||||
ld_path (Path): Path to the ld executable.
|
||||
linker_script (Path): Path to the linker script.
|
||||
dummy_obj (Path): Path to the dummy object file.
|
||||
output_elf (Path): Path to the output ELF file.
|
||||
"""
|
||||
command = [
|
||||
str(ld_path),
|
||||
str(dummy_obj),
|
||||
"-T",
|
||||
str(linker_script),
|
||||
"-o",
|
||||
str(output_elf),
|
||||
]
|
||||
print(f"Creating dummy ELF file: {output_elf}")
|
||||
_run_command(command, show_output=True)
|
||||
|
||||
|
||||
def _update_elf_sections(
|
||||
objcopy_path: Path, bin_file: Path, elf_file: Path, section_name: str
|
||||
):
|
||||
"""
|
||||
Update the ELF file sections with binary data.
|
||||
|
||||
Args:
|
||||
objcopy_path (Path): Path to the objcopy executable.
|
||||
bin_file (Path): Path to the binary file.
|
||||
elf_file (Path): Path to the ELF file.
|
||||
section_name (str): Name of the section to update.
|
||||
"""
|
||||
command = [
|
||||
str(objcopy_path),
|
||||
"--update-section",
|
||||
f"{section_name}={bin_file}",
|
||||
str(elf_file),
|
||||
]
|
||||
print(
|
||||
f"Updating ELF file '{elf_file}' section '{section_name}' with binary file '{bin_file}'"
|
||||
)
|
||||
_run_command(command, show_output=True)
|
||||
|
||||
|
||||
def bin_to_elf(
|
||||
bin_file: Path,
|
||||
map_file: Path,
|
||||
as_path: Path,
|
||||
ld_path: Path,
|
||||
objcopy_path: Path,
|
||||
output_elf: Path,
|
||||
):
|
||||
"""
|
||||
Convert a binary file to ELF format.
|
||||
|
||||
Args:
|
||||
bin_file (Path): Path to the input binary file.
|
||||
map_file (Path): Path to the map file.
|
||||
as_path (Path): Path to the assembler executable.
|
||||
ld_path (Path): Path to the linker executable.
|
||||
objcopy_path (Path): Path to the objcopy executable.
|
||||
output_elf (Path): Path to the output ELF file.
|
||||
|
||||
Returns:
|
||||
Path: Path to the generated ELF file.
|
||||
"""
|
||||
# Generate a linker script based on the map file
|
||||
linker_script = _generate_linker_script(map_file)
|
||||
|
||||
# Create a minimal dummy object file
|
||||
dummy_obj_path = bin_file.with_name("dummy.o")
|
||||
_create_dummy_object_file(as_path, dummy_obj_path)
|
||||
|
||||
# Create a dummy ELF file using the generated linker script
|
||||
_create_dummy_elf(ld_path, linker_script, dummy_obj_path, output_elf)
|
||||
|
||||
# Update the ELF sections with binary data
|
||||
_update_elf_sections(objcopy_path, bin_file, output_elf, ".text")
|
||||
|
||||
# Clean up dummy object file
|
||||
if dummy_obj_path.exists():
|
||||
dummy_obj_path.unlink()
|
||||
|
||||
if linker_script.exists():
|
||||
linker_script.unlink()
|
||||
|
||||
return output_elf
|
||||
318
libraries/FastLED/ci/ci/boards.py
Normal file
318
libraries/FastLED/ci/ci/boards.py
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
# dataclasses
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
|
||||
# An open source version of the esp-idf 5.1 platform for the ESP32 that
|
||||
# gives esp32 boards the same build environment as the Arduino 2.3.1+.
|
||||
|
||||
# Set to a specific release, we may want to update this in the future.
|
||||
ESP32_IDF_5_1_PIOARDUINO = "https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip"
|
||||
|
||||
# TODO: Upgrade toolkit to 5.3
|
||||
ESP32_IDF_5_3_PIOARDUINO = "https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10/platform-espressif32.zip"
|
||||
ESP32_IDF_5_1_PIOARDUINO_LATEST = (
|
||||
"https://github.com/pioarduino/platform-espressif32.git#develop"
|
||||
)
|
||||
ESP32_IDF_4_4_LATEST = "platformio/espressif32"
|
||||
APOLLO3_2_2_0 = "https://github.com/nigelb/platform-apollo3blue"
|
||||
# Top of trunk.
|
||||
# ESP32_IDF_5_1_PIOARDUINO = "https://github.com/pioarduino/platform-espressif32"
|
||||
|
||||
# Old fork that we were using
|
||||
# ESP32_IDF_5_1_PIOARDUINO = "https://github.com/zackees/platform-espressif32#Arduino/IDF5"
|
||||
|
||||
ALL: list["Board"] = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class Board:
|
||||
board_name: str
|
||||
real_board_name: str | None = None
|
||||
platform: str | None = None
|
||||
platform_needs_install: bool = False
|
||||
use_pio_run: bool = (
|
||||
False # some platforms like esp32-c2-devkitm-1 will only work with pio run
|
||||
)
|
||||
platform_packages: str | None = None
|
||||
framework: str | None = None
|
||||
board_build_mcu: str | None = None
|
||||
board_build_core: str | None = None
|
||||
board_build_filesystem_size: str | None = None
|
||||
build_flags: list[str] | None = None # Reserved for future use.
|
||||
defines: list[str] | None = None
|
||||
board_partitions: str | None = None # Reserved for future use.
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
ALL.append(self)
|
||||
|
||||
def get_real_board_name(self) -> str:
|
||||
return self.real_board_name if self.real_board_name else self.board_name
|
||||
|
||||
def to_dictionary(self) -> dict[str, list[str]]:
|
||||
out: dict[str, list[str]] = {}
|
||||
if self.real_board_name:
|
||||
out[self.board_name] = [f"board={self.real_board_name}"]
|
||||
options = out.setdefault(self.board_name, [])
|
||||
if self.platform:
|
||||
options.append(f"platform={self.platform}")
|
||||
if self.platform_needs_install:
|
||||
options.append("platform_needs_install=true")
|
||||
if self.platform_packages:
|
||||
options.append(f"platform_packages={self.platform_packages}")
|
||||
if self.framework:
|
||||
options.append(f"framework={self.framework}")
|
||||
if self.board_build_core:
|
||||
options.append(f"board_build.core={self.board_build_core}")
|
||||
if self.board_build_mcu:
|
||||
options.append(f"board_build.mcu={self.board_build_mcu}")
|
||||
if self.board_build_filesystem_size:
|
||||
options.append(
|
||||
f"board_build.filesystem_size={self.board_build_filesystem_size}"
|
||||
)
|
||||
if self.defines:
|
||||
for define in self.defines:
|
||||
options.append(f"build_flags=-D{define}")
|
||||
return out
|
||||
|
||||
def __repr__(self) -> str:
|
||||
json_str = json.dumps(self.to_dictionary(), indent=4, sort_keys=True)
|
||||
return json_str
|
||||
|
||||
def __hash__(self) -> int:
|
||||
data_str = self.__repr__()
|
||||
return hash(data_str)
|
||||
|
||||
|
||||
# [env:sparkfun_xrp_controller]
|
||||
# platform = https://github.com/maxgerhardt/platform-raspberrypi
|
||||
# board = sparkfun_xrp_controller
|
||||
# framework = arduino
|
||||
# lib_deps = fastled/FastLED @ ^3.9.16
|
||||
|
||||
|
||||
WEBTARGET = Board(
|
||||
board_name="web",
|
||||
)
|
||||
|
||||
DUE = Board(
|
||||
board_name="due",
|
||||
platform="atmelsam",
|
||||
)
|
||||
|
||||
|
||||
SPARKFUN_XRP_CONTROLLER_2350B = Board(
|
||||
board_name="sparkfun_xrp_controller",
|
||||
platform="https://github.com/maxgerhardt/platform-raspberrypi",
|
||||
platform_needs_install=True,
|
||||
)
|
||||
|
||||
APOLLO3_RED_BOARD = Board(
|
||||
board_name="apollo3_red",
|
||||
real_board_name="SparkFun_RedBoard_Artemis_ATP",
|
||||
platform=APOLLO3_2_2_0,
|
||||
platform_packages="framework-arduinoapollo3@https://github.com/sparkfun/Arduino_Apollo3#v2.2.0",
|
||||
platform_needs_install=True,
|
||||
)
|
||||
|
||||
APOLLO3_SPARKFUN_THING_PLUS_EXPLORERABLE = Board(
|
||||
board_name="apollo3_thing_explorable",
|
||||
real_board_name="SparkFun_Thing_Plus_expLoRaBLE",
|
||||
platform=APOLLO3_2_2_0,
|
||||
platform_packages="framework-arduinoapollo3@https://github.com/sparkfun/Arduino_Apollo3#v2.2.0",
|
||||
platform_needs_install=True,
|
||||
)
|
||||
|
||||
ESP32DEV = Board(
|
||||
board_name="esp32dev",
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
)
|
||||
|
||||
ESP32DEV_IDF3_3 = Board(
|
||||
board_name="esp32dev_idf33",
|
||||
real_board_name="esp32dev",
|
||||
platform="espressif32@1.11.2",
|
||||
)
|
||||
|
||||
ESP32DEV_IDF4_4 = Board(
|
||||
board_name="esp32dev_idf44",
|
||||
real_board_name="esp32dev",
|
||||
platform=ESP32_IDF_4_4_LATEST,
|
||||
)
|
||||
|
||||
GIGA_R1 = Board(
|
||||
board_name="giga_r1",
|
||||
platform="ststm32",
|
||||
framework="arduino",
|
||||
real_board_name="giga_r1_m7",
|
||||
)
|
||||
|
||||
# ESP01 = Board(
|
||||
# board_name="esp01",
|
||||
# platform=ESP32_IDF_5_1_PIOARDUINO,
|
||||
# )
|
||||
|
||||
ESP32_C2_DEVKITM_1 = Board(
|
||||
board_name="esp32c2",
|
||||
real_board_name="esp32-c2-devkitm-1",
|
||||
use_pio_run=True,
|
||||
platform="https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF5",
|
||||
defines=["CONFIG_IDF_TARGET_ESP32C2=1"],
|
||||
)
|
||||
|
||||
ESP32_C3_DEVKITM_1 = Board(
|
||||
board_name="esp32c3",
|
||||
real_board_name="esp32-c3-devkitm-1",
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
)
|
||||
|
||||
ESP32_C6_DEVKITC_1 = Board(
|
||||
board_name="esp32c6",
|
||||
real_board_name="esp32-c6-devkitc-1",
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
)
|
||||
|
||||
ESP32_S3_DEVKITC_1 = Board(
|
||||
board_name="esp32s3",
|
||||
real_board_name="seeed_xiao_esp32s3", # Seeed Xiao ESP32-S3 has psram.
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
defines=[
|
||||
"BOARD_HAS_PSRAM",
|
||||
],
|
||||
build_flags=[ # Reserved for future use.
|
||||
"-mfix-esp32-psram-cache-issue",
|
||||
"-mfix-esp32-psram-cache-strategy=memw",
|
||||
],
|
||||
board_partitions="huge_app.csv", # Reserved for future use.
|
||||
)
|
||||
|
||||
ESP32_S2_DEVKITM_1 = Board(
|
||||
board_name="esp32s2",
|
||||
real_board_name="esp32dev",
|
||||
board_build_mcu="esp32s2",
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
)
|
||||
|
||||
ESP32_H2_DEVKITM_1 = Board(
|
||||
board_name="esp32-h2-devkitm-1",
|
||||
platform_needs_install=True, # Install platform package to get the boards
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
)
|
||||
|
||||
ADA_FEATHER_NRF52840_SENSE = Board(
|
||||
board_name="adafruit_feather_nrf52840_sense",
|
||||
platform="nordicnrf52",
|
||||
)
|
||||
|
||||
XIAOBLESENSE_ADAFRUIT_NRF52 = Board(
|
||||
board_name="xiaoblesense_adafruit",
|
||||
platform="https://github.com/maxgerhardt/platform-nordicnrf52",
|
||||
platform_needs_install=True, # Install platform package to get the boards
|
||||
)
|
||||
|
||||
XIAOBLESENSE_NRF52 = Board(
|
||||
board_name="xiaoblesense",
|
||||
platform="https://github.com/maxgerhardt/platform-nordicnrf52",
|
||||
platform_needs_install=True,
|
||||
)
|
||||
|
||||
NRF52840 = Board(
|
||||
board_name="nrf52840_dk",
|
||||
real_board_name="xiaoble_adafruit",
|
||||
platform="https://github.com/maxgerhardt/platform-nordicnrf52",
|
||||
platform_needs_install=True,
|
||||
)
|
||||
|
||||
RPI_PICO = Board(
|
||||
board_name="rpipico",
|
||||
platform="https://github.com/maxgerhardt/platform-raspberrypi.git",
|
||||
platform_needs_install=True, # Install platform package to get the boards
|
||||
platform_packages="framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git",
|
||||
framework="arduino",
|
||||
board_build_core="earlephilhower",
|
||||
board_build_filesystem_size="0.5m",
|
||||
)
|
||||
|
||||
RPI_PICO2 = Board(
|
||||
board_name="rpipico2",
|
||||
platform="https://github.com/maxgerhardt/platform-raspberrypi.git",
|
||||
platform_needs_install=True, # Install platform package to get the boards
|
||||
platform_packages="framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git",
|
||||
framework="arduino",
|
||||
board_build_core="earlephilhower",
|
||||
board_build_filesystem_size="0.5m",
|
||||
)
|
||||
|
||||
BLUEPILL = Board(
|
||||
board_name="bluepill",
|
||||
real_board_name="bluepill_f103c8",
|
||||
platform="ststm32",
|
||||
)
|
||||
|
||||
# maple_mini_b20
|
||||
MAPLE_MINI = Board(
|
||||
board_name="maple_mini",
|
||||
real_board_name="maple_mini_b20",
|
||||
platform="ststm32",
|
||||
)
|
||||
|
||||
ATTINY88 = Board(
|
||||
board_name="attiny88",
|
||||
platform="atmelavr",
|
||||
)
|
||||
|
||||
# ATtiny1604
|
||||
ATTINY1616 = Board(
|
||||
board_name="ATtiny1616",
|
||||
platform="atmelmegaavr",
|
||||
)
|
||||
|
||||
UNO_R4_WIFI = Board(
|
||||
board_name="uno_r4_wifi",
|
||||
platform="renesas-ra",
|
||||
)
|
||||
|
||||
NANO_EVERY = Board(
|
||||
board_name="nano_every",
|
||||
platform="atmelmegaavr",
|
||||
)
|
||||
|
||||
ESP32DEV_I2S = Board(
|
||||
board_name="esp32dev_i2s",
|
||||
real_board_name="esp32dev",
|
||||
platform=ESP32_IDF_4_4_LATEST,
|
||||
)
|
||||
|
||||
ESP32S3_RMT51 = Board(
|
||||
board_name="esp32rmt_51",
|
||||
real_board_name="esp32-s3-devkitc-1",
|
||||
platform_needs_install=True,
|
||||
platform=ESP32_IDF_5_3_PIOARDUINO,
|
||||
defines=[
|
||||
"FASTLED_RMT5=1",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _make_board_map(boards: list[Board]) -> dict[str, Board]:
|
||||
# make board map, but assert on duplicate board names
|
||||
board_map: dict[str, Board] = {}
|
||||
for board in boards:
|
||||
assert (
|
||||
board.board_name not in board_map
|
||||
), f"Duplicate board name: {board.board_name}"
|
||||
board_map[board.board_name] = board
|
||||
return board_map
|
||||
|
||||
|
||||
_BOARD_MAP: dict[str, Board] = _make_board_map(ALL)
|
||||
|
||||
|
||||
def get_board(board_name: str, no_project_options: bool = False) -> Board:
|
||||
if no_project_options:
|
||||
return Board(board_name=board_name)
|
||||
if board_name not in _BOARD_MAP:
|
||||
# empty board without any special overrides, assume platformio will know what to do with it.
|
||||
return Board(board_name=board_name)
|
||||
else:
|
||||
return _BOARD_MAP[board_name]
|
||||
212
libraries/FastLED/ci/ci/compile_for_board.py
Normal file
212
libraries/FastLED/ci/ci/compile_for_board.py
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
|
||||
from ci.boards import Board # type: ignore
|
||||
from ci.locked_print import locked_print
|
||||
|
||||
ERROR_HAPPENED = False
|
||||
|
||||
|
||||
IS_GITHUB = "GITHUB_ACTIONS" in os.environ
|
||||
FIRST_BUILD_LOCK = Lock()
|
||||
USE_FIRST_BUILD_LOCK = IS_GITHUB
|
||||
|
||||
|
||||
def errors_happened() -> bool:
|
||||
"""Return whether any errors happened during the build."""
|
||||
return ERROR_HAPPENED
|
||||
|
||||
|
||||
def _fastled_js_is_parent_directory(p: Path) -> bool:
|
||||
"""Check if fastled_js is a parent directory of the given path."""
|
||||
# Check if fastled_js is a parent directory of p
|
||||
return "fastled_js" in str(p.absolute())
|
||||
|
||||
|
||||
def compile_for_board_and_example(
|
||||
board: Board,
|
||||
example: Path,
|
||||
build_dir: str | None,
|
||||
verbose_on_failure: bool,
|
||||
libs: list[str] | None,
|
||||
) -> tuple[bool, str]:
|
||||
"""Compile the given example for the given board."""
|
||||
global ERROR_HAPPENED # pylint: disable=global-statement
|
||||
if board.board_name == "web":
|
||||
locked_print(f"Skipping web target for example {example}")
|
||||
return True, ""
|
||||
board_name = board.board_name
|
||||
use_pio_run = board.use_pio_run
|
||||
real_board_name = board.get_real_board_name()
|
||||
libs = libs or []
|
||||
builddir = (
|
||||
Path(build_dir) / board_name if build_dir else Path(".build") / board_name
|
||||
)
|
||||
builddir.mkdir(parents=True, exist_ok=True)
|
||||
srcdir = builddir / "src"
|
||||
# Remove the previous *.ino file if it exists, everything else is recycled
|
||||
# to speed up the next build.
|
||||
if srcdir.exists():
|
||||
shutil.rmtree(srcdir, ignore_errors=False)
|
||||
locked_print(f"*** Building example {example} for board {board_name} ***")
|
||||
cwd: str | None = None
|
||||
shell: bool = False
|
||||
# Copy all files from the example directory to the "src" directory
|
||||
for src_file in example.rglob("*"):
|
||||
if src_file.is_file():
|
||||
if _fastled_js_is_parent_directory(src_file):
|
||||
# Skip the fastled_js folder, it's not needed for the build.
|
||||
continue
|
||||
src_dir = src_file.parent
|
||||
path = src_dir.relative_to(example)
|
||||
dst_dir = srcdir / path
|
||||
os.makedirs(dst_dir, exist_ok=True)
|
||||
locked_print(f"Copying {src_file} to {dst_dir / src_file.name}")
|
||||
os.makedirs(srcdir, exist_ok=True)
|
||||
shutil.copy(src_file, dst_dir / src_file.name)
|
||||
# libs = ["src", "ci"]
|
||||
if use_pio_run:
|
||||
# we have to copy a few folders of pio ci in order to get this to work.
|
||||
for lib in libs:
|
||||
project_libdir = Path(lib)
|
||||
assert project_libdir.exists()
|
||||
build_lib = builddir / "lib" / lib
|
||||
shutil.rmtree(build_lib, ignore_errors=True)
|
||||
shutil.copytree(project_libdir, build_lib)
|
||||
|
||||
cwd = str(builddir)
|
||||
cmd_list = [
|
||||
"pio",
|
||||
"run",
|
||||
]
|
||||
# in this case we need to manually copy the example to the src directory
|
||||
# because platformio doesn't support building a single file.
|
||||
# ino_file = example / f"{example.name}.ino"
|
||||
else:
|
||||
cmd_list = [
|
||||
"pio",
|
||||
"ci",
|
||||
"--board",
|
||||
real_board_name,
|
||||
*[f"--lib={lib}" for lib in libs],
|
||||
"--keep-build-dir",
|
||||
f"--build-dir={builddir.as_posix()}",
|
||||
]
|
||||
cmd_list.append(f"{example.as_posix()}/*ino")
|
||||
cmd_str = subprocess.list2cmdline(cmd_list)
|
||||
msg_lsit = [
|
||||
"\n\n******************************",
|
||||
f"* Running command in cwd: {cwd if cwd else os.getcwd()}",
|
||||
f"* {cmd_str}",
|
||||
"******************************\n",
|
||||
]
|
||||
msg = "\n".join(msg_lsit)
|
||||
locked_print(msg)
|
||||
result = subprocess.run(
|
||||
cmd_list,
|
||||
cwd=cwd,
|
||||
shell=shell,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
stdout = result.stdout
|
||||
# replace all instances of "lib/src" => "src" so intellisense can find the files
|
||||
# with one click.
|
||||
stdout = stdout.replace("lib/src", "src").replace("lib\\src", "src")
|
||||
locked_print(stdout)
|
||||
if result.returncode != 0:
|
||||
if not verbose_on_failure:
|
||||
ERROR_HAPPENED = True
|
||||
return False, stdout
|
||||
if ERROR_HAPPENED:
|
||||
return False, ""
|
||||
ERROR_HAPPENED = True
|
||||
locked_print(
|
||||
f"*** Error compiling example {example} for board {board_name} ***"
|
||||
)
|
||||
# re-running command with verbose output to see what the defines are.
|
||||
cmd_list.append("-v")
|
||||
cmd_str = subprocess.list2cmdline(cmd_list)
|
||||
msg_lsit = [
|
||||
"\n\n******************************",
|
||||
"* Re-running failed command but with verbose output:",
|
||||
f"* {cmd_str}",
|
||||
"******************************\n",
|
||||
]
|
||||
msg = "\n".join(msg_lsit)
|
||||
locked_print(msg)
|
||||
result = subprocess.run(
|
||||
cmd_list,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
stdout = result.stdout
|
||||
# replace all instances of "lib/src" => "src" so intellisense can find the files
|
||||
# with one click.
|
||||
stdout = stdout.replace("lib/src", "src").replace("lib\\src", "src")
|
||||
stdout = (
|
||||
stdout
|
||||
+ "\n\nThis is a second attempt, but with verbose output, look above for compiler errors.\n"
|
||||
)
|
||||
locked_print(stdout)
|
||||
return False, stdout
|
||||
locked_print(f"*** Finished building example {example} for board {board_name} ***")
|
||||
return True, stdout
|
||||
|
||||
|
||||
# Function to process task queues for each board
|
||||
def compile_examples(
|
||||
board: Board,
|
||||
examples: list[Path],
|
||||
build_dir: str | None,
|
||||
verbose_on_failure: bool,
|
||||
libs: list[str] | None,
|
||||
) -> tuple[bool, str]:
|
||||
"""Process the task queue for the given board."""
|
||||
global ERROR_HAPPENED # pylint: disable=global-statement
|
||||
board_name = board.board_name
|
||||
is_first = True
|
||||
for example in examples:
|
||||
example = example.relative_to(Path(".").resolve())
|
||||
if ERROR_HAPPENED:
|
||||
return True, ""
|
||||
locked_print(f"\n*** Building {example} for board {board_name} ***")
|
||||
if is_first:
|
||||
locked_print(
|
||||
f"*** Building for first example {example} board {board_name} ***"
|
||||
)
|
||||
if is_first and USE_FIRST_BUILD_LOCK:
|
||||
with FIRST_BUILD_LOCK:
|
||||
# Github runners are memory limited and the first job is the most
|
||||
# memory intensive since all the artifacts are being generated in parallel.
|
||||
success, message = compile_for_board_and_example(
|
||||
board=board,
|
||||
example=example,
|
||||
build_dir=build_dir,
|
||||
verbose_on_failure=verbose_on_failure,
|
||||
libs=libs,
|
||||
)
|
||||
else:
|
||||
success, message = compile_for_board_and_example(
|
||||
board=board,
|
||||
example=example,
|
||||
build_dir=build_dir,
|
||||
verbose_on_failure=verbose_on_failure,
|
||||
libs=libs,
|
||||
)
|
||||
is_first = False
|
||||
if not success:
|
||||
ERROR_HAPPENED = True
|
||||
return (
|
||||
False,
|
||||
f"Error building {example} for board {board_name}. stdout:\n{message}",
|
||||
)
|
||||
return True, ""
|
||||
157
libraries/FastLED/ci/ci/concurrent_run.py
Normal file
157
libraries/FastLED/ci/ci/concurrent_run.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import os
|
||||
import time
|
||||
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from ci.boards import Board # type: ignore
|
||||
from ci.compile_for_board import compile_examples, errors_happened
|
||||
from ci.cpu_count import cpu_count
|
||||
from ci.create_build_dir import create_build_dir
|
||||
from ci.locked_print import locked_print
|
||||
|
||||
# Board initialization doesn't take a lot of memory or cpu so it's safe to run in parallel
|
||||
PARRALLEL_PROJECT_INITIALIZATION = (
|
||||
os.environ.get("PARRALLEL_PROJECT_INITIALIZATION", "1") == "1"
|
||||
)
|
||||
|
||||
|
||||
def _banner_print(msg: str) -> None:
|
||||
"""Print a banner message."""
|
||||
# will produce
|
||||
#######
|
||||
# msg #
|
||||
#######
|
||||
lines = msg.splitlines()
|
||||
for line in lines:
|
||||
print("#" * (len(line) + 4))
|
||||
print(f"# {line} #")
|
||||
print("#" * (len(line) + 4))
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConcurrentRunArgs:
|
||||
projects: list[Board]
|
||||
examples: list[Path]
|
||||
skip_init: bool
|
||||
defines: list[str]
|
||||
extra_packages: list[str]
|
||||
libs: list[str] | None
|
||||
build_dir: str | None
|
||||
extra_scripts: str | None
|
||||
cwd: str | None
|
||||
board_dir: str | None
|
||||
build_flags: list[str] | None
|
||||
verbose: bool = False
|
||||
extra_examples: dict[Board, list[Path]] | None = None
|
||||
|
||||
|
||||
def concurrent_run(
|
||||
args: ConcurrentRunArgs,
|
||||
) -> int:
|
||||
projects = args.projects
|
||||
examples = args.examples
|
||||
skip_init = args.skip_init
|
||||
defines = args.defines
|
||||
extra_packages = args.extra_packages
|
||||
build_dir = args.build_dir
|
||||
extra_scripts = args.extra_scripts
|
||||
cwd = args.cwd
|
||||
start_time = time.time()
|
||||
first_project = projects[0]
|
||||
prev_cwd: str | None = None
|
||||
board_dir = args.board_dir
|
||||
libs = args.libs
|
||||
extra_examples: dict[Board, list[Path]] = args.extra_examples or {}
|
||||
if cwd:
|
||||
prev_cwd = os.getcwd()
|
||||
locked_print(f"Changing to directory {cwd}")
|
||||
os.chdir(cwd)
|
||||
|
||||
start_time = time.time()
|
||||
create_build_dir(
|
||||
board=first_project,
|
||||
defines=defines,
|
||||
no_install_deps=skip_init,
|
||||
extra_packages=extra_packages,
|
||||
build_dir=build_dir,
|
||||
board_dir=board_dir,
|
||||
build_flags=args.build_flags,
|
||||
extra_scripts=extra_scripts,
|
||||
)
|
||||
diff = time.time() - start_time
|
||||
|
||||
msg = f"Build directory created in {diff:.2f} seconds for board"
|
||||
locked_print(msg)
|
||||
|
||||
verbose = args.verbose
|
||||
# This is not memory/cpu bound but is instead network bound so we can run one thread
|
||||
# per board to speed up the process.
|
||||
parallel_init_workers = 1 if not PARRALLEL_PROJECT_INITIALIZATION else len(projects)
|
||||
# Initialize the build directories for all boards
|
||||
with ThreadPoolExecutor(max_workers=parallel_init_workers) as executor:
|
||||
future_to_board: dict[Future, Board] = {}
|
||||
for board in projects:
|
||||
future = executor.submit(
|
||||
create_build_dir,
|
||||
board,
|
||||
defines,
|
||||
skip_init,
|
||||
extra_packages,
|
||||
build_dir,
|
||||
board_dir,
|
||||
args.build_flags,
|
||||
extra_scripts,
|
||||
)
|
||||
future_to_board[future] = board
|
||||
for future in as_completed(future_to_board):
|
||||
board = future_to_board[future]
|
||||
success, msg = future.result()
|
||||
if not success:
|
||||
locked_print(
|
||||
f"Error initializing build_dir for board {board.board_name}:\n{msg}"
|
||||
)
|
||||
# cancel all other tasks
|
||||
for f in future_to_board:
|
||||
f.cancel()
|
||||
return 1
|
||||
else:
|
||||
locked_print(
|
||||
f"Finished initializing build_dir for board {board.board_name}"
|
||||
)
|
||||
init_end_time = time.time()
|
||||
init_time = (init_end_time - start_time) / 60
|
||||
locked_print(f"\nAll build directories initialized in {init_time:.2f} minutes.")
|
||||
errors: list[str] = []
|
||||
# Run the compilation process
|
||||
num_cpus = max(1, min(cpu_count(), len(projects)))
|
||||
with ThreadPoolExecutor(max_workers=num_cpus) as executor:
|
||||
future_to_board = {
|
||||
executor.submit(
|
||||
compile_examples,
|
||||
board,
|
||||
examples + extra_examples.get(board, []),
|
||||
build_dir,
|
||||
verbose,
|
||||
libs=libs,
|
||||
): board
|
||||
for board in projects
|
||||
}
|
||||
for future in as_completed(future_to_board):
|
||||
board = future_to_board[future]
|
||||
success, msg = future.result()
|
||||
if not success:
|
||||
msg = f"Compilation failed for board {board}: {msg}"
|
||||
errors.append(msg)
|
||||
locked_print(f"Compilation failed for board {board}: {msg}.\nStopping.")
|
||||
for f in future_to_board:
|
||||
f.cancel()
|
||||
break
|
||||
if prev_cwd:
|
||||
locked_print(f"Changing back to directory {prev_cwd}")
|
||||
os.chdir(prev_cwd)
|
||||
if errors_happened():
|
||||
locked_print("\nDone. Errors happened during compilation.")
|
||||
locked_print("\n".join(errors))
|
||||
return 1
|
||||
return 0
|
||||
8
libraries/FastLED/ci/ci/cpu_count.py
Normal file
8
libraries/FastLED/ci/ci/cpu_count.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import os
|
||||
|
||||
|
||||
def cpu_count() -> int:
|
||||
"""Get the number of CPUs."""
|
||||
if "GITHUB_ACTIONS" in os.environ:
|
||||
return 4
|
||||
return os.cpu_count() or 1
|
||||
223
libraries/FastLED/ci/ci/create_build_dir.py
Normal file
223
libraries/FastLED/ci/ci/create_build_dir.py
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
from ci.boards import Board # type: ignore
|
||||
from ci.locked_print import locked_print
|
||||
|
||||
|
||||
def _install_global_package(package: str) -> None:
|
||||
# example pio pkg -g -p "https://github.com/maxgerhardt/platform-raspberrypi.git".
|
||||
locked_print(f"*** Installing {package} ***")
|
||||
cmd_list = [
|
||||
"pio",
|
||||
"pkg",
|
||||
"install",
|
||||
"-g",
|
||||
"-p",
|
||||
package,
|
||||
]
|
||||
cmd_str = subprocess.list2cmdline(cmd_list)
|
||||
locked_print(f"Running command:\n\n{cmd_str}\n\n")
|
||||
result = subprocess.run(
|
||||
cmd_str,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
locked_print(result.stdout)
|
||||
locked_print(f"*** Finished installing {package} ***")
|
||||
|
||||
|
||||
def insert_tool_aliases(meta_json: dict[str, dict]) -> None:
|
||||
for board in meta_json.keys():
|
||||
aliases: dict[str, str | None] = {}
|
||||
cc_path = meta_json[board].get("cc_path")
|
||||
cc_path = Path(cc_path) if cc_path else None
|
||||
if cc_path:
|
||||
# get the prefix of the base name of the compiler.
|
||||
cc_base = cc_path.name
|
||||
parent = cc_path.parent
|
||||
prefix = cc_base.split("gcc")[0]
|
||||
suffix = cc_path.suffix
|
||||
# create the aliases
|
||||
for tool in [
|
||||
"gcc",
|
||||
"g++",
|
||||
"ar",
|
||||
"objcopy",
|
||||
"objdump",
|
||||
"size",
|
||||
"nm",
|
||||
"ld",
|
||||
"as",
|
||||
"ranlib",
|
||||
"strip",
|
||||
"c++filt",
|
||||
"readelf",
|
||||
"addr2line",
|
||||
]:
|
||||
name = f"{prefix}{tool}" + suffix
|
||||
tool_path = Path(str(parent / name))
|
||||
if tool_path.exists():
|
||||
aliases[tool] = str(tool_path)
|
||||
else:
|
||||
aliases[tool] = None
|
||||
meta_json[board]["aliases"] = aliases
|
||||
|
||||
|
||||
def remove_readonly(func, path, _):
|
||||
"Clear the readonly bit and reattempt the removal"
|
||||
if os.name == "nt":
|
||||
os.system(f"attrib -r {path}")
|
||||
else:
|
||||
try:
|
||||
os.chmod(path, 0o777)
|
||||
except Exception:
|
||||
print(f"Error removing readonly attribute from {path}")
|
||||
|
||||
func(path)
|
||||
|
||||
|
||||
def create_build_dir(
|
||||
board: Board,
|
||||
defines: list[str],
|
||||
no_install_deps: bool,
|
||||
extra_packages: list[str],
|
||||
build_dir: str | None,
|
||||
board_dir: str | None,
|
||||
build_flags: list[str] | None,
|
||||
extra_scripts: str | None,
|
||||
) -> tuple[bool, str]:
|
||||
"""Create the build directory for the given board."""
|
||||
# filter out "web" board because it's not a real board.
|
||||
if board.board_name == "web":
|
||||
locked_print(f"Skipping web target for board {board.board_name}")
|
||||
return True, ""
|
||||
if board.defines:
|
||||
defines.extend(board.defines)
|
||||
# remove duplicates
|
||||
defines = list(set(defines))
|
||||
board_name = board.board_name
|
||||
real_board_name = board.get_real_board_name()
|
||||
locked_print(f"*** Initializing environment for {board_name} ***")
|
||||
# builddir = Path(build_dir) / board if build_dir else Path(".build") / board
|
||||
build_dir = build_dir or ".build"
|
||||
builddir = Path(build_dir) / board_name
|
||||
builddir.mkdir(parents=True, exist_ok=True)
|
||||
# if lib directory (where FastLED lives) exists, remove it. This is necessary to run on
|
||||
# recycled build directories for fastled to update. This is a fast operation.
|
||||
srcdir = builddir / "lib"
|
||||
if srcdir.exists():
|
||||
shutil.rmtree(srcdir, onerror=remove_readonly)
|
||||
platformio_ini = builddir / "platformio.ini"
|
||||
if platformio_ini.exists():
|
||||
try:
|
||||
platformio_ini.unlink()
|
||||
except OSError as e:
|
||||
locked_print(f"Error removing {platformio_ini}: {e}")
|
||||
if board_dir:
|
||||
dst_dir = builddir / "boards"
|
||||
if dst_dir.exists():
|
||||
shutil.rmtree(dst_dir)
|
||||
shutil.copytree(str(board_dir), str(builddir / "boards"))
|
||||
if board.platform_needs_install:
|
||||
if board.platform:
|
||||
try:
|
||||
_install_global_package(board.platform)
|
||||
except subprocess.CalledProcessError as e:
|
||||
stdout = e.stdout
|
||||
return False, stdout
|
||||
else:
|
||||
warnings.warn("Platform install was specified but no platform was given.")
|
||||
|
||||
cmd_list = [
|
||||
"pio",
|
||||
"project",
|
||||
"init",
|
||||
"--project-dir",
|
||||
builddir.as_posix(),
|
||||
"--board",
|
||||
real_board_name,
|
||||
]
|
||||
if board.platform:
|
||||
cmd_list.append(f"--project-option=platform={board.platform}")
|
||||
if board.platform_packages:
|
||||
cmd_list.append(f"--project-option=platform_packages={board.platform_packages}")
|
||||
if board.framework:
|
||||
cmd_list.append(f"--project-option=framework={board.framework}")
|
||||
if board.board_build_core:
|
||||
cmd_list.append(f"--project-option=board_build.core={board.board_build_core}")
|
||||
if board.board_build_filesystem_size:
|
||||
cmd_list.append(
|
||||
f"--project-option=board_build.filesystem_size={board.board_build_filesystem_size}"
|
||||
)
|
||||
if build_flags is not None:
|
||||
for build_flag in build_flags:
|
||||
cmd_list.append(f"--project-option=build_flags={build_flag}")
|
||||
if defines:
|
||||
build_flags_str = " ".join(f"-D{define}" for define in defines)
|
||||
cmd_list.append(f"--project-option=build_flags={build_flags_str}")
|
||||
if extra_packages:
|
||||
cmd_list.append(f'--project-option=lib_deps={",".join(extra_packages)}')
|
||||
if no_install_deps:
|
||||
cmd_list.append("--no-install-dependencies")
|
||||
if extra_scripts:
|
||||
p = Path(extra_scripts)
|
||||
cmd_list.append(f"--project-option=extra_scripts={p.resolve()}")
|
||||
cmd_str = subprocess.list2cmdline(cmd_list)
|
||||
locked_print(f"\n\nRunning command:\n {cmd_str}\n")
|
||||
result = subprocess.run(
|
||||
cmd_str,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
stdout = result.stdout
|
||||
locked_print(result.stdout)
|
||||
if result.returncode != 0:
|
||||
locked_print(f"*** Error setting up board {board_name} ***")
|
||||
return False, stdout
|
||||
locked_print(f"*** Finished initializing environment for board {board_name} ***")
|
||||
# dumping enviorment variables to help debug.
|
||||
# this is the command: pio run --target envdump
|
||||
cwd = str(builddir.resolve())
|
||||
cmd_list = [
|
||||
"pio",
|
||||
"project",
|
||||
"metadata",
|
||||
"--json-output",
|
||||
]
|
||||
cmd_str = subprocess.list2cmdline(cmd_list)
|
||||
stdout = subprocess.run(
|
||||
cmd_list,
|
||||
cwd=cwd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
check=False,
|
||||
).stdout
|
||||
|
||||
try:
|
||||
data = json.loads(stdout)
|
||||
# now dump the values to the file at the root of the build directory.
|
||||
matadata_json = builddir / "build_info.json"
|
||||
try:
|
||||
insert_tool_aliases(data)
|
||||
formatted = json.dumps(data, indent=4, sort_keys=True)
|
||||
with open(matadata_json, "w") as f:
|
||||
f.write(formatted)
|
||||
except Exception:
|
||||
with open(matadata_json, "w") as f:
|
||||
f.write(stdout)
|
||||
except json.JSONDecodeError:
|
||||
msg = f"build_info.json will not be generated because of error because stdout does not look like a json file:\n#### STDOUT ####\n{stdout}\n#### END STDOUT ####\n"
|
||||
locked_print(msg)
|
||||
return True, stdout
|
||||
205
libraries/FastLED/ci/ci/elf.py
Normal file
205
libraries/FastLED/ci/ci/elf.py
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_command(command: list, show_output=False):
|
||||
"""
|
||||
Run a command using subprocess and capture the output.
|
||||
|
||||
Args:
|
||||
command (list): Command to run.
|
||||
show_output (bool): Print command and its output if True.
|
||||
|
||||
Returns:
|
||||
str: Standard output of the command.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the command fails.
|
||||
"""
|
||||
if show_output:
|
||||
print(f"Running command: {' '.join(command)}")
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"Command failed: {' '.join(command)}\n{result.stderr}")
|
||||
if show_output and result.stdout:
|
||||
print(f"Command output: {result.stdout}")
|
||||
return result.stdout
|
||||
|
||||
|
||||
def analyze_elf_file(objdump_path: Path, cppfilt_path: Path, elf_file: Path):
|
||||
"""
|
||||
Analyze the ELF file using objdump to display its contents.
|
||||
|
||||
Args:
|
||||
objdump_path (Path): Path to the objdump executable.
|
||||
cppfilt_path (Path): Path to the c++filt executable.
|
||||
elf_file (Path): Path to the ELF file.
|
||||
"""
|
||||
command = [str(objdump_path), "-h", str(elf_file)] # "-h" option shows headers.
|
||||
print(f"Analyzing ELF file: {elf_file}")
|
||||
output = run_command(command, show_output=True)
|
||||
print("\nELF File Analysis:")
|
||||
print(output)
|
||||
list_symbols_and_sizes(objdump_path, cppfilt_path, elf_file)
|
||||
|
||||
|
||||
def cpp_filt(cppfilt_path: Path, input_text: str) -> str:
|
||||
"""
|
||||
Demangle C++ symbols using c++filt.
|
||||
|
||||
Args:
|
||||
cppfilt_path (Path): Path to c++filt executable.
|
||||
input_text (str): Text to demangle.
|
||||
|
||||
Returns:
|
||||
str: Demangled text.
|
||||
"""
|
||||
command = [str(cppfilt_path), "-t", "-n"]
|
||||
print(f"Running c++filt on input text with {cppfilt_path}")
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
stdout, stderr = process.communicate(input=input_text)
|
||||
if process.returncode != 0:
|
||||
raise RuntimeError(f"Error running c++filt: {stderr}")
|
||||
return stdout
|
||||
|
||||
|
||||
def dump_symbol_sizes(nm_path: Path, cpp_filt_path: Path, elf_file: Path) -> str:
|
||||
nm_command = [
|
||||
str(nm_path),
|
||||
"-S",
|
||||
"--size-sort",
|
||||
str(elf_file),
|
||||
]
|
||||
print(f"Listing symbols and sizes in ELF file: {elf_file}")
|
||||
print("Running command: ", " ".join(nm_command))
|
||||
nm_result = subprocess.run(
|
||||
nm_command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
if nm_result.returncode != 0:
|
||||
raise RuntimeError(f"Error running nm command: {nm_result.stderr}")
|
||||
|
||||
cpp_filt_command = [str(cpp_filt_path), "--no-strip-underscore"]
|
||||
print("Running c++filt command: ", " ".join(cpp_filt_command))
|
||||
cpp_filt_result = subprocess.run(
|
||||
cpp_filt_command,
|
||||
input=nm_result.stdout,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
if cpp_filt_result.returncode != 0:
|
||||
raise RuntimeError(f"Error running c++filt command: {cpp_filt_result.stderr}")
|
||||
|
||||
# now reverse sort the lines
|
||||
lines = cpp_filt_result.stdout.splitlines()
|
||||
|
||||
@dataclass
|
||||
class Entry:
|
||||
address: str
|
||||
size: int
|
||||
everything_else: str
|
||||
|
||||
def parse_line(line: str) -> Entry:
|
||||
address, size, *rest = line.split()
|
||||
return Entry(address, int(size, 16), " ".join(rest))
|
||||
|
||||
data: list[Entry] = [parse_line(line) for line in lines]
|
||||
data.sort(key=lambda x: x.size, reverse=True)
|
||||
lines = [f"{d.size:6d} {d.everything_else}" for d in data]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def demangle_symbol(cppfilt_path: Path, symbol: str) -> str:
|
||||
"""
|
||||
Demangle a C++ symbol using c++filt.
|
||||
|
||||
Args:
|
||||
cppfilt_path (Path): Path to the c++filt executable.
|
||||
symbol (str): The symbol to demangle.
|
||||
|
||||
Returns:
|
||||
str: The demangled symbol.
|
||||
"""
|
||||
command = [str(cppfilt_path), symbol]
|
||||
return run_command(command, show_output=False).strip()
|
||||
|
||||
|
||||
def list_symbols_and_sizes(objdump_path: Path, cppfilt_path: Path, elf_file: Path):
|
||||
"""
|
||||
List all symbols and their sizes from the ELF file using objdump.
|
||||
|
||||
Args:
|
||||
objdump_path (Path): Path to the objdump executable.
|
||||
cppfilt_path (Path): Path to the c++filt executable.
|
||||
elf_file (Path): Path to the ELF file.
|
||||
"""
|
||||
command = [
|
||||
str(objdump_path),
|
||||
"-t",
|
||||
str(elf_file),
|
||||
] # "-t" option lists symbols with sizes.
|
||||
print(f"Listing symbols and sizes in ELF file: {elf_file}")
|
||||
output = run_command(command, show_output=False)
|
||||
|
||||
symbols = []
|
||||
for line in output.splitlines():
|
||||
parts = line.split()
|
||||
# Expected parts length can vary, check if size and section index (parts[2] & parts[4]) are valid
|
||||
if len(parts) > 5 and parts[2].isdigit() and parts[4].startswith("."):
|
||||
symbol = {
|
||||
"name": parts[-1],
|
||||
"size": int(parts[2], 16), # size is in hex format
|
||||
"section": parts[4],
|
||||
"type": parts[3],
|
||||
}
|
||||
symbols.append(symbol)
|
||||
|
||||
if symbols:
|
||||
print("\nSymbols and Sizes in ELF File:")
|
||||
for symbol in symbols:
|
||||
demangled_name = demangle_symbol(cppfilt_path, symbol["name"])
|
||||
print(
|
||||
f"Symbol: {demangled_name}, Size: {symbol['size']} bytes, Type: {symbol['type']}, Section: {symbol['section']}"
|
||||
)
|
||||
else:
|
||||
print("No symbols found or unable to parse symbols correctly.")
|
||||
|
||||
|
||||
def check_elf_format(objdump_path: Path, elf_file: Path):
|
||||
"""
|
||||
Check the format of the ELF file using objdump to confirm it's being read correctly.
|
||||
|
||||
Args:
|
||||
objdump_path (Path): Path to the objdump executable.
|
||||
elf_file (Path): Path to the ELF file.
|
||||
"""
|
||||
command = [str(objdump_path), "-f", str(elf_file)]
|
||||
print(f"Checking ELF file format: {elf_file}")
|
||||
output = run_command(command, show_output=True)
|
||||
print("\nELF File Format Information:")
|
||||
print(output)
|
||||
|
||||
|
||||
def check_section_contents(objdump_path: Path, elf_file: Path):
|
||||
"""
|
||||
Dump the contents of all sections in the ELF file using objdump.
|
||||
|
||||
Args:
|
||||
objdump_path (Path): Path to the objdump executable.
|
||||
elf_file (Path): Path to the ELF file.
|
||||
"""
|
||||
command = [str(objdump_path), "-s", str(elf_file)]
|
||||
print(f"Dumping all sections of ELF file: {elf_file}")
|
||||
output = run_command(command, show_output=True)
|
||||
print("\nELF File Sections Content:")
|
||||
print(output)
|
||||
11
libraries/FastLED/ci/ci/locked_print.py
Normal file
11
libraries/FastLED/ci/ci/locked_print.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
from threading import Lock
|
||||
|
||||
PRINT_LOCK = Lock()
|
||||
|
||||
|
||||
def locked_print(string: str):
|
||||
"""Print with a lock to prevent garbled output for multiple threads."""
|
||||
with PRINT_LOCK:
|
||||
# print only prints so much, break up the string into lines
|
||||
for line in string.splitlines():
|
||||
print(line)
|
||||
19
libraries/FastLED/ci/ci/map_dump.py
Normal file
19
libraries/FastLED/ci/ci/map_dump.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def map_dump(map_file: Path) -> None:
|
||||
# os.system("uv run fpvgcc ci/tests/uno/firmware.map --lmap root")
|
||||
|
||||
cmds = [
|
||||
f"uv run fpvgcc {map_file} --sar",
|
||||
f"uv run fpvgcc {map_file} --lmap root",
|
||||
f"uv run fpvgcc {map_file} --uf",
|
||||
f"uv run fpvgcc {map_file} --uregions",
|
||||
# --usections
|
||||
f"uv run fpvgcc {map_file} --usections",
|
||||
f"uv run fpvgcc {map_file} --la",
|
||||
]
|
||||
for cmd in cmds:
|
||||
print("\nRunning command: ", cmd)
|
||||
os.system(cmd)
|
||||
5
libraries/FastLED/ci/ci/paths.py
Normal file
5
libraries/FastLED/ci/ci/paths.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from pathlib import Path
|
||||
|
||||
_HERE = Path(__file__).resolve().parent
|
||||
PROJECT_ROOT = _HERE.parent.parent
|
||||
BUILD = PROJECT_ROOT / ".build"
|
||||
139
libraries/FastLED/ci/ci/running_process.py
Normal file
139
libraries/FastLED/ci/ci/running_process.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
import subprocess
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class RunningProcess:
|
||||
"""
|
||||
A class to manage and stream output from a running subprocess.
|
||||
|
||||
This class provides functionality to execute shell commands, stream their output
|
||||
in real-time, and control the subprocess execution.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
command: str | list[str],
|
||||
cwd: Path | None = None,
|
||||
check: bool = False,
|
||||
auto_run: bool = True,
|
||||
echo: bool = True,
|
||||
):
|
||||
"""
|
||||
Initialize the RunningProcess instance. Note that stderr is merged into stdout!!
|
||||
|
||||
Args:
|
||||
command (str): The command to execute.
|
||||
cwd (Path | None): The working directory to execute the command in.
|
||||
check (bool): If True, raise an exception if the command returns a non-zero exit code.
|
||||
auto_run (bool): If True, automatically run the command when the instance is created.
|
||||
echo (bool): If True, print the output of the command to the console in real-time.
|
||||
"""
|
||||
if isinstance(command, list):
|
||||
command = subprocess.list2cmdline(command)
|
||||
self.command = command
|
||||
self.cwd = str(cwd) if cwd is not None else None
|
||||
self.buffer: list[str] = []
|
||||
self.proc: subprocess.Popen | None = None
|
||||
self.check = check
|
||||
self.auto_run = auto_run
|
||||
self.echo = echo
|
||||
self.reader_thread: threading.Thread | None = None
|
||||
self.shutdown: threading.Event = threading.Event()
|
||||
if auto_run:
|
||||
self.run()
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Execute the command and stream its output in real-time.
|
||||
|
||||
Returns:
|
||||
str: The full output of the command.
|
||||
|
||||
Raises:
|
||||
subprocess.CalledProcessError: If the command returns a non-zero exit code.
|
||||
"""
|
||||
|
||||
self.proc = subprocess.Popen(
|
||||
self.command,
|
||||
shell=True,
|
||||
cwd=self.cwd,
|
||||
bufsize=256,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, # Merge stderr into stdout
|
||||
text=True, # Automatically decode bytes to str
|
||||
)
|
||||
|
||||
def output_reader():
|
||||
try:
|
||||
assert self.proc is not None
|
||||
assert self.proc.stdout is not None
|
||||
for line in iter(self.proc.stdout.readline, ""):
|
||||
if self.shutdown.is_set():
|
||||
break
|
||||
line = line.rstrip()
|
||||
if self.echo:
|
||||
print(line) # Print to console in real time
|
||||
self.buffer.append(line)
|
||||
finally:
|
||||
if self.proc and self.proc.stdout:
|
||||
self.proc.stdout.close()
|
||||
|
||||
# Start output reader thread
|
||||
self.reader_thread = threading.Thread(target=output_reader, daemon=True)
|
||||
self.reader_thread.start()
|
||||
|
||||
def wait(self) -> int:
|
||||
"""
|
||||
Wait for the process to complete.
|
||||
|
||||
Raises:
|
||||
ValueError: If the process hasn't been started.
|
||||
"""
|
||||
if self.proc is None:
|
||||
raise ValueError("Process is not running.")
|
||||
rtn = self.proc.wait()
|
||||
assert self.reader_thread is not None
|
||||
self.reader_thread.join(timeout=1)
|
||||
return rtn
|
||||
|
||||
def kill(self) -> None:
|
||||
"""
|
||||
Immediately terminate the process with SIGKILL.
|
||||
|
||||
Raises:
|
||||
ValueError: If the process hasn't been started.
|
||||
"""
|
||||
if self.proc is None:
|
||||
return
|
||||
self.shutdown.set()
|
||||
self.proc.kill()
|
||||
|
||||
def terminate(self) -> None:
|
||||
"""
|
||||
Gracefully terminate the process with SIGTERM.
|
||||
|
||||
Raises:
|
||||
ValueError: If the process hasn't been started.
|
||||
"""
|
||||
if self.proc is None:
|
||||
raise ValueError("Process is not running.")
|
||||
self.shutdown.set()
|
||||
self.proc.terminate()
|
||||
|
||||
@property
|
||||
def returncode(self) -> int | None:
|
||||
if self.proc is None:
|
||||
return None
|
||||
return self.proc.returncode
|
||||
|
||||
@property
|
||||
def stdout(self) -> str:
|
||||
"""
|
||||
Get the complete stdout output of the process.
|
||||
|
||||
Returns:
|
||||
str: The complete stdout output as a string, or None if process hasn't completed.
|
||||
"""
|
||||
self.wait()
|
||||
return "\n".join(self.buffer)
|
||||
205
libraries/FastLED/ci/ci/tools.py
Normal file
205
libraries/FastLED/ci/ci/tools.py
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from ci.paths import BUILD
|
||||
|
||||
|
||||
@dataclass
|
||||
class Tools:
|
||||
as_path: Path
|
||||
ld_path: Path
|
||||
objcopy_path: Path
|
||||
objdump_path: Path
|
||||
cpp_filt_path: Path
|
||||
nm_path: Path
|
||||
|
||||
|
||||
def load_tools(build_info_path: Path) -> Tools:
|
||||
build_info = json.loads(build_info_path.read_text())
|
||||
board_info = build_info[next(iter(build_info))]
|
||||
aliases = board_info["aliases"]
|
||||
as_path = Path(aliases["as"])
|
||||
ld_path = Path(aliases["ld"])
|
||||
objcopy_path = Path(aliases["objcopy"])
|
||||
objdump_path = Path(aliases["objdump"])
|
||||
cpp_filt_path = Path(aliases["c++filt"])
|
||||
nm_path = Path(aliases["nm"])
|
||||
if sys.platform == "win32":
|
||||
as_path = as_path.with_suffix(".exe")
|
||||
ld_path = ld_path.with_suffix(".exe")
|
||||
objcopy_path = objcopy_path.with_suffix(".exe")
|
||||
objdump_path = objdump_path.with_suffix(".exe")
|
||||
cpp_filt_path = cpp_filt_path.with_suffix(".exe")
|
||||
nm_path = nm_path.with_suffix(".exe")
|
||||
out = Tools(as_path, ld_path, objcopy_path, objdump_path, cpp_filt_path, nm_path)
|
||||
tools = [as_path, ld_path, objcopy_path, objdump_path, cpp_filt_path, nm_path]
|
||||
for tool in tools:
|
||||
if not tool.exists():
|
||||
raise FileNotFoundError(f"Tool not found: {tool}")
|
||||
return out
|
||||
|
||||
|
||||
def _list_builds() -> list[Path]:
|
||||
str_paths = os.listdir(BUILD)
|
||||
paths = [BUILD / p for p in str_paths]
|
||||
dirs = [p for p in paths if p.is_dir()]
|
||||
return dirs
|
||||
|
||||
|
||||
def _check_build(build: Path) -> bool:
|
||||
# 1. should contain a build_info.json file
|
||||
# 2. should contain a .pio/build directory
|
||||
has_build_info = (build / "build_info.json").exists()
|
||||
has_pio_build = (build / ".pio" / "build").exists()
|
||||
return has_build_info and has_pio_build
|
||||
|
||||
|
||||
def _prompt_build() -> Path:
|
||||
builds = _list_builds()
|
||||
if not builds:
|
||||
print("Error: No builds found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print("Select a build:")
|
||||
for i, build in enumerate(builds):
|
||||
print(f" [{i}]: {build}")
|
||||
while True:
|
||||
try:
|
||||
which = int(input("Enter the number of the build to use: "))
|
||||
if 0 <= which < len(builds):
|
||||
valid = _check_build(BUILD / builds[which])
|
||||
if valid:
|
||||
return BUILD / builds[which]
|
||||
print("Error: Invalid build", file=sys.stderr)
|
||||
else:
|
||||
print("Error: Invalid selection", file=sys.stderr)
|
||||
continue
|
||||
except ValueError:
|
||||
print("Error: Invalid input", file=sys.stderr)
|
||||
continue
|
||||
|
||||
|
||||
def _prompt_object_file(build: Path) -> Path:
|
||||
# Look for object files in .pio/build directory
|
||||
build_dir = build / ".pio" / "build"
|
||||
object_files = []
|
||||
|
||||
# Walk through build directory to find .o files
|
||||
for root, _, files in os.walk(build_dir):
|
||||
for file in files:
|
||||
if file.endswith(".o") and "FrameworkArduino" not in file:
|
||||
full_path = Path(root) / file
|
||||
if "FrameworkArduino" not in full_path.parts:
|
||||
object_files.append(full_path)
|
||||
|
||||
if not object_files:
|
||||
print("Error: No object files found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("\nSelect an object file:")
|
||||
for i, obj_file in enumerate(object_files):
|
||||
print(f" [{i}]: {obj_file.relative_to(build_dir)}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
which = int(input("Enter the number of the object file to use: "))
|
||||
if 0 <= which < len(object_files):
|
||||
return object_files[which]
|
||||
print("Error: Invalid selection", file=sys.stderr)
|
||||
except ValueError:
|
||||
print("Error: Invalid input", file=sys.stderr)
|
||||
continue
|
||||
|
||||
|
||||
def cli() -> None:
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Dump object file information using build tools"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"build_path",
|
||||
type=Path,
|
||||
nargs="?",
|
||||
help="Path to build directory containing build info JSON file",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--symbols", action="store_true", help="Dump symbol table using nm"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--disassemble", action="store_true", help="Dump disassembly using objdump"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
build_path = args.build_path
|
||||
symbols = args.symbols
|
||||
disassemble = args.disassemble
|
||||
|
||||
# Check if object file was provided and exists
|
||||
if build_path is None:
|
||||
build_path = _prompt_build()
|
||||
else:
|
||||
if not _check_build(build_path):
|
||||
print("Error: Invalid build directory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
assert build_path is not None
|
||||
assert build_path
|
||||
|
||||
build_info_path = build_path / "build_info.json"
|
||||
assert build_info_path.exists(), f"File not found: {build_info_path}"
|
||||
|
||||
tools = load_tools(build_info_path)
|
||||
|
||||
if not symbols and not disassemble:
|
||||
while True:
|
||||
print(
|
||||
"Error: Please specify at least one action to perform", file=sys.stderr
|
||||
)
|
||||
action = input(
|
||||
"Enter 's' to dump symbols, 'd' to disassemble, or 'q' to quit: "
|
||||
)
|
||||
if action == "s":
|
||||
symbols = True
|
||||
break
|
||||
elif action == "d":
|
||||
disassemble = True
|
||||
break
|
||||
elif action == "q":
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("Error: Invalid action", file=sys.stderr)
|
||||
|
||||
object_file = _prompt_object_file(build_path)
|
||||
if symbols:
|
||||
import subprocess
|
||||
|
||||
cmd_str = subprocess.list2cmdline(
|
||||
[str(tools.objdump_path), str(object_file), "--syms"]
|
||||
)
|
||||
print(f"Running command: {cmd_str}")
|
||||
subprocess.run([str(tools.objdump_path), str(object_file)])
|
||||
|
||||
if disassemble:
|
||||
import subprocess
|
||||
|
||||
cmd_str = subprocess.list2cmdline(
|
||||
[str(tools.objdump_path), "-d", str(object_file)]
|
||||
)
|
||||
print(f"Running command: {cmd_str}")
|
||||
subprocess.run([str(tools.objdump_path), "-d", str(object_file)])
|
||||
|
||||
if not (symbols or disassemble):
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
cli()
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting...")
|
||||
sys.exit(1)
|
||||
58
libraries/FastLED/ci/compiled_size.py
Normal file
58
libraries/FastLED/ci/compiled_size.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _get_board_info(path: Path) -> dict:
|
||||
build_info = json.loads(path.read_text())
|
||||
assert build_info.keys(), f"No boards found in {build_info}"
|
||||
assert (
|
||||
len(build_info.keys()) == 1
|
||||
), f"Multiple boards found in {build_info}, so correct board should be specified"
|
||||
return build_info[next(iter(build_info))]
|
||||
|
||||
|
||||
def check_firmware_size(board: str) -> int:
|
||||
root_build_dir = Path(".build") / board
|
||||
build_info_json = root_build_dir / "build_info.json"
|
||||
board_info = _get_board_info(build_info_json)
|
||||
assert board_info, f"Board {board} not found in {build_info_json}"
|
||||
prog_path = Path(board_info["prog_path"])
|
||||
base_path = prog_path.parent
|
||||
suffixes = [".bin", ".hex", ".uf2"]
|
||||
firmware: Path
|
||||
for suffix in suffixes:
|
||||
firmware = base_path / f"firmware{suffix}"
|
||||
if firmware.exists():
|
||||
break
|
||||
else:
|
||||
msg = (
|
||||
", ".join([f"firmware{suffix}" for suffix in suffixes])
|
||||
+ f" not found in {base_path}"
|
||||
)
|
||||
raise FileNotFoundError(msg)
|
||||
return firmware.stat().st_size
|
||||
|
||||
|
||||
def main(board: str):
|
||||
try:
|
||||
size = check_firmware_size(board)
|
||||
print(f"Firmware size for {board}: {size} bytes")
|
||||
except FileNotFoundError as e:
|
||||
print(f"Error: {e}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"Error: Unable to parse build_info.json for {board}")
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check FastLED firmware size for the specified board."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--board", type=str, required=True, help="Board to check firmware size for"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args.board)
|
||||
233
libraries/FastLED/ci/compiled_size_history.py
Normal file
233
libraries/FastLED/ci/compiled_size_history.py
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import dateutil.parser # type: ignore
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def run_command(command):
|
||||
process = subprocess.Popen(
|
||||
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
|
||||
)
|
||||
output, error = process.communicate()
|
||||
return output.decode("utf-8"), error.decode("utf-8")
|
||||
|
||||
|
||||
def step_back_commits(steps):
|
||||
step_back_command = f"git reset --hard HEAD~{steps}"
|
||||
output, error = run_command(step_back_command)
|
||||
if error:
|
||||
print(f"Error stepping back {steps} commit(s): {error}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def check_firmware_size(board: str) -> int:
|
||||
root_build_dir = Path(".build") / board
|
||||
build_info_json = root_build_dir / "build_info.json"
|
||||
build_info = json.loads(build_info_json.read_text())
|
||||
board_info = build_info.get(board)
|
||||
assert board_info, f"Board {board} not found in {build_info_json}"
|
||||
prog_path = Path(board_info["prog_path"])
|
||||
base_path = prog_path.parent
|
||||
suffixes = [".bin", ".hex", ".uf2"]
|
||||
firmware: Path
|
||||
for suffix in suffixes:
|
||||
firmware = base_path / f"firmware{suffix}"
|
||||
if firmware.exists():
|
||||
break
|
||||
else:
|
||||
msg = (
|
||||
", ".join([f"firmware{suffix}" for suffix in suffixes])
|
||||
+ f" not found in {base_path}"
|
||||
)
|
||||
raise FileNotFoundError(msg)
|
||||
size_command = f"du -b {firmware}"
|
||||
output, error = run_command(size_command)
|
||||
if error:
|
||||
print(f"Error checking firmware size: {error}")
|
||||
return -1
|
||||
size_in_bytes = output.strip().split()[0]
|
||||
return int(size_in_bytes)
|
||||
|
||||
|
||||
def get_commit_hash():
|
||||
hash_command = "git rev-parse HEAD"
|
||||
output, error = run_command(hash_command)
|
||||
if error:
|
||||
print(f"Error getting commit hash: {error}")
|
||||
return None
|
||||
return output.strip()
|
||||
|
||||
|
||||
def get_commit_date(commit_hash):
|
||||
date_command = f"git show -s --format=%ci {commit_hash}"
|
||||
output, error = run_command(date_command)
|
||||
if error:
|
||||
print(f"Error getting commit date: {error}")
|
||||
return None
|
||||
return dateutil.parser.parse(output.strip()).isoformat()
|
||||
|
||||
|
||||
def main(
|
||||
board: str,
|
||||
num_commits: int,
|
||||
skip_step: int,
|
||||
start_commit: str | None = None,
|
||||
end_commit: str | None = None,
|
||||
):
|
||||
# change to the script dir
|
||||
os.chdir(str(HERE))
|
||||
# Create tmp directory if it doesn't exist
|
||||
|
||||
if os.path.exists("tmp"):
|
||||
shutil.rmtree("tmp")
|
||||
os.makedirs("tmp", exist_ok=True)
|
||||
|
||||
# Change to the tmp directory
|
||||
os.chdir("tmp")
|
||||
|
||||
# 1. Git clone FastLED repository
|
||||
print("Cloning FastLED repository...")
|
||||
clone_command = "git clone https://github.com/FastLED/FastLED.git"
|
||||
output, error = run_command(clone_command)
|
||||
# if error:
|
||||
# print(f"Error cloning repository: {error}")
|
||||
# os.chdir("..")
|
||||
# return
|
||||
|
||||
# Change to the FastLED directory
|
||||
os.chdir("FastLED")
|
||||
|
||||
# Checkout the latest commit
|
||||
run_command("git checkout master")
|
||||
|
||||
# If end_commit is specified, checkout that commit
|
||||
# if end_commit:
|
||||
# print(f"Checking out end commit: {end_commit}")
|
||||
# checkout_command = f"git checkout {end_commit}"
|
||||
# output, error = run_command(checkout_command)
|
||||
# #if error:
|
||||
# # print(f"Error checking out end commit: {error}")
|
||||
# # return
|
||||
|
||||
# Prepare CSV file
|
||||
csv_filename = "../../firmware_sizes.csv"
|
||||
with open(csv_filename, "w", newline="") as csvfile:
|
||||
csvwriter = csv.writer(csvfile)
|
||||
csvwriter.writerow(["datetime", "commit_hash", "binary_size"])
|
||||
|
||||
commits_checked = 0
|
||||
first_iteration = True
|
||||
while True:
|
||||
current_commit = get_commit_hash()
|
||||
|
||||
if first_iteration and start_commit:
|
||||
first_iteration = False
|
||||
while True:
|
||||
if current_commit == start_commit:
|
||||
break
|
||||
if not step_back_commits(1):
|
||||
break
|
||||
current_commit = get_commit_hash()
|
||||
|
||||
if num_commits and commits_checked >= num_commits:
|
||||
print(f"Checked {num_commits} commits")
|
||||
break
|
||||
|
||||
if end_commit and current_commit == end_commit:
|
||||
print(f"Checked until end commit: {end_commit}")
|
||||
break
|
||||
|
||||
# 2. Run ci-compile.py for current commit
|
||||
print(f"\nChecking commit {commits_checked + 1}")
|
||||
|
||||
# remove .build/esp32dev/pio/build/esp32dev/ directory
|
||||
board_files = Path(".build") / board / ".pio" / "build" / board
|
||||
if board_files.exists():
|
||||
shutil.rmtree(str(board_files), ignore_errors=True)
|
||||
compile_command = f"python3 ci/ci-compile.py {board} --examples Blink"
|
||||
output, error = run_command(compile_command)
|
||||
if error:
|
||||
print(f"Error running ci-compile.py: {error}")
|
||||
if not step_back_commits(skip_step):
|
||||
break
|
||||
continue
|
||||
|
||||
# 3. Check firmware size and get commit hash
|
||||
print("Checking firmware size...")
|
||||
try:
|
||||
size = check_firmware_size(board)
|
||||
except FileNotFoundError as e:
|
||||
print(f"Error checking firmware size: {e}")
|
||||
if not step_back_commits(skip_step):
|
||||
break
|
||||
continue
|
||||
except AssertionError as e:
|
||||
print(f"Error: {e}")
|
||||
if not step_back_commits(skip_step):
|
||||
break
|
||||
continue
|
||||
commit_hash = get_commit_hash()
|
||||
if size and commit_hash:
|
||||
commit_date = get_commit_date(commit_hash)
|
||||
print(f"Firmware size: {size} bytes")
|
||||
|
||||
# Write to CSV incrementally
|
||||
with open(csv_filename, "a", newline="") as csvfile:
|
||||
csvwriter = csv.writer(csvfile)
|
||||
csvwriter.writerow([commit_date, commit_hash, size])
|
||||
|
||||
print(f"Result appended to {csv_filename}")
|
||||
|
||||
commits_checked += 1
|
||||
|
||||
# 4. Step back one commit
|
||||
print("Stepping back 1 commit...")
|
||||
if not step_back_commits(1):
|
||||
break
|
||||
|
||||
# Don't remove the tmp directory
|
||||
print("\nTemporary directory 'tmp' has been left intact for inspection.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check FastLED firmware size for multiple commits."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--num-commits", type=int, default=1, help="Number of commits to check"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-step",
|
||||
type=int,
|
||||
default=1,
|
||||
help="Number of commits to skip between checks",
|
||||
)
|
||||
parser.add_argument("--start-commit", type=str, help="Starting commit hash")
|
||||
parser.add_argument("--end-commit", type=str, help="Ending commit hash")
|
||||
parser.add_argument(
|
||||
"--board", type=str, required=True, help="Board to check firmware size for"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.start_commit or args.end_commit:
|
||||
if not (args.start_commit and not args.end_commit):
|
||||
print("Both start commit and end commit must be specified.")
|
||||
exit(1)
|
||||
# if start_commit is specified, end_commit must be specified
|
||||
|
||||
num_commits = args.num_commits
|
||||
if args.start_commit and args.end_commit:
|
||||
if args.start_commit == args.end_commit:
|
||||
print("Start commit and end commit are the same.")
|
||||
exit(1)
|
||||
num_commits = 999999
|
||||
|
||||
main(args.board, num_commits, args.skip_step, args.start_commit, args.end_commit)
|
||||
293
libraries/FastLED/ci/cpp_test_compile.py
Normal file
293
libraries/FastLED/ci/cpp_test_compile.py
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Tuple
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
from ci.running_process import RunningProcess
|
||||
|
||||
BUILD_DIR = PROJECT_ROOT / "tests" / ".build"
|
||||
BUILD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def clean_build_directory():
|
||||
print("Cleaning build directory...")
|
||||
shutil.rmtree(BUILD_DIR, ignore_errors=True)
|
||||
BUILD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
print("Build directory cleaned.")
|
||||
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
|
||||
WASM_BUILD = False
|
||||
USE_ZIG = False
|
||||
USE_CLANG = False
|
||||
|
||||
|
||||
def _has_system_clang_compiler() -> bool:
|
||||
CLANG = shutil.which("clang")
|
||||
CLANGPP = shutil.which("clang++")
|
||||
LLVM_AR = shutil.which("llvm-ar")
|
||||
return CLANG is not None and CLANGPP is not None and LLVM_AR is not None
|
||||
|
||||
|
||||
def use_clang_compiler() -> Tuple[Path, Path, Path]:
|
||||
assert _has_system_clang_compiler(), "Clang system compiler not found"
|
||||
CLANG = shutil.which("clang")
|
||||
CLANGPP = shutil.which("clang++")
|
||||
LLVM_AR = shutil.which("llvm-ar")
|
||||
assert CLANG is not None, "clang compiler not found"
|
||||
assert CLANGPP is not None, "clang++ compiler not found"
|
||||
assert LLVM_AR is not None, "llvm-ar not found"
|
||||
# Set environment variables for C and C++ compilers
|
||||
os.environ["CC"] = CLANG
|
||||
os.environ["CXX"] = CLANGPP
|
||||
os.environ["AR"] = LLVM_AR
|
||||
|
||||
os.environ["CXXFLAGS"] = os.environ.get("CXXFLAGS", "") + " -ferror-limit=1"
|
||||
os.environ["CFLAGS"] = os.environ.get("CFLAGS", "") + " -ferror-limit=1"
|
||||
|
||||
if WASM_BUILD:
|
||||
wasm_flags = [
|
||||
"--target=wasm32",
|
||||
"-O3",
|
||||
"-flto",
|
||||
# "-nostdlib",
|
||||
# "-Wl,--no-entry",
|
||||
# "-Wl,--export-all",
|
||||
# "-Wl,--lto-O3",
|
||||
# "-Wl,-z,stack-size=8388608", # 8 * 1024 * 1024 (8MiB)
|
||||
]
|
||||
os.environ["CFLAGS"] = " ".join(wasm_flags)
|
||||
os.environ["CXXFLAGS"] = " ".join(wasm_flags)
|
||||
|
||||
print(f"CC: {CLANG}")
|
||||
print(f"CXX: {CLANGPP}")
|
||||
print(f"AR: {LLVM_AR}")
|
||||
|
||||
return Path(CLANG), Path(CLANGPP), Path(LLVM_AR)
|
||||
|
||||
|
||||
def use_zig_compiler() -> Tuple[Path, Path, Path]:
|
||||
assert 0 == os.system(
|
||||
"uv run python -m ziglang version"
|
||||
), "Zig-clang compiler not found"
|
||||
uv_path_str: str | None = shutil.which("uv")
|
||||
assert uv_path_str is not None, "uv not found in PATH"
|
||||
uv_path = Path(uv_path_str).resolve()
|
||||
zig_command = f'"{uv_path}" run python -m ziglang'
|
||||
# We are going to build up shell scripts that look like cc, c++, and ar. It will contain the actual build command.
|
||||
CC_PATH = BUILD_DIR / "cc"
|
||||
CXX_PATH = BUILD_DIR / "c++"
|
||||
AR_PATH = BUILD_DIR / "ar"
|
||||
if sys.platform == "win32":
|
||||
CC_PATH = CC_PATH.with_suffix(".cmd")
|
||||
CXX_PATH = CXX_PATH.with_suffix(".cmd")
|
||||
AR_PATH = AR_PATH.with_suffix(".cmd")
|
||||
CC_PATH.write_text(f"@echo off\n{zig_command} cc %* 2>&1\n")
|
||||
CXX_PATH.write_text(f"@echo off\n{zig_command} c++ %* 2>&1\n")
|
||||
AR_PATH.write_text(f"@echo off\n{zig_command} ar %* 2>&1\n")
|
||||
else:
|
||||
cc_cmd = f'#!/bin/bash\n{zig_command} cc "$@"\n'
|
||||
cxx_cmd = f'#!/bin/bash\n{zig_command} c++ "$@"\n'
|
||||
ar_cmd = f'#!/bin/bash\n{zig_command} ar "$@"\n'
|
||||
CC_PATH.write_text(cc_cmd)
|
||||
CXX_PATH.write_text(cxx_cmd)
|
||||
AR_PATH.write_text(ar_cmd)
|
||||
CC_PATH.chmod(0o755)
|
||||
CXX_PATH.chmod(0o755)
|
||||
AR_PATH.chmod(0o755)
|
||||
|
||||
# if WASM_BUILD:
|
||||
# wasm_flags = [
|
||||
# # "--target=wasm32",
|
||||
# # "-O3",
|
||||
# # "-flto",
|
||||
# # "-nostdlib",
|
||||
# "-Wl,--no-entry",
|
||||
# # "-Wl,--export-all",
|
||||
# # "-Wl,--lto-O3",
|
||||
# "-Wl,-z,stack-size=8388608", # 8 * 1024 * 1024 (8MiB)
|
||||
# ]
|
||||
# os.environ["CFLAGS"] = " ".join(wasm_flags)
|
||||
# os.environ["CXXFLAGS"] = " ".join(wasm_flags)
|
||||
|
||||
cc, cxx = CC_PATH, CXX_PATH
|
||||
# use the system path, so on windows this looks like "C:\Program Files\Zig\zig.exe"
|
||||
cc_path: Path | str = cc.resolve()
|
||||
cxx_path: Path | str = cxx.resolve()
|
||||
if sys.platform == "win32":
|
||||
cc_path = str(cc_path).replace("/", "\\")
|
||||
cxx_path = str(cxx_path).replace("/", "\\")
|
||||
|
||||
# print out the paths
|
||||
print(f"CC: {cc_path}")
|
||||
print(f"CXX: {cxx_path}")
|
||||
print(f"AR: {AR_PATH}")
|
||||
# sys.exit(1)
|
||||
|
||||
# Set environment variables for C and C++ compilers
|
||||
os.environ["CC"] = str(cc_path)
|
||||
os.environ["CXX"] = str(cxx_path)
|
||||
os.environ["AR"] = str(AR_PATH)
|
||||
return CC_PATH, CXX_PATH, AR_PATH
|
||||
|
||||
|
||||
def run_command(command: str, cwd: Path | None = None) -> None:
|
||||
process = RunningProcess(command, cwd=cwd)
|
||||
process.wait()
|
||||
if process.returncode != 0:
|
||||
print(f"{Path(__file__).name}: Error executing command: {command}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def compile_fastled(specific_test: str | None = None) -> None:
|
||||
if USE_ZIG:
|
||||
print("USING ZIG COMPILER")
|
||||
rtn = subprocess.run(
|
||||
"python -m ziglang version", shell=True, capture_output=True
|
||||
).returncode
|
||||
zig_is_installed = rtn == 0
|
||||
assert (
|
||||
zig_is_installed
|
||||
), 'Zig compiler not when using "python -m ziglang version" command'
|
||||
use_zig_compiler()
|
||||
elif USE_CLANG:
|
||||
print("USING CLANG COMPILER")
|
||||
use_clang_compiler()
|
||||
|
||||
cmake_configure_command_list: list[str] = [
|
||||
"cmake",
|
||||
"-S",
|
||||
str(PROJECT_ROOT / "tests"),
|
||||
"-B",
|
||||
str(BUILD_DIR),
|
||||
"-G",
|
||||
"Ninja",
|
||||
"-DCMAKE_VERBOSE_MAKEFILE=ON",
|
||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
||||
]
|
||||
|
||||
if WASM_BUILD:
|
||||
cmake_configure_command_list.extend(
|
||||
[
|
||||
"-DCMAKE_C_COMPILER_TARGET=wasm32-wasi",
|
||||
"-DCMAKE_CXX_COMPILER_TARGET=wasm32-wasi",
|
||||
"-DCMAKE_C_COMPILER_WORKS=TRUE",
|
||||
"-DCMAKE_CXX_COMPILER_WORKS=TRUE",
|
||||
"-DCMAKE_SYSTEM_NAME=Generic",
|
||||
"-DCMAKE_CROSSCOMPILING=TRUE",
|
||||
"-DCMAKE_EXE_LINKER_FLAGS=-Wl,--no-entry -Wl,--export-all -Wl,--lto-O3 -Wl,-z,stack-size=8388608",
|
||||
]
|
||||
)
|
||||
|
||||
cmake_configure_command = subprocess.list2cmdline(cmake_configure_command_list)
|
||||
run_command(cmake_configure_command, cwd=BUILD_DIR)
|
||||
|
||||
# Build the project
|
||||
if specific_test:
|
||||
cmake_build_command = f"cmake --build {BUILD_DIR} --target test_{specific_test}"
|
||||
else:
|
||||
cmake_build_command = f"cmake --build {BUILD_DIR}"
|
||||
run_command(cmake_build_command)
|
||||
|
||||
print("FastLED library compiled successfully.")
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Compile FastLED library with different compiler options."
|
||||
)
|
||||
parser.add_argument("--use-zig", action="store_true", help="Use Zig compiler")
|
||||
parser.add_argument("--use-clang", action="store_true", help="Use Clang compiler")
|
||||
parser.add_argument("--wasm", action="store_true", help="Build for WebAssembly")
|
||||
parser.add_argument(
|
||||
"--clean",
|
||||
action="store_true",
|
||||
help="Clean the build directory before compiling",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--test",
|
||||
help="Specific test to compile (without test_ prefix)",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def get_build_info(args: argparse.Namespace) -> dict[str, str | dict[str, str]]:
|
||||
return {
|
||||
"USE_ZIG": str(USE_ZIG),
|
||||
"USE_CLANG": str(USE_CLANG),
|
||||
"WASM_BUILD": str(WASM_BUILD),
|
||||
"CC": os.environ.get("CC", ""),
|
||||
"CXX": os.environ.get("CXX", ""),
|
||||
"AR": os.environ.get("AR", ""),
|
||||
"CFLAGS": os.environ.get("CFLAGS", ""),
|
||||
"CXXFLAGS": os.environ.get("CXXFLAGS", ""),
|
||||
"ARGS": {
|
||||
"use_zig": str(args.use_zig),
|
||||
"use_clang": str(args.use_clang),
|
||||
"wasm": str(args.wasm),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def should_clean_build(build_info: dict[str, str | dict[str, str]]) -> bool:
|
||||
build_info_file = BUILD_DIR / "build_info.json"
|
||||
if not build_info_file.exists():
|
||||
return True
|
||||
|
||||
with open(build_info_file, "r") as f:
|
||||
old_build_info = json.load(f)
|
||||
|
||||
return old_build_info != build_info
|
||||
|
||||
|
||||
def update_build_info(build_info: dict[str, str | dict[str, str]]):
|
||||
build_info_file = BUILD_DIR / "build_info.json"
|
||||
with open(build_info_file, "w") as f:
|
||||
json.dump(build_info, f, indent=2)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
global USE_ZIG, USE_CLANG, WASM_BUILD
|
||||
|
||||
args = parse_arguments()
|
||||
USE_ZIG = args.use_zig # use Zig's clang compiler
|
||||
USE_CLANG = args.use_clang # Use pure Clang for WASM builds
|
||||
WASM_BUILD = args.wasm
|
||||
|
||||
using_gcc = not USE_ZIG and not USE_CLANG and not WASM_BUILD
|
||||
if using_gcc:
|
||||
if not shutil.which("g++"):
|
||||
print(
|
||||
"gcc compiler not found in PATH, falling back zig's built in clang compiler"
|
||||
)
|
||||
USE_ZIG = True
|
||||
USE_CLANG = False
|
||||
|
||||
if USE_CLANG:
|
||||
if not _has_system_clang_compiler():
|
||||
print(
|
||||
"Clang compiler not found in PATH, falling back to Zig-clang compiler"
|
||||
)
|
||||
USE_ZIG = True
|
||||
USE_CLANG = False
|
||||
|
||||
os.chdir(str(HERE))
|
||||
print(f"Current directory: {Path('.').absolute()}")
|
||||
|
||||
build_info = get_build_info(args)
|
||||
if args.clean or should_clean_build(build_info):
|
||||
clean_build_directory()
|
||||
|
||||
compile_fastled(args.test)
|
||||
update_build_info(build_info)
|
||||
print("FastLED library compiled successfully.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
269
libraries/FastLED/ci/cpp_test_run.py
Normal file
269
libraries/FastLED/ci/cpp_test_run.py
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
|
||||
@dataclass
|
||||
class FailedTest:
|
||||
name: str
|
||||
return_code: int
|
||||
stdout: str
|
||||
|
||||
|
||||
def run_command(command, use_gdb=False) -> tuple[int, str]:
|
||||
captured_lines = []
|
||||
if use_gdb:
|
||||
with tempfile.NamedTemporaryFile(mode="w+", delete=False) as gdb_script:
|
||||
gdb_script.write("set pagination off\n")
|
||||
gdb_script.write("run\n")
|
||||
gdb_script.write("bt full\n")
|
||||
gdb_script.write("info registers\n")
|
||||
gdb_script.write("x/16i $pc\n")
|
||||
gdb_script.write("thread apply all bt full\n")
|
||||
gdb_script.write("quit\n")
|
||||
|
||||
gdb_command = (
|
||||
f"gdb -return-child-result -batch -x {gdb_script.name} --args {command}"
|
||||
)
|
||||
process = subprocess.Popen(
|
||||
gdb_command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, # Merge stderr into stdout
|
||||
shell=True,
|
||||
text=True,
|
||||
bufsize=1, # Line buffered
|
||||
)
|
||||
assert process.stdout is not None
|
||||
# Stream and capture output
|
||||
while True:
|
||||
line = process.stdout.readline()
|
||||
if not line and process.poll() is not None:
|
||||
break
|
||||
if line:
|
||||
captured_lines.append(line.rstrip())
|
||||
print(line, end="") # Print in real-time
|
||||
|
||||
os.unlink(gdb_script.name)
|
||||
output = "\n".join(captured_lines)
|
||||
return process.returncode, output
|
||||
else:
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, # Merge stderr into stdout
|
||||
shell=True,
|
||||
text=True,
|
||||
bufsize=1, # Line buffered
|
||||
)
|
||||
assert process.stdout is not None
|
||||
# Stream and capture output
|
||||
while True:
|
||||
line = process.stdout.readline()
|
||||
if not line and process.poll() is not None:
|
||||
break
|
||||
if line:
|
||||
captured_lines.append(line.rstrip())
|
||||
print(line, end="") # Print in real-time
|
||||
|
||||
output = "\n".join(captured_lines)
|
||||
return process.returncode, output
|
||||
|
||||
|
||||
def compile_tests(clean: bool = False, unknown_args: list[str] = []) -> None:
|
||||
os.chdir(str(PROJECT_ROOT))
|
||||
print("Compiling tests...")
|
||||
command = ["uv", "run", "ci/cpp_test_compile.py"]
|
||||
if clean:
|
||||
command.append("--clean")
|
||||
command.extend(unknown_args)
|
||||
return_code, _ = run_command(" ".join(command))
|
||||
if return_code != 0:
|
||||
print("Compilation failed:")
|
||||
sys.exit(1)
|
||||
print("Compilation successful.")
|
||||
|
||||
|
||||
def run_tests(specific_test: str | None = None) -> None:
|
||||
test_dir = os.path.join("tests", ".build", "bin")
|
||||
if not os.path.exists(test_dir):
|
||||
print(f"Test directory not found: {test_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
print("Running tests...")
|
||||
failed_tests: list[FailedTest] = []
|
||||
files = os.listdir(test_dir)
|
||||
# filter out all pdb files (windows) and only keep test_ executables
|
||||
files = [f for f in files if not f.endswith(".pdb") and f.startswith("test_")]
|
||||
|
||||
# If specific test is specified, filter for just that test
|
||||
if specific_test:
|
||||
test_name = f"test_{specific_test}"
|
||||
if sys.platform == "win32":
|
||||
test_name += ".exe"
|
||||
files = [f for f in files if f == test_name]
|
||||
if not files:
|
||||
print(f"Test {test_name} not found in {test_dir}")
|
||||
sys.exit(1)
|
||||
for test_file in files:
|
||||
test_path = os.path.join(test_dir, test_file)
|
||||
if os.path.isfile(test_path) and os.access(test_path, os.X_OK):
|
||||
print(f"Running test: {test_file}")
|
||||
return_code, stdout = run_command(test_path)
|
||||
|
||||
output = stdout
|
||||
failure_pattern = re.compile(r"Test .+ failed with return code (\d+)")
|
||||
failure_match = failure_pattern.search(output)
|
||||
is_crash = failure_match is not None
|
||||
|
||||
if is_crash:
|
||||
print("Test crashed. Re-running with GDB to get stack trace...")
|
||||
_, gdb_stdout = run_command(test_path, use_gdb=True)
|
||||
stdout += "\n--- GDB Output ---\n" + gdb_stdout
|
||||
|
||||
# Extract crash information
|
||||
crash_info = extract_crash_info(gdb_stdout)
|
||||
print(f"Crash occurred at: {crash_info.file}:{crash_info.line}")
|
||||
print(f"Cause: {crash_info.cause}")
|
||||
print(f"Stack: {crash_info.stack}")
|
||||
|
||||
print("Test output:")
|
||||
print(stdout)
|
||||
if return_code == 0:
|
||||
print("Test passed")
|
||||
elif is_crash:
|
||||
if failure_match:
|
||||
print(f"Test crashed with return code {failure_match.group(1)}")
|
||||
else:
|
||||
print(f"Test crashed with return code {return_code}")
|
||||
else:
|
||||
print(f"Test failed with return code {return_code}")
|
||||
|
||||
print("-" * 40)
|
||||
if return_code != 0:
|
||||
failed_tests.append(FailedTest(test_file, return_code, stdout))
|
||||
if failed_tests:
|
||||
for failed_test in failed_tests:
|
||||
print(
|
||||
f"Test {failed_test.name} failed with return code {failed_test.return_code}\n{failed_test.stdout}"
|
||||
)
|
||||
tests_failed = len(failed_tests)
|
||||
failed_test_names = [test.name for test in failed_tests]
|
||||
print(
|
||||
f"{tests_failed} test{'s' if tests_failed != 1 else ''} failed: {', '.join(failed_test_names)}"
|
||||
)
|
||||
sys.exit(1)
|
||||
print("All tests passed.")
|
||||
|
||||
|
||||
@dataclass
|
||||
class CrashInfo:
|
||||
cause: str = "Unknown"
|
||||
stack: str = "Unknown"
|
||||
file: str = "Unknown"
|
||||
line: str = "Unknown"
|
||||
|
||||
|
||||
def extract_crash_info(gdb_output: str) -> CrashInfo:
|
||||
lines = gdb_output.split("\n")
|
||||
crash_info = CrashInfo()
|
||||
|
||||
try:
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith("Program received signal"):
|
||||
try:
|
||||
crash_info.cause = line.split(":", 1)[1].strip()
|
||||
except IndexError:
|
||||
crash_info.cause = line.strip()
|
||||
elif line.startswith("#0"):
|
||||
crash_info.stack = line
|
||||
for j in range(i, len(lines)):
|
||||
if "at" in lines[j]:
|
||||
try:
|
||||
_, location = lines[j].split("at", 1)
|
||||
location = location.strip()
|
||||
if ":" in location:
|
||||
crash_info.file, crash_info.line = location.rsplit(
|
||||
":", 1
|
||||
)
|
||||
else:
|
||||
crash_info.file = location
|
||||
except ValueError:
|
||||
pass # If split fails, we keep the default values
|
||||
break
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Error parsing GDB output: {e}")
|
||||
|
||||
return crash_info
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Compile and run C++ tests")
|
||||
parser.add_argument(
|
||||
"--compile-only",
|
||||
action="store_true",
|
||||
help="Only compile the tests without running them",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--run-only",
|
||||
action="store_true",
|
||||
help="Only run the tests without compiling them",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-run-failed-test",
|
||||
action="store_true",
|
||||
help="Only run the tests that failed in the previous run",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--clean", action="store_true", help="Clean build before compiling"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--test",
|
||||
help="Specific test to run (without test_ prefix)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--clang",
|
||||
help="Use Clang compiler",
|
||||
action="store_true",
|
||||
)
|
||||
args, unknown = parser.parse_known_args()
|
||||
args.unknown = unknown
|
||||
return args
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
run_only = args.run_only
|
||||
compile_only = args.compile_only
|
||||
specific_test = args.test
|
||||
only_run_failed_test = args.only_run_failed_test
|
||||
use_clang = args.clang
|
||||
|
||||
if not run_only:
|
||||
passthrough_args = args.unknown
|
||||
if use_clang:
|
||||
passthrough_args.append("--use-clang")
|
||||
compile_tests(clean=args.clean, unknown_args=passthrough_args)
|
||||
|
||||
if not compile_only:
|
||||
if specific_test:
|
||||
run_tests(specific_test)
|
||||
else:
|
||||
cmd = "ctest --test-dir tests/.build --output-on-failure"
|
||||
if only_run_failed_test:
|
||||
cmd += " --rerun-failed"
|
||||
rtn, stdout = run_command(cmd)
|
||||
if rtn != 0:
|
||||
print("Failed tests:")
|
||||
print(stdout)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
186
libraries/FastLED/ci/docs.py
Normal file
186
libraries/FastLED/ci/docs.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
"""
|
||||
Work in progress to generate doxygen via a script instead of a GitHub action.
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from download import download # type: ignore
|
||||
|
||||
# Configs
|
||||
DOXYGEN_VERSION = (
|
||||
"1.13.2" # DOXYGEN_AWESOME styler is has certain restrictions with doxygen version
|
||||
)
|
||||
DOXYGEN_AWESOME_VERSION = "2.3.4" # deprecating
|
||||
DOXYFILE_PATH = Path("docs/Doxyfile")
|
||||
HTML_OUTPUT_DIR = Path("docs/html")
|
||||
DOXYGEN_CSS_REPO = "https://github.com/jothepro/doxygen-awesome-css" # deprecating
|
||||
|
||||
|
||||
HERE = Path(__file__).parent.resolve()
|
||||
PROJECT_ROOT = HERE.parent
|
||||
|
||||
DOCS_ROOT = PROJECT_ROOT / "docs"
|
||||
DOCS_TOOL_PATH = PROJECT_ROOT / ".tools_cache"
|
||||
DOCS_OUTPUT_PATH = DOCS_ROOT / "html"
|
||||
|
||||
|
||||
def run(
|
||||
cmd: str,
|
||||
cwd: Optional[str] = None,
|
||||
shell: bool = True,
|
||||
check: bool = True,
|
||||
capture: bool = True,
|
||||
) -> str:
|
||||
print(f"Running: {cmd}")
|
||||
result = subprocess.run(
|
||||
cmd, shell=shell, cwd=cwd, check=False, capture_output=capture, text=False
|
||||
)
|
||||
if capture:
|
||||
stdout = result.stdout.decode("utf-8") if result.stdout else ""
|
||||
stderr = result.stderr.decode("utf-8") if result.stderr else ""
|
||||
else:
|
||||
stdout = ""
|
||||
stderr = ""
|
||||
if result.returncode != 0:
|
||||
msg = f"Command failed with exit code {result.returncode}:\nstdout:\n{stdout}\n\nstderr:\n{stderr}"
|
||||
warnings.warn(msg)
|
||||
if check:
|
||||
raise subprocess.CalledProcessError(
|
||||
result.returncode, cmd, output=result.stdout
|
||||
)
|
||||
return stdout.strip()
|
||||
|
||||
|
||||
def get_git_info() -> Tuple[str, str]:
|
||||
release_tag = os.environ.get("RELEASE_TAG", "")
|
||||
|
||||
try:
|
||||
latest_tag = run("git tag | grep -E '^[0-9]' | sort -V | tail -1")
|
||||
latest_tag = latest_tag if latest_tag else ""
|
||||
except subprocess.CalledProcessError:
|
||||
latest_tag = ""
|
||||
|
||||
git_sha_short = run("git rev-parse --short HEAD")
|
||||
full_sha = run("git rev-parse HEAD")
|
||||
project_number = release_tag or latest_tag or git_sha_short
|
||||
commit_message = (
|
||||
f"{project_number} ({full_sha})"
|
||||
if project_number != git_sha_short
|
||||
else project_number
|
||||
)
|
||||
|
||||
print(f"Project number: {project_number}")
|
||||
print(f"Commit message: {commit_message}")
|
||||
return project_number, commit_message
|
||||
|
||||
|
||||
def install_doxygen_windows() -> Path:
|
||||
print("Installing Doxygen...")
|
||||
doxygen_url = (
|
||||
f"https://www.doxygen.nl/files/doxygen-{DOXYGEN_VERSION}.windows.x64.bin.zip"
|
||||
)
|
||||
zip_path = DOCS_TOOL_PATH / f"doxygen-{DOXYGEN_VERSION}.zip"
|
||||
extract_dir = DOCS_TOOL_PATH / f"doxygen-{DOXYGEN_VERSION}"
|
||||
|
||||
# Create tool path if it doesn't exist
|
||||
DOCS_TOOL_PATH.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
download(doxygen_url, zip_path)
|
||||
shutil.unpack_archive(str(zip_path), extract_dir)
|
||||
bin_path = next(extract_dir.glob("**/doxygen.exe"), None)
|
||||
if not bin_path:
|
||||
raise FileNotFoundError("Doxygen executable not found after extraction.")
|
||||
print(f"Doxygen installed at: {bin_path}")
|
||||
return bin_path
|
||||
|
||||
|
||||
def install_doxygen_unix() -> Path:
|
||||
print("Installing Doxygen...")
|
||||
archive = f"doxygen-{DOXYGEN_VERSION}.linux.bin.tar.gz"
|
||||
url = f"https://www.doxygen.nl/files/{archive}"
|
||||
|
||||
# Create tool path if it doesn't exist
|
||||
DOCS_TOOL_PATH.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
# Change to tool directory for download and extraction
|
||||
original_dir = os.getcwd()
|
||||
os.chdir(str(DOCS_TOOL_PATH))
|
||||
|
||||
try:
|
||||
run(f"wget -q {url}")
|
||||
run(f"tar -xf {archive}")
|
||||
bin_dir = DOCS_TOOL_PATH / f"doxygen-{DOXYGEN_VERSION}"
|
||||
return bin_dir / "bin" / "doxygen"
|
||||
finally:
|
||||
os.chdir(original_dir)
|
||||
|
||||
|
||||
def install_theme() -> Path:
|
||||
print("Installing Doxygen Awesome Theme...")
|
||||
theme_path = DOCS_ROOT / "doxygen-awesome-css"
|
||||
if theme_path.exists():
|
||||
return theme_path
|
||||
run(
|
||||
f"git clone --depth 1 -b v{DOXYGEN_AWESOME_VERSION} {DOXYGEN_CSS_REPO}",
|
||||
cwd=str(DOCS_ROOT),
|
||||
)
|
||||
return theme_path
|
||||
|
||||
|
||||
def generate_docs(doxygen_bin: Path) -> None:
|
||||
print("Generating documentation...")
|
||||
cmd_str = f'"{doxygen_bin}" {DOXYFILE_PATH.name}'
|
||||
run(cmd_str, cwd=str(DOCS_ROOT), capture=False)
|
||||
|
||||
|
||||
# def install_graphviz() -> None:
|
||||
# url: str = get_latest_release_for_platform()
|
||||
# print(url)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
is_windows = platform.system() == "Windows"
|
||||
# is_macos = platform.system() == "Darwin"
|
||||
_, commit_msg = get_git_info()
|
||||
|
||||
if is_windows:
|
||||
doxygen_bin = install_doxygen_windows()
|
||||
# add to path C:\Program Files\Graphviz\bin\
|
||||
os.environ["PATH"] += os.pathsep + r"C:\Program Files\Graphviz\bin"
|
||||
else:
|
||||
doxygen_bin = install_doxygen_unix()
|
||||
|
||||
# install_theme()
|
||||
|
||||
# install_graphviz() # Work in progress
|
||||
|
||||
# Verify Graphviz installation
|
||||
try:
|
||||
dot_version = run("dot -V", check=False)
|
||||
print(f"Graphviz detected: {dot_version}")
|
||||
except Exception:
|
||||
warnings.warn(
|
||||
"Graphviz (dot) not found in PATH. Diagrams may not be generated."
|
||||
)
|
||||
|
||||
# Check it graphviz is installed
|
||||
# if linux
|
||||
if not is_windows:
|
||||
run("dot -Tsvg -Kneato -Grankdir=LR", check=True)
|
||||
|
||||
generate_docs(doxygen_bin=doxygen_bin)
|
||||
|
||||
print(f"\n✅ Docs generated in: {HTML_OUTPUT_DIR}")
|
||||
print(f"📄 Commit message: {commit_msg}")
|
||||
print("✨ You can now manually deploy to GitHub Pages or automate this step.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
197
libraries/FastLED/ci/inspect_binary.py
Normal file
197
libraries/FastLED/ci/inspect_binary.py
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
from ci.bin_2_elf import bin_to_elf
|
||||
from ci.elf import dump_symbol_sizes
|
||||
from ci.map_dump import map_dump
|
||||
|
||||
|
||||
def cpp_filt(cpp_filt_path: Path, input_text: str) -> str:
|
||||
"""
|
||||
Demangle C++ symbols using c++filt.
|
||||
|
||||
Args:
|
||||
cpp_filt_path (Path): Path to c++filt executable.
|
||||
input_text (str): Text to demangle.
|
||||
|
||||
Returns:
|
||||
str: Demangled text.
|
||||
"""
|
||||
if not cpp_filt_path.exists():
|
||||
raise FileNotFoundError(f"cppfilt not found at '{cpp_filt_path}'")
|
||||
command = [str(cpp_filt_path), "-t", "-n"]
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
stdout, stderr = process.communicate(input=input_text)
|
||||
if process.returncode != 0:
|
||||
raise RuntimeError(f"Error running c++filt: {stderr}")
|
||||
return stdout
|
||||
|
||||
|
||||
def demangle_gnu_linkonce_symbols(cpp_filt_path: Path, map_text: str) -> str:
|
||||
"""
|
||||
Demangle .gnu.linkonce.t symbols in the map file.
|
||||
|
||||
Args:
|
||||
cpp_filt_path (Path): Path to c++filt executable.
|
||||
map_text (str): Content of the map file.
|
||||
|
||||
Returns:
|
||||
str: Map file content with demangled symbols.
|
||||
"""
|
||||
# Extract all .gnu.linkonce.t symbols
|
||||
pattern = r"\.gnu\.linkonce\.t\.(.+?)\s"
|
||||
matches = re.findall(pattern, map_text)
|
||||
|
||||
if not matches:
|
||||
return map_text
|
||||
|
||||
# Create a block of text with the extracted symbols
|
||||
symbols_block = "\n".join(matches)
|
||||
|
||||
# Demangle the symbols
|
||||
demangled_block = cpp_filt(cpp_filt_path, symbols_block)
|
||||
|
||||
# Create a dictionary of mangled to demangled symbols
|
||||
demangled_dict = dict(zip(matches, demangled_block.strip().split("\n")))
|
||||
|
||||
# Replace the mangled symbols with demangled ones in the original text
|
||||
for mangled, demangled in demangled_dict.items():
|
||||
map_text = map_text.replace(
|
||||
f".gnu.linkonce.t.{mangled}", f".gnu.linkonce.t.{demangled}"
|
||||
)
|
||||
|
||||
return map_text
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert a binary file to ELF using map file."
|
||||
)
|
||||
parser.add_argument("--first", action="store_true", help="Inspect the first board")
|
||||
parser.add_argument("--cwd", type=Path, help="Custom working directory")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def load_build_info(build_info_path: Path) -> dict:
|
||||
"""
|
||||
Load build information from a JSON file.
|
||||
|
||||
Args:
|
||||
build_info_path (Path): Path to the build_info.json file.
|
||||
|
||||
Returns:
|
||||
dict: Parsed JSON data.
|
||||
"""
|
||||
if not build_info_path.exists():
|
||||
raise FileNotFoundError(f"Build info JSON not found at '{build_info_path}'")
|
||||
return json.loads(build_info_path.read_text())
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
if args.cwd:
|
||||
root_build_dir = args.cwd / ".build"
|
||||
else:
|
||||
root_build_dir = Path(".build")
|
||||
|
||||
board_dirs = [d for d in root_build_dir.iterdir() if d.is_dir()]
|
||||
if not board_dirs:
|
||||
print(f"No board directories found in {root_build_dir.absolute()}")
|
||||
return 1
|
||||
|
||||
print("Available boards:")
|
||||
for i, board_dir in enumerate(board_dirs):
|
||||
print(f"[{i}]: {board_dir.name}")
|
||||
|
||||
which = (
|
||||
0
|
||||
if args.first
|
||||
else int(input("Enter the number of the board you want to inspect: "))
|
||||
)
|
||||
board_dir = board_dirs[which]
|
||||
build_info_json = board_dir / "build_info.json"
|
||||
|
||||
build_info = load_build_info(build_info_json)
|
||||
board = board_dir.name
|
||||
board_info = build_info.get(board) or build_info[next(iter(build_info))]
|
||||
|
||||
# Validate paths from build_info.json
|
||||
elf_path = Path(board_info.get("prog_path", ""))
|
||||
if not elf_path.exists():
|
||||
print(
|
||||
f"Error: ELF path '{elf_path}' does not exist. Check the 'prog_path' in build_info.json."
|
||||
)
|
||||
return 1
|
||||
|
||||
bin_file = elf_path.with_suffix(".bin")
|
||||
if not bin_file.exists():
|
||||
# use .hex or .uf2 if .bin doesn't exist
|
||||
bin_file = elf_path.with_suffix(".hex")
|
||||
if not bin_file.exists():
|
||||
bin_file = elf_path.with_suffix(".uf2")
|
||||
if not bin_file.exists():
|
||||
print(f"Error: Binary file not found for '{elf_path}'")
|
||||
return 1
|
||||
cpp_filt_path = Path(board_info["aliases"]["c++filt"])
|
||||
ld_path = Path(board_info["aliases"]["ld"])
|
||||
as_path = Path(board_info["aliases"]["as"])
|
||||
nm_path = Path(board_info["aliases"]["nm"])
|
||||
objcopy_path = Path(board_info["aliases"]["objcopy"])
|
||||
nm_path = Path(board_info["aliases"]["nm"])
|
||||
map_file = board_dir / "firmware.map"
|
||||
if not map_file.exists():
|
||||
# Search for the map file
|
||||
map_file = bin_file.with_suffix(".map")
|
||||
if not map_file.exists():
|
||||
possible_map_files = list(board_dir.glob("**/firmware.map"))
|
||||
if possible_map_files:
|
||||
map_file = possible_map_files[0]
|
||||
else:
|
||||
print("Error: firmware.map file not found")
|
||||
return 1
|
||||
|
||||
try:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
temp_dir_path = Path(temp_dir)
|
||||
output_elf = bin_to_elf(
|
||||
bin_file,
|
||||
map_file,
|
||||
as_path,
|
||||
ld_path,
|
||||
objcopy_path,
|
||||
temp_dir_path / "output.elf",
|
||||
)
|
||||
out = dump_symbol_sizes(nm_path, cpp_filt_path, output_elf)
|
||||
print(out)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error while converting binary to ELF, binary analysis will not work on this build: {e}"
|
||||
)
|
||||
|
||||
map_dump(map_file)
|
||||
|
||||
# Demangle .gnu.linkonce.t symbols and print map file
|
||||
print("\n##################################################")
|
||||
print("# Map file dump:")
|
||||
print("##################################################\n")
|
||||
map_text = map_file.read_text()
|
||||
demangled_map_text = demangle_gnu_linkonce_symbols(cpp_filt_path, map_text)
|
||||
print(demangled_map_text)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
72
libraries/FastLED/ci/inspect_elf.py
Normal file
72
libraries/FastLED/ci/inspect_elf.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from ci.elf import dump_symbol_sizes
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
PROJECT_ROOT = HERE.parent
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Inspect a compiled binary")
|
||||
parser.add_argument("--first", action="store_true", help="Inspect the first board")
|
||||
parser.add_argument("--cwd", type=str, help="Custom working directory")
|
||||
parser.add_argument("--elf", type=str, help="Path to the ELF file to inspect")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
if args.elf:
|
||||
firmware_path = Path(args.elf)
|
||||
if not firmware_path.exists():
|
||||
print(f"ELF file not found: {firmware_path}")
|
||||
return 1
|
||||
|
||||
if args.cwd:
|
||||
# os.chdir(args.cwd)
|
||||
root_build_dir = Path(args.cwd) / ".build"
|
||||
else:
|
||||
root_build_dir = Path(".build")
|
||||
|
||||
# Find the first board directory
|
||||
board_dirs = [d for d in root_build_dir.iterdir() if d.is_dir()]
|
||||
if not board_dirs:
|
||||
# print("No board directories found in .build")
|
||||
print(f"No board directories found in {root_build_dir.absolute()}")
|
||||
return 1
|
||||
|
||||
# display all the boards to the user and ask them to select which one they want by number
|
||||
print("Available boards:")
|
||||
for i, board_dir in enumerate(board_dirs):
|
||||
print(f"[{i}]: {board_dir.name}")
|
||||
|
||||
if args.first:
|
||||
which = 0
|
||||
else:
|
||||
which = int(input("Enter the number of the board you want to inspect: "))
|
||||
|
||||
board_dir = board_dirs[which]
|
||||
board = board_dir.name
|
||||
|
||||
build_info_json = board_dir / "build_info.json"
|
||||
build_info = json.loads(build_info_json.read_text())
|
||||
board_info = build_info.get(board) or build_info[next(iter(build_info))]
|
||||
|
||||
firmware_path = Path(board_info["prog_path"])
|
||||
cpp_filt_path = Path(board_info["aliases"]["c++filt"])
|
||||
|
||||
print(f"Dumping symbol sizes for {board} firmware: {firmware_path}")
|
||||
try:
|
||||
nm_path = Path(board_info["aliases"]["nm"])
|
||||
symbol_sizes = dump_symbol_sizes(nm_path, cpp_filt_path, firmware_path)
|
||||
print(symbol_sizes)
|
||||
except Exception as e:
|
||||
print(f"Error while dumping symbol sizes: {e}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
129
libraries/FastLED/ci/inspect_obj.py
Normal file
129
libraries/FastLED/ci/inspect_obj.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ci.paths import BUILD
|
||||
from ci.tools import load_tools
|
||||
|
||||
|
||||
def _list_builds() -> list[Path]:
|
||||
str_paths = os.listdir(BUILD)
|
||||
paths = [BUILD / p for p in str_paths]
|
||||
dirs = [p for p in paths if p.is_dir()]
|
||||
return dirs
|
||||
|
||||
|
||||
def _check_build(build: Path) -> bool:
|
||||
# 1. should contain a build_info.json file
|
||||
# 2. should contain a .pio/build directory
|
||||
has_build_info = (build / "build_info.json").exists()
|
||||
has_pio_build = (build / ".pio" / "build").exists()
|
||||
return has_build_info and has_pio_build
|
||||
|
||||
|
||||
def _prompt_build() -> Path:
|
||||
builds = _list_builds()
|
||||
if not builds:
|
||||
print("Error: No builds found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print("Select a build:")
|
||||
for i, build in enumerate(builds):
|
||||
print(f" [{i}]: {build}")
|
||||
while True:
|
||||
try:
|
||||
which = int(input("Enter the number of the build to use: "))
|
||||
if 0 <= which < len(builds):
|
||||
valid = _check_build(BUILD / builds[which])
|
||||
if valid:
|
||||
return BUILD / builds[which]
|
||||
print("Error: Invalid build", file=sys.stderr)
|
||||
else:
|
||||
print("Error: Invalid selection", file=sys.stderr)
|
||||
continue
|
||||
except ValueError:
|
||||
print("Error: Invalid input", file=sys.stderr)
|
||||
continue
|
||||
|
||||
|
||||
def _prompt_object_file(build: Path) -> Path:
|
||||
# Look for object files in .pio/build directory
|
||||
build_dir = build / ".pio" / "build"
|
||||
object_files = []
|
||||
|
||||
# Walk through build directory to find .o files
|
||||
for root, _, files in os.walk(build_dir):
|
||||
for file in files:
|
||||
if file.endswith(".o") and "FrameworkArduino" not in file:
|
||||
full_path = Path(root) / file
|
||||
if "FrameworkArduino" not in full_path.parts:
|
||||
object_files.append(full_path)
|
||||
|
||||
if not object_files:
|
||||
print("Error: No object files found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("\nSelect an object file:")
|
||||
for i, obj_file in enumerate(object_files):
|
||||
print(f" [{i}]: {obj_file.relative_to(build_dir)}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
which = int(input("Enter the number of the object file to use: "))
|
||||
if 0 <= which < len(object_files):
|
||||
return object_files[which]
|
||||
print("Error: Invalid selection", file=sys.stderr)
|
||||
except ValueError:
|
||||
print("Error: Invalid input", file=sys.stderr)
|
||||
continue
|
||||
|
||||
|
||||
def cli() -> None:
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Dump object file information using build tools"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"build_path",
|
||||
type=Path,
|
||||
nargs="?",
|
||||
help="Path to build directory containing build info JSON file",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
build_path = args.build_path
|
||||
|
||||
# Check if object file was provided and exists
|
||||
if build_path is None:
|
||||
build_path = _prompt_build()
|
||||
else:
|
||||
if not _check_build(build_path):
|
||||
print("Error: Invalid build directory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
assert build_path is not None
|
||||
assert build_path
|
||||
|
||||
build_info_path = build_path / "build_info.json"
|
||||
assert build_info_path.exists(), f"File not found: {build_info_path}"
|
||||
|
||||
tools = load_tools(build_info_path)
|
||||
|
||||
object_file = _prompt_object_file(build_path)
|
||||
|
||||
cmd = [str(tools.objdump_path), "--syms", str(object_file)]
|
||||
if sys.platform == "win32":
|
||||
cmd = ["cmd", "/c"] + cmd
|
||||
cmd_str = subprocess.list2cmdline(cmd)
|
||||
subprocess.run(cmd, check=True)
|
||||
print("\nDone. Command used:", cmd_str)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
cli()
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting...")
|
||||
sys.exit(1)
|
||||
16
libraries/FastLED/ci/kitchensink/kitchensink.ino.cpp
Normal file
16
libraries/FastLED/ci/kitchensink/kitchensink.ino.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "FastLED.h"
|
||||
|
||||
// Let's include a bunch of stuff and see if it breaks the build.
|
||||
#include <WiFi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <NetworkUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
}
|
||||
17
libraries/FastLED/ci/kitchensink/platformio.ini
Normal file
17
libraries/FastLED/ci/kitchensink/platformio.ini
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[platformio]
|
||||
src_dir = symlink://../../../src
|
||||
|
||||
[env:dev]
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
|
||||
board = esp32-s3-devkitc-1
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
https://github.com/dvarrel/AsyncTCP
|
||||
https://github.com/mathieucarbou/ESPAsyncWebServer
|
||||
ArduinoJson
|
||||
FS
|
||||
ArduinoOTA
|
||||
ESPmDNS
|
||||
|
||||
lib_ldf_mode=deep
|
||||
build_flags=-DFASTLED_STUB_MAIN_INCLUDE_INO="../ci/kitchensink/kitchensink.ino.cpp"
|
||||
11
libraries/FastLED/ci/native/platformio.ini
Normal file
11
libraries/FastLED/ci/native/platformio.ini
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[platformio]
|
||||
src_dir = symlink://../../../src
|
||||
|
||||
[env:dev]
|
||||
platform = platformio/native
|
||||
|
||||
build_flags =
|
||||
-DFASTLED_STUB_IMPL
|
||||
-DFASTLED_STUB_MAIN_INCLUDE_INO="../examples/Blink/Blink.ino"
|
||||
-std=c++17
|
||||
|
||||
42
libraries/FastLED/ci/optimization_report.py
Normal file
42
libraries/FastLED/ci/optimization_report.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert a binary file to ELF using map file."
|
||||
)
|
||||
parser.add_argument("--first", action="store_true", help="Inspect the first board")
|
||||
parser.add_argument("--cwd", type=Path, help="Custom working directory")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
if args.cwd:
|
||||
root_build_dir = args.cwd / ".build"
|
||||
else:
|
||||
root_build_dir = Path(".build")
|
||||
board_dirs = [d for d in root_build_dir.iterdir() if d.is_dir()]
|
||||
if not board_dirs:
|
||||
print(f"No board directories found in {root_build_dir.absolute()}")
|
||||
return 1
|
||||
print("Available boards:")
|
||||
for i, board_dir in enumerate(board_dirs):
|
||||
print(f"[{i}]: {board_dir.name}")
|
||||
which = (
|
||||
0
|
||||
if args.first
|
||||
else int(input("Enter the number of the board you want to inspect: "))
|
||||
)
|
||||
board_dir = board_dirs[which]
|
||||
# build_info_json = board_dir / "build_info.json"
|
||||
optimization_report = board_dir / "optimization_report.txt"
|
||||
text = optimization_report.read_text(encoding="utf-8")
|
||||
print(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
419
libraries/FastLED/ci/run-clang-format.py
Normal file
419
libraries/FastLED/ci/run-clang-format.py
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
#!/usr/bin/env python
|
||||
"""A wrapper script around clang-format, suitable for linting multiple files
|
||||
and to use for continuous integration.
|
||||
|
||||
This is an alternative API for the clang-format command line.
|
||||
It runs over multiple files and directories in parallel.
|
||||
A diff output is produced and a sensible exit code is returned.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import codecs
|
||||
import difflib
|
||||
import errno
|
||||
import fnmatch
|
||||
import io
|
||||
import multiprocessing
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
from functools import partial
|
||||
|
||||
try:
|
||||
from subprocess import DEVNULL # py3k
|
||||
except ImportError:
|
||||
DEVNULL = open(os.devnull, "wb") # type: ignore
|
||||
|
||||
|
||||
DEFAULT_EXTENSIONS = "c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx"
|
||||
DEFAULT_CLANG_FORMAT_IGNORE = ".clang-format-ignore"
|
||||
|
||||
|
||||
class ExitStatus:
|
||||
SUCCESS = 0
|
||||
DIFF = 1
|
||||
TROUBLE = 2
|
||||
|
||||
|
||||
def excludes_from_file(ignore_file):
|
||||
excludes = []
|
||||
try:
|
||||
with io.open(ignore_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
if line.startswith("#"):
|
||||
# ignore comments
|
||||
continue
|
||||
pattern = line.rstrip()
|
||||
if not pattern:
|
||||
# allow empty lines
|
||||
continue
|
||||
excludes.append(pattern)
|
||||
except EnvironmentError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
return excludes
|
||||
|
||||
|
||||
def list_files(files, recursive=False, extensions=None, exclude=None):
|
||||
if extensions is None:
|
||||
extensions = []
|
||||
if exclude is None:
|
||||
exclude = []
|
||||
|
||||
out = []
|
||||
for file in files:
|
||||
if recursive and os.path.isdir(file):
|
||||
for dirpath, dnames, fnames in os.walk(file):
|
||||
fpaths = [os.path.join(dirpath, fname) for fname in fnames]
|
||||
for pattern in exclude:
|
||||
# os.walk() supports trimming down the dnames list
|
||||
# by modifying it in-place,
|
||||
# to avoid unnecessary directory listings.
|
||||
dnames[:] = [
|
||||
x
|
||||
for x in dnames
|
||||
if not fnmatch.fnmatch(os.path.join(dirpath, x), pattern)
|
||||
]
|
||||
fpaths = [x for x in fpaths if not fnmatch.fnmatch(x, pattern)]
|
||||
for f in fpaths:
|
||||
ext = os.path.splitext(f)[1][1:]
|
||||
if ext in extensions:
|
||||
out.append(f)
|
||||
else:
|
||||
out.append(file)
|
||||
return out
|
||||
|
||||
|
||||
def make_diff(file, original, reformatted):
|
||||
return list(
|
||||
difflib.unified_diff(
|
||||
original,
|
||||
reformatted,
|
||||
fromfile="{}\t(original)".format(file),
|
||||
tofile="{}\t(reformatted)".format(file),
|
||||
n=3,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class DiffError(Exception):
|
||||
def __init__(self, message, errs=None):
|
||||
super(DiffError, self).__init__(message)
|
||||
self.errs = errs or []
|
||||
|
||||
|
||||
class UnexpectedError(Exception):
|
||||
def __init__(self, message, exc=None):
|
||||
super(UnexpectedError, self).__init__(message)
|
||||
self.formatted_traceback = traceback.format_exc()
|
||||
self.exc = exc
|
||||
|
||||
|
||||
def run_clang_format_diff_wrapper(args, file):
|
||||
try:
|
||||
ret = run_clang_format_diff(args, file)
|
||||
return ret
|
||||
except DiffError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise UnexpectedError("{}: {}: {}".format(file, e.__class__.__name__, e), e)
|
||||
|
||||
|
||||
def run_clang_format_diff(args, file):
|
||||
try:
|
||||
with io.open(file, "r", encoding="utf-8") as f:
|
||||
original = f.readlines()
|
||||
except IOError as exc:
|
||||
raise DiffError(str(exc))
|
||||
|
||||
if args.in_place:
|
||||
invocation = [args.clang_format_executable, "-i", file]
|
||||
else:
|
||||
invocation = [args.clang_format_executable, file]
|
||||
|
||||
if args.style:
|
||||
invocation.extend(["--style", args.style])
|
||||
|
||||
if args.dry_run:
|
||||
print(" ".join(invocation))
|
||||
return [], []
|
||||
|
||||
# Use of utf-8 to decode the process output.
|
||||
#
|
||||
# Hopefully, this is the correct thing to do.
|
||||
#
|
||||
# It's done due to the following assumptions (which may be incorrect):
|
||||
# - clang-format will returns the bytes read from the files as-is,
|
||||
# without conversion, and it is already assumed that the files use utf-8.
|
||||
# - if the diagnostics were internationalized, they would use utf-8:
|
||||
# > Adding Translations to Clang
|
||||
# >
|
||||
# > Not possible yet!
|
||||
# > Diagnostic strings should be written in UTF-8,
|
||||
# > the client can translate to the relevant code page if needed.
|
||||
# > Each translation completely replaces the format string
|
||||
# > for the diagnostic.
|
||||
# > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation
|
||||
#
|
||||
# It's not pretty, due to Python 2 & 3 compatibility.
|
||||
encoding_py3 = {}
|
||||
if sys.version_info[0] >= 3:
|
||||
encoding_py3["encoding"] = "utf-8"
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
invocation,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
**encoding_py3,
|
||||
)
|
||||
except OSError as exc:
|
||||
raise DiffError(
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(invocation), exc
|
||||
)
|
||||
)
|
||||
proc_stdout = proc.stdout
|
||||
proc_stderr = proc.stderr
|
||||
assert proc_stdout is not None
|
||||
assert proc_stderr is not None
|
||||
if sys.version_info[0] < 3:
|
||||
# make the pipes compatible with Python 3,
|
||||
# reading lines should output unicode
|
||||
encoding = "utf-8"
|
||||
proc_stdout = codecs.getreader(encoding)(proc_stdout)
|
||||
proc_stderr = codecs.getreader(encoding)(proc_stderr)
|
||||
# hopefully the stderr pipe won't get full and block the process
|
||||
outs = list(proc_stdout.readlines())
|
||||
errs = list(proc_stderr.readlines())
|
||||
proc.wait()
|
||||
if proc.returncode:
|
||||
raise DiffError(
|
||||
"Command '{}' returned non-zero exit status {}".format(
|
||||
subprocess.list2cmdline(invocation), proc.returncode
|
||||
),
|
||||
errs,
|
||||
)
|
||||
if args.in_place:
|
||||
return [], errs
|
||||
return make_diff(file, original, outs), errs
|
||||
|
||||
|
||||
def bold_red(s):
|
||||
return "\x1b[1m\x1b[31m" + s + "\x1b[0m"
|
||||
|
||||
|
||||
def colorize(diff_lines):
|
||||
def bold(s):
|
||||
return "\x1b[1m" + s + "\x1b[0m"
|
||||
|
||||
def cyan(s):
|
||||
return "\x1b[36m" + s + "\x1b[0m"
|
||||
|
||||
def green(s):
|
||||
return "\x1b[32m" + s + "\x1b[0m"
|
||||
|
||||
def red(s):
|
||||
return "\x1b[31m" + s + "\x1b[0m"
|
||||
|
||||
for line in diff_lines:
|
||||
if line[:4] in ["--- ", "+++ "]:
|
||||
yield bold(line)
|
||||
elif line.startswith("@@ "):
|
||||
yield cyan(line)
|
||||
elif line.startswith("+"):
|
||||
yield green(line)
|
||||
elif line.startswith("-"):
|
||||
yield red(line)
|
||||
else:
|
||||
yield line
|
||||
|
||||
|
||||
def print_diff(diff_lines, use_color):
|
||||
if use_color:
|
||||
diff_lines = colorize(diff_lines)
|
||||
if sys.version_info[0] < 3:
|
||||
sys.stdout.writelines((line.encode("utf-8") for line in diff_lines))
|
||||
else:
|
||||
sys.stdout.writelines(diff_lines)
|
||||
|
||||
|
||||
def print_trouble(prog, message, use_colors):
|
||||
error_text = "error:"
|
||||
if use_colors:
|
||||
error_text = bold_red(error_text)
|
||||
print("{}: {} {}".format(prog, error_text, message), file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--clang-format-executable",
|
||||
metavar="EXECUTABLE",
|
||||
help="path to the clang-format executable",
|
||||
default="clang-format",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extensions",
|
||||
help="comma separated list of file extensions (default: {})".format(
|
||||
DEFAULT_EXTENSIONS
|
||||
),
|
||||
default=DEFAULT_EXTENSIONS,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--recursive",
|
||||
action="store_true",
|
||||
help="run recursively over directories",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d", "--dry-run", action="store_true", help="just print the list of files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--in-place",
|
||||
action="store_true",
|
||||
help="format file instead of printing differences",
|
||||
)
|
||||
parser.add_argument("files", metavar="file", nargs="+")
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quiet",
|
||||
action="store_true",
|
||||
help="disable output, useful for the exit code",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
metavar="N",
|
||||
type=int,
|
||||
default=0,
|
||||
help="run N clang-format jobs in parallel" " (default number of cpus + 1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--color",
|
||||
default="auto",
|
||||
choices=["auto", "always", "never"],
|
||||
help="show colored diff (default: auto)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--exclude",
|
||||
metavar="PATTERN",
|
||||
action="append",
|
||||
default=[],
|
||||
help="exclude paths matching the given glob-like pattern(s)"
|
||||
" from recursive search",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--style",
|
||||
help="formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# use default signal handling, like diff return SIGINT value on ^C
|
||||
# https://bugs.python.org/issue14229#msg156446
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
try:
|
||||
signal.SIGPIPE # type: ignore
|
||||
except AttributeError:
|
||||
# compatibility, SIGPIPE does not exist on Windows
|
||||
pass
|
||||
else:
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL) # type: ignore
|
||||
|
||||
colored_stdout = False
|
||||
colored_stderr = False
|
||||
if args.color == "always":
|
||||
colored_stdout = True
|
||||
colored_stderr = True
|
||||
elif args.color == "auto":
|
||||
colored_stdout = sys.stdout.isatty()
|
||||
colored_stderr = sys.stderr.isatty()
|
||||
|
||||
version_invocation = [args.clang_format_executable, str("--version")]
|
||||
try:
|
||||
subprocess.check_call(version_invocation, stdout=DEVNULL)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
return ExitStatus.TROUBLE
|
||||
except OSError as e:
|
||||
print_trouble(
|
||||
parser.prog,
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(version_invocation), e
|
||||
),
|
||||
use_colors=colored_stderr,
|
||||
)
|
||||
return ExitStatus.TROUBLE
|
||||
|
||||
retcode = ExitStatus.SUCCESS
|
||||
|
||||
excludes = excludes_from_file(DEFAULT_CLANG_FORMAT_IGNORE)
|
||||
excludes.extend(args.exclude)
|
||||
|
||||
files = list_files(
|
||||
args.files,
|
||||
recursive=args.recursive,
|
||||
exclude=excludes,
|
||||
extensions=args.extensions.split(","),
|
||||
)
|
||||
|
||||
if not files:
|
||||
return
|
||||
|
||||
njobs = args.j
|
||||
if njobs == 0:
|
||||
njobs = multiprocessing.cpu_count() + 1
|
||||
njobs = min(len(files), njobs)
|
||||
|
||||
if njobs == 1:
|
||||
# execute directly instead of in a pool,
|
||||
# less overhead, simpler stacktraces
|
||||
it = (run_clang_format_diff_wrapper(args, file) for file in files)
|
||||
pool = None
|
||||
else:
|
||||
pool = multiprocessing.Pool(njobs)
|
||||
it = pool.imap_unordered(partial(run_clang_format_diff_wrapper, args), files)
|
||||
pool.close()
|
||||
while True:
|
||||
try:
|
||||
outs, errs = next(it)
|
||||
except StopIteration:
|
||||
break
|
||||
except DiffError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
sys.stderr.writelines(e.errs)
|
||||
except UnexpectedError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
sys.stderr.write(e.formatted_traceback)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
# stop at the first unexpected error,
|
||||
# something could be very wrong,
|
||||
# don't process all files unnecessarily
|
||||
if pool:
|
||||
pool.terminate()
|
||||
break
|
||||
else:
|
||||
sys.stderr.writelines(errs)
|
||||
if outs == []:
|
||||
continue
|
||||
if not args.quiet:
|
||||
print_diff(outs, use_color=colored_stdout)
|
||||
if retcode == ExitStatus.SUCCESS:
|
||||
retcode = ExitStatus.DIFF
|
||||
if pool:
|
||||
pool.join()
|
||||
return retcode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
29
libraries/FastLED/ci/run_test_wasm_local_compile.py
Normal file
29
libraries/FastLED/ci/run_test_wasm_local_compile.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"""
|
||||
Unit test file.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class ApiTester(unittest.TestCase):
|
||||
"""Main tester class."""
|
||||
|
||||
def test_build_all_examples(self) -> None:
|
||||
"""Test command line interface (CLI)."""
|
||||
from fastled import Api, Test # type: ignore
|
||||
|
||||
with Api.server(auto_updates=True) as server:
|
||||
|
||||
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__":
|
||||
unittest.main()
|
||||
66
libraries/FastLED/ci/tests/test_bin_2_elf.py
Normal file
66
libraries/FastLED/ci/tests/test_bin_2_elf.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import subprocess
|
||||
import unittest
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
from ci.bin_2_elf import bin_to_elf
|
||||
from ci.elf import dump_symbol_sizes
|
||||
from ci.paths import PROJECT_ROOT
|
||||
from ci.tools import Tools, load_tools
|
||||
|
||||
HERE = Path(__file__).resolve().parent.absolute()
|
||||
UNO = HERE / "uno"
|
||||
OUTPUT = HERE / "output"
|
||||
|
||||
|
||||
BUILD_INFO_PATH = PROJECT_ROOT / ".build" / "uno" / "build_info.json"
|
||||
|
||||
DISABLED = True
|
||||
|
||||
|
||||
class TestBinToElf(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if DISABLED:
|
||||
return
|
||||
uno_build = PROJECT_ROOT / ".build" / "uno"
|
||||
print(f"Checking for Uno build in: {uno_build}")
|
||||
if not uno_build.exists():
|
||||
print("Uno build not found. Running compilation...")
|
||||
try:
|
||||
subprocess.run(
|
||||
"uv run ci/ci-compile.py uno --examples Blink",
|
||||
shell=True,
|
||||
check=True,
|
||||
)
|
||||
print("Compilation completed successfully.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error during compilation: {e}")
|
||||
raise
|
||||
|
||||
@unittest.skip("Skip bin to elf conversion test")
|
||||
def test_bin_to_elf_conversion(self) -> None:
|
||||
if DISABLED:
|
||||
return
|
||||
tools: Tools = load_tools(BUILD_INFO_PATH)
|
||||
bin_file = UNO / "firmware.hex"
|
||||
map_file = UNO / "firmware.map"
|
||||
output_elf = OUTPUT / "output.elf"
|
||||
try:
|
||||
bin_to_elf(
|
||||
bin_file,
|
||||
map_file,
|
||||
tools.as_path,
|
||||
tools.ld_path,
|
||||
tools.objcopy_path,
|
||||
output_elf,
|
||||
)
|
||||
stdout = dump_symbol_sizes(tools.nm_path, tools.cpp_filt_path, output_elf)
|
||||
print(stdout)
|
||||
except Exception as e:
|
||||
warnings.warn(f"Error while converting binary to ELF: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
49
libraries/FastLED/ci/tests/test_elf.py
Normal file
49
libraries/FastLED/ci/tests/test_elf.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import subprocess
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from ci.elf import dump_symbol_sizes
|
||||
from ci.paths import PROJECT_ROOT
|
||||
from ci.tools import Tools, load_tools
|
||||
|
||||
HERE = Path(__file__).resolve().parent.absolute()
|
||||
UNO = HERE / "uno"
|
||||
OUTPUT = HERE / "output"
|
||||
ELF_FILE = UNO / "firmware.elf"
|
||||
BUILD_INFO_PATH = PROJECT_ROOT / ".build" / "uno" / "build_info.json"
|
||||
|
||||
|
||||
PLATFORMIO_PATH = Path.home() / ".platformio"
|
||||
PLATFORMIO_PACKAGES_PATH = PLATFORMIO_PATH / "packages"
|
||||
TOOLCHAIN_AVR = PLATFORMIO_PACKAGES_PATH / "toolchain-atmelavr"
|
||||
|
||||
|
||||
def init() -> None:
|
||||
uno_build = PROJECT_ROOT / ".build" / "uno"
|
||||
print(f"Checking for Uno build in: {uno_build}")
|
||||
if not BUILD_INFO_PATH.exists() or not TOOLCHAIN_AVR.exists():
|
||||
print("Uno build not found. Running compilation...")
|
||||
try:
|
||||
subprocess.run(
|
||||
"uv run ci/ci-compile.py uno --examples Blink",
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=str(PROJECT_ROOT),
|
||||
)
|
||||
print("Compilation completed successfully.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error during compilation: {e}")
|
||||
raise
|
||||
|
||||
|
||||
class TestBinToElf(unittest.TestCase):
|
||||
|
||||
def test_bin_to_elf_conversion(self) -> None:
|
||||
init()
|
||||
tools: Tools = load_tools(BUILD_INFO_PATH)
|
||||
msg = dump_symbol_sizes(tools.nm_path, tools.cpp_filt_path, ELF_FILE)
|
||||
print(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
16
libraries/FastLED/ci/tests/test_map_parser.py
Normal file
16
libraries/FastLED/ci/tests/test_map_parser.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from ci.map_dump import map_dump
|
||||
|
||||
HERE = Path(__file__).resolve().parent.absolute()
|
||||
UNO = HERE / "uno"
|
||||
|
||||
|
||||
class TestMapParser(unittest.TestCase):
|
||||
def test_map_parser(self):
|
||||
map_dump(UNO / "firmware.map")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
119
libraries/FastLED/ci/tests/test_missing_pragma_once.py
Normal file
119
libraries/FastLED/ci/tests/test_missing_pragma_once.py
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import os
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
SRC_ROOT = PROJECT_ROOT / "src"
|
||||
|
||||
NUM_WORKERS = (os.cpu_count() or 1) * 4
|
||||
|
||||
# Files that are allowed to not have #pragma once
|
||||
EXCLUDED_FILES = [
|
||||
# Add any exceptions here
|
||||
]
|
||||
|
||||
EXCLUDED_DIRS = [
|
||||
"third_party",
|
||||
"platforms",
|
||||
]
|
||||
|
||||
|
||||
class TestMissingPragmaOnce(unittest.TestCase):
|
||||
|
||||
def check_file(self, file_path: str) -> list[str]:
|
||||
"""Check if a header file has #pragma once directive or if a cpp file incorrectly has it."""
|
||||
failings: list[str] = []
|
||||
|
||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
||||
content = f.read()
|
||||
|
||||
if file_path.endswith(".h"):
|
||||
# For header files, check if #pragma once is missing
|
||||
if "#pragma once" not in content:
|
||||
failings.append(f"Missing #pragma once in {file_path}")
|
||||
elif file_path.endswith(".cpp"):
|
||||
# For cpp files, check if #pragma once is incorrectly present
|
||||
if "#pragma once" in content:
|
||||
failings.append(f"Incorrect #pragma once in cpp file: {file_path}")
|
||||
|
||||
return failings
|
||||
|
||||
def test_pragma_once_usage(self) -> None:
|
||||
"""
|
||||
Searches through files to:
|
||||
1. Check for missing #pragma once in header files
|
||||
2. Check for incorrect #pragma once in cpp files
|
||||
"""
|
||||
files_to_check = []
|
||||
current_dir = None
|
||||
|
||||
# Collect files to check
|
||||
for root, dirs, files in os.walk(SRC_ROOT):
|
||||
# Log when we enter a new directory
|
||||
rel_path = os.path.relpath(root, SRC_ROOT)
|
||||
if current_dir != rel_path:
|
||||
current_dir = rel_path
|
||||
print(f"Traversing directory: {rel_path}")
|
||||
if rel_path in EXCLUDED_DIRS:
|
||||
print(f" Skipping excluded directory: {rel_path}")
|
||||
dirs[:] = [] # Skip this directory and its subdirectories
|
||||
continue
|
||||
|
||||
# Check if this directory should be excluded
|
||||
# if any(os.path.normpath(root).startswith(os.path.normpath(excluded_dir))
|
||||
# for excluded_dir in EXCLUDED_DIRS):
|
||||
# print(f" Skipping excluded directory: {rel_path}")
|
||||
# continue
|
||||
for excluded_dir in EXCLUDED_DIRS:
|
||||
npath = os.path.normpath(root)
|
||||
npath_excluded = os.path.normpath(excluded_dir)
|
||||
print(f"Checking {npath} against excluded {npath_excluded}")
|
||||
if npath.startswith(npath_excluded):
|
||||
print(f" Skipping excluded directory: {rel_path}")
|
||||
break
|
||||
|
||||
for file in files:
|
||||
if file.endswith((".h", ".cpp")): # Check both header and cpp files
|
||||
file_path = os.path.join(root, file)
|
||||
|
||||
# Check if file is excluded
|
||||
# if any(file_path.endswith(excluded) for excluded in EXCLUDED_FILES):
|
||||
# print(f" Skipping excluded file: {file}")
|
||||
# continue
|
||||
for excluded in EXCLUDED_FILES:
|
||||
# print(f"Checking {file_path} against excluded {excluded}")
|
||||
if file_path.endswith(excluded):
|
||||
print(f" Skipping excluded file: {file}")
|
||||
break
|
||||
|
||||
files_to_check.append(file_path)
|
||||
|
||||
print(f"Found {len(files_to_check)} files to check")
|
||||
|
||||
# Process files in parallel
|
||||
all_failings = []
|
||||
with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
|
||||
futures = [
|
||||
executor.submit(self.check_file, file_path)
|
||||
for file_path in files_to_check
|
||||
]
|
||||
for future in futures:
|
||||
all_failings.extend(future.result())
|
||||
|
||||
# Report results
|
||||
if all_failings:
|
||||
msg = f"Found {len(all_failings)} pragma once issues: \n" + "\n".join(
|
||||
all_failings
|
||||
)
|
||||
for failing in all_failings:
|
||||
print(failing)
|
||||
self.fail(msg)
|
||||
else:
|
||||
print("All files have proper pragma once usage.")
|
||||
|
||||
print(f"Pragma once check completed. Processed {len(files_to_check)} files.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
132
libraries/FastLED/ci/tests/test_no_banned_headers.py
Normal file
132
libraries/FastLED/ci/tests/test_no_banned_headers.py
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import os
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
SRC_ROOT = PROJECT_ROOT / "src"
|
||||
PLATFORMS_DIR = os.path.join(SRC_ROOT, "platforms")
|
||||
PLATFORMS_ESP_DIR = os.path.join(PLATFORMS_DIR, "esp")
|
||||
|
||||
NUM_WORKERS = (os.cpu_count() or 1) * 4
|
||||
|
||||
ENABLE_PARANOID_GNU_HEADER_INSPECTION = False
|
||||
|
||||
if ENABLE_PARANOID_GNU_HEADER_INSPECTION:
|
||||
BANNED_HEADERS_ESP = ["esp32-hal.h"]
|
||||
else:
|
||||
BANNED_HEADERS_ESP = []
|
||||
|
||||
|
||||
BANNED_HEADERS_CORE = [
|
||||
"assert.h",
|
||||
"iostream",
|
||||
"stdio.h",
|
||||
"cstdio",
|
||||
"cstdlib",
|
||||
"vector",
|
||||
"list",
|
||||
"map",
|
||||
"set",
|
||||
"queue",
|
||||
"deque",
|
||||
"algorithm",
|
||||
"memory",
|
||||
"thread",
|
||||
"mutex",
|
||||
"chrono",
|
||||
"fstream",
|
||||
"sstream",
|
||||
"iomanip",
|
||||
"exception",
|
||||
"stdexcept",
|
||||
"typeinfo",
|
||||
"ctime",
|
||||
"cmath",
|
||||
"complex",
|
||||
"valarray",
|
||||
"cfloat",
|
||||
"cassert",
|
||||
"cerrno",
|
||||
"cctype",
|
||||
"cwctype",
|
||||
"cstring",
|
||||
"cwchar",
|
||||
"cuchar",
|
||||
"cstdint",
|
||||
"cstddef", # this certainally fails
|
||||
"type_traits", # this certainally fails
|
||||
"Arduino.h",
|
||||
] + BANNED_HEADERS_ESP
|
||||
|
||||
EXCLUDED_FILES = [
|
||||
"stub_main.cpp",
|
||||
]
|
||||
|
||||
|
||||
class TestNoBannedHeaders(unittest.TestCase):
|
||||
|
||||
def check_file(self, file_path: str) -> list[str]:
|
||||
failings: list[str] = []
|
||||
banned_headers_list = []
|
||||
if file_path.startswith(PLATFORMS_DIR):
|
||||
# continue # Skip the platforms directory
|
||||
if file_path.startswith(PLATFORMS_ESP_DIR):
|
||||
banned_headers_list = BANNED_HEADERS_ESP
|
||||
else:
|
||||
return failings
|
||||
if len(banned_headers_list) == 0:
|
||||
return failings
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
|
||||
for line_number, line in enumerate(f, 1):
|
||||
if line.startswith("//"):
|
||||
continue
|
||||
for header in banned_headers_list:
|
||||
if (
|
||||
f"#include <{header}>" in line or f'#include "{header}"' in line
|
||||
) and "// ok include" not in line:
|
||||
failings.append(
|
||||
f"Found banned header '{header}' in {file_path}:{line_number}"
|
||||
)
|
||||
return failings
|
||||
|
||||
def test_no_banned_headers(self) -> None:
|
||||
"""Searches through the program files to check for banned headers, excluding src/platforms."""
|
||||
files_to_check = []
|
||||
for root, _, files in os.walk(SRC_ROOT):
|
||||
for file in files:
|
||||
if file.endswith(
|
||||
(".cpp", ".h", ".hpp")
|
||||
): # Add or remove file extensions as needed
|
||||
file_path = os.path.join(root, file)
|
||||
if not any(
|
||||
file_path.endswith(excluded) for excluded in EXCLUDED_FILES
|
||||
):
|
||||
files_to_check.append(file_path)
|
||||
|
||||
all_failings = []
|
||||
with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
|
||||
futures = [
|
||||
executor.submit(self.check_file, file_path)
|
||||
for file_path in files_to_check
|
||||
]
|
||||
for future in futures:
|
||||
all_failings.extend(future.result())
|
||||
|
||||
if all_failings:
|
||||
msg = f"Found {len(all_failings)} banned header(s): \n" + "\n".join(
|
||||
all_failings
|
||||
)
|
||||
for failing in all_failings:
|
||||
print(failing)
|
||||
self.fail(
|
||||
msg + "\n"
|
||||
"You can add '// ok include' at the end of the line to silence this error for specific inclusions."
|
||||
)
|
||||
else:
|
||||
print("No banned headers found.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import os
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
SRC_ROOT = PROJECT_ROOT / "src"
|
||||
PLATFORMS_DIR = os.path.join(SRC_ROOT, "platforms")
|
||||
|
||||
NUM_WORKERS = (os.cpu_count() or 1) * 4
|
||||
|
||||
|
||||
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):
|
||||
if line.startswith("//"):
|
||||
continue
|
||||
if "using namespace fl;" in line:
|
||||
failings.append(f"{file_path}:{line_number}: {line.strip()}")
|
||||
return failings
|
||||
|
||||
def test_no_using_namespace(self) -> None:
|
||||
"""Searches through the program files to check for banned headers, excluding src/platforms."""
|
||||
files_to_check = []
|
||||
for root, _, files in os.walk(SRC_ROOT):
|
||||
for file in files:
|
||||
if file.endswith(
|
||||
(".h", ".hpp")
|
||||
): # Add or remove file extensions as needed
|
||||
file_path = os.path.join(root, file)
|
||||
files_to_check.append(file_path)
|
||||
|
||||
all_failings = []
|
||||
with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
|
||||
futures = [
|
||||
executor.submit(self.check_file, file_path)
|
||||
for file_path in files_to_check
|
||||
]
|
||||
for future in futures:
|
||||
all_failings.extend(future.result())
|
||||
|
||||
if all_failings:
|
||||
msg = (
|
||||
f'Found {len(all_failings)} header file(s) "using namespace fl": \n'
|
||||
+ "\n".join(all_failings)
|
||||
)
|
||||
for failing in all_failings:
|
||||
print(failing)
|
||||
self.fail(msg)
|
||||
else:
|
||||
print("No using namespace fl; found in headers.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
79
libraries/FastLED/ci/tests/test_wasm_clang_format.py
Normal file
79
libraries/FastLED/ci/tests/test_wasm_clang_format.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import os
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
NUM_WORKERS = (os.cpu_count() or 1) * 4
|
||||
|
||||
|
||||
WASM_ROOT = PROJECT_ROOT / "src" / "platforms" / "wasm"
|
||||
|
||||
|
||||
class TestMissingPragmaOnce(unittest.TestCase):
|
||||
|
||||
def check_file(self, file_path: str) -> list[str]:
|
||||
"""Check if a header file has #pragma once directive or if a cpp file incorrectly has it."""
|
||||
failings: list[str] = []
|
||||
|
||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
||||
if file_path.endswith(".h") or file_path.endswith(".cpp"):
|
||||
content = f.read()
|
||||
# For header files, check if #pragma once is missing
|
||||
if "EM_ASM_" in content and "// clang-format off\n" not in content:
|
||||
if "clang-format off" not in content:
|
||||
failings.append(f"Missing clang-format off in {file_path}")
|
||||
else:
|
||||
failings.append(f"clang-format off is malformed in {file_path}")
|
||||
|
||||
return failings
|
||||
|
||||
def test_esm_asm_and_clang_format(self) -> None:
|
||||
files_to_check = []
|
||||
current_dir = None
|
||||
|
||||
# Collect files to check
|
||||
for root, _, files in os.walk(WASM_ROOT):
|
||||
# Log when we enter a new directory
|
||||
rel_path = os.path.relpath(root, WASM_ROOT)
|
||||
if current_dir != rel_path:
|
||||
current_dir = rel_path
|
||||
print(f"Traversing directory: {rel_path}")
|
||||
|
||||
for file in files:
|
||||
if file.endswith((".h", ".cpp")): # Check both header and cpp files
|
||||
file_path = os.path.join(root, file)
|
||||
files_to_check.append(file_path)
|
||||
|
||||
print(f"Found {len(files_to_check)} files to check")
|
||||
|
||||
# Process files in parallel
|
||||
all_failings = []
|
||||
with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
|
||||
futures = [
|
||||
executor.submit(self.check_file, file_path)
|
||||
for file_path in files_to_check
|
||||
]
|
||||
for future in futures:
|
||||
all_failings.extend(future.result())
|
||||
|
||||
# Report results
|
||||
if all_failings:
|
||||
msg = (
|
||||
f"Found {len(all_failings)} clang format issues in wasm: \n"
|
||||
+ "\n".join(all_failings)
|
||||
)
|
||||
for failing in all_failings:
|
||||
print(failing)
|
||||
print(
|
||||
"Please be aware you need // then one space then clang-format off then a new line exactly"
|
||||
)
|
||||
self.fail(msg)
|
||||
else:
|
||||
print("All files passed the check.")
|
||||
|
||||
print(f"Clange format check completed. Processed {len(files_to_check)} files.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
63
libraries/FastLED/ci/tests/test_wrong_defines.py
Normal file
63
libraries/FastLED/ci/tests/test_wrong_defines.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import os
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from ci.paths import PROJECT_ROOT
|
||||
|
||||
SRC_ROOT = PROJECT_ROOT / "src"
|
||||
# PLATFORMS_DIR = os.path.join(SRC_ROOT, "platforms")
|
||||
|
||||
NUM_WORKERS = (os.cpu_count() or 1) * 4
|
||||
|
||||
WRONG_DEFINES: dict[str, str] = {
|
||||
"#if ESP32": "Use #ifdef ESP32 instead of #if ESP32",
|
||||
"#if defined(FASTLED_RMT5)": "Use #ifdef FASTLED_RMT5 instead of #if defined(FASTLED_RMT5)",
|
||||
"#if defined(FASTLED_ESP_HAS_CLOCKLESS_SPI)": "Use #ifdef FASTLED_ESP_HAS_CLOCKLESS_SPI instead of #if defined(FASTLED_ESP_HAS_CLOCKLESS_SPI)",
|
||||
}
|
||||
|
||||
|
||||
class TestWrongDefines(unittest.TestCase):
|
||||
|
||||
def check_file(self, file_path) -> list[str]:
|
||||
failings = []
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
for line_number, line in enumerate(f, 1):
|
||||
line = line.strip()
|
||||
if line.startswith("//"):
|
||||
continue
|
||||
for needle, message in WRONG_DEFINES.items():
|
||||
if needle in line:
|
||||
failings.append(f"{file_path}:{line_number}: {message}")
|
||||
return failings
|
||||
|
||||
def test_no_bad_defines(self) -> None:
|
||||
"""Searches through the program files to check for banned headers, excluding src/platforms."""
|
||||
files_to_check = []
|
||||
for root, _, files in os.walk(SRC_ROOT):
|
||||
for file in files:
|
||||
if file.endswith(
|
||||
(".cpp", ".h", ".hpp")
|
||||
): # Add or remove file extensions as needed
|
||||
file_path = os.path.join(root, file)
|
||||
files_to_check.append(file_path)
|
||||
|
||||
all_failings = []
|
||||
with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
|
||||
futures = [
|
||||
executor.submit(self.check_file, file_path)
|
||||
for file_path in files_to_check
|
||||
]
|
||||
for future in futures:
|
||||
all_failings.extend(future.result())
|
||||
|
||||
if all_failings:
|
||||
msg = f"Found {len(all_failings)} bad defines: \n" + "\n".join(all_failings)
|
||||
for failing in all_failings:
|
||||
print(failing)
|
||||
self.fail("Please fix the defines: \n" + msg + "\n")
|
||||
else:
|
||||
print("No bad defines found.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
BIN
libraries/FastLED/ci/tests/uno/firmware.elf
Normal file
BIN
libraries/FastLED/ci/tests/uno/firmware.elf
Normal file
Binary file not shown.
237
libraries/FastLED/ci/tests/uno/firmware.hex
Normal file
237
libraries/FastLED/ci/tests/uno/firmware.hex
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
:100000000C9435000C945D000C945D000C945D0024
|
||||
:100010000C945D000C945D000C945D000C945D00EC
|
||||
:100020000C945D000C945D000C945D000C945D00DC
|
||||
:100030000C945D000C945D000C945D000C945D00CC
|
||||
:100040000C948D050C945D000C945D000C945D0087
|
||||
:100050000C945D000C945D000C945D000C945D00AC
|
||||
:100060000C945D000C945D00BB0611241FBECFEF05
|
||||
:10007000D8E0DEBFCDBF11E0A0E0B1E0EEE8FEE0E9
|
||||
:1000800002C005900D92AE32B107D9F721E0AEE281
|
||||
:10009000B1E001C01D92A637B207E1F710E0C5E359
|
||||
:1000A000D0E004C02197FE010E943A07C433D10773
|
||||
:1000B000C9F70E94D7050C9445070C9400003FB780
|
||||
:1000C000F8948091550190915601A0915701B091FB
|
||||
:1000D000580126B5A89B05C02F3F19F00196A11D18
|
||||
:1000E000B11D3FBFBA2FA92F982F8827BC01CD0182
|
||||
:1000F000620F711D811D911D42E0660F771F881FE1
|
||||
:10010000991F4A95D1F708952F923F924F925F928F
|
||||
:100110006F927F928F929F92AF92BF92CF92DF9217
|
||||
:10012000EF92FF920F931F93CF93DF93CDB7DEB77C
|
||||
:10013000C358D1090FB6F894DEBF0FBECDBF782EDD
|
||||
:100140008091660190916701A0916801B091690169
|
||||
:10015000892B8A2B8B2BD9F00E945F0000917201B2
|
||||
:10016000109173012091740130917501601B710B26
|
||||
:10017000820B930B00916601109167012091680139
|
||||
:10018000309169016017710782079307C8F20E94D6
|
||||
:100190005F00609372017093730180937401909378
|
||||
:1001A0007501E0916E01F0916F01309759F0409127
|
||||
:1001B0006A0150916B0160916C0170916D01872D06
|
||||
:1001C0000995782EFE01319680E8DF011D928A950F
|
||||
:1001D000E9F7E0907001F09071016F015E01B1E804
|
||||
:1001E000AB0EB11C4F01472C512CE114F10409F462
|
||||
:1001F0005CC08A149B0409F458C0D701ED91FC91AE
|
||||
:100200000484F585E02DC7010995F401819391934C
|
||||
:100210004F0180916401909165018436910518F435
|
||||
:10022000D7011C961C92D701ED91FC91228033805E
|
||||
:10023000F501108211821282772019F187010A5F7D
|
||||
:100240001F4FF0E0E0E0D8012D918D012223A9F0AD
|
||||
:1002500012966C90662089F030E02F5F3F4FD201FC
|
||||
:100260000E9405079B01AC01A62DB0E011960E94EB
|
||||
:100270001B07D501AE0FBF1F8C933196E330F105FC
|
||||
:1002800011F7F501008111812281D7011D964D9151
|
||||
:100290005C911E9712966D917C91C701F1010995B1
|
||||
:1002A000D7011496ED90FC90A0CF009170011091B1
|
||||
:1002B00071010115110599F0CA14DB0481F0F601F2
|
||||
:1002C000619171916F01D801ED91FC910684F785E0
|
||||
:1002D000E02DC8010995F80104811581EACF8091CC
|
||||
:1002E0006101909162019C012F5F3F4F3093620149
|
||||
:1002F0002093610149970CF44AC08FB7F89420917C
|
||||
:10030000590130915A0140915B0150915C018FBFBE
|
||||
:1003100080915D0190915E01A0915F01B0916001BB
|
||||
:10032000281B390B4A0B5B0B21F421E030E040E045
|
||||
:1003300050E0E0916101F091620188EE93E0E89F66
|
||||
:10034000B001E99F700DF89F700D1124072E000C6D
|
||||
:10035000880B990B0E94E30630936501209364019A
|
||||
:1003600010926201109261012FB7F89480915901A7
|
||||
:1003700090915A01A0915B01B0915C012FBF8093D5
|
||||
:100380005D0190935E01A0935F01B0936001CD5732
|
||||
:10039000DF4F0FB6F894DEBF0FBECDBFDF91CF9118
|
||||
:1003A0001F910F91FF90EF90DF90CF90BF90AF9093
|
||||
:1003B0009F908F907F906F905F904F903F902F9085
|
||||
:1003C00008958F929F92AF92BF92CF92DF92EF9259
|
||||
:1003D000FF920E945F004B015C0184EFC82EDD2478
|
||||
:1003E000D394E12CF12C0E945F00681979098A09E5
|
||||
:1003F0009B09683E734081059105A8F321E0C21A6C
|
||||
:10040000D108E108F10888EE880E83E0981EA11C4F
|
||||
:10041000B11CC114D104E104F10429F7FF90EF905D
|
||||
:10042000DF90CF90BF90AF909F908F90089580E91C
|
||||
:1004300091E008950F931F93CF93DF9320912F01A5
|
||||
:100440002F5F322F377030932F0120FF2BC020E811
|
||||
:1004500031FD2064347009F02062205FFC01EC0162
|
||||
:10046000239600E011E06485662329F070E0C8015E
|
||||
:100470000E94CF066F5F6187822F869F080E80E003
|
||||
:10048000811D1124811110C01682662311F0615064
|
||||
:1004900061873196EC17FD0731F7DF91CF911F91FE
|
||||
:1004A0000F91089520E0D4CF81508683EECF4F92F4
|
||||
:1004B0005F927F928F929F92AF92BF92CF92DF9284
|
||||
:1004C000EF92FF920F931F93CF93DF932C01EB01D9
|
||||
:1004D0000E945F00F20125893689621B730B6A3026
|
||||
:1004E0007105B0F3F8948A819B81181619060CF0F7
|
||||
:1004F000CDC1E881F9816BB1862E689483F83BB158
|
||||
:10050000377F3BB9DA848F812D2D281B822F2F83D3
|
||||
:100510004F85042E000C550BAA81BB817D85FC8480
|
||||
:10052000EE847F5FF394E3949E819884B984AB84D6
|
||||
:100530001181C12C6C2D0C2D2C2D2181112788941B
|
||||
:100540002111280F08F42FEF8195889470FD120F68
|
||||
:100550001795889471FD120F1795889472FD120FEC
|
||||
:100560001795889473FD120F1795889474FD120FD8
|
||||
:100570001795889475FD120F1795889476FD120FC4
|
||||
:100580001795889477FD120F17958894622F711133
|
||||
:10059000612F8D0D162F002C8BB800C017FF3BB9B3
|
||||
:1005A00020816627889400C000C0002C3BB921112F
|
||||
:1005B000290F00C0002C8BB800C016FF3BB908F40F
|
||||
:1005C0002FEF9195889400C000C0002C3BB9F0FC3F
|
||||
:1005D000620F00C0002C8BB800C015FF3BB96795B7
|
||||
:1005E0008894F1FC620F00C000C0002C3BB96795F5
|
||||
:1005F000889400C0002C8BB800C014FF3BB9F2FCFB
|
||||
:10060000620F6795889400C000C0002C3BB9F3FCD2
|
||||
:10061000620F00C0002C8BB800C013FF3BB9679578
|
||||
:100620008894F4FC620F00C000C0002C3BB96795B1
|
||||
:10063000889400C0002C8BB800C012FF3BB9F5FCB9
|
||||
:10064000620F6795889400C000C0002C3BB9F6FC8F
|
||||
:10065000620F00C0002C8BB800C011FF3BB967953A
|
||||
:100660008894F7FC620F00C000C0002C3BB967956E
|
||||
:10067000889400C0002C8BB800C010FF3BB9122F2B
|
||||
:10068000F110162F9B0D00C000C0002C3BB900C01C
|
||||
:1006900000C0002C8BB800C017FF3BB92281662731
|
||||
:1006A000889400C000C0002C3BB92111290D00C066
|
||||
:1006B000002C8BB800C016FF3BB908F42FEFE40FF5
|
||||
:1006C000F51F00C000C0002C3BB9E0FC620F00C069
|
||||
:1006D000002C8BB800C015FF3BB967958894E1FCEE
|
||||
:1006E000620F00C000C0002C3BB96795889400C021
|
||||
:1006F000002C8BB800C014FF3BB9E2FC620F679579
|
||||
:10070000889400C000C0002C3BB9E3FC620F00C01D
|
||||
:10071000002C8BB800C013FF3BB967958894E4FCAC
|
||||
:10072000620F00C000C0002C3BB96795889400C0E0
|
||||
:10073000002C8BB800C012FF3BB9E5FC620F679537
|
||||
:10074000889400C000C0002C3BB9E6FC620F00C0DA
|
||||
:10075000002C8BB800C011FF3BB967958894E7FC6B
|
||||
:10076000620F00C000C0002C3BB96795889400C0A0
|
||||
:10077000002C8BB800C010FF3BB9122FE110162FD0
|
||||
:10078000919400C000C0002C3BB99A0C00C000C07E
|
||||
:100790008BB800C017FF3BB921816627889400C041
|
||||
:1007A00000C0002C3BB92111280F00C0002C8BB8D1
|
||||
:1007B00000C016FF3BB908F42FEF8195889400C064
|
||||
:1007C00000C0002C3BB970FD620F00C0002C8BB83C
|
||||
:1007D00000C015FF3BB96795889471FD620F00C09A
|
||||
:1007E00000C0002C3BB96795889400C0002C8BB8E2
|
||||
:1007F00000C014FF3BB972FD620F6795889400C07A
|
||||
:1008000000C0002C3BB973FD620F00C0002C8BB8F8
|
||||
:1008100000C013FF3BB96795889474FD620F00C058
|
||||
:1008200000C0002C3BB96795889400C0002C8BB8A1
|
||||
:1008300000C012FF3BB975FD620F6795889400C038
|
||||
:1008400000C0002C3BB976FD620F00C0002C8BB8B5
|
||||
:1008500000C011FF3BB96795889477FD620F00C017
|
||||
:1008600000C0002C3BB96795889400C0002C8BB861
|
||||
:1008700000C010FF3BB9122F7111162F8D0D00C053
|
||||
:1008800000C0002C3BB9119709F086CE4A815B81EC
|
||||
:1008900020EE31E0DA010E941407DC01CB01F4E024
|
||||
:1008A000B695A79597958795FA95D1F730E020E012
|
||||
:1008B000B901EAE94E9F040E611D5E9F600D711D36
|
||||
:1008C0001124650F711D860F971FA11DB11D893E53
|
||||
:1008D00043E09407A105B10508F434C0885E934055
|
||||
:1008E000A109B10942E0B695A795979587954A95D4
|
||||
:1008F000D1F747E0849F080E211D949F200D311DE4
|
||||
:100900001124290F311D60912E0170E0860F971F71
|
||||
:10091000820F931F4091590150915A0160915B01E0
|
||||
:1009200070915C01292F3327420F531F611D711DE8
|
||||
:100930004093590150935A0160935B0170935C019D
|
||||
:1009400080932E0178940E945F00F201768B658B74
|
||||
:10095000DF91CF911F910F91FF90EF90DF90CF909B
|
||||
:10096000BF90AF909F908F907F905F904F90089531
|
||||
:1009700081E090E00895539A08956F927F928F924C
|
||||
:10098000CF92DF92EF92FF920F931F93CF93DF935B
|
||||
:10099000CDB7DEB762970FB6F894DEBF0FBECDBFFE
|
||||
:1009A0006C017A013801822EDC011C962C91CA015F
|
||||
:1009B00057FF04C088279927841B950B7A83698386
|
||||
:1009C0009C838B839E838D836D867E868F8621306C
|
||||
:1009D00049F5CE0101960E941A0283E0888B1A8A9B
|
||||
:1009E000198AF7FE02C08DEF888BD601ED91FC913C
|
||||
:1009F0000288F389E02DBE016F5F7F4FC601099524
|
||||
:100A000062960FB6F894DEBF0FBECDBFDF91CF91D7
|
||||
:100A10001F910F91FF90EF90DF90CF908F907F907C
|
||||
:100A20006F9008951C861B861A86198618861F8269
|
||||
:100A3000D4CFEF92FF920F931F93CF93DF93CDB755
|
||||
:100A4000DEB762970FB6F894DEBF0FBECDBF7C0154
|
||||
:100A5000DC011C968C917A8369835C834B835E8373
|
||||
:100A60004D830D871E872F878130F9F4CE010196C3
|
||||
:100A70000E941A02188A1A8A198AD701ED91FC91EC
|
||||
:100A80000288F389E02DBE016F5F7F4FC701099592
|
||||
:100A900062960FB6F894DEBF0FBECDBFDF91CF9147
|
||||
:100AA0001F910F91FF90EF9008951C861B861A8668
|
||||
:100AB000198618861F82DECF90E080E00895FC0141
|
||||
:100AC00064870895FC01848590E00895FC01858584
|
||||
:100AD000968508950F931F93CF93DF9300D01F92B5
|
||||
:100AE000CDB7DEB7AB0119821A821B82DC01ED9112
|
||||
:100AF000FC910190F081E02D00E010E020E0BE01CB
|
||||
:100B00006F5F7F4F09950F900F900F90DF91CF91FE
|
||||
:100B10001F910F9108950E9440071F920F920FB6E8
|
||||
:100B20000F9211242F933F938F939F93AF93BF9373
|
||||
:100B30008091590190915A01A0915B01B0915C01A3
|
||||
:100B40003091540123E0230F2D3758F50196A11D54
|
||||
:100B5000B11D209354018093590190935A01A093A1
|
||||
:100B60005B01B0935C018091550190915601A09179
|
||||
:100B70005701B09158010196A11DB11D80935501F7
|
||||
:100B800090935601A0935701B0935801BF91AF9134
|
||||
:100B90009F918F913F912F910F900FBE0F901F90BB
|
||||
:100BA000189526E8230F0296A11DB11DD2CF789487
|
||||
:100BB00084B5826084BD84B5816084BD85B5826062
|
||||
:100BC00085BD85B5816085BD80916E008160809313
|
||||
:100BD0006E0010928100809181008260809381007C
|
||||
:100BE000809181008160809381008091800081608C
|
||||
:100BF000809380008091B10084608093B1008091E7
|
||||
:100C0000B00081608093B00080917A00846080930E
|
||||
:100C10007A0080917A00826080937A0080917A00D5
|
||||
:100C2000816080937A0080917A00806880937A0056
|
||||
:100C30001092C10080914901811155C01092350177
|
||||
:100C4000109234018FEF80933801809339018093A3
|
||||
:100C50003A0180933B0180933C0180933D0181E008
|
||||
:100C600080933E011092400110923F0180E797E18E
|
||||
:100C7000909342018093410183E090E0909344017E
|
||||
:100C80008093430110924601109245011092370162
|
||||
:100C9000109236018091700190917101892B31F48D
|
||||
:100CA00082E391E09093710180937001E0913001B3
|
||||
:100CB000F0913101309721F082E391E095838483B4
|
||||
:100CC00082E391E0909331018093300110924801CA
|
||||
:100CD000109247018AE191E09093330180933201B1
|
||||
:100CE00081E080934901539A81E591E09093350129
|
||||
:100CF0008093340181E090E09093400180933F0124
|
||||
:100D00008091660190916701A0916801B09169019D
|
||||
:100D1000843C29E09207A105B10520F484EC99E018
|
||||
:100D2000A0E0B0E08093660190936701A093680112
|
||||
:100D3000B0936901CFEF00E010E0C0935101109231
|
||||
:100D4000520110925301809163010E9484000E941D
|
||||
:100D5000E1011092510110925201109253018091C1
|
||||
:100D600063010E9484000E94E1010115110529F32D
|
||||
:100D70000E940000E2CFE3E6F1E08FEF8083128271
|
||||
:100D80001182148613868FEF9FEFDC018783908793
|
||||
:100D9000A187B2871382148215821682089597FB69
|
||||
:100DA000072E16F4009407D077FD09D00E9426077D
|
||||
:100DB00007FC05D03EF4909581959F4F089570955E
|
||||
:100DC00061957F4F0895A1E21A2EAA1BBB1BFD015E
|
||||
:100DD0000DC0AA1FBB1FEE1FFF1FA217B307E4071A
|
||||
:100DE000F50720F0A21BB30BE40BF50B661F771F72
|
||||
:100DF000881F991F1A9469F7609570958095909552
|
||||
:100E00009B01AC01BD01CF010895A29FB001B39F2A
|
||||
:100E1000C001A39F700D811D1124911DB29F700D03
|
||||
:100E2000811D1124911D08950E940507B7FF0895A3
|
||||
:100E3000821B930B08950E940507A59F900DB49FF8
|
||||
:100E4000900DA49F800D911D11240895AA1BBB1B1A
|
||||
:100E500051E107C0AA1FBB1FA617B70710F0A61BBA
|
||||
:100E6000B70B881F991F5A95A9F780959095BC01DB
|
||||
:100E7000CD010895EE0FFF1F0590F491E02D099428
|
||||
:0E0E800081E090E0F8940C944507F894FFCFC1
|
||||
:100E8E00000000008B058B058B056A056605B8040E
|
||||
:100E9E0062055F055C05000000001905BD04BB047A
|
||||
:0E0EAE006A056605B80462055F051702570263
|
||||
:00000001FF
|
||||
789
libraries/FastLED/ci/tests/uno/firmware.map
Normal file
789
libraries/FastLED/ci/tests/uno/firmware.map
Normal file
|
|
@ -0,0 +1,789 @@
|
|||
Archive member included to satisfy reference by file (symbol)
|
||||
|
||||
.pio\build\uno\lib6ec\libsrc.a(FastLED.cpp.o)
|
||||
.pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin) (_ZN14CLEDController7m_pHeadE)
|
||||
.pio\build\uno\lib6ec\libsrc.a(crgb.cpp.o)
|
||||
.pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin) (_ZN4CRGB17computeAdjustmentEhRKS_S1_)
|
||||
.pio\build\uno\lib6ec\libsrc.a(lib8tion.cpp.o)
|
||||
FastLED.cpp.o (symbol from plugin) (memset8)
|
||||
.pio\build\uno\libFrameworkArduino.a(abi.cpp.o)
|
||||
.pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin) (__cxa_pure_virtual)
|
||||
.pio\build\uno\libFrameworkArduino.a(hooks.c.o)
|
||||
FastLED.cpp.o (symbol from plugin) (yield)
|
||||
.pio\build\uno\libFrameworkArduino.a(main.cpp.o)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o (main)
|
||||
.pio\build\uno\libFrameworkArduino.a(wiring.c.o)
|
||||
.pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin) (timer0_millis)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o (exit)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__divmodhi4)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__udivmodsi4)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__do_copy_data)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__do_clear_bss)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__do_global_ctors)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__umulhisi3)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__usmulhisi3)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (__muluhisi3)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o) (__udivmodhi4)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o) (__tablejump2__)
|
||||
c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(abort.o)
|
||||
C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o (abort)
|
||||
|
||||
Discarded input sections
|
||||
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
.text 0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController4sizeEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController5lanesEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController13beginShowLedsEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController11endShowLedsEPv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZNK14CLEDController17getMaxRefreshRateEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19CPixelLEDControllerIL6EOrder66ELi1ELm4294967295EE5lanesEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZNK19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EE17getMaxRefreshRateEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDControllerC5Ev
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZTV14CLEDController
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController13getAdjustmentEh
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController9showColorERK4CRGBih
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController9clearLedsEi
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8CFastLED4showEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19CPixelLEDControllerIL6EOrder66ELi1ELm4294967295EEC5Ev
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZTV19CPixelLEDControllerIL6EOrder66ELi1ELm4294967295EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EEC5Ev
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZTV19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN22WS2812Controller800KhzILh3EL6EOrder66EEC5Ev
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZTV22WS2812Controller800KhzILh3EL6EOrder66EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8NEOPIXELILh3EEC5Ev
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZTV8NEOPIXELILh3EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8CFastLED7addLedsI8NEOPIXELLh3EEER14CLEDControllerP4CRGBii
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZGVZN8CFastLED7addLedsI8NEOPIXELLh3EEER14CLEDControllerP4CRGBiiE1c
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZZN8CFastLED7addLedsI8NEOPIXELLh3EEER14CLEDControllerP4CRGBiiE1c
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN7_AVRPINILh3ELh8E18__gen_struct_PORTD17__gen_struct_DDRD17__gen_struct_PINDE9setOutputEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EE4initEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8CMinWaitILi10EE4waitEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EE15showRGBInternalER15PixelControllerILS0_66ELi1ELm4294967295EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8CMinWaitILi10EE4markEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19ClocklessControllerILh3ELi4ELi10ELi6EL6EOrder66ELi0ELb0ELi10EE10showPixelsER15PixelControllerILS0_66ELi1ELm4294967295EE
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN15PixelControllerIL6EOrder66ELi1ELm4294967295EE11initOffsetsEi
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN15PixelControllerIL6EOrder66ELi1ELm4294967295EE21init_binary_ditheringEv
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZZN15PixelControllerIL6EOrder66ELi1ELm4294967295EE21init_binary_ditheringEvE1R
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN15PixelControllerIL6EOrder66ELi1ELm4294967295EE16enable_ditheringEh
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN15PixelControllerIL6EOrder66ELi1ELm4294967295EEC5EPK4CRGBiRS2_h
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19CPixelLEDControllerIL6EOrder66ELi1ELm4294967295EE4showEPK4CRGBiS2_
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN15PixelControllerIL6EOrder66ELi1ELm4294967295EEC5ERK4CRGBiRS2_h
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN19CPixelLEDControllerIL6EOrder66ELi1ELm4294967295EE9showColorERK4CRGBiS2_
|
||||
0x00000000 0x0 .pio\build\uno\src\Blink.ino.cpp.o (symbol from plugin)
|
||||
.data 0x00000000 0x0 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
.text 0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController12clearLedDataEv
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController13beginShowLedsEv
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController11endShowLedsEPv
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController13getAdjustmentEh
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController8showLedsEh
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN14CLEDController9showColorERK4CRGBh
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZNK14CLEDController17getMaxRefreshRateEv
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.gnu.linkonce.t._ZN8CFastLED4showEv
|
||||
0x00000000 0x0 FastLED.cpp.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 crgb.cpp.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 lib8tion.cpp.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 abi.cpp.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 hooks.c.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 main.cpp.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 wiring.c.o (symbol from plugin)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.mul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.div
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.prologue
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.builtins
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.fmul
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text.libgcc.fixed
|
||||
0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
.text 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(abort.o)
|
||||
.data 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(abort.o)
|
||||
.bss 0x00000000 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(abort.o)
|
||||
|
||||
Memory Configuration
|
||||
|
||||
Name Origin Length Attributes
|
||||
text 0x00000000 0x00020000 xr
|
||||
data 0x00800060 0x0000ffa0 rw !x
|
||||
eeprom 0x00810000 0x00010000 rw !x
|
||||
fuse 0x00820000 0x00000003 rw !x
|
||||
lock 0x00830000 0x00000400 rw !x
|
||||
signature 0x00840000 0x00000400 rw !x
|
||||
user_signatures 0x00850000 0x00000400 rw !x
|
||||
*default* 0x00000000 0xffffffff
|
||||
|
||||
Linker script and memory map
|
||||
|
||||
Address of section .data set to 0x800100
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
LOAD .pio\build\uno\src\Blink.ino.cpp.o
|
||||
LOAD C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
START GROUP
|
||||
LOAD .pio\build\uno\liba19\libSoftwareSerial.a
|
||||
LOAD .pio\build\uno\lib8b0\libSPI.a
|
||||
LOAD .pio\build\uno\lib6ec\libsrc.a
|
||||
LOAD .pio\build\uno\libFrameworkArduinoVariant.a
|
||||
LOAD .pio\build\uno\libFrameworkArduino.a
|
||||
END GROUP
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libm.a
|
||||
START GROUP
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libm.a
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a
|
||||
LOAD c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libatmega328p.a
|
||||
END GROUP
|
||||
0x00020000 __TEXT_REGION_LENGTH__ = DEFINED (__TEXT_REGION_LENGTH__)?__TEXT_REGION_LENGTH__:0x20000
|
||||
0x0000ffa0 __DATA_REGION_LENGTH__ = DEFINED (__DATA_REGION_LENGTH__)?__DATA_REGION_LENGTH__:0xffa0
|
||||
0x00010000 __EEPROM_REGION_LENGTH__ = DEFINED (__EEPROM_REGION_LENGTH__)?__EEPROM_REGION_LENGTH__:0x10000
|
||||
[0x00000003] __FUSE_REGION_LENGTH__ = DEFINED (__FUSE_REGION_LENGTH__)?__FUSE_REGION_LENGTH__:0x400
|
||||
0x00000400 __LOCK_REGION_LENGTH__ = DEFINED (__LOCK_REGION_LENGTH__)?__LOCK_REGION_LENGTH__:0x400
|
||||
0x00000400 __SIGNATURE_REGION_LENGTH__ = DEFINED (__SIGNATURE_REGION_LENGTH__)?__SIGNATURE_REGION_LENGTH__:0x400
|
||||
0x00000400 __USER_SIGNATURE_REGION_LENGTH__ = DEFINED (__USER_SIGNATURE_REGION_LENGTH__)?__USER_SIGNATURE_REGION_LENGTH__:0x400
|
||||
|
||||
.hash
|
||||
*(.hash)
|
||||
|
||||
.dynsym
|
||||
*(.dynsym)
|
||||
|
||||
.dynstr
|
||||
*(.dynstr)
|
||||
|
||||
.gnu.version
|
||||
*(.gnu.version)
|
||||
|
||||
.gnu.version_d
|
||||
*(.gnu.version_d)
|
||||
|
||||
.gnu.version_r
|
||||
*(.gnu.version_r)
|
||||
|
||||
.rel.init
|
||||
*(.rel.init)
|
||||
|
||||
.rela.init
|
||||
*(.rela.init)
|
||||
|
||||
.rel.text
|
||||
*(.rel.text)
|
||||
*(.rel.text.*)
|
||||
*(.rel.gnu.linkonce.t*)
|
||||
|
||||
.rela.text
|
||||
*(.rela.text)
|
||||
*(.rela.text.*)
|
||||
*(.rela.gnu.linkonce.t*)
|
||||
|
||||
.rel.fini
|
||||
*(.rel.fini)
|
||||
|
||||
.rela.fini
|
||||
*(.rela.fini)
|
||||
|
||||
.rel.rodata
|
||||
*(.rel.rodata)
|
||||
*(.rel.rodata.*)
|
||||
*(.rel.gnu.linkonce.r*)
|
||||
|
||||
.rela.rodata
|
||||
*(.rela.rodata)
|
||||
*(.rela.rodata.*)
|
||||
*(.rela.gnu.linkonce.r*)
|
||||
|
||||
.rel.data
|
||||
*(.rel.data)
|
||||
*(.rel.data.*)
|
||||
*(.rel.gnu.linkonce.d*)
|
||||
|
||||
.rela.data
|
||||
*(.rela.data)
|
||||
*(.rela.data.*)
|
||||
*(.rela.gnu.linkonce.d*)
|
||||
|
||||
.rel.ctors
|
||||
*(.rel.ctors)
|
||||
|
||||
.rela.ctors
|
||||
*(.rela.ctors)
|
||||
|
||||
.rel.dtors
|
||||
*(.rel.dtors)
|
||||
|
||||
.rela.dtors
|
||||
*(.rela.dtors)
|
||||
|
||||
.rel.got
|
||||
*(.rel.got)
|
||||
|
||||
.rela.got
|
||||
*(.rela.got)
|
||||
|
||||
.rel.bss
|
||||
*(.rel.bss)
|
||||
|
||||
.rela.bss
|
||||
*(.rela.bss)
|
||||
|
||||
.rel.plt
|
||||
*(.rel.plt)
|
||||
|
||||
.rela.plt
|
||||
*(.rela.plt)
|
||||
|
||||
.text 0x00000000 0xe8e
|
||||
*(.vectors)
|
||||
.vectors 0x00000000 0x68 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
0x00000000 __vector_default
|
||||
0x00000000 __vectors
|
||||
*(.vectors)
|
||||
*(.progmem.gcc*)
|
||||
0x00000068 . = ALIGN (0x2)
|
||||
0x00000068 __trampolines_start = .
|
||||
*(.trampolines)
|
||||
.trampolines 0x00000068 0x0 linker stubs
|
||||
*(.trampolines*)
|
||||
0x00000068 __trampolines_end = .
|
||||
*libprintf_flt.a:*(.progmem.data)
|
||||
*libc.a:*(.progmem.data)
|
||||
*(.progmem*)
|
||||
0x00000068 . = ALIGN (0x2)
|
||||
*(.jumptables)
|
||||
*(.jumptables*)
|
||||
*(.lowtext)
|
||||
*(.lowtext*)
|
||||
0x00000068 __ctors_start = .
|
||||
*(.ctors)
|
||||
.ctors 0x00000068 0x2 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
0x0000006a __ctors_end = .
|
||||
0x0000006a __dtors_start = .
|
||||
*(.dtors)
|
||||
0x0000006a __dtors_end = .
|
||||
SORT(*)(.ctors)
|
||||
SORT(*)(.dtors)
|
||||
*(.init0)
|
||||
.init0 0x0000006a 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
0x0000006a __init
|
||||
*(.init0)
|
||||
*(.init1)
|
||||
*(.init1)
|
||||
*(.init2)
|
||||
.init2 0x0000006a 0xc c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
*(.init2)
|
||||
*(.init3)
|
||||
*(.init3)
|
||||
*(.init4)
|
||||
.init4 0x00000076 0x16 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
0x00000076 __do_copy_data
|
||||
.init4 0x0000008c 0x10 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
0x0000008c __do_clear_bss
|
||||
*(.init4)
|
||||
*(.init5)
|
||||
*(.init5)
|
||||
*(.init6)
|
||||
.init6 0x0000009c 0x16 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
0x0000009c __do_global_ctors
|
||||
*(.init6)
|
||||
*(.init7)
|
||||
*(.init7)
|
||||
*(.init8)
|
||||
*(.init8)
|
||||
*(.init9)
|
||||
.init9 0x000000b2 0x8 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
*(.init9)
|
||||
*(.text)
|
||||
.text 0x000000ba 0x4 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
0x000000ba __vector_22
|
||||
0x000000ba __vector_1
|
||||
0x000000ba __vector_24
|
||||
0x000000ba __vector_12
|
||||
0x000000ba __bad_interrupt
|
||||
0x000000ba __vector_6
|
||||
0x000000ba __vector_3
|
||||
0x000000ba __vector_23
|
||||
0x000000ba __vector_25
|
||||
0x000000ba __vector_11
|
||||
0x000000ba __vector_13
|
||||
0x000000ba __vector_17
|
||||
0x000000ba __vector_19
|
||||
0x000000ba __vector_7
|
||||
0x000000ba __vector_5
|
||||
0x000000ba __vector_4
|
||||
0x000000ba __vector_9
|
||||
0x000000ba __vector_2
|
||||
0x000000ba __vector_21
|
||||
0x000000ba __vector_15
|
||||
0x000000ba __vector_8
|
||||
0x000000ba __vector_14
|
||||
0x000000ba __vector_10
|
||||
0x000000ba __vector_18
|
||||
0x000000ba __vector_20
|
||||
.text 0x000000be 0xaf0 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
0x00000b1a __vector_16
|
||||
0x00000bae . = ALIGN (0x2)
|
||||
*(.text.*)
|
||||
.text.startup 0x00000bae 0x1f0 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
0x00000bae main
|
||||
.text.libgcc.div
|
||||
0x00000d9e 0x28 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
0x00000d9e _div
|
||||
0x00000d9e __divmodhi4
|
||||
.text.libgcc.div
|
||||
0x00000dc6 0x44 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
0x00000dc6 __udivmodsi4
|
||||
.text.libgcc.mul
|
||||
0x00000e0a 0x1e c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
0x00000e0a __umulhisi3
|
||||
.text.libgcc.mul
|
||||
0x00000e28 0xe c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
0x00000e28 __usmulhisi3
|
||||
0x00000e2c __usmulhisi3_tail
|
||||
.text.libgcc.mul
|
||||
0x00000e36 0x16 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
0x00000e36 __muluhisi3
|
||||
.text.libgcc.div
|
||||
0x00000e4c 0x28 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
0x00000e4c __udivmodhi4
|
||||
.text.libgcc 0x00000e74 0xc c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
0x00000e74 __tablejump2__
|
||||
.text.avr-libc
|
||||
0x00000e80 0xa c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5\libc.a(abort.o)
|
||||
0x00000e80 abort
|
||||
0x00000e8a . = ALIGN (0x2)
|
||||
*(.fini9)
|
||||
.fini9 0x00000e8a 0x0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
0x00000e8a _exit
|
||||
0x00000e8a exit
|
||||
*(.fini9)
|
||||
*(.fini8)
|
||||
*(.fini8)
|
||||
*(.fini7)
|
||||
*(.fini7)
|
||||
*(.fini6)
|
||||
*(.fini6)
|
||||
*(.fini5)
|
||||
*(.fini5)
|
||||
*(.fini4)
|
||||
*(.fini4)
|
||||
*(.fini3)
|
||||
*(.fini3)
|
||||
*(.fini2)
|
||||
*(.fini2)
|
||||
*(.fini1)
|
||||
*(.fini1)
|
||||
*(.fini0)
|
||||
.fini0 0x00000e8a 0x4 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
*(.fini0)
|
||||
0x00000e8e _etext = .
|
||||
|
||||
.data 0x00800100 0x2e load address 0x00000e8e
|
||||
0x00800100 PROVIDE (__data_start, .)
|
||||
*(.data)
|
||||
*(.data*)
|
||||
*(.gnu.linkonce.d*)
|
||||
*(.rodata)
|
||||
.rodata 0x00800100 0x2e C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
*(.rodata*)
|
||||
*(.gnu.linkonce.r*)
|
||||
0x0080012e . = ALIGN (0x2)
|
||||
0x0080012e _edata = .
|
||||
0x0080012e PROVIDE (__data_end, .)
|
||||
|
||||
.bss 0x0080012e 0x48
|
||||
0x0080012e PROVIDE (__bss_start, .)
|
||||
*(.bss)
|
||||
.bss 0x0080012e 0x48 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
0x00800176 PROVIDE (__bss_end, .)
|
||||
0x00000e8e __data_load_start = LOADADDR (.data)
|
||||
0x00000ebc __data_load_end = (__data_load_start + SIZEOF (.data))
|
||||
|
||||
.noinit 0x00800176 0x0
|
||||
[!provide] PROVIDE (__noinit_start, .)
|
||||
*(.noinit*)
|
||||
[!provide] PROVIDE (__noinit_end, .)
|
||||
0x00800176 _end = .
|
||||
[!provide] PROVIDE (__heap_start, .)
|
||||
|
||||
.eeprom 0x00810000 0x0
|
||||
*(.eeprom*)
|
||||
0x00810000 __eeprom_end = .
|
||||
|
||||
.fuse
|
||||
*(.fuse)
|
||||
*(.lfuse)
|
||||
*(.hfuse)
|
||||
*(.efuse)
|
||||
|
||||
.lock
|
||||
*(.lock*)
|
||||
|
||||
.signature
|
||||
*(.signature*)
|
||||
|
||||
.user_signatures
|
||||
*(.user_signatures*)
|
||||
|
||||
.stab
|
||||
*(.stab)
|
||||
|
||||
.stabstr
|
||||
*(.stabstr)
|
||||
|
||||
.stab.excl
|
||||
*(.stab.excl)
|
||||
|
||||
.stab.exclstr
|
||||
*(.stab.exclstr)
|
||||
|
||||
.stab.index
|
||||
*(.stab.index)
|
||||
|
||||
.stab.indexstr
|
||||
*(.stab.indexstr)
|
||||
|
||||
.comment 0x00000000 0x11
|
||||
*(.comment)
|
||||
.comment 0x00000000 0x11 C:\Users\niteris\AppData\Local\Temp\ccAA6ajC.ltrans0.ltrans.o
|
||||
0x12 (size before relaxing)
|
||||
|
||||
.note.gnu.avr.deviceinfo
|
||||
0x00000000 0x40
|
||||
.note.gnu.avr.deviceinfo
|
||||
0x00000000 0x40 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
|
||||
.note.gnu.build-id
|
||||
*(.note.gnu.build-id)
|
||||
|
||||
.debug
|
||||
*(.debug)
|
||||
|
||||
.line
|
||||
*(.line)
|
||||
|
||||
.debug_srcinfo
|
||||
*(.debug_srcinfo)
|
||||
|
||||
.debug_sfnames
|
||||
*(.debug_sfnames)
|
||||
|
||||
.debug_aranges 0x00000000 0x160
|
||||
*(.debug_aranges)
|
||||
.debug_aranges
|
||||
0x00000000 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.debug_aranges
|
||||
0x00000020 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.debug_aranges
|
||||
0x00000040 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.debug_aranges
|
||||
0x00000060 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.debug_aranges
|
||||
0x00000080 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.debug_aranges
|
||||
0x000000a0 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.debug_aranges
|
||||
0x000000c0 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.debug_aranges
|
||||
0x000000e0 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.debug_aranges
|
||||
0x00000100 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.debug_aranges
|
||||
0x00000120 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.debug_aranges
|
||||
0x00000140 0x20 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
|
||||
.debug_pubnames
|
||||
*(.debug_pubnames)
|
||||
|
||||
.debug_info 0x00000000 0xdfd
|
||||
*(.debug_info .gnu.linkonce.wi.*)
|
||||
.debug_info 0x00000000 0x5f4 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
.debug_info 0x000005f4 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.debug_info 0x000006af 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.debug_info 0x0000076a 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.debug_info 0x00000825 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.debug_info 0x000008e0 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.debug_info 0x0000099b 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.debug_info 0x00000a56 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.debug_info 0x00000b11 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.debug_info 0x00000bcc 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.debug_info 0x00000c87 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.debug_info 0x00000d42 0xbb c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
|
||||
.debug_abbrev 0x00000000 0x67e
|
||||
*(.debug_abbrev)
|
||||
.debug_abbrev 0x00000000 0x5a2 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
.debug_abbrev 0x000005a2 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.debug_abbrev 0x000005b6 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.debug_abbrev 0x000005ca 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.debug_abbrev 0x000005de 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.debug_abbrev 0x000005f2 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.debug_abbrev 0x00000606 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.debug_abbrev 0x0000061a 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.debug_abbrev 0x0000062e 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.debug_abbrev 0x00000642 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.debug_abbrev 0x00000656 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.debug_abbrev 0x0000066a 0x14 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
|
||||
.debug_line 0x00000000 0x71a
|
||||
*(.debug_line .debug_line.* .debug_line_end)
|
||||
.debug_line 0x00000000 0x1a c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
.debug_line 0x0000001a 0x62 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_exit.o)
|
||||
.debug_line 0x0000007c 0xc8 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_divmodhi4.o)
|
||||
.debug_line 0x00000144 0x122 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodsi4.o)
|
||||
.debug_line 0x00000266 0x98 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_copy_data.o)
|
||||
.debug_line 0x000002fe 0x86 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_clear_bss.o)
|
||||
.debug_line 0x00000384 0x92 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_ctors.o)
|
||||
.debug_line 0x00000416 0xb0 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_umulhisi3.o)
|
||||
.debug_line 0x000004c6 0x7a c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_usmulhisi3.o)
|
||||
.debug_line 0x00000540 0x92 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_muluhisi3.o)
|
||||
.debug_line 0x000005d2 0xce c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_udivmodhi4.o)
|
||||
.debug_line 0x000006a0 0x7a c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/avr5\libgcc.a(_tablejump2.o)
|
||||
|
||||
.debug_frame
|
||||
*(.debug_frame)
|
||||
|
||||
.debug_str 0x00000000 0x208
|
||||
*(.debug_str)
|
||||
.debug_str 0x00000000 0x208 c:/users/niteris/.platformio/packages/toolchain-atmelavr/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
|
||||
|
||||
.debug_loc
|
||||
*(.debug_loc)
|
||||
|
||||
.debug_macinfo
|
||||
*(.debug_macinfo)
|
||||
|
||||
.debug_weaknames
|
||||
*(.debug_weaknames)
|
||||
|
||||
.debug_funcnames
|
||||
*(.debug_funcnames)
|
||||
|
||||
.debug_typenames
|
||||
*(.debug_typenames)
|
||||
|
||||
.debug_varnames
|
||||
*(.debug_varnames)
|
||||
|
||||
.debug_pubtypes
|
||||
*(.debug_pubtypes)
|
||||
|
||||
.debug_ranges
|
||||
*(.debug_ranges)
|
||||
|
||||
.debug_macro
|
||||
*(.debug_macro)
|
||||
OUTPUT(.pio\build\uno\firmware.elf elf32-avr)
|
||||
LOAD linker stubs
|
||||
46
libraries/FastLED/ci/wasm_compile.py
Normal file
46
libraries/FastLED/ci/wasm_compile.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
def parse_args() -> Tuple[argparse.Namespace, list[str]]:
|
||||
parser = argparse.ArgumentParser(description="Compile wasm")
|
||||
parser.add_argument(
|
||||
"sketch_dir",
|
||||
nargs="?",
|
||||
default="examples/wasm",
|
||||
help="The directory of the sketch to compile",
|
||||
)
|
||||
# return parser.parse_args()
|
||||
known_args, unknown_args = parser.parse_known_args()
|
||||
return known_args, unknown_args
|
||||
|
||||
|
||||
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()
|
||||
|
||||
# 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__":
|
||||
sys.exit(main())
|
||||
108
libraries/FastLED/ci/wasm_test.py
Normal file
108
libraries/FastLED/ci/wasm_test.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.async_api import async_playwright # type: ignore
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
PROJECT_ROOT = HERE.parent
|
||||
|
||||
|
||||
# Ensure Playwright browsers are installed
|
||||
def install_playwright_browsers():
|
||||
print("Installing Playwright browsers...")
|
||||
try:
|
||||
# Simulate the `playwright install` command
|
||||
os.system(f"{sys.executable} -m playwright install chromium")
|
||||
print("Playwright browsers installed successfully.")
|
||||
except Exception as e:
|
||||
print(f"Failed to install Playwright browsers: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Start an HTTP server on the dynamic port
|
||||
def start_http_server(port: int, directory: Path):
|
||||
from fastled import Test # type: ignore
|
||||
|
||||
server_process = Test.spawn_http_server(
|
||||
directory=directory, port=port, open_browser=False
|
||||
)
|
||||
return server_process
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
install_playwright_browsers()
|
||||
# Find an available port
|
||||
port = (
|
||||
8080 # Todo, figure out why the http server ignores any port other than 8080.
|
||||
)
|
||||
print(f"Using port: {port}")
|
||||
|
||||
# Start the HTTP server
|
||||
os.chdir(str(PROJECT_ROOT))
|
||||
directory = Path("examples/wasm/fastled_js")
|
||||
server_process = start_http_server(port=port, directory=directory)
|
||||
|
||||
try:
|
||||
# Give the server some time to start
|
||||
time.sleep(2)
|
||||
|
||||
# Use Playwright to test the server
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch()
|
||||
page = await browser.new_page()
|
||||
|
||||
try:
|
||||
await page.goto(f"http://localhost:{port}", timeout=30000)
|
||||
|
||||
# Listen for console messages
|
||||
def console_log_handler(msg):
|
||||
if "INVALID_OPERATION" in msg.text:
|
||||
print(
|
||||
"INVALID_OPERATION detected in console log", file=sys.stderr
|
||||
)
|
||||
raise Exception("INVALID_OPERATION detected in console log")
|
||||
|
||||
page.on("console", console_log_handler)
|
||||
|
||||
# Evaluate and monitor window.frameCallCount
|
||||
await page.evaluate(
|
||||
"""
|
||||
window.frameCallCount = 0;
|
||||
globalThis.FastLED_onFrame = (jsonStr) => {
|
||||
console.log('FastLED_onFrame called with:', jsonStr);
|
||||
window.frameCallCount++;
|
||||
};
|
||||
"""
|
||||
)
|
||||
await page.wait_for_timeout(5000)
|
||||
|
||||
call_count = await page.evaluate("window.frameCallCount")
|
||||
if call_count > 0:
|
||||
print(
|
||||
f"Success: FastLED.js was initialized and FastLED_onFrame was called {call_count} times"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"Error: FastLED.js had something go wrong and FastLED_onFrame was not called within 5 seconds",
|
||||
file=sys.stderr,
|
||||
)
|
||||
raise Exception("FastLED.js failed to initialize")
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}", file=sys.stderr)
|
||||
raise Exception(f"An error occurred: {e}") from e
|
||||
|
||||
finally:
|
||||
await browser.close()
|
||||
|
||||
finally:
|
||||
# Terminate the server process
|
||||
server_process.terminate()
|
||||
|
||||
|
||||
# Run the main function
|
||||
if __name__ == "__main__":
|
||||
sys.exit(asyncio.run(main()))
|
||||
25
libraries/FastLED/clean
Executable file
25
libraries/FastLED/clean
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
# cd to the directory of the script
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
rm -rf .venv
|
||||
rm -rf .build
|
||||
rm -rf .pio
|
||||
rm -rf ci/tmp
|
||||
rm -rf tests/.build
|
||||
|
||||
rm -rf .*_cache
|
||||
rm -rf __pycache__
|
||||
rm -rf .tools
|
||||
|
||||
rm -rf ci/__pycache__
|
||||
rm -rf ci/.*_cache
|
||||
|
||||
|
||||
|
||||
# remove any CMakeCache.txt files
|
||||
find . -name "CMakeCache.txt" -type f -delete
|
||||
rm -f uv.lock
|
||||
134
libraries/FastLED/code_of_conduct.md
Normal file
134
libraries/FastLED/code_of_conduct.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
* "Trolling" and excessive complaints without the due benefit of contributing code.
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders via a bug report with the title [CODE OF CONDUCT] as the beginning text.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
|
||||
at [https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
37
libraries/FastLED/compile
Executable file
37
libraries/FastLED/compile
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Function to find Python executable
|
||||
find_python() {
|
||||
if command -v python3 &> /dev/null; then
|
||||
echo "python3"
|
||||
elif command -v python &> /dev/null; then
|
||||
echo "python"
|
||||
else
|
||||
echo "Python not found. Please install Python 3."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if uv is installed, if not, install it
|
||||
if ! command -v uv &> /dev/null; then
|
||||
echo "uv command not found. Installing uv..."
|
||||
PYTHON=$(find_python)
|
||||
$PYTHON -m pip install uv
|
||||
fi
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
# if .venv not found
|
||||
if [ ! -d .venv ]; then
|
||||
# create virtual environment
|
||||
./install
|
||||
fi
|
||||
|
||||
interactive_stmt=""
|
||||
# if no arguments
|
||||
if [ $# -eq 0 ]; then
|
||||
# set interactive statement
|
||||
interactive_stmt="--interactive"
|
||||
fi
|
||||
|
||||
uv run ci/ci-compile.py $interactive_stmt "$@"
|
||||
41
libraries/FastLED/compile.bat
Executable file
41
libraries/FastLED/compile.bat
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
@echo off
|
||||
setlocal
|
||||
|
||||
rem Function to find Python executable
|
||||
where python >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
set "PYTHON=python"
|
||||
) else (
|
||||
where python3 >nul 2>nul
|
||||
if %errorlevel% equ 0 (
|
||||
set "PYTHON=python3"
|
||||
) else (
|
||||
echo Python not found. Please install Python 3.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
rem Check if uv is installed, if not, install it
|
||||
where uv >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo "uv" command not found. Please install "uv" by running "pip install uv" and try again.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
rem Change to the directory of the batch file
|
||||
cd /d "%~dp0"
|
||||
|
||||
rem Check if .venv directory exists
|
||||
if not exist .venv (
|
||||
rem Create virtual environment
|
||||
call install.bat
|
||||
)
|
||||
|
||||
set "interactive_stmt="
|
||||
rem Check if no arguments were provided
|
||||
if "%~1"=="" (
|
||||
set "interactive_stmt=--interactive"
|
||||
)
|
||||
|
||||
rem Run the Python script
|
||||
.venv\Scripts\python.exe ci\ci-compile.py %interactive_stmt% %*
|
||||
2
libraries/FastLED/component.mk
Normal file
2
libraries/FastLED/component.mk
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := ./src src/platforms/esp/32
|
||||
COMPONENT_SRCDIRS := ./src src/platforms/esp/32
|
||||
31
libraries/FastLED/cool_projects.md
Normal file
31
libraries/FastLED/cool_projects.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
* Advanced Color Gradient using online version of FastLED.
|
||||
* https://wokwi.com/projects/285170662915441160
|
||||
* LedMapper tool for irregular shapes
|
||||
* https://github.com/jasoncoon/led-mapper
|
||||
* list of projects on reddit:
|
||||
* https://www.reddit.com/r/FastLED/wiki/index/user_examples/
|
||||
* mesh networked esp32 with mutli wifi connections for redundancy
|
||||
|
||||
* https://github.com/Souravgoswami/Arduino-FastLED-Cool-Effects
|
||||
* FastLED-IR: https://github.com/marcmerlin/FastLED-IR
|
||||
* https://github.com/marcmerlin/NeoMatrix-FastLED-IR?tab=readme-ov-file
|
||||
|
||||
* Tree IR:
|
||||
* https://www.evilgeniuslabs.org/tree-v2
|
||||
|
||||
* Esp32 server for fastled
|
||||
* https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
|
||||
* Strip tease - cool fx for strips
|
||||
* https://github.com/lpaolini/Striptease?tab=readme-ov-file
|
||||
|
||||
|
||||
* Soulematelights:
|
||||
* https://editor.soulmatelights.com/gallery
|
||||
|
||||
|
||||
* https://github.com/marcmerlin/FastLED_NeoMatrix_SmartMatrix_LEDMatrix_GFX_Demos/blob/master/LEDMatrix/Table_Mark_Estes/Table_Mark_Estes.ino
|
||||
|
||||
|
||||
* llm-min.txt
|
||||
* https://github.com/marv1nnnnn/llm-min.txt
|
||||
3
libraries/FastLED/dev.sh
Executable file
3
libraries/FastLED/dev.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
uv run dev/dev.py
|
||||
58
libraries/FastLED/dev/ANIMartRIX.hpp
Normal file
58
libraries/FastLED/dev/ANIMartRIX.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/// @file DemoReel100.ino
|
||||
/// @brief FastLED "100 lines of code" demo reel, showing off some effects
|
||||
/// @example DemoReel100.ino
|
||||
|
||||
|
||||
#include "fx/2d/animartrix.hpp"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "FastLED.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define WIDTH 22 // how many columns?
|
||||
#define HEIGHT 22 // how many rows?
|
||||
|
||||
|
||||
#define DEBUG_PRINT 0
|
||||
|
||||
#define NUM_LED (WIDTH * HEIGHT)
|
||||
#define SERPENTINE true
|
||||
|
||||
#define CYCLE_THROUGH_ANIMATIONS 10
|
||||
|
||||
CRGB leds[NUM_LED]; // framebuffer
|
||||
|
||||
XYMap xyMap(WIDTH, HEIGHT, SERPENTINE);
|
||||
AnimartrixPtr fxAnimator = AnimartrixPtr::New(xyMap, POLAR_WAVES);
|
||||
|
||||
void setup() {
|
||||
FastLED.addLeds<WS2811, 2, GRB>(leds, NUM_LED);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(5, 2000); // optional current limiting [5V, 2000mA]
|
||||
Serial.begin(115200); // check serial monitor for current fps count
|
||||
// fill_rainbow(leds, NUM_LED, 0);
|
||||
fill_solid(leds, NUM_LED, CRGB::Black);
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint32_t now = millis();
|
||||
// Change animation every 10 seconds
|
||||
#if CYCLE_THROUGH_ANIMATIONS > 0
|
||||
EVERY_N_SECONDS(CYCLE_THROUGH_ANIMATIONS) {
|
||||
fxAnimator->fxNext();
|
||||
#if DEBUG_PRINT
|
||||
std::cout << "New animation: " << fxAnimator.fxName() << std::endl;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
fxAnimator->draw(Fx::DrawContext{millis(), leds});
|
||||
FastLED.show();
|
||||
uint32_t elapsed = millis() - now;
|
||||
|
||||
EVERY_N_SECONDS(1) {
|
||||
#if DEBUG_PRINT
|
||||
std::cout << "frame time: " << elapsed << "ms" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
1
libraries/FastLED/dev/NoiseRing.hpp
Normal file
1
libraries/FastLED/dev/NoiseRing.hpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "../examples/FxNoiseRing/FxNoiseRing.ino"
|
||||
88
libraries/FastLED/dev/apa102hd.hpp
Normal file
88
libraries/FastLED/dev/apa102hd.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/// @file Apa102HD.ino
|
||||
/// @brief Example showing how to use the APA102HD gamma correction.
|
||||
///
|
||||
/// In this example we compare two strips of LEDs.
|
||||
/// One strip is in HD mode, the other is in software gamma mode.
|
||||
///
|
||||
/// Each strip is a linear ramp of brightnesses, from 0 to 255.
|
||||
/// Showcasing all the different brightnesses.
|
||||
///
|
||||
/// Why do we love gamma correction? Gamma correction more closely
|
||||
/// matches how humans see light. Led values are measured in fractions
|
||||
/// of max power output (1/255, 2/255, etc.), while humans see light
|
||||
/// in a logarithmic way. Gamma correction converts to this eye friendly
|
||||
/// curve. Gamma correction wants a LED with a high bit depth. The APA102
|
||||
/// gives us the standard 3 components (red, green, blue) with 8 bits each, it
|
||||
/// *also* has a 5 bit brightness component. This gives us a total of 13 bits,
|
||||
/// which allows us to achieve a higher dynamic range. This means deeper fades.
|
||||
///
|
||||
/// Example:
|
||||
/// CRGB leds[NUM_LEDS] = {0};
|
||||
/// void setup() {
|
||||
/// FastLED.addLeds<
|
||||
/// APA102HD, // <--- This selects HD mode.
|
||||
/// STRIP_0_DATA_PIN,
|
||||
/// STRIP_0_CLOCK_PIN,
|
||||
/// RGB
|
||||
/// >(leds, NUM_LEDS);
|
||||
/// }
|
||||
|
||||
#define FASTLED_ALL_PINS_HARDWARE_SPI 1
|
||||
#include <Arduino.h>
|
||||
#include <FastLED.h>
|
||||
#include <lib8tion.h>
|
||||
|
||||
#define NUM_LEDS 20
|
||||
// uint8_t DATA_PIN, uint8_t CLOCK_PIN,
|
||||
|
||||
#define STRIP_0_DATA_PIN 1
|
||||
#define STRIP_0_CLOCK_PIN 2
|
||||
#define STRIP_1_DATA_PIN 3
|
||||
#define STRIP_1_CLOCK_PIN 4
|
||||
|
||||
|
||||
CRGB leds_hd[NUM_LEDS] = {0}; // HD mode implies gamma.
|
||||
CRGB leds[NUM_LEDS] = {0}; // Software gamma mode.
|
||||
|
||||
// This is the regular gamma correction function that we used to have
|
||||
// to do. It's used here to showcase the difference between APA102HD
|
||||
// mode which does the gamma correction for you.
|
||||
CRGB software_gamma(const CRGB& in) {
|
||||
CRGB out;
|
||||
// dim8_raw are the old gamma correction functions.
|
||||
out.r = dim8_raw(in.r);
|
||||
out.g = dim8_raw(in.g);
|
||||
out.b = dim8_raw(in.b);
|
||||
return out;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
delay(500); // power-up safety delay
|
||||
// Two strips of LEDs, one in HD mode, one in software gamma mode.
|
||||
FastLED.addLeds<APA102HD, STRIP_0_DATA_PIN, STRIP_0_CLOCK_PIN, RGB>(leds_hd, NUM_LEDS);
|
||||
FastLED.addLeds<APA102, STRIP_1_DATA_PIN, STRIP_1_CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
}
|
||||
|
||||
uint8_t wrap_8bit(int i) {
|
||||
// Module % operator here wraps a large "i" so that it is
|
||||
// always in [0, 255] range when returned. For example, if
|
||||
// "i" is 256, then this will return 0. If "i" is 257
|
||||
// then this will return 1. No matter how big the "i" is, the
|
||||
// output range will always be [0, 255]
|
||||
return i % 256;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Draw a a linear ramp of brightnesses to showcase the difference between
|
||||
// the HD and non-HD mode.
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
uint8_t brightness = map(i, 0, NUM_LEDS - 1, 0, 255);
|
||||
CRGB c(brightness, brightness, brightness); // Just make a shade of white.
|
||||
leds_hd[i] = c; // The APA102HD leds do their own gamma correction.
|
||||
CRGB c_gamma_corrected = software_gamma(c);
|
||||
leds[i] = c_gamma_corrected; // Set the software gamma corrected
|
||||
// values to the other strip.
|
||||
}
|
||||
FastLED.show(); // All leds are now written out.
|
||||
delay(8); // Wait 8 milliseconds until the next frame.
|
||||
}
|
||||
34
libraries/FastLED/dev/cylon.hpp
Normal file
34
libraries/FastLED/dev/cylon.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/// @brief An animation that moves a single LED back and forth (Larson Scanner effect) using the fx library cylon
|
||||
/// @example Cylon.ino
|
||||
|
||||
#include <FastLED.h>
|
||||
#include "fx/1d/cylon.hpp"
|
||||
|
||||
// How many leds in your strip?
|
||||
#define NUM_LEDS 64
|
||||
|
||||
// For led chips like Neopixels, which have a data line, ground, and power, you just
|
||||
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
|
||||
// ground, and power).
|
||||
#define DATA_PIN 2
|
||||
|
||||
// Define the array of leds
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
// Create a Cylon instance
|
||||
Cylon cylon(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(57600);
|
||||
Serial.println("resetting");
|
||||
FastLED.addLeds<WS2812,DATA_PIN,BRG>(leds,NUM_LEDS).setRgbw();
|
||||
FastLED.setBrightness(84);
|
||||
cylon.lazyInit();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print("x");
|
||||
cylon.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
delay(cylon.delay_ms);
|
||||
}
|
||||
46
libraries/FastLED/dev/demoreel100.hpp
Normal file
46
libraries/FastLED/dev/demoreel100.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/// @file DemoReel100.ino
|
||||
/// @brief FastLED "100 lines of code" demo reel, showing off some effects
|
||||
/// @example DemoReel100.ino
|
||||
|
||||
#include <FastLED.h>
|
||||
#include "fx/1d/demoreel100.hpp"
|
||||
|
||||
#define DATA_PIN 2
|
||||
//#define CLK_PIN 4
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER BRG
|
||||
#define NUM_LEDS 64
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define BRIGHTNESS 96
|
||||
#define FRAMES_PER_SECOND 120
|
||||
|
||||
DemoReel100Ref demoReel = DemoReel100Ref::New(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // 3 second delay for recovery
|
||||
|
||||
// tell FastLED about the LED strip configuration
|
||||
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip).setRgbw();
|
||||
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
|
||||
|
||||
// set master brightness control
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
|
||||
// Initialize the DemoReel100 instance
|
||||
demoReel.lazyInit();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Run the DemoReel100 draw function
|
||||
demoReel.draw(millis(), leds);
|
||||
|
||||
// send the 'leds' array out to the actual LED strip
|
||||
FastLED.show();
|
||||
// insert a delay to keep the framerate modest
|
||||
FastLED.delay(1000/FRAMES_PER_SECOND);
|
||||
}
|
||||
|
||||
|
||||
17
libraries/FastLED/dev/dev.ino
Normal file
17
libraries/FastLED/dev/dev.ino
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
|
||||
#if defined(ESP32)
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
// use gcc intialize constructor
|
||||
// to set log level to ESP_LOG_VERBOSE
|
||||
// before setup() is called
|
||||
__attribute__((constructor))
|
||||
void on_startup() {
|
||||
esp_log_level_set("*", ESP_LOG_VERBOSE); // set all components to ERROR level
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
|
||||
#include "../examples/FestivalStick/FestivalStick.ino"
|
||||
125
libraries/FastLED/dev/dev.py
Normal file
125
libraries/FastLED/dev/dev.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
PROJECT_ROOT = HERE.parent
|
||||
PLATFORMIO_INI = PROJECT_ROOT / "platformio.ini"
|
||||
|
||||
ESP32C6 = """
|
||||
[platformio]
|
||||
src_dir = dev ; target is ./dev/dev.ino
|
||||
|
||||
[env:dev]
|
||||
; This is the espressif32 platform which is the 4.1 toolchain as of 2024-Aug-23rd
|
||||
; platform = espressif32
|
||||
; The following platform enables the espressif32 platform to use the 5.1 toolchain, simulating
|
||||
; the new Arduino 2.3.1+ toolchain.
|
||||
|
||||
# Developement branch of the open source espressif32 platform
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10/platform-espressif32.zip
|
||||
|
||||
framework = arduino
|
||||
board = esp32-c6-devkitc-1
|
||||
|
||||
upload_protocol = esptool
|
||||
|
||||
monitor_filters =
|
||||
default
|
||||
esp32_exception_decoder ; Decode exceptions so that they are human readable.
|
||||
|
||||
; Symlink in the FastLED library so that changes to the library are reflected in the project
|
||||
; build immediatly.
|
||||
lib_deps =
|
||||
FastLED=symlink://./
|
||||
|
||||
build_type = debug
|
||||
|
||||
build_flags =
|
||||
-DDEBUG
|
||||
-g
|
||||
-Og
|
||||
-DCORE_DEBUG_LEVEL=5
|
||||
-DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE
|
||||
;-DFASTLED_RMT5=1
|
||||
-DFASTLED_ESP32_SPI_BULK_TRANSFER=1
|
||||
-DENABLE_ESP32_I2S_YVES_DRIVER=1
|
||||
|
||||
check_tool = clangtidy
|
||||
"""
|
||||
|
||||
ESP32S3 = """
|
||||
[platformio]
|
||||
src_dir = dev ; target is ./dev/dev.ino
|
||||
|
||||
[env:dev]
|
||||
; This is the espressif32 platform which is the 4.1 toolchain as of 2024-Aug-23rd
|
||||
; platform = espressif32
|
||||
; The following platform enables the espressif32 platform to use the 5.1 toolchain, simulating
|
||||
; the new Arduino 2.3.1+ toolchain.
|
||||
|
||||
# Developement branch of the open source espressif32 platform
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10/platform-espressif32.zip
|
||||
|
||||
framework = arduino
|
||||
board = esp32-s3-devkitc-1
|
||||
|
||||
upload_protocol = esptool
|
||||
|
||||
monitor_filters =
|
||||
default
|
||||
esp32_exception_decoder ; Decode exceptions so that they are human readable.
|
||||
|
||||
; Symlink in the FastLED library so that changes to the library are reflected in the project
|
||||
; build immediatly.
|
||||
lib_deps =
|
||||
FastLED=symlink://./
|
||||
|
||||
build_type = debug
|
||||
|
||||
build_flags =
|
||||
-DDEBUG
|
||||
-g
|
||||
-Og
|
||||
-DCORE_DEBUG_LEVEL=5
|
||||
-DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE
|
||||
;-DFASTLED_RMT5=1
|
||||
-DFASTLED_ESP32_SPI_BULK_TRANSFER=1
|
||||
-DENABLE_ESP32_I2S_YVES_DRIVER=1
|
||||
|
||||
check_tool = clangtidy
|
||||
"""
|
||||
|
||||
_ALL = {"esp32c6": ESP32C6, "esp32s3": ESP32S3}
|
||||
|
||||
|
||||
def prompt_user(msg: str) -> int:
|
||||
while True:
|
||||
try:
|
||||
return int(input(msg))
|
||||
except ValueError:
|
||||
print("Please enter a valid integer")
|
||||
continue
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("This tool will update the platformio.ini file with the selected platform")
|
||||
print("Please select a platform:")
|
||||
print("[0]: Exit")
|
||||
for i, platform in enumerate(_ALL.keys()):
|
||||
print(f"[{i+1}]: {platform}")
|
||||
val = prompt_user("Enter a number: ")
|
||||
if val == 0:
|
||||
sys.exit(0)
|
||||
if val < 0 or val > len(_ALL):
|
||||
print("Invalid selection")
|
||||
sys.exit(1)
|
||||
platform = list(_ALL.keys())[val - 1]
|
||||
with PLATFORMIO_INI.open("w") as f:
|
||||
f.write(_ALL[platform])
|
||||
print(f"Selected platform: {platform}")
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
libraries/FastLED/dev/esp_virtual_driver.hpp
Normal file
1
libraries/FastLED/dev/esp_virtual_driver.hpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "../examples/EspI2SDemo/EspI2SDemo.ino"
|
||||
2
libraries/FastLED/dev/fake_main_for_esp32dev.cpp
Normal file
2
libraries/FastLED/dev/fake_main_for_esp32dev.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// For some reason, platformio refuses to compile unless at least one .cpp file is present in this directory.
|
||||
// This file is not used in the build process, but is required to satisfy platformio.
|
||||
33
libraries/FastLED/dev/fire2012.hpp
Normal file
33
libraries/FastLED/dev/fire2012.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <FastLED.h>
|
||||
#include "fx/1d/fire2012.hpp"
|
||||
|
||||
#define LED_PIN 2
|
||||
#define COLOR_ORDER BRG
|
||||
#define CHIPSET WS2811
|
||||
#define NUM_LEDS 30
|
||||
|
||||
#define BRIGHTNESS 128
|
||||
#define FRAMES_PER_SECOND 30
|
||||
#define COOLING 55
|
||||
#define SPARKING 120
|
||||
#define REVERSE_DIRECTION false
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
Fire2012 fire(NUM_LEDS, COOLING, SPARKING, REVERSE_DIRECTION);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // sanity delay
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip)
|
||||
.setRgbw();
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
fire.draw(millis(), leds); // run simulation frame, passing leds array
|
||||
|
||||
FastLED.show(); // display this frame
|
||||
FastLED.delay(1000 / FRAMES_PER_SECOND);
|
||||
}
|
||||
|
||||
55
libraries/FastLED/dev/fx_engine.hpp
Normal file
55
libraries/FastLED/dev/fx_engine.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/// @file Noise.ino
|
||||
/// @brief Demonstrates how to use noise generation on a 2D LED matrix
|
||||
/// @example Noise.ino
|
||||
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#include "fx/2d/noisepalette.h"
|
||||
#include "fx/2d/animartrix.hpp"
|
||||
#include "fx/fx_engine.h"
|
||||
#include "fx/storage/sd.h"
|
||||
|
||||
#define LED_PIN 2
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
#define MATRIX_WIDTH 22
|
||||
#define MATRIX_HEIGHT 22
|
||||
#define GRID_SERPENTINE 1
|
||||
|
||||
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
|
||||
|
||||
#define SCALE 20
|
||||
#define SPEED 30
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
XYMap xyMap(MATRIX_WIDTH, MATRIX_HEIGHT, GRID_SERPENTINE);
|
||||
NoisePaletteRef noisePalette = Fx::make<NoisePalette>(xyMap);
|
||||
AnimartrixRef animartrix = Fx::make<Animartrix>(xyMap, POLAR_WAVES);
|
||||
|
||||
FxEngine fxEngine(NUM_LEDS);
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(96);
|
||||
noisePalette->lazyInit();
|
||||
noisePalette->setSpeed(SPEED);
|
||||
noisePalette->setScale(SCALE);
|
||||
noisePalette->setPalettePreset(2);
|
||||
fxEngine.addFx(noisePalette);
|
||||
fxEngine.addFx(animartrix);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_SECONDS(1) {
|
||||
fxEngine.nextFx(500);
|
||||
}
|
||||
fxEngine.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
}
|
||||
75
libraries/FastLED/dev/noisepalette.hpp
Normal file
75
libraries/FastLED/dev/noisepalette.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/// @file Noise.ino
|
||||
/// @brief Demonstrates how to use noise generation on a 2D LED matrix
|
||||
/// @example Noise.ino
|
||||
|
||||
#include "fx/2d/noisepalette.h"
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 2
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
#define MATRIX_WIDTH 22
|
||||
#define MATRIX_HEIGHT 22
|
||||
#define GRID_SERPENTINE 1
|
||||
|
||||
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
|
||||
|
||||
// This example combines two features of FastLED to produce a remarkable range
|
||||
// of effects from a relatively small amount of code. This example combines
|
||||
// FastLED's color palette lookup functions with FastLED's Perlin noise
|
||||
// generator, and the combination is extremely powerful.
|
||||
//
|
||||
// You might want to look at the "ColorPalette" and "Noise" examples separately
|
||||
// if this example code seems daunting.
|
||||
//
|
||||
//
|
||||
// The basic setup here is that for each frame, we generate a new array of
|
||||
// 'noise' data, and then map it onto the LED matrix through a color palette.
|
||||
//
|
||||
// Periodically, the color palette is changed, and new noise-generation
|
||||
// parameters are chosen at the same time. In this example, specific
|
||||
// noise-generation values have been selected to match the given color palettes;
|
||||
// some are faster, or slower, or larger, or smaller than others, but there's no
|
||||
// reason these parameters can't be freely mixed-and-matched.
|
||||
//
|
||||
// In addition, this example includes some fast automatic 'data smoothing' at
|
||||
// lower noise speeds to help produce smoother animations in those cases.
|
||||
//
|
||||
// The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
|
||||
// used, as well as some 'hand-defined' ones, and some proceedurally generated
|
||||
// palettes.
|
||||
|
||||
// Scale determines how far apart the pixels in our noise matrix are. Try
|
||||
// changing these values around to see how it affects the motion of the display.
|
||||
// The higher the value of scale, the more "zoomed out" the noise iwll be. A
|
||||
// value of 1 will be so zoomed in, you'll mostly see solid colors.
|
||||
#define SCALE 20
|
||||
|
||||
// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll
|
||||
// use the z-axis for "time". speed determines how fast time moves forward. Try
|
||||
// 1 for a very slow moving effect, or 60 for something that ends up looking
|
||||
// like water.
|
||||
#define SPEED 30
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
XYMap xyMap(MATRIX_WIDTH, MATRIX_HEIGHT, GRID_SERPENTINE);
|
||||
NoisePaletteRef noisePalette = Fx::make<NoisePaletteRef>(xyMap);
|
||||
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(96);
|
||||
noisePalette->lazyInit();
|
||||
noisePalette->setSpeed(SPEED);
|
||||
noisePalette->setScale(SCALE);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_MILLISECONDS(5000) { noisePalette->changeToRandomPalette(); }
|
||||
noisePalette->draw(DrawContext{millis(), leds});
|
||||
FastLED.show();
|
||||
}
|
||||
26
libraries/FastLED/dev/noisewave.hpp
Normal file
26
libraries/FastLED/dev/noisewave.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <FastLED.h>
|
||||
#include "fx/1d/noisewave.hpp"
|
||||
|
||||
#define LED_PIN 2
|
||||
#define COLOR_ORDER BRG
|
||||
#define CHIPSET WS2811
|
||||
#define NUM_LEDS 484
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
NoiseWaveRef noiseWave = Fx::make<NoiseWave>(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // sanity delay
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(128);
|
||||
noiseWave->lazyInit();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
noiseWave->draw(DrawContext{millis(), leds});
|
||||
FastLED.show();
|
||||
FastLED.delay(1000 / 60);
|
||||
}
|
||||
|
||||
26
libraries/FastLED/dev/pacifica.hpp
Normal file
26
libraries/FastLED/dev/pacifica.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#define FASTLED_ALLOW_INTERRUPTS 0
|
||||
#include <FastLED.h>
|
||||
#include "fx/1d/pacifica.hpp"
|
||||
|
||||
#define DATA_PIN 2
|
||||
#define NUM_LEDS 60
|
||||
#define MAX_POWER_MILLIAMPS 500
|
||||
#define LED_TYPE WS2812B
|
||||
#define COLOR_ORDER BRG
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
Pacifica pacifica(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // 3 second delay for boot recovery, and a moment of silence
|
||||
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_POWER_MILLIAMPS);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_MILLISECONDS(20) {
|
||||
pacifica.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
}
|
||||
}
|
||||
28
libraries/FastLED/dev/pride2015.hpp
Normal file
28
libraries/FastLED/dev/pride2015.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#include <FastLED.h>
|
||||
#include "fx/1d/pride2015.hpp"
|
||||
|
||||
#define DATA_PIN 2
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER BRG
|
||||
#define NUM_LEDS 200
|
||||
#define BRIGHTNESS 255
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
Pride2015 pride(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // 3 second delay for recovery
|
||||
|
||||
// tell FastLED about the LED strip configuration
|
||||
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip)
|
||||
.setDither(BRIGHTNESS < 255);
|
||||
|
||||
// set master brightness control
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
pride.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
}
|
||||
48
libraries/FastLED/dev/rgborder.hpp
Normal file
48
libraries/FastLED/dev/rgborder.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include "fx/pride2015.hpp"
|
||||
|
||||
#define DATA_PIN 2
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
#define NUM_LEDS 200
|
||||
#define BRIGHTNESS 128
|
||||
|
||||
#define DELAY 500
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void fill(CRGB c) {
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(CRGB color, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
fill(color);
|
||||
FastLED.show();
|
||||
delay(DELAY); // On for 500ms
|
||||
fill(CRGB::Black);
|
||||
FastLED.show();
|
||||
delay(DELAY); // Off for 500ms
|
||||
}
|
||||
delay(DELAY * 2); // Pause for 1s
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// tell FastLED about the LED strip configuration
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip)
|
||||
.setDither(BRIGHTNESS < 255);
|
||||
|
||||
// set master brightness control
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Blink red once,
|
||||
Blink(CRGB::Red, 1);
|
||||
// Blink green twice
|
||||
Blink(CRGB::Green, 2);
|
||||
// Blink blue three times
|
||||
Blink(CRGB::Blue, 3);
|
||||
}
|
||||
106
libraries/FastLED/dev/rmt51.hpp
Normal file
106
libraries/FastLED/dev/rmt51.hpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
|
||||
#include <FastLED.h>
|
||||
#include <iostream>
|
||||
|
||||
// How many leds in your strip?
|
||||
#define NUM_LEDS 10
|
||||
|
||||
// For led chips like WS2812, which have a data line, ground, and power, you just
|
||||
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
|
||||
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
|
||||
// Clock pin only needed for SPI based chipsets when not using hardware SPI
|
||||
#define DATA_PIN 2
|
||||
|
||||
// Define the array of leds
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
// Time scaling factors for each component
|
||||
#define TIME_FACTOR_HUE 60
|
||||
#define TIME_FACTOR_SAT 100
|
||||
#define TIME_FACTOR_VAL 100
|
||||
|
||||
#define DELAY 200
|
||||
#define BRIGHNESS 8
|
||||
|
||||
// #define COLOR_ORDER_TEST
|
||||
// #define TIMING_TEST
|
||||
#define STRESS_TEST
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
FastLED.addLeds<WS2812, 2, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
#ifdef STRESS_TEST
|
||||
FastLED.addLeds<WS2812, 1, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 3, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 4, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 5, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 6, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 7, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 8, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
FastLED.addLeds<WS2812, 9, BRG>(leds, NUM_LEDS).setRgbw(RgbwDefault());
|
||||
#endif
|
||||
FastLED.setBrightness(BRIGHNESS); // Set global brightness to 50%
|
||||
delay(2000); // If something ever goes wrong this delay will allow upload.
|
||||
}
|
||||
|
||||
void fill(CRGB color) {
|
||||
for (int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
void Blink(CRGB color, int times) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
fill(color);
|
||||
FastLED.show();
|
||||
delay(DELAY);
|
||||
fill(CRGB::Black);
|
||||
FastLED.show();
|
||||
delay(DELAY);
|
||||
}
|
||||
delay(DELAY*2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void blink_loop() {
|
||||
Blink(CRGB::Red, 1);
|
||||
Blink(CRGB::Green, 2);
|
||||
Blink(CRGB::Blue, 3);
|
||||
Blink(CRGB::White, 4);
|
||||
delay(DELAY);
|
||||
// long delay to make the cycle visible
|
||||
delay(DELAY * 4);
|
||||
}
|
||||
|
||||
|
||||
void hue_loop() {
|
||||
uint32_t ms = millis();
|
||||
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Use different noise functions for each LED and each color component
|
||||
uint8_t hue = inoise16(ms * TIME_FACTOR_HUE, i * 1000, 0) >> 8;
|
||||
uint8_t sat = inoise16(ms * TIME_FACTOR_SAT, i * 2000, 1000) >> 8;
|
||||
uint8_t val = inoise16(ms * TIME_FACTOR_VAL, i * 3000, 2000) >> 8;
|
||||
|
||||
// Map the noise to full range for saturation and value
|
||||
sat = map(sat, 0, 255, 30, 255);
|
||||
val = map(val, 0, 255, 100, 255);
|
||||
|
||||
leds[i] = CHSV(hue, sat, val);
|
||||
}
|
||||
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef COLOR_ORDER_TEST
|
||||
blink_loop();
|
||||
#elif defined(TIMING_TEST)
|
||||
timing_loop();
|
||||
#else
|
||||
hue_loop();
|
||||
#endif
|
||||
}
|
||||
53
libraries/FastLED/dev/s3_parallel.hpp
Normal file
53
libraries/FastLED/dev/s3_parallel.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#include <FastLED.h>
|
||||
#include <iostream>
|
||||
|
||||
#define NUM_LEDS_PER_STRIP 60 // Number of LEDs in each strip
|
||||
#define NUM_STRIPS 3 // Number of parallel strips
|
||||
|
||||
// Define the pins for each strip
|
||||
#define STRIP_1_PIN 13
|
||||
#define STRIP_2_PIN 12
|
||||
#define STRIP_3_PIN 14
|
||||
#define STRIP_4_PIN 14
|
||||
|
||||
// Create separate LED arrays for each strip
|
||||
CRGB leds1[NUM_LEDS_PER_STRIP];
|
||||
CRGB leds2[NUM_LEDS_PER_STRIP];
|
||||
CRGB leds3[NUM_LEDS_PER_STRIP];
|
||||
CRGB leds4[NUM_LEDS_PER_STRIP];
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
//Initialize FastLED for multiple strips
|
||||
FastLED.addLeds<WS2812B, STRIP_1_PIN, GRB>(leds1, NUM_LEDS_PER_STRIP);
|
||||
FastLED.addLeds<WS2812B, STRIP_2_PIN, GRB>(leds2, NUM_LEDS_PER_STRIP);
|
||||
FastLED.addLeds<WS2812B, STRIP_3_PIN, GRB>(leds3, NUM_LEDS_PER_STRIP);
|
||||
FastLED.addLeds<WS2812B, STRIP_4_PIN, GRB>(leds3, NUM_LEDS_PER_STRIP);
|
||||
Serial.println("Setup");
|
||||
std::cout << "Setup" << std::endl;
|
||||
|
||||
FastLED.setBrightness(64); // Set initial brightness (0-255)
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Create a simple rainbow pattern
|
||||
static uint8_t hue = 0;
|
||||
|
||||
// Update each strip
|
||||
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
|
||||
leds1[i] = CHSV(hue + (i * 4), 255, 255);
|
||||
leds2[i] = CHSV(hue + (i * 4), 255, 255);
|
||||
leds3[i] = CHSV(hue + (i * 4), 255, 255);
|
||||
leds4[i] = CHSV(hue + (i * 4), 255, 255);
|
||||
}
|
||||
|
||||
FastLED.show();
|
||||
|
||||
EVERY_N_MILLISECONDS(20) {
|
||||
hue++;
|
||||
}
|
||||
EVERY_N_SECONDS(1) {
|
||||
// Serial.println("Alive");
|
||||
std::cout << "Alive" << std::endl;
|
||||
}
|
||||
}
|
||||
49
libraries/FastLED/dev/scale_up.hpp
Normal file
49
libraries/FastLED/dev/scale_up.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/// @file Noise.ino
|
||||
/// @brief Demonstrates how to use noise generation on a 2D LED matrix
|
||||
/// @example Noise.ino
|
||||
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#include "fx/2d/noisepalette.h"
|
||||
#include "fx/fx_engine.h"
|
||||
#include "fx/2d/animartrix.hpp"
|
||||
#include "fx/2d/scale_up.h"
|
||||
#include "fx/fx_engine.h"
|
||||
|
||||
#define LED_PIN 2
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
#define MATRIX_SMALL_WIDTH 11
|
||||
#define MATRIX_SMALL_HEIGHT 11
|
||||
#define MATRIX_WIDTH 22
|
||||
#define MATRIX_HEIGHT 22
|
||||
#define GRID_SERPENTINE 1
|
||||
|
||||
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
|
||||
|
||||
#define SCALE 20
|
||||
#define SPEED 30
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
XYMap xyMap(MATRIX_WIDTH, MATRIX_HEIGHT, GRID_SERPENTINE);
|
||||
XYMap xyMapSmall = XYMap::constructRectangularGrid(MATRIX_SMALL_WIDTH, MATRIX_SMALL_HEIGHT);
|
||||
AnimartrixRef animartrix = Fx::make<Animatrix>(xyMapSmall, POLAR_WAVES);
|
||||
ScaleUp scaleUp(xyMap, animartrix.get());
|
||||
FxEngine fxEngine(NUM_LEDS);
|
||||
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(96);
|
||||
fxEngine.addFx(&scaleUp);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
fxEngine.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
}
|
||||
49
libraries/FastLED/dev/sd_card.hpp
Normal file
49
libraries/FastLED/dev/sd_card.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/// @file Noise.ino
|
||||
/// @brief Demonstrates how to use noise generation on a 2D LED matrix
|
||||
/// @example Noise.ino
|
||||
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#include "fx/storage/sd.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define SCALE 20
|
||||
#define SPEED 30
|
||||
#define CS_PIN 5
|
||||
|
||||
FsRef SD_CARD_READER = FsRef::New(CS_PIN);
|
||||
|
||||
|
||||
void runFsTest() {
|
||||
cout << "Running SD card test" << endl;
|
||||
SD_CARD_READER->begin(CS_PIN);
|
||||
FileHandleRef file = SD_CARD_READER->openRead("/test.txt");
|
||||
if (!file) {
|
||||
cout << "Failed to open file" << endl;
|
||||
return;
|
||||
}
|
||||
cout << "File opened" << endl;
|
||||
char buffer[256];
|
||||
size_t bytesRead = file->read((uint8_t*)buffer, sizeof(buffer));
|
||||
cout << "Read " << bytesRead << " bytes" << endl;
|
||||
cout << "File contents: " << buffer << endl;
|
||||
file->close();
|
||||
cout << "File closed" << endl;
|
||||
SD_CARD_READER->end();
|
||||
cout << "SD card test complete" << endl;
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
runFsTest();
|
||||
delay(1000);
|
||||
}
|
||||
61
libraries/FastLED/dev/test_video_fx.hpp
Normal file
61
libraries/FastLED/dev/test_video_fx.hpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/// @file VideoTest.ino
|
||||
/// @brief Demonstrates a video test using NoisePalette to generate content
|
||||
/// @example VideoTest.ino
|
||||
|
||||
#include <FastLED.h>
|
||||
#include "fx/2d/video.hpp"
|
||||
#include "fx/2d/noisepalette.hpp"
|
||||
#include "fx/fx_engine.h"
|
||||
#include "ref.h"
|
||||
|
||||
#define LED_PIN 2
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
#define MATRIX_WIDTH 16
|
||||
#define MATRIX_HEIGHT 16
|
||||
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
|
||||
|
||||
#define SCALE 20
|
||||
#define SPEED 30
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
VideoFxRef videoFx;
|
||||
NoisePaletteRef noisePalette;
|
||||
FxEngine fxEngine(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
|
||||
// Create and initialize XYMap
|
||||
XYMap xymap(MATRIX_WIDTH, MATRIX_HEIGHT);
|
||||
|
||||
// Create and initialize NoisePalette object
|
||||
noisePalette = NoisePaletteRef::New(xymap);
|
||||
noisePalette->lazyInit();
|
||||
noisePalette->setSpeed(SPEED);
|
||||
noisePalette->setScale(SCALE);
|
||||
|
||||
// Create and initialize VideoFx object
|
||||
videoFx = VideoFxRef::New(xymap, noisePalette);
|
||||
|
||||
// Add the video effect to the FxEngine
|
||||
fxEngine.addFx(videoFx);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_MILLISECONDS(5000) { noisePalette->changeToRandomPalette(); }
|
||||
|
||||
// Draw the frame
|
||||
fxEngine.draw(millis(), leds);
|
||||
|
||||
// Show the LEDs
|
||||
FastLED.show();
|
||||
|
||||
FastLED.delay(1000 / 60); // 60 fps
|
||||
}
|
||||
30
libraries/FastLED/dev/twinklefox.hpp
Normal file
30
libraries/FastLED/dev/twinklefox.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "FastLED.h"
|
||||
#include "fx/1d/twinklefox.hpp"
|
||||
|
||||
#define NUM_LEDS 100
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER BRG
|
||||
#define DATA_PIN 2
|
||||
#define VOLTS 12
|
||||
#define MAX_MA 4000
|
||||
|
||||
CRGBArray<NUM_LEDS> leds;
|
||||
TwinkleFox twinkleFox(NUM_LEDS);
|
||||
|
||||
void setup() {
|
||||
delay(3000); // safety startup delay
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, MAX_MA);
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip)
|
||||
.setRgbw();
|
||||
|
||||
twinkleFox.lazyInit();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
EVERY_N_SECONDS(SECONDS_PER_PALETTE) {
|
||||
twinkleFox.chooseNextColorPalette(twinkleFox.targetPalette);
|
||||
}
|
||||
twinkleFox.draw(millis(), leds);
|
||||
FastLED.show();
|
||||
}
|
||||
88
libraries/FastLED/dev/video_test.hpp
Normal file
88
libraries/FastLED/dev/video_test.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/// @file VideoTest.ino
|
||||
/// @brief Demonstrates a simple video test using alternating black/red pixels
|
||||
/// @example VideoTest.ino
|
||||
|
||||
#include <FastLED.h>
|
||||
#include "fl/bytestreammemory.h"
|
||||
#include "fx/2d/video.hpp"
|
||||
#include "fx/fx_engine.h"
|
||||
#include "fl/ptr.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace fl;
|
||||
|
||||
#define LED_PIN 2
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
#define MATRIX_WIDTH 22
|
||||
#define MATRIX_HEIGHT 22
|
||||
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
const int BYTES_PER_FRAME = 3 * MATRIX_WIDTH * MATRIX_HEIGHT;
|
||||
const int NUM_FRAMES = 2;
|
||||
const uint32_t BUFFER_SIZE = BYTES_PER_FRAME * NUM_FRAMES;
|
||||
|
||||
ByteStreamMemoryPtr memoryStream;
|
||||
VideoPtr videoFx;
|
||||
FxEngine fxEngine(NUM_LEDS);
|
||||
|
||||
using namespace fl;
|
||||
|
||||
|
||||
void write_one_frame(ByteStreamMemoryPtr memoryStream) {
|
||||
//memoryStream->seek(0); // Reset to the beginning of the stream
|
||||
uint32_t total_bytes_written = 0;
|
||||
int toggle = (millis() / 500) % 2;
|
||||
for (uint32_t i = 0; i < NUM_LEDS; ++i) {
|
||||
CRGB color = (i % 2 == toggle) ? CRGB::Black : CRGB::Red;
|
||||
size_t bytes_written = memoryStream->write(color.raw, 3);
|
||||
if (bytes_written != 3) {
|
||||
std::cout << "Error writing to memory stream at LED " << i << std::endl;
|
||||
}
|
||||
total_bytes_written += bytes_written;
|
||||
}
|
||||
std::cout << "Total bytes written: " << total_bytes_written << " / " << BUFFER_SIZE << std::endl;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
delay(1000); // sanity delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS)
|
||||
.setCorrection(TypicalLEDStrip);
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
|
||||
// Create and fill the ByteStreamMemory with test data
|
||||
memoryStream = Ptr::New<ByteStreamMemory>(BUFFER_SIZE);
|
||||
write_one_frame(memoryStream); // Write initial frame data
|
||||
|
||||
// Create and initialize Video fx object
|
||||
XYMap xymap(MATRIX_WIDTH, MATRIX_HEIGHT);
|
||||
videoFx = Fx::make<VideoPtr>(xymap);
|
||||
videoFx->beginStream(memoryStream);
|
||||
|
||||
// Add the video effect to the FxEngine
|
||||
fxEngine.addFx(videoFx);
|
||||
|
||||
std::cout << "Setup complete. Starting main loop." << std::endl;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Reset the memory stream position before reading
|
||||
//memoryStream->seek(0);
|
||||
write_one_frame(memoryStream); // Write next frame data
|
||||
|
||||
// Draw the frame
|
||||
fxEngine.draw(millis(), leds);
|
||||
|
||||
// Debug output
|
||||
//std::cout << "First LED: R=" << (int)leds[0].r << " G=" << (int)leds[0].g << " B=" << (int)leds[0].b << std::endl;
|
||||
//std::cout << "Last LED: R=" << (int)leds[NUM_LEDS-1].r << " G=" << (int)leds[NUM_LEDS-1].g << " B=" << (int)leds[NUM_LEDS-1].b << std::endl;
|
||||
|
||||
// Show the LEDs
|
||||
FastLED.show();
|
||||
|
||||
delay(100); // Adjust this delay to control frame rate
|
||||
}
|
||||
2976
libraries/FastLED/docs/Doxyfile
Normal file
2976
libraries/FastLED/docs/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
264
libraries/FastLED/docs/DoxygenLayout.xml
Normal file
264
libraries/FastLED/docs/DoxygenLayout.xml
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.11.0 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="topics" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="" intro="">
|
||||
<tab type="modulelist" visible="yes" title="" intro=""/>
|
||||
<tab type="modulemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="concepts" visible="yes" title="">
|
||||
</tab>
|
||||
<tab type="interfaces" visible="yes" title="">
|
||||
<tab type="interfacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="structs" visible="yes" title="">
|
||||
<tab type="structlist" visible="yes" title="" intro=""/>
|
||||
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
</tab>
|
||||
<tab type="exceptions" visible="yes" title="">
|
||||
<tab type="exceptionlist" visible="yes" title="" intro=""/>
|
||||
<tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||
<tab type="globals" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<detaileddescription title=""/>
|
||||
<includes visible="$SHOW_HEADERFILE"/>
|
||||
<inheritancegraph visible="yes"/>
|
||||
<collaborationgraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<concepts visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a concept page -->
|
||||
<concept>
|
||||
<detaileddescription title=""/>
|
||||
<includes visible="$SHOW_HEADERFILE"/>
|
||||
<definition visible="yes" title=""/>
|
||||
<authorsection visible="yes"/>
|
||||
</concept>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<detaileddescription title=""/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="yes"/>
|
||||
<includedbygraph visible="yes"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<concepts visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<detaileddescription title=""/>
|
||||
<groupgraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<modules visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<concepts visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a C++20 module page -->
|
||||
<module>
|
||||
<briefdescription visible="yes"/>
|
||||
<exportedmodules visible="yes"/>
|
||||
<memberdecl>
|
||||
<concepts visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<enums title=""/>
|
||||
<typedefs title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups title=""/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
</module>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
11
libraries/FastLED/docs/include/fastled-docs.css
Normal file
11
libraries/FastLED/docs/include/fastled-docs.css
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
FastLED Doxygen Stylesheet
|
||||
https://github.com/FastLED/FastLED/
|
||||
*/
|
||||
|
||||
/** Hide "Detailed UIDescription" sub-header when the
|
||||
* detailed description is at the top of a page.
|
||||
*/
|
||||
.contents a#details + h2.groupheader {
|
||||
display:none;
|
||||
}
|
||||
BIN
libraries/FastLED/docs/include/fastled_logo.png
Normal file
BIN
libraries/FastLED/docs/include/fastled_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue