Set up an animation framework and a pleasing Flame animation
This commit is contained in:
parent
762ba275b6
commit
c9e0775b4b
|
@ -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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef __ANIMATION_H__
|
||||||
|
#define __ANIMATION_H__
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
// 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
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <base.h>
|
||||||
|
#include <rng.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
11
base/base.h
11
base/base.h
|
@ -55,15 +55,4 @@ inline int dio_read(dio_t *line) {
|
||||||
return (*(line->pin) & _BV(line->addr)) > 0;
|
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
|
#endif
|
||||||
|
|
57
flake.nix
57
flake.nix
|
@ -41,12 +41,57 @@
|
||||||
|
|
||||||
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
|
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o base.o -c ${src}/base/base.c
|
|
||||||
'';
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out
|
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 }:
|
{ mcu, chip_select, f_cpu }:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||||
|
lib = pkgs.lib;
|
||||||
avr = pkgs.pkgsCross.avr.buildPackages;
|
avr = pkgs.pkgsCross.avr.buildPackages;
|
||||||
in pkgs.stdenv.mkDerivation rec {
|
in pkgs.stdenv.mkDerivation rec {
|
||||||
name = "flame";
|
name = "flame";
|
||||||
|
@ -194,6 +240,8 @@
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
(packages."x86_64-linux"."base" { inherit mcu chip_select f_cpu; })
|
(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"."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; };
|
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}
|
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o prime-tx.elf main.o ${OBJECT_FILES}
|
||||||
$OBJCOPY -O ihex prime-tx.elf prime-tx.hex
|
$OBJCOPY -O ihex prime-tx.elf prime-tx.hex
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
cp prime-tx.elf prime-tx.hex $out
|
cp prime-tx.elf prime-tx.hex $out
|
||||||
|
|
44
flame/main.c
44
flame/main.c
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
#include <base.h>
|
#include <base.h>
|
||||||
#include <sk9822.h>
|
#include <sk9822.h>
|
||||||
|
#include <rng.h>
|
||||||
|
#include <animation.h>
|
||||||
|
|
||||||
#define FPS 60
|
#define FPS 60
|
||||||
#define FRAME_DELAY_MS 1000 / FPS
|
#define FRAME_DELAY_MS 1000 / FPS
|
||||||
|
|
||||||
uint8_t random_step(uint8_t value, uint8_t min, uint8_t max, rng_t *rng) {
|
uint8_t random_step(uint8_t value, uint8_t min, uint8_t max, rng_t *rng) {
|
||||||
int8_t step = (rng_sample(rng) % 32) - 16;
|
int8_t step = (rng_sample(rng) % 20) - 10;
|
||||||
uint16_t new_value = value + step;
|
int new_value = value + step;
|
||||||
if (new_value > max) {
|
if (new_value > max) {
|
||||||
return max;
|
return max;
|
||||||
} else if (new_value < min) {
|
} else if (new_value < min) {
|
||||||
|
@ -28,9 +30,9 @@ typedef struct {
|
||||||
rgb_t lamp;
|
rgb_t lamp;
|
||||||
color_scheme_e color_scheme;
|
color_scheme_e color_scheme;
|
||||||
|
|
||||||
int8_t red_step;
|
line_t red_line;
|
||||||
int8_t green_step;
|
line_t green_line;
|
||||||
int8_t blue_step;
|
line_t blue_line;
|
||||||
|
|
||||||
uint8_t frame;
|
uint8_t frame;
|
||||||
uint8_t duration;
|
uint8_t duration;
|
||||||
|
@ -38,11 +40,11 @@ typedef struct {
|
||||||
|
|
||||||
animation_t animation_new(void) {
|
animation_t animation_new(void) {
|
||||||
return (animation_t){
|
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,
|
.color_scheme = normal,
|
||||||
.red_step = 0,
|
.red_line = line_new(0, 0, 0, 0),
|
||||||
.green_step = 0,
|
.green_line = line_new(0, 0, 0, 0),
|
||||||
.blue_step = 0,
|
.blue_line = line_new(0, 0, 0, 0),
|
||||||
|
|
||||||
.frame = 0,
|
.frame = 0,
|
||||||
.duration = 0,
|
.duration = 0,
|
||||||
|
@ -55,10 +57,10 @@ void animation_flicker(animation_t *animation, rng_t *rng) {
|
||||||
switch (animation->color_scheme) {
|
switch (animation->color_scheme) {
|
||||||
case normal:
|
case normal:
|
||||||
rdest = random_step(animation->lamp.r, 180, 255, rng);
|
rdest = random_step(animation->lamp.r, 180, 255, rng);
|
||||||
gdest = random_step(animation->lamp.g, 10, 40, rng);
|
gdest = random_step(animation->lamp.g, 20, 50, rng);
|
||||||
animation->red_step = 60 / (rdest - animation->lamp.r);
|
animation->red_line = line_new(0, animation->lamp.r, 30, rdest);
|
||||||
animation->green_step = 60 / (gdest - animation->lamp.g);
|
animation->green_line = line_new(0, animation->lamp.g, 30, gdest);
|
||||||
animation->duration = 60;
|
animation->duration = 30;
|
||||||
break;
|
break;
|
||||||
case creepy:
|
case creepy:
|
||||||
break;
|
break;
|
||||||
|
@ -72,25 +74,15 @@ void animation_step(animation_t *animation, rng_t *rng) {
|
||||||
if (animation->frame == animation->duration) {
|
if (animation->frame == animation->duration) {
|
||||||
animation->frame = 0;
|
animation->frame = 0;
|
||||||
animation->duration = 0;
|
animation->duration = 0;
|
||||||
animation->red_step = 0;
|
|
||||||
animation->green_step = 0;
|
|
||||||
animation->blue_step = 0;
|
|
||||||
} else {
|
} else {
|
||||||
animation->frame++;
|
animation->frame++;
|
||||||
animation->lamp.r += animation->red_step;
|
animation->lamp.r = line_next(&animation->red_line);
|
||||||
animation->lamp.g += animation->green_step;
|
animation->lamp.g = line_next(&animation->green_line);
|
||||||
animation->lamp.b += animation->blue_step;
|
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) {
|
int main (void) {
|
||||||
DDRB = _BV(2) | _BV(1) | _BV(0);
|
DDRB = _BV(2) | _BV(1) | _BV(0);
|
||||||
PORTB = 0;
|
PORTB = 0;
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
You should have received a copy of the GNU General Public License along with Lumeto. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "base.h"
|
#include "rng.h"
|
||||||
|
|
||||||
rng_t rng_new(uint8_t seed) {
|
rng_t rng_new(uint8_t seed) {
|
||||||
rng_t rng = { .mod = 255, .a = 253, .c = 41, .seed = 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;
|
return state->seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void strobe_line(gpio_t *line, uint32_t us) {
|
|
||||||
set_line(line);
|
|
||||||
_delay_us(us);
|
|
||||||
clear_line(line);
|
|
||||||
_delay_us(us);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
Loading…
Reference in New Issue