Skip to content

Instantly share code, notes, and snippets.

@routevegetable
Created March 23, 2020 05:39
Show Gist options
  • Save routevegetable/0b9361d75d60f1cdf95841fd1fae4935 to your computer and use it in GitHub Desktop.
Save routevegetable/0b9361d75d60f1cdf95841fd1fae4935 to your computer and use it in GitHub Desktop.
ws2811 mood lighting
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdbool.h>
#include <time.h>
#include "clk.h"
#include "gpio.h"
#include "dma.h"
#include "pwm.h"
#include "version.h"
#include "ws2811.h"
#include <math.h>
#define TARGET_FREQ WS2811_TARGET_FREQ
#define GPIO_PIN 10
#define STRIP_TYPE WS2811_STRIP_GBR // WS2812/SK6812RGB integrated chip+leds
#define LED_COUNT 138
ws2811_t ledstring =
{
.freq = TARGET_FREQ,
.channel =
{
[0] =
{
.gpionum = GPIO_PIN,
.count = LED_COUNT,
.invert = 0,
.brightness = 255,
.strip_type = STRIP_TYPE,
},
[1] =
{
.gpionum = 0,
.count = 0,
.invert = 0,
.brightness = 0,
},
},
};
typedef struct
{
float pos;
float vel;
float blue;
float green;
float red;
int width;
} ball_t;
#define BALL_COUNT 10
#define WIDTH_MIN 10
#define WIDTH_MAX 14
#define BALL_VEL_MIN 10
#define BALL_VEL_MAX 40
#define FPS 25
#define LED_MAX 0x32
ball_t balls[BALL_COUNT];
static uint8_t running = 1;
float rand_float(float min, float max)
{
int r = rand();
float frac = (float)r / (float)RAND_MAX;
return (min + (max-min) * frac);
}
void ball_init(ball_t *ball)
{
ball->width = rand_float(WIDTH_MIN,WIDTH_MAX);
ball->pos = -ball->width / 2;
ball->vel = rand_float(BALL_VEL_MIN, BALL_VEL_MAX);
if(rand() & 1)
{
ball->vel = -ball->vel;
ball->pos = LED_COUNT + ball->width / 2;
}
ball->red = 0;//rand_float(0,0.5);
ball->green = rand_float(0,1);
ball->blue = 1-ball->green;//rand_float(0,1);
}
void balls_init(void)
{
for(int i = 0; i < BALL_COUNT; i++)
ball_init(&balls[i]);
}
void balls_step(float t)
{
for(int i = 0; i < BALL_COUNT; i++)
{
balls[i].pos += balls[i].vel * t;
if(balls[i].pos > (LED_COUNT + balls[i].width) ||
balls[i].pos < (0 - balls[i].width))
{
ball_init(&balls[i]);
}
}
}
float to_led(float v)
{
return ((float)LED_MAX) * powf(v, 1.5f);
}
void balls_render(ws2811_led_t *leds)
{
for(int i = 0; i < LED_COUNT; i++)
{
float max_r = 0;
float max_g = 0;
float max_b = 0;
for(int j = 0; j < BALL_COUNT; j++)
{
float half_width = balls[j].width/2;
float ball_left = (float)balls[j].pos - half_width;
float ball_right = (float)balls[j].pos + half_width;
if(ball_left < i && ball_right > i)
{
float ball_frac = ((float)i - ball_left) / balls[j].width;
// float x = sin(ball_frac * 3.14159f);
if(balls[j].vel > 0) ball_frac = 1-ball_frac;
float x = cos(ball_frac * 3.14159f / 2);
float r = x * balls[j].red;
float g = x * balls[j].green;
float b = x * balls[j].blue;
if(r > max_r) max_r = r;
if(g > max_g) max_g = g;
if(b > max_b) max_b = b;
}
}
int red = to_led(max_r);
int blue = to_led(/*0.5f-0.5f* */max_b);
int green = to_led(max_g);
leds[i] = (blue << 16) | (green << 8) | red;
}
}
static void ctrl_c_handler(int signum)
{
(void)(signum);
running = 0;
}
static void setup_handlers(void)
{
struct sigaction sa =
{
.sa_handler = ctrl_c_handler,
};
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
}
int main(int argc, char *argv[])
{
ws2811_return_t ret;
(void)argc;
(void)argv;
setup_handlers();
if ((ret = ws2811_init(&ledstring)) != WS2811_SUCCESS)
{
fprintf(stderr, "ws2811_init failed: %s\n", ws2811_get_return_t_str(ret));
return ret;
}
srand(time(0));
balls_init();
while (running)
{
balls_step(1.f/FPS);
balls_render(ledstring.channel[0].leds);
ws2811_render(&ledstring);
usleep(1000000 / FPS);
}
ws2811_render(&ledstring);
ws2811_fini(&ledstring);
printf ("\n");
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment