#include #include "logger.h" #include "utils.h" #include "ws2801.h" #include "fader.h" uint32_t numModules; float fadestep = 1; double nextFrame; int somethingChanged = 0; // indicates when a ws2801 update is required static const double interval = 0.01f; struct Colour { float red, green, blue; // value range is 0.0 to 255.0 }; struct Colour *curColour; struct Colour *targetColour; int fader_init(uint32_t nMod) { 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; } // 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) { curColour[module].red = targetColour[module].red = r; curColour[module].green = targetColour[module].green = g; curColour[module].blue = targetColour[module].blue = b; somethingChanged = 1; } void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b) { targetColour[module].red = r; targetColour[module].green = g; targetColour[module].blue = b; } void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b) { curColour[module].red += r; curColour[module].green += g; curColour[module].blue += b; 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; } targetColour[module].red += r; targetColour[module].green += g; targetColour[module].blue += b; if(targetColour[module].red > 255) { targetColour[module].red = 255; } if(targetColour[module].green > 255) { targetColour[module].green = 255; } if(targetColour[module].blue > 255) { targetColour[module].blue = 255; } 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); ws2801_set_colour(i, (uint8_t)curColour[i].red, (uint8_t)curColour[i].green, (uint8_t)curColour[i].blue); } if(somethingChanged) { ws2801_send_update(); somethingChanged = 0; } } void fader_wait_frame(void) { sleep_until(nextFrame); nextFrame += interval; }