initial commit

This commit is contained in:
2026-02-12 00:45:31 -08:00
commit 5f168f370b
3024 changed files with 804889 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
#if defined(FASTLED_USE_STUB_ARDUINO) || defined(__EMSCRIPTEN__)
// STUB platform implementation - excluded for WASM builds which provide their own Arduino.cpp
#include "./Arduino.h" // ok include
SerialEmulation Serial;
SerialEmulation Serial1;
SerialEmulation Serial2;
SerialEmulation Serial3;
#endif

View File

@@ -0,0 +1,256 @@
// Arduino.h emulation for the WebAssembly platform.
// This allows us to compile sketches as is for the WebAssembly platform.
#pragma once
// Standard Arduino define - indicates Arduino environment and version
// Using a modern Arduino IDE version number (1.8.19 = 10819)
#ifndef ARDUINO
#define ARDUINO 1
#endif
#include "fl/str.h"
#include <algorithm>
#include <random>
#include "fl/stdint.h"
#include <stdio.h>
#include <string>
#include "fl/ostream.h"
#include "fl/namespace.h"
// Arduino timing functions - provided by time_stub.h
#include "time_stub.h"
#include "fl/math_macros.h"
#include "fl/math.h"
FASTLED_USING_NAMESPACE
template <typename T>
T min(T a, T b) {
return a < b ? a : b;
}
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
namespace fl {
inline long map(long x, long in_min, long in_max, long out_min, long out_max) {
const long run = in_max - in_min;
if (run == 0) {
return 0; // AVR returns -1, SAM returns 0
}
const long rise = out_max - out_min;
const long delta = x - in_min;
return (delta * rise) / run + out_min;
}
// constrain
template <typename T> T constrain(T x, T a, T b) {
return x < a ? a : (x > b ? b : x);
}
} // namespace fl
using fl::constrain;
using fl::map;
inline long random(long min, long max) {
if (min == max) {
return min;
}
std::random_device rd;
std::mt19937 gen(rd());
// Arduino random is exclusive of the max value, but
// std::uniform_int_distribution is inclusive. So we subtract 1 from the max
// value.
std::uniform_int_distribution<> dis(min, max - 1);
return dis(gen);
}
inline int analogRead(int) { return random(0, 1023); }
inline long random(long max) { return random(0, max); }
// Arduino-compatible random() with no parameters - returns full range random long
inline long random() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<long> dis;
return dis(gen);
}
#ifndef A0
#define A0 0
#endif
#ifndef A1
#define A1 1
#endif
#ifndef A2
#define A2 2
#endif
#ifndef A3
#define A3 3
#endif
#ifndef A4
#define A4 4
#endif
#ifndef A5
#define A5 5
#endif
#ifndef A6
#define A6 6
#endif
#ifndef A7
#define A7 7
#endif
#ifndef A8
#define A8 8
#endif
#ifndef A9
#define A9 9
#endif
#ifndef A10
#define A10 10
#endif
#ifndef A11
#define A11 11
#endif
struct SerialEmulation {
void begin(int) {}
template <typename T> void print(T val) {
fl::cout << val;
}
template <typename T> void println(T val) {
fl::cout << val << fl::endl;
}
// Two-argument print overloads for formatting
void print(float _val, int digits) {
// Clamp digits to reasonable range
digits = digits < 0 ? 0 : (digits > 9 ? 9 : digits);
double val = static_cast<double>(_val);
// Use literal format strings to avoid linter warnings
switch(digits) {
case 0: printf("%.0f", val); break;
case 1: printf("%.1f", val); break;
case 2: printf("%.2f", val); break;
case 3: printf("%.3f", val); break;
case 4: printf("%.4f", val); break;
case 5: printf("%.5f", val); break;
case 6: printf("%.6f", val); break;
case 7: printf("%.7f", val); break;
case 8: printf("%.8f", val); break;
case 9: printf("%.9f", val); break;
}
}
void print(double val, int digits) {
// Clamp digits to reasonable range
digits = digits < 0 ? 0 : (digits > 9 ? 9 : digits);
// Use literal format strings to avoid linter warnings
switch(digits) {
case 0: printf("%.0f", val); break;
case 1: printf("%.1f", val); break;
case 2: printf("%.2f", val); break;
case 3: printf("%.3f", val); break;
case 4: printf("%.4f", val); break;
case 5: printf("%.5f", val); break;
case 6: printf("%.6f", val); break;
case 7: printf("%.7f", val); break;
case 8: printf("%.8f", val); break;
case 9: printf("%.9f", val); break;
}
}
void print(int val, int base) {
if (base == 16) printf("%x", val);
else if (base == 8) printf("%o", val);
else if (base == 2) {
// Binary output
for (int i = 31; i >= 0; i--) {
printf("%d", (val >> i) & 1);
}
}
else printf("%d", val);
}
void print(unsigned int val, int base) {
if (base == 16) printf("%x", val);
else if (base == 8) printf("%o", val);
else if (base == 2) {
// Binary output
for (int i = 31; i >= 0; i--) {
printf("%d", (val >> i) & 1);
}
}
else printf("%u", val);
}
void println() { printf("\n"); }
int available() { return 0; }
int read() { return 0; }
void write(uint8_t) {}
void write(const char *s) { printf("%s", s); }
void write(const uint8_t *s, size_t n) { fwrite(s, 1, n, stdout); }
void write(const char *s, size_t n) { fwrite(s, 1, n, stdout); }
void flush() {}
void end() {}
uint8_t peek() { return 0; }
};
#define LED_BUILTIN 13
#define HIGH 1
#define LOW 0
#define INPUT 0
#define OUTPUT 1
#define INPUT_PULLUP 2
inline void digitalWrite(int, int) {}
inline void analogWrite(int, int) {}
inline int digitalRead(int) { return LOW; }
inline void pinMode(int, int) {}
// avr flash memory macro is disabled.
#ifdef F
#undef F
#endif
#define F(x) x
// Found in the wild for scintillating example
#ifdef FL_PGM_READ_PTR_NEAR
#undef FL_PGM_READ_PTR_NEAR
#endif
#define FL_PGM_READ_PTR_NEAR(addr) (*(addr))
typedef unsigned char byte;
// Define Serial instances for stub compilation
extern SerialEmulation Serial;
extern SerialEmulation Serial1;
extern SerialEmulation Serial2;
extern SerialEmulation Serial3;
typedef SerialEmulation HardwareSerial;
typedef SerialEmulation SoftwareSerial;

