#include <FastLED.h>
#define LED_PIN 6
#define BUTTON_TEST_PIN 2
#define WALK_SPEED 0.75 // m/s
#define LED_DENSITY 60 // chip/m
#define LED_COUNT 100
#define TARGET_FPS 60 // fps - 1/s - Hz
float tickStep = WALK_SPEED * LED_DENSITY / TARGET_FPS;
float tickRate = 1 / TARGET_FPS * 1000;
#define FRONT_LENGTH 15
#define MID_LENGTH 5
#define BACK_LENGTH 15
int beamLength = FRONT_LENGTH + MID_LENGTH + BACK_LENGTH;
CRGB leds[LED_COUNT];
bool buttonTestState = false;
bool effectActive = false;
void setup()
{
pinMode(BUTTON_TEST_PIN, INPUT);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, LED_COUNT);
fill_solid(leds, LED_COUNT, CRGB::Black);
FastLED.show();
}
void loop()
{
buttonTestState = digitalRead(BUTTON_TEST_PIN);
if (buttonTestState == HIGH && !effectActive)
{
effectActive = true;
}
if (effectActive)
{
for (float i = 0; i <= LED_COUNT + beamLength; i += tickStep)
{
int* resultArray = ForwardWave(i, FRONT_LENGTH, MID_LENGTH, BACK_LENGTH);
for (int i = 0; i < LED_COUNT + beamLength; i++)
{
int x = i - beamLength;
if (0 <= x)
{
leds[x] = HSLtoRGB(50, resultArray[i], resultArray[i]);
}
}
FastLED.show();
delay(tickRate);
delete[] resultArray;
}
effectActive = false;
}
}
int* ForwardWave(float offset, int t1, int t2, int t3) {
float* ramp = GenerateRamp(offset, t1, t2, t3);
int* resultArray = new int[LED_COUNT + beamLength];
for (int i = 0; i <= LED_COUNT + beamLength - 1; i++) {
resultArray[i] = (int)ramp[i];
}
delete[] ramp; // Free the allocated memory
return resultArray;
}
float* GenerateRamp(float offset, int t1, int t2, int t3) {
int rampLength = (int)offset + t1 + t2 + t3;
float* ramp = new float[rampLength];
for (int i = 0; i < rampLength; i++) {
if (i < offset) {
ramp[i] = 0;
} else if (i < offset + t1) {
ramp[i] = min((i + 1 - offset) / t1 * 100, 100);
} else if (i < offset + t1 + t2) {
ramp[i] = 100;
} else {
ramp[i] = max(100 - ((float)(i - offset - t1 - t2) / t3 * 100), 0);
}
}
return ramp;
}
CRGB HSLtoRGB(int h, int s, int l) {
// Normalize h, s, and l to the range [0, 1]
float H = h % 360;
float S = constrain(s / 100.0, 0, 1);
float L = constrain(l / 100.0, 0, 1);
// Calculate C, X, and m
float C = (1 - abs(2 * L - 1)) * S;
float X = C * (1 - abs(fmod(H / 60.0, 2) - 1));
float m = L - C / 2;
// Initialize temporary variables for R', G', and B'
float Rp, Gp, Bp;
// Calculate R', G', and B' based on the HSL to RGB conversion formula
if (H >= 0 && H < 60) {
Rp = C;
Gp = X;
Bp = 0;
} else if (H >= 60 && H < 120) {
Rp = X;
Gp = C;
Bp = 0;
} else if (H >= 120 && H < 180) {
Rp = 0;
Gp = C;
Bp = X;
} else if (H >= 180 && H < 240) {
Rp = 0;
Gp = X;
Bp = C;
} else if (H >= 240 && H < 300) {
Rp = X;
Gp = 0;
Bp = C;
} else {
Rp = C;
Gp = 0;
Bp = X;
}
// Calculate final RGB values and scale to the range [0, 255]
int r = constrain((Rp + m) * 255, 0, 255);
int g = constrain((Gp + m) * 255, 0, 255);
int b = constrain((Bp + m) * 255, 0, 255);
return CRGB(r, g, b);
}