/* Copyright 2022, Savanni D'Gerinel This file is part of Savanni's AVR library. This AVR library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This AVR library 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this AVR library. If not, see . */ #include #include #include "lantern.h" uint8_t bound_uint8(int value, uint8_t min, uint8_t max) { if (value > max) { return max; } else if (value < min) { return min; } else { return value; } } uint8_t random_step(uint8_t value, uint8_t min, uint8_t max) { int8_t step = (rand() % 40) - 20; int new_value = value + step; return bound_uint8(new_value, min, max); } animation_t animation_new(void) { return (animation_t) { .color = { .brightness = 7, .r = 0, .g = 0, .b = 0 }, .red_line = time_line_new(0, 0, 0, 0), .green_line = time_line_new(0, 0, 0, 0), .blue_line = time_line_new(0, 0, 0, 0), .frame = 0, .duration = 0, }; } void animation_begin(animation_t *self, uint8_t rdest, uint8_t gdest, uint8_t bdest, uint8_t duration) { self->red_line = time_line_new(0, self->color.r, duration, rdest); self->green_line = time_line_new(0, self->color.g, duration, gdest); self->blue_line = time_line_new(0, self->color.b, duration, bdest); self->frame = 0; self->duration = duration; } void animation_step(animation_t *self) { if (self->frame == self->duration) { self->frame = 0; self->duration = 0; } else { self->frame++; self->color.r = bound_uint8(time_line_next(&self->red_line), 0, 255); self->color.g = bound_uint8(time_line_next(&self->green_line), 0, 255); self->color.b = bound_uint8(time_line_next(&self->blue_line), 0, 255); } } bool animation_running(animation_t *self) { return self->frame != self->duration; } lantern_t lantern_new(sk9822_t lights) { sk9822_init(&lights); return (lantern_t){ .lights = lights, .color_scheme = normal, .animations = { animation_new(), animation_new(), animation_new(), animation_new(), animation_new(), animation_new(), animation_new(), animation_new(), animation_new(), } }; } void lantern_start_normal(lantern_t *self, int light_idx) { switch (light_idx) { case 0: animation_begin( &self->animations[0], random_step(self->animations[0].color.r, 180, 255), random_step(self->animations[0].color.g, 20, 50), 0, 5); animation_begin( &self->animations[3], random_step(self->animations[3].color.r, 180, 255), random_step(self->animations[3].color.g, 20, 50), 0, 5); animation_begin( &self->animations[6], random_step(self->animations[3].color.r, 180, 255), random_step(self->animations[3].color.g, 20, 50), 0, 5); break; case 1: animation_begin( &self->animations[1], random_step(self->animations[1].color.r, 160, 230), random_step(self->animations[1].color.g, 10, 30), 0, 5); animation_begin( &self->animations[4], random_step(self->animations[4].color.r, 160, 230), random_step(self->animations[4].color.g, 10, 30), 0, 5); animation_begin( &self->animations[7], random_step(self->animations[7].color.r, 160, 230), random_step(self->animations[7].color.g, 10, 30), 0, 5); break; case 2: animation_begin( &self->animations[2], random_step(self->animations[2].color.r, 140, 170), random_step(self->animations[2].color.g, 0, 10), 0, 5); animation_begin( &self->animations[5], random_step(self->animations[5].color.r, 140, 170), random_step(self->animations[5].color.g, 0, 10), 0, 5); animation_begin( &self->animations[8], random_step(self->animations[8].color.r, 140, 170), random_step(self->animations[8].color.g, 0, 10), 0, 5); break; } } void lantern_start_spooky(lantern_t *self, int light_idx) { switch (light_idx) { case 0: animation_begin( &self->animations[0], 0, random_step(self->animations[0].color.g, 80, 120), 0, 5); animation_begin( &self->animations[3], 0, random_step(self->animations[3].color.g, 80, 120), 0, 5); animation_begin( &self->animations[6], 0, random_step(self->animations[6].color.g, 80, 120), 0, 5); break; case 1: animation_begin( &self->animations[1], 0, random_step(self->animations[1].color.g, 60, 100), 0, 5); animation_begin( &self->animations[4], 0, random_step(self->animations[4].color.g, 60, 100), 0, 5); animation_begin( &self->animations[7], 0, random_step(self->animations[7].color.g, 60, 100), 0, 5); break; case 2: animation_begin( &self->animations[2], 0, random_step(self->animations[2].color.g, 20, 40), 0, 5); animation_begin( &self->animations[5], 0, random_step(self->animations[5].color.g, 20, 40), 0, 5); animation_begin( &self->animations[8], 0, random_step(self->animations[8].color.g, 20, 40), 0, 5); break; } } void lantern_start_eerie(lantern_t *self, int light_idx) { switch (light_idx) { case 0: animation_begin( &self->animations[0], random_step(self->animations[0].color.r, 20, 40), random_step(self->animations[0].color.g, 20, 40), random_step(self->animations[0].color.b, 80, 120), 5); animation_begin( &self->animations[3], random_step(self->animations[3].color.r, 20, 40), random_step(self->animations[3].color.g, 20, 40), random_step(self->animations[3].color.b, 80, 120), 5); animation_begin( &self->animations[6], random_step(self->animations[6].color.r, 20, 40), random_step(self->animations[6].color.g, 20, 40), random_step(self->animations[6].color.b, 80, 120), 5); break; case 1: animation_begin( &self->animations[1], random_step(self->animations[1].color.r, 0, 30), random_step(self->animations[1].color.g, 0, 30), random_step(self->animations[1].color.b, 60, 100), 5); animation_begin( &self->animations[4], random_step(self->animations[4].color.r, 0, 30), random_step(self->animations[4].color.g, 0, 30), random_step(self->animations[4].color.b, 60, 100), 5); animation_begin( &self->animations[7], random_step(self->animations[7].color.r, 0, 30), random_step(self->animations[7].color.g, 0, 30), random_step(self->animations[7].color.b, 60, 100), 5); break; case 2: animation_begin( &self->animations[2], random_step(self->animations[2].color.r, 0, 10), random_step(self->animations[2].color.g, 0, 10), random_step(self->animations[2].color.b, 20, 40), 5); animation_begin( &self->animations[5], random_step(self->animations[5].color.r, 0, 10), random_step(self->animations[5].color.g, 0, 10), random_step(self->animations[5].color.b, 20, 40), 5); animation_begin( &self->animations[8], random_step(self->animations[8].color.r, 0, 10), random_step(self->animations[8].color.g, 0, 10), random_step(self->animations[8].color.b, 20, 40), 5); break; } } void lantern_set_mode(lantern_t *self, color_scheme_e scheme) { self->color_scheme = scheme; } void lantern_step(lantern_t *self, rgb_t colors[LIGHT_COUNT]) { for (int i = 0; i < LIGHT_COUNT; i++) { if (!animation_running(&self->animations[i])) { switch (self->color_scheme) { case normal: lantern_start_normal(self, i); break; case spooky: lantern_start_spooky(self, i); break; case eerie: lantern_start_eerie(self, i); break; case flash: break; } } animation_step(&self->animations[i]); colors[i] = self->animations[i].color; } } /* void lantern_show(lantern_t *lantern, display_t *display) { char msg1[20]; char msg2[20]; snprintf(msg1, 20, "[%d,%d] %x,%x,%x", lantern->animations[0].frame, lantern->animations[0].duration, lantern->animations[0].color.r, lantern->animations[0].color.g, lantern->animations[0].color.b ); snprintf(msg2, 20, "%x,%x,%x %x,%x,%x", lantern->animations[1].color.r, lantern->animations[1].color.g, lantern->animations[1].color.b, lantern->animations[2].color.r, lantern->animations[2].color.g, lantern->animations[2].color.b ); display_clear(display); display_write_message(display, msg1); display_set_location(display, 1, 0); display_write_message(display, msg2); } */