View File

@@ -0,0 +1,30 @@
# FastLED Platform: stub
Native (nohardware) platform used for tests and host builds; may delegate to WASM clockless for browser builds or a generic stub.
## Files (quick pass)
- `fastled_stub.h`: Aggregator enabling stub clockless and SPI; defines `HAS_HARDWARE_PIN_SUPPORT` for compatibility.
- `clockless_stub.h`: Selects between WASM clockless (`emscripten`) or `clockless_stub_generic.h` when `FASTLED_STUB_IMPL` is set.
## Subdirectories
- `generic/`: Generic stub sysdefs/pin helpers used when not targeting WASM.
## Behavior
- Used by C++ unit tests and host builds to provide a hardwarefree implementation. When compiled to WASM, this path can route to the WASM clockless backend for browser visualization.
## Unit test usage
- The stub platform is the default for C++ unit tests. It provides nohardware implementations for pin, SPI, and clockless paths so rendering logic can be validated on hosts.
- Tests that verify export behavior use the `shared/active_strip_data` facilities to snapshot frame/strip data without physical LEDs.
- When targeting browser demos, the stub can route to the WASM clockless backend under `emscripten` to visualize frames without hardware.
## Optional feature defines
- **`FASTLED_STUB_IMPL`**: Enable stubbed platform behavior. Default set in `led_sysdefs_stub_generic.h` when targeting stub builds.
- **`FASTLED_HAS_MILLIS`**: Default `1`.
- **`FASTLED_ALLOW_INTERRUPTS`**: Default `1`.
- **`FASTLED_USE_PROGMEM`**: Default `0`.
- **`FASTLED_ALL_PINS_HARDWARE_SPI`**: Declared in stub SPI header for compatibility.
- Optional thread helpers: **`FASTLED_USE_PTHREAD_DELAY`**, **`FASTLED_USE_PTHREAD_YIELD`** influence time/yield behavior in `time_stub.cpp`.
Define before including `FastLED.h` to override.

View File

@@ -0,0 +1,9 @@
#pragma once
#if defined(__EMSCRIPTEN__)
#include "platforms/wasm/clockless.h"
#elif defined(FASTLED_STUB_IMPL)
#include "platforms/stub/clockless_stub_generic.h"
#else
#error "This file should only be included for stub or emscripten builds"
#endif

