diff --git a/animation/animation.c b/animation/animation.c new file mode 100644 index 0000000..1a14a2c --- /dev/null +++ b/animation/animation.c @@ -0,0 +1,43 @@ +#include "animation.h" + +line_t line_new(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { + uint8_t dx = x1 - x0; + int8_t dy = y1 - y0; + int8_t inc = dy > 0 ? 1 : dy == 0 ? 0 : -1; + int8_t m = 2 * dy; + int8_t error = 0; + + if (m > 0) { + error = m - dx; + } else { + error = m + dx; + } + + return (line_t){ .y = y0, .m = m, .error = error, .inc = inc, .dx = dx }; +} + +uint8_t line_next(line_t *slope) { + slope->error += slope->m; + + if (slope->m > 0) { + if (slope->error >= 0) { + slope->y += slope->inc; + slope->error -= 2 * slope->dx; + } + } else { + if (slope->error <= 0) { + slope->y += slope->inc; + slope->error += 2 * slope->dx; + } + } + + return slope->y; +} + +/* +void line_print(line_t *line) { + printf("y: %d\tm: %d\terror: %d\tinc: %d\t:dx: %d\n", line->y, line->m, line->error, line->inc, line->dx); +} +*/ + + diff --git a/animation/animation.h b/animation/animation.h new file mode 100644 index 0000000..a29a074 --- /dev/null +++ b/animation/animation.h @@ -0,0 +1,27 @@ +#ifndef __ANIMATION_H__ +#define __ANIMATION_H__ + +#include + +// line_t provides a simplified implementation of Bresenham's line drawing +// technique. At this time, it assumes a transition of x = 0 -> 60, and a dy +// between -59 and 59. I am not sure I understand Bresenham's algorithm yet, +// but I'll need to revisit all of this if I want to expand the boundaries. +typedef struct line_s { + uint8_t y; + int8_t m; + int8_t error; + int8_t inc; + uint8_t dx; +} line_t; + +// Construct a new line object. x1 must be greater than x0, and dy must be less than dx. +line_t line_new(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1); + +// Calculate the next y value of the line. +uint8_t line_next(line_t *line); + +// Diagnostic printout of the current state of line_t. +// void line_print(line_t *line); + +#endif diff --git a/animation/bresenham.c b/animation/bresenham.c new file mode 100644 index 0000000..722e26f --- /dev/null +++ b/animation/bresenham.c @@ -0,0 +1,32 @@ +#include + +void bresenham(int x1, int y1, int x2, int y2) { + int dx = x2 - x1; + int dy = y2 - y1; + int m = 2 * dy; + int err = 0; + + if (m > 0) { + err = m - dx; + } else if (m < 0) { + err = m + dx; + } + for (int x = x1, y = y1; x <= x2; x++) { + printf("(%d, %d) [%d]\n", x, y, err); + + err += m; + + if (m > 0) { + if (err >= 0) { + y++; + err -= 2 * dx; + } + } else if (m < 0) { + if (err <= 0) { + y--; + err += 2 * dx; + } + } + } +} + diff --git a/animation/main.c b/animation/main.c new file mode 100644 index 0000000..3ba4c1b --- /dev/null +++ b/animation/main.c @@ -0,0 +1,21 @@ +#include +#include +#include + +typedef struct RGB_s { + uint8_t brightness; + uint8_t r; + uint8_t g; + uint8_t b; +} rgb_t; + + +int main (void) { + rng_t rng = rng_new(0); + animation_t animation = animation_new(); + + for (int i = 0; i < 120; i++) { + animation_step(&animation, &rng); + printf("[%d] %d %d %d\n", animation.frame, animation.lamp.r, animation.lamp.g, animation.lamp.b); + } +} diff --git a/base/base.h b/base/base.h index 2f0bb4c..7baab60 100644 --- a/base/base.h +++ b/base/base.h @@ -55,15 +55,4 @@ inline int dio_read(dio_t *line) { return (*(line->pin) & _BV(line->addr)) > 0; } -typedef struct RNG { - uint8_t mod; - int8_t a; - int8_t c; - uint8_t seed; -} rng_t; - -rng_t rng_new(uint8_t seed); - -uint8_t rng_sample(rng_t *state); - #endif diff --git a/flake.nix b/flake.nix index 256d2c0..9c905cd 100644 --- a/flake.nix +++ b/flake.nix @@ -41,12 +41,57 @@ CFLAGS = cflags { inherit mcu chip_select f_cpu; }; - buildPhase = '' - ${avr.gcc}/bin/avr-gcc ${CFLAGS} -o base.o -c ${src}/base/base.c - ''; installPhase = '' mkdir $out - cp base/base.h base.o $out/ + cp base/base.h $out/ + ''; + }; + + packages."x86_64-linux"."rng" = + { mcu, chip_select, f_cpu }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + avr = pkgs.pkgsCross.avr.buildPackages; + in pkgs.stdenv.mkDerivation rec { + name = "rng"; + src = ./.; + + buildInputs = [ + (packages."x86_64-linux"."base" { inherit mcu chip_select f_cpu; }) + ]; + + CFLAGS = cflags { inherit mcu chip_select f_cpu; }; + INCLUDE_DIRS = pkgs.lib.concatStringsSep " " (map (dir: "-I${dir}") buildInputs); + OBJECT_FILES = pkgs.lib.concatStringsSep " " (map (dir: "${dir}/*.o") buildInputs); + + buildPhase = '' + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o rng.o -c ${src}/rng/rng.c + ''; + + installPhase = '' + mkdir $out + cp rng/rng.h rng.o $out/ + ''; + }; + + packages."x86_64-linux"."animation" = + { mcu, chip_select, f_cpu }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + avr = pkgs.pkgsCross.avr.buildPackages; + in pkgs.stdenv.mkDerivation rec { + name = "animation"; + src = ./.; + + CFLAGS = cflags { inherit mcu chip_select f_cpu; }; + + buildPhase = '' + ${avr.gcc}/bin/avr-gcc ${CFLAGS} -o animation.o -c ${src}/animation/animation.c + ''; + + installPhase = '' + mkdir $out + cp animation/animation.h animation.o $out/ ''; }; @@ -186,6 +231,7 @@ { mcu, chip_select, f_cpu }: let pkgs = import nixpkgs { system = "x86_64-linux"; }; + lib = pkgs.lib; avr = pkgs.pkgsCross.avr.buildPackages; in pkgs.stdenv.mkDerivation rec { name = "flame"; @@ -194,6 +240,8 @@ buildInputs = [ (packages."x86_64-linux"."base" { inherit mcu chip_select f_cpu; }) (packages."x86_64-linux"."sk9822" { inherit mcu chip_select f_cpu; }) + (packages."x86_64-linux"."rng" { inherit mcu chip_select f_cpu; }) + (packages."x86_64-linux"."animation" { inherit mcu chip_select f_cpu; }) ]; CFLAGS = cflags { inherit mcu chip_select f_cpu; }; @@ -239,6 +287,7 @@ ${avr.gcc}/bin/avr-gcc ${CFLAGS} -o prime-tx.elf main.o ${OBJECT_FILES} $OBJCOPY -O ihex prime-tx.elf prime-tx.hex ''; + installPhase = '' mkdir $out cp prime-tx.elf prime-tx.hex $out diff --git a/flame/main.c b/flame/main.c index d52b56a..10d1ebb 100644 --- a/flame/main.c +++ b/flame/main.c @@ -3,13 +3,15 @@ #include #include +#include +#include #define FPS 60 #define FRAME_DELAY_MS 1000 / FPS uint8_t random_step(uint8_t value, uint8_t min, uint8_t max, rng_t *rng) { - int8_t step = (rng_sample(rng) % 32) - 16; - uint16_t new_value = value + step; + int8_t step = (rng_sample(rng) % 20) - 10; + int new_value = value + step; if (new_value > max) { return max; } else if (new_value < min) { @@ -28,9 +30,9 @@ typedef struct { rgb_t lamp; color_scheme_e color_scheme; - int8_t red_step; - int8_t green_step; - int8_t blue_step; + line_t red_line; + line_t green_line; + line_t blue_line; uint8_t frame; uint8_t duration; @@ -38,11 +40,11 @@ typedef struct { animation_t animation_new(void) { return (animation_t){ - .lamp = (rgb_t){ .brightness = 9, .r = 212, .g = 50, .b = 0 }, + .lamp = (rgb_t){ .brightness = 1, .r = 200, .g = 30, .b = 0 }, .color_scheme = normal, - .red_step = 0, - .green_step = 0, - .blue_step = 0, + .red_line = line_new(0, 0, 0, 0), + .green_line = line_new(0, 0, 0, 0), + .blue_line = line_new(0, 0, 0, 0), .frame = 0, .duration = 0, @@ -55,10 +57,10 @@ void animation_flicker(animation_t *animation, rng_t *rng) { switch (animation->color_scheme) { case normal: rdest = random_step(animation->lamp.r, 180, 255, rng); - gdest = random_step(animation->lamp.g, 10, 40, rng); - animation->red_step = 60 / (rdest - animation->lamp.r); - animation->green_step = 60 / (gdest - animation->lamp.g); - animation->duration = 60; + gdest = random_step(animation->lamp.g, 20, 50, rng); + animation->red_line = line_new(0, animation->lamp.r, 30, rdest); + animation->green_line = line_new(0, animation->lamp.g, 30, gdest); + animation->duration = 30; break; case creepy: break; @@ -72,25 +74,15 @@ void animation_step(animation_t *animation, rng_t *rng) { if (animation->frame == animation->duration) { animation->frame = 0; animation->duration = 0; - animation->red_step = 0; - animation->green_step = 0; - animation->blue_step = 0; } else { animation->frame++; - animation->lamp.r += animation->red_step; - animation->lamp.g += animation->green_step; - animation->lamp.b += animation->blue_step; + animation->lamp.r = line_next(&animation->red_line); + animation->lamp.g = line_next(&animation->green_line); + animation->lamp.b = line_next(&animation->blue_line); } } } -/* -void flicker(rgb_t *pixel, rng_t *rng) { - pixel->r = random_step(pixel->r, 180, 255, rng); - pixel->g = random_step(pixel->g, 10, 40, rng); -} -*/ - int main (void) { DDRB = _BV(2) | _BV(1) | _BV(0); PORTB = 0; diff --git a/base/base.c b/rng/rng.c similarity index 86% rename from base/base.c rename to rng/rng.c index 1f9ba37..ac4a067 100644 --- a/base/base.c +++ b/rng/rng.c @@ -10,7 +10,7 @@ Lumeto is distributed in the hope that it will be useful, but WITHOUT ANY WARRAN You should have received a copy of the GNU General Public License along with Lumeto. If not, see . */ -#include "base.h" +#include "rng.h" rng_t rng_new(uint8_t seed) { rng_t rng = { .mod = 255, .a = 253, .c = 41, .seed = seed }; @@ -22,12 +22,3 @@ uint8_t rng_sample(rng_t *state) { return state->seed; } -/* -void strobe_line(gpio_t *line, uint32_t us) { - set_line(line); - _delay_us(us); - clear_line(line); - _delay_us(us); -} -*/ - diff --git a/rng/rng.h b/rng/rng.h new file mode 100644 index 0000000..c98e374 --- /dev/null +++ b/rng/rng.h @@ -0,0 +1,18 @@ +#include +#include + +#ifndef __RNG_H__ +#define __RNG_H__ + +typedef struct RNG { + uint8_t mod; + int8_t a; + int8_t c; + uint8_t seed; +} rng_t; + +rng_t rng_new(uint8_t seed); + +uint8_t rng_sample(rng_t *state); + +#endif