Created
March 23, 2020 05:39
-
-
Save routevegetable/0b9361d75d60f1cdf95841fd1fae4935 to your computer and use it in GitHub Desktop.
ws2811 mood lighting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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