View File

@@ -0,0 +1,23 @@
#pragma once
#include "fl/namespace.h"
#include "eorder.h"
#include "fl/unused.h"
FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 0>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
public:
virtual void init() { }
protected:
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
FASTLED_UNUSED(pixels);
}
};
FASTLED_NAMESPACE_END

View File

@@ -0,0 +1,32 @@
#pragma once
#include "FastLED.h"
namespace fl {
static void stub_compile_tests() {
#if FASTLED_USE_PROGMEM != 0
#error "FASTLED_USE_PROGMEM should be 0 for stub platforms"
#endif
#if SKETCH_HAS_LOTS_OF_MEMORY != 1
#error "SKETCH_HAS_LOTS_OF_MEMORY should be 1 for stub platforms"
#endif
#if FASTLED_ALLOW_INTERRUPTS != 1
#error "FASTLED_ALLOW_INTERRUPTS should be 1 for stub platforms"
#endif
#ifndef F_CPU
#error "F_CPU should be defined for stub platforms"
#endif
// Stub platforms should define basic pin functions
#ifndef digitalPinToBitMask
#error "digitalPinToBitMask should be defined for stub platforms"
#endif
#ifndef digitalPinToPort
#error "digitalPinToPort should be defined for stub platforms"
#endif
}
} // namespace fl

View File

@@ -0,0 +1,18 @@
#ifndef __INC_FASTLED_STUB_H
#define __INC_FASTLED_STUB_H
// fastpin_stub.h isn't needed (as it's not used by clockless)
#include "fastspi_stub.h"
#include "clockless_stub.h"
/**
* Could avoid clockless and fastspi with
* #define NO_HARDWARE_PIN_SUPPORT
* #undef HAS_HARDWARE_PIN_SUPPORT
* But then compiling throws pragma message about "Forcing software SPI"
*/
#ifndef HAS_HARDWARE_PIN_SUPPORT
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif // __INC_FASTLED_STUB_H

View File

@@ -0,0 +1,10 @@
#pragma once
#ifdef __EMSCRIPTEN__
#include "platforms/wasm/fastspi_wasm.h"
#elif defined(FASTLED_STUB_IMPL)
#include "platforms/stub/fastspi_stub_generic.h"
#else
#error "This file should only be included for stub or emscripten builds"
#endif

View File

@@ -0,0 +1,28 @@
#pragma once
#ifndef FASTLED_STUB_IMPL
#error "why is this being included?"
#endif
#include "fl/stdint.h"
#include "fl/namespace.h"
#include "fl/unused.h"
// Signal to the engine that all pins are hardware SPI
#define FASTLED_ALL_PINS_HARDWARE_SPI
namespace fl {
class StubSPIOutput {
public:
StubSPIOutput() { }
void select() { }
void init() {}
void waitFully() {}
void release() {}
void writeByte(uint8_t byte) { FASTLED_UNUSED(byte); }
void writeWord(uint16_t word) { FASTLED_UNUSED(word); }
};
} // namespace fl

View File

@@ -0,0 +1,19 @@
#ifdef FASTLED_STUB_IMPL // Only use this if explicitly defined.
#include "platforms/stub/led_sysdefs_stub.h"
#include "fl/unused.h"
#include "fl/compiler_control.h"
// No timing-related includes needed here anymore
void pinMode(uint8_t pin, uint8_t mode) {
// Empty stub as we don't actually ever write anything
FASTLED_UNUSED(pin);
FASTLED_UNUSED(mode);
}
// Timing functions are now provided by time_stub.cpp
// This keeps only pinMode here for simplicity
#endif // FASTLED_STUB_IMPL

View File

@@ -0,0 +1,14 @@
#ifdef FASTLED_STUB_IMPL // Only use this if explicitly defined.
#include "platforms/stub/led_sysdefs_stub.h"
#if defined(__EMSCRIPTEN__)
#include "platforms/wasm/led_sysdefs_wasm.h"
#else
#include "platforms/stub/generic/led_sysdefs_generic.hpp"
#endif
#endif // FASTLED_STUB_IMPL

View File

@@ -0,0 +1,7 @@
#pragma once
#ifdef __EMSCRIPTEN__
#include "platforms/wasm/led_sysdefs_wasm.h"
#else
#include "led_sysdefs_stub_generic.h"
#endif

