diff --git a/flake.nix b/flake.nix index 0e90d64..715c36c 100644 --- a/flake.nix +++ b/flake.nix @@ -255,9 +255,11 @@ psrc = ./lantern; pbuildInputs = [ + (packages."x86_64-linux"."animation" { inherit gcc cflags; }) (packages."x86_64-linux"."dio" { inherit gcc cflags; }) - (packages."x86_64-linux"."shift-register" { inherit gcc cflags; }) (packages."x86_64-linux"."display" { inherit gcc cflags; }) + (packages."x86_64-linux"."rng" { inherit gcc cflags; }) + (packages."x86_64-linux"."shift-register" { inherit gcc cflags; }) (packages."x86_64-linux"."sk9822" { inherit gcc cflags; }) ]; }; diff --git a/lantern/main.c b/lantern/main.c index 0590460..2cad31e 100644 --- a/lantern/main.c +++ b/lantern/main.c @@ -12,31 +12,215 @@ You should have received a copy of the GNU General Public License along with thi #include #include +#include +#include +#include #include +#include +#include #define FPS 15 -#define ANIMATION_DELAY 1000 / 15 +// #define FRAME_DELAY_MS 1000 / FPS +#define FRAME_DELAY_MS 1000 +#define LIGHT_COUNT 3 -uint8_t bound (uint8_t value, uint8_t min, uint8_t max) { - if (value < min) { +typedef enum { + test, + normal, + creepy, + eerie, + flash +} color_scheme_e; + +uint8_t random_step(uint8_t value, uint8_t min, uint8_t max, rng_t *rng) { + int8_t step = (rng_sample(rng) % 20) - 10; + int new_value = value + step; + if (new_value > max) { + return max; + } else if (new_value < min) { return min; - } else if (value > max) { - return max; } else { - return value; + return new_value; } } -void flash_status(dio_t *light) { - dio_set(light, 1); - _delay_ms(100); - dio_set(light, 0); +typedef struct { + rgb_t color; + + time_line_t red_line; + time_line_t green_line; + time_line_t blue_line; + + uint8_t frame; + uint8_t duration; +} animation_t; + +animation_t animation_new(void) { + return (animation_t) { + .color = { .brightness = 1, .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 = time_line_next(&self->red_line); + self->color.g = time_line_next(&self->green_line); + self->color.b = time_line_next(&self->blue_line); + } +} + +bool animation_running(animation_t *self) { + return self->frame != self->duration; +} + +typedef struct { + sk9822_t lights; + + color_scheme_e color_scheme; + animation_t animations[LIGHT_COUNT]; +} lantern_t; + + +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(), + } + }; +} + +void lantern_start_test(lantern_t *self) { + animation_begin( + &self->animations[0], + 255, + 0, + 0, + 120); + animation_begin( + &self->animations[1], + 0, + 255, + 0, + 120); + animation_begin( + &self->animations[2], + 0, + 0, + 255, + 120); +} + +void lantern_start_normal(lantern_t *self, rng_t *rng) { + animation_begin( + &self->animations[0], + random_step(self->animations[0].color.r, 180, 255, rng), + random_step(self->animations[0].color.g, 20, 50, rng), + 0, + FPS); + animation_begin( + &self->animations[1], + random_step(self->animations[1].color.r, 160, 230, rng), + random_step(self->animations[1].color.g, 10, 30, rng), + 0, + FPS); + animation_begin( + &self->animations[2], + random_step(self->animations[2].color.r, 140, 170, rng), + random_step(self->animations[2].color.g, 0, 10, rng), + 0, + FPS); +} + +void lantern_set_mode(lantern_t *self, color_scheme_e scheme) { + self->color_scheme = scheme; +} + +void lantern_step(lantern_t *self, rng_t *rng, rgb_t colors[LIGHT_COUNT]) { + if (!animation_running(&self->animations[0])) { + switch (self->color_scheme) { + case test: + lantern_start_test(self); + break; + case normal: + lantern_start_normal(self, rng); + break; + case creepy: + break; + case eerie: + break; + case flash: + break; + } + } + + for (int i = 0; i < LIGHT_COUNT; i++) { + animation_step(&self->animations[i]); + colors[i] = self->animations[i].color; + } +} + +void display_lantern(display_t *display, lantern_t *lantern) { + 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); } int main(void) { dio_t status_light = { .ddr = &DDRC, .port = &PORTC, .pin = &PINC, .addr = 7 }; dio_set_direction(&status_light, LINE_OUT); + display_t display = { + .reg = { + .output = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 7 }, + .shift_clock = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 6 }, + .latch_clock = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 5 }, + } + }; + + display_init(&display); + dio_t buttons[4] = { { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 5 }, { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 6 }, @@ -52,12 +236,40 @@ int main(void) { .clock_pin = { .ddr = &DDRD, .port = &PORTD, .pin = &PIND, .addr = 0 } }; + rgb_t colors[LIGHT_COUNT]; + + lantern_t lantern = lantern_new(lights); + lantern_set_mode(&lantern, test); + + rng_t rng = rng_new(15); + + display_clear(&display); + display_write_message(&display, "ready"); + + _delay_ms(5000); + + display_lantern(&display, &lantern); + _delay_ms(1000); + + lantern_step(&lantern, &rng, colors); + sk9822_send(&lights, colors, LIGHT_COUNT); + + while(1) { + lantern_step(&lantern, &rng, colors); + sk9822_send(&lights, colors, LIGHT_COUNT); + display_lantern(&display, &lantern); + _delay_ms(FRAME_DELAY_MS); + } + + /* rgb_t colors[3] = { { .brightness = 1, .r = 128, .g = 0, .b = 0, }, { .brightness = 1, .r = 0, .g = 128, .b = 0, }, { .brightness = 1, .r = 0, .g = 0, .b = 128, }, }; + */ + /* sk9822_init(&lights); sk9822_send(&lights, colors, 3); @@ -81,6 +293,7 @@ int main(void) { } _delay_ms(ANIMATION_DELAY); } + */ return 0; }