SystemK/NeoPixels/Animations/Flamethrower.c
2025-01-25 13:45:14 -06:00

107 lines
3.1 KiB
C

/*
* This program source code file is part of SystemK, a library in the KTag project.
*
* 🛡️ <https://ktag.clubk.club> 🃞
*
* Copyright © 2016-2025 Joseph P. Kearney and the KTag developers.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* There should be a copy of the GNU Affero General Public License in the LICENSE
* file in the root of this repository. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SystemK.h"
#define RED_DELTA_MAX 15
#define GREEN_DELTA_MAX 8
#define MAX_RED 128
#define MIN_RED RED_DELTA_MAX
#define MIN_GREEN 1
#define LESS_GREEN_THAN_RED 20
static int16_t RedLevel = 0;
static int16_t GreenLevel = 0;
// From https://stackoverflow.com/a/1180465
static uint8_t lfsr113_Bits (uint32_t min, uint32_t max)
{
static uint32_t z1 = 12345, z2 = 12345, z3 = 12345, z4 = 12345;
uint32_t b;
b = ((z1 << 6) ^ z1) >> 13;
z1 = ((z1 & 4294967294U) << 18) ^ b;
b = ((z2 << 2) ^ z2) >> 27;
z2 = ((z2 & 4294967288U) << 2) ^ b;
b = ((z3 << 13) ^ z3) >> 21;
z3 = ((z3 & 4294967280U) << 7) ^ b;
b = ((z4 << 3) ^ z4) >> 12;
z4 = ((z4 & 4294967168U) << 13) ^ b;
uint64_t raw = (z1 ^ z2 ^ z3 ^ z4);
uint32_t scaled = ((((max - min) * raw) + (UINT32_MAX / 2)) / UINT32_MAX) + min;
return (uint8_t) scaled;
}
static void Reset(void * Data)
{
RedLevel = MIN_RED;
GreenLevel = MIN_GREEN;
}
// TODO: Need to reimplement this with HSB--see https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
static AnimationStepResult_T NextStep(void)
{
// get our next changes in red and green
int16_t delta_red = (lfsr113_Bits(0, RED_DELTA_MAX*2) - RED_DELTA_MAX);
int16_t delta_green = (lfsr113_Bits(0, GREEN_DELTA_MAX*2) - GREEN_DELTA_MAX);
RedLevel = RedLevel + delta_red;
if (RedLevel > MAX_RED)
{
RedLevel = MAX_RED;
}
else if (RedLevel < MIN_RED)
{
RedLevel = MIN_RED;
}
RedLevel = (uint8_t) RedLevel;
GreenLevel = GreenLevel + delta_green;
// Green has to be less than red, to keep the flame red-orange-yellow.
if (RedLevel > LESS_GREEN_THAN_RED)
{
if (GreenLevel > (RedLevel - LESS_GREEN_THAN_RED))
{
GreenLevel = (RedLevel - LESS_GREEN_THAN_RED);
}
else if (GreenLevel < MIN_GREEN)
{
GreenLevel = MIN_GREEN;
}
}
else
{
GreenLevel = MIN_GREEN;
}
GreenLevel = (uint8_t) GreenLevel;
NeoPixels_Set_Color(NEOPIXEL_CHANNEL_BARREL, BARREL_FLASH_PIXEL, Color(0xFF, RedLevel, GreenLevel, 0x00));
return ANIMATION_ONGOING;
}
Animation_T Flamethrower_Animation =
{
.Reset = Reset,
.NextStep = NextStep
};