sk6812d/src/fader.c

164 lines
4.0 KiB
C

#include <malloc.h>
#include "logger.h"
#include "utils.h"
#include "sk6812.h"
#include "fader.h"
uint32_t numModules;
float fadestep = 1;
double nextFrame;
int somethingChanged = 0; // indicates when a sk6812 update is required
static const double interval = 1.0f / 75.0f;
struct Colour {
float red, green, blue, white; // value range is 0.0 to 255.0
};
struct Colour *curColour;
struct Colour *targetColour;
struct sk6812_ctx *ledCtx; // global context for the one strip we control
int fader_init(uint32_t nMod, struct sk6812_ctx *ctx)
{
numModules = nMod;
curColour = malloc(nMod * sizeof(struct Colour));
if(!curColour) {
LOG(LVL_ERR, "fader: could not allocate the array of current colours!");
return -1;
}
targetColour = malloc(nMod * sizeof(struct Colour));
if(!targetColour) {
LOG(LVL_ERR, "fader: could not allocate the array of target colours!");
return -1;
}
for(uint32_t i = 0; i < numModules; i++) {
curColour[i].red = targetColour[i].red = 0;
curColour[i].green = targetColour[i].green = 0;
curColour[i].blue = targetColour[i].blue = 0;
curColour[i].white = targetColour[i].white = 0;
}
// store LED context (initalized externally)
ledCtx = ctx;
// timestamp for the first frame
nextFrame = get_hires_time() + interval;
return 0;
}
void fader_shutdown(void)
{
free(curColour);
free(targetColour);
}
void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
curColour[module].red = targetColour[module].red = r;
curColour[module].green = targetColour[module].green = g;
curColour[module].blue = targetColour[module].blue = b;
curColour[module].white = targetColour[module].white = w;
somethingChanged = 1;
}
void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
targetColour[module].red = r;
targetColour[module].green = g;
targetColour[module].blue = b;
targetColour[module].white = w;
}
void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
curColour[module].red += r;
curColour[module].green += g;
curColour[module].blue += b;
curColour[module].white += w;
if(curColour[module].red > 255) { curColour[module].red = 255; }
if(curColour[module].green > 255) { curColour[module].green = 255; }
if(curColour[module].blue > 255) { curColour[module].blue = 255; }
if(curColour[module].white > 255) { curColour[module].white = 255; }
targetColour[module] = curColour[module];
somethingChanged = 1;
}
void fader_set_fadestep(uint8_t newFadestep)
{
// The original avr implementition had a frame rate of 25fps (interval 0,04 sec.).
// This scales the fadestep to the current frame rate.
fadestep = (float)newFadestep * interval / 0.04f;
}
/*!
* Fade the colour value in cur towards target.
*
* \param cur The colour value to update.
* \param target The target value that should be reached.
* \param changed Output value which is set to 1 if cur was changed.
*/
void fade_colour(float *cur, const float *target, int *changed)
{
float diff;
if(*cur > *target) {
diff = *cur - *target;
if(diff < fadestep) {
*cur = *target;
} else {
*cur -= fadestep;
}
*changed = 1;
} else if(*cur < *target) {
diff = *target - *cur;
if(diff < fadestep) {
*cur = *target;
} else {
*cur += fadestep;
}
*changed = 1;
}
}
void fader_update(void)
{
for(uint32_t i = 0; i < numModules; i++) {
fade_colour(&(curColour[i].red), &(targetColour[i].red), &somethingChanged);
fade_colour(&(curColour[i].green), &(targetColour[i].green), &somethingChanged);
fade_colour(&(curColour[i].blue), &(targetColour[i].blue), &somethingChanged);
fade_colour(&(curColour[i].white), &(targetColour[i].white), &somethingChanged);
sk6812_set_colour(ledCtx, i,
(uint8_t)curColour[i].red,
(uint8_t)curColour[i].green,
(uint8_t)curColour[i].blue,
(uint8_t)curColour[i].white);
}
if(somethingChanged) {
sk6812_send_update(ledCtx);
somethingChanged = 0;
}
}
void fader_wait_frame(void)
{
sleep_until(nextFrame);
nextFrame += interval;
}