View File

@@ -0,0 +1,65 @@
#ifndef __INC_LED_SYSDEFS_STUB_H
#define __INC_LED_SYSDEFS_STUB_H
#ifndef FASTLED_STUB_IMPL
#define FASTLED_STUB_IMPL
#endif
#include "fl/stdint.h"
#ifndef F_CPU
#define F_CPU 1000000000
#endif // F_CPU
#ifndef FASTLED_HAS_MILLIS
#define FASTLED_HAS_MILLIS 1
#endif // FASTLED_HAS_MILLIS
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#define FASTLED_USE_PROGMEM 0
#define INTERRUPT_THRESHOLD 0
#define digitalPinToBitMask(P) ( 0 )
#define digitalPinToPort(P) ( 0 )
#define portOutputRegister(P) ( 0 )
#define portInputRegister(P) ( 0 )
#ifndef INPUT
#define INPUT 0
#endif
#ifndef OUTPUT
#define OUTPUT 1
#endif
#ifndef INPUT_PULLUP
#define INPUT_PULLUP 2
#endif
#if INPUT != 0
#error "INPUT is not 0"
#endif
#if OUTPUT != 1
#error "OUTPUT is not 1"
#endif
#if INPUT_PULLUP != 2
#error "INPUT_PULLUP is not 2"
#endif
typedef volatile uint32_t RoReg;
typedef volatile uint32_t RwReg;
extern "C" {
void pinMode(uint8_t pin, uint8_t mode);
uint32_t millis(void);
uint32_t micros(void);
void delay(int ms);
void yield(void);
}
#endif // __INC_LED_SYSDEFS_STUB_H

View File

@@ -0,0 +1,86 @@
#ifdef FASTLED_STUB_IMPL // Only use this if explicitly defined.
#include "time_stub.h"
#include "fl/function.h"
#include <chrono>
#include <thread>
#if defined(FASTLED_USE_PTHREAD_DELAY) || defined(FASTLED_USE_PTHREAD_YIELD)
#include <time.h>
#include <errno.h>
#include <sched.h>
#endif
static auto start_time = std::chrono::system_clock::now();
// Global delay function override for fast testing
static fl::function<void(uint32_t)> g_delay_override;
extern "C" {
#ifndef __EMSCRIPTEN__
// STUB timing functions - excluded for WASM builds which provide their own implementations
// WASM timing functions are in src/platforms/wasm/timer.cpp and src/platforms/wasm/js.cpp
uint32_t millis() {
auto current_time = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count();
}
uint32_t micros() {
auto current_time = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(current_time - start_time).count();
}
void delay(int ms) {
// Use override function if set (for fast testing)
if (g_delay_override) {
g_delay_override(static_cast<uint32_t>(ms));
return;
}
// Default delay implementation
#ifdef FASTLED_USE_PTHREAD_DELAY
if (ms <= 0) {
return; // nothing to wait for
}
struct timespec req;
req.tv_sec = ms / 1000;
req.tv_nsec = (ms % 1000) * 1000000L;
// nanosleep may be interrupted by a signal; retry until the full time has elapsed
while (nanosleep(&req, &req) == -1 && errno == EINTR) {
// continue sleeping for the remaining time
}
#else
if (ms > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
#endif
}
void delayMicroseconds(int us) {
if (us > 0) {
std::this_thread::sleep_for(std::chrono::microseconds(us));
}
}
void yield() {
#ifdef FASTLED_USE_PTHREAD_YIELD
// POSIX thread yield to allow other threads to run
sched_yield();
#else
std::this_thread::yield();
#endif
}
#endif // __EMSCRIPTEN__
} // extern "C"
// Function to set delay override (C++ linkage for test runner)
void setDelayFunction(const fl::function<void(uint32_t)>& delayFunc) {
g_delay_override = delayFunc;
}
#endif // FASTLED_STUB_IMPL

View File

@@ -0,0 +1,18 @@
#pragma once
#include "fl/stdint.h"
#include "fl/function.h"
// Stub timing functions for Arduino compatibility
// These provide timing functionality when using the stub platform
extern "C" {
uint32_t millis(void);
uint32_t micros(void);
void delay(int ms);
void delayMicroseconds(int us);
void yield(void);
}
// C++ function to override delay behavior for fast testing
void setDelayFunction(const fl::function<void(uint32_t)>& delayFunc);