106 lines
2.1 KiB
C
106 lines
2.1 KiB
C
#include <animation.h>
|
|
#include <stdint.h>
|
|
#include <systick.h>
|
|
|
|
void animation_reset(struct animation *ani)
|
|
{
|
|
if (!ani)
|
|
return;
|
|
|
|
ani->state = ANI_RED;
|
|
ani->step = 0u;
|
|
ani->last_tick = systick_get_global_tick();
|
|
ani->next_interval = 0ul;
|
|
}
|
|
|
|
static void clear_dmx_universe(uint8_t *universe, uint32_t len)
|
|
{
|
|
uint32_t idx;
|
|
|
|
for (idx = 0; idx < len; idx++) {
|
|
universe[idx] = 0u;
|
|
}
|
|
}
|
|
|
|
static enum animation_state next_col_state(enum animation_state current)
|
|
{
|
|
enum animation_state next;
|
|
|
|
switch (current) {
|
|
case ANI_RED:
|
|
next = ANI_GREEN;
|
|
break;
|
|
case ANI_GREEN:
|
|
next = ANI_BLUE;
|
|
break;
|
|
case ANI_BLUE:
|
|
next = ANI_RAINBOW;
|
|
break;
|
|
default:
|
|
next = ANI_RED;
|
|
break;
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
void animation_process(struct animation *ani, uint8_t *dmx_universe)
|
|
{
|
|
uint32_t tick;
|
|
uint32_t new_tick;
|
|
uint32_t i;
|
|
|
|
if (!ani || !dmx_universe)
|
|
return;
|
|
|
|
/* Check if time for next step is reached */
|
|
tick = systick_get_global_tick();
|
|
/* Calculate next tick. Overflow expected */
|
|
new_tick = ani->last_tick + ani->next_interval;
|
|
if (new_tick < ani->last_tick) {
|
|
/* Tick overflowed. */
|
|
if (!(tick >= new_tick && tick < ani->last_tick))
|
|
return;
|
|
} else {
|
|
if (tick < new_tick)
|
|
return;
|
|
}
|
|
|
|
ani->last_tick = tick;
|
|
|
|
switch (ani->state) {
|
|
case ANI_RED:
|
|
case ANI_GREEN:
|
|
case ANI_BLUE:
|
|
for (i = 0; i < 32; i++) {
|
|
dmx_universe[i * 4 + 0] = ani->state == ANI_RED ? (uint8_t)ani->step : 0u;
|
|
dmx_universe[i * 4 + 1] = ani->state == ANI_GREEN ? (uint8_t)ani->step : 0u;
|
|
dmx_universe[i * 4 + 2] = ani->state == ANI_BLUE ? (uint8_t)ani->step : 0u;
|
|
dmx_universe[i * 4 + 3] = 0u;
|
|
}
|
|
if (ani->step + 10 > 0xFFul) {
|
|
ani->step = 0;
|
|
ani->state = next_col_state(ani->state);
|
|
} else {
|
|
ani->step += 10;
|
|
}
|
|
ani->next_interval = 20;
|
|
break;
|
|
case ANI_RAINBOW:
|
|
/* TODO: Implement Rainbow mode */
|
|
ani->next_interval = 10;
|
|
clear_dmx_universe(dmx_universe, 129u);
|
|
ani->state = ANI_FLASH_WHITE;
|
|
break;
|
|
case ANI_FLASH_WHITE:
|
|
dmx_universe[128] = ani->step & 1 ? 0xFF : 0;
|
|
ani->next_interval = ani->step & 1 ? 60 : 260;
|
|
ani->step += 1u;
|
|
|
|
if (ani->step >= 11u) {
|
|
ani->state = ANI_RED;
|
|
ani->step = 0u;
|
|
}
|
|
break;
|
|
}
|
|
} |