/* * This program source code file is part of SystemK, a library in the KTag project. * * 🛡️ 🃞 * * 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 . */ #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 };