132 lines
3.7 KiB
C
132 lines
3.7 KiB
C
|
#ifndef _potion_leds_h
|
||
|
#define _potion_leds_h
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stddef.h>
|
||
|
#include <unistd.h>
|
||
|
#include "rom/ets_sys.h"
|
||
|
#include "shared.h"
|
||
|
#include "driver/gpio.h"
|
||
|
|
||
|
// pack the struct to match exactly 8 * 4 = 32bits
|
||
|
struct __attribute__((__packed__)) led_components_t {
|
||
|
uint8_t global; // global baseline brightness, highest 3 bits should always be ones
|
||
|
// RGB component values
|
||
|
uint8_t red;
|
||
|
uint8_t green;
|
||
|
uint8_t blue;
|
||
|
};
|
||
|
|
||
|
// union of components and their representation as a u32
|
||
|
// allows for easier sending of data over serial
|
||
|
union led_t {
|
||
|
struct led_components_t components;
|
||
|
uint32_t bits;
|
||
|
};
|
||
|
|
||
|
// point on a gradient
|
||
|
struct gradient_point_t {
|
||
|
union led_t led; // value of the led at this point
|
||
|
size_t offset; // offset (measured in leds) from the beginning
|
||
|
};
|
||
|
|
||
|
// buffer that will be written out to the led strip over serial
|
||
|
// for leds to work, the
|
||
|
uint32_t g_serial_out_buffer[62];
|
||
|
// 60-long slice of the out buffer that represents the first few leds
|
||
|
union led_t* g_leds = (uint32_t*)(g_serial_out_buffer + 1);
|
||
|
|
||
|
#define CLOCK 4
|
||
|
#define DATA 5
|
||
|
|
||
|
static
|
||
|
void send_leds() {
|
||
|
LOGLN("Writing to leds");
|
||
|
// index of the bit being written
|
||
|
// the first 5 bits represent the bit of the byte represented by the rest of the int
|
||
|
int write_bit = 0;
|
||
|
int write_next = 0;
|
||
|
|
||
|
gpio_set_level(CLOCK, 0);
|
||
|
|
||
|
while(write_bit < sizeof(g_serial_out_buffer) * 8) {
|
||
|
// fetch the bit being adressed
|
||
|
write_next = 0x1 & (g_serial_out_buffer[write_bit >> 5] >> (write_bit & 0x1F));
|
||
|
// set clock out to high, triggering a rising edge
|
||
|
gpio_set_level(CLOCK, 1);
|
||
|
// write bit to data out
|
||
|
gpio_set_level(DATA, write_next);
|
||
|
|
||
|
os_delay_us(10);
|
||
|
// set clock to low, triggering a falling edge
|
||
|
gpio_set_level(CLOCK, 0);
|
||
|
os_delay_us(10);
|
||
|
|
||
|
write_bit++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void leds_init() {
|
||
|
g_serial_out_buffer[0] = 0;
|
||
|
g_serial_out_buffer[61] = 0xFFFFFFFF;
|
||
|
for(int i = 0; i < 60; ++i) {
|
||
|
g_leds[i].components = (struct led_components_t) {
|
||
|
.red = 255,
|
||
|
.green = 10,
|
||
|
.blue = 255,
|
||
|
.global = 0xE0 | 0
|
||
|
};
|
||
|
}
|
||
|
|
||
|
gpio_config_t config = {
|
||
|
.intr_type = GPIO_INTR_DISABLE,
|
||
|
.mode = GPIO_MODE_OUTPUT,
|
||
|
.pin_bit_mask = 0x18030,
|
||
|
.pull_up_en = 0,
|
||
|
.pull_down_en = 0,
|
||
|
};
|
||
|
gpio_config(&config);
|
||
|
}
|
||
|
|
||
|
static inline
|
||
|
uint8_t lerp_uint8(uint8_t a, uint8_t b, float t) {
|
||
|
int dir = b - a;
|
||
|
return a + t * dir;
|
||
|
}
|
||
|
|
||
|
static inline
|
||
|
void lerp_led(union led_t* out, const union led_t* from, const union led_t* to, float t) {
|
||
|
out->components.red = lerp_uint8(from->components.red, to->components.red, t);
|
||
|
out->components.green = lerp_uint8(from->components.green, to->components.green, t);
|
||
|
out->components.blue = lerp_uint8(from->components.blue, to->components.blue, t);
|
||
|
uint8_t glob_from = from->components.global & 0x1F;
|
||
|
uint8_t glob_to = to->components.global & 0x1F;
|
||
|
out->components.global = 0xE0 | lerp_uint8(glob_from, glob_to, t);
|
||
|
}
|
||
|
|
||
|
static inline
|
||
|
void lerp_points_between(const struct gradient_point_t from, const struct gradient_point_t to) {
|
||
|
const int dif = to.offset - from.offset;
|
||
|
float t = 0.f;
|
||
|
for(int led = from.offset; led < to.offset; ++led) {
|
||
|
t = (float)(led - from.offset) / (float)dif;
|
||
|
lerp_led(g_leds + led, &from.led, &to.led, t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
void leds_set_gradient(struct gradient_point_t* points, size_t points_len) {
|
||
|
struct gradient_point_t from = points[0];
|
||
|
struct gradient_point_t to;
|
||
|
for(int i = 1; i < points_len; ++i) {
|
||
|
to = points[i];
|
||
|
lerp_points_between(from, to);
|
||
|
from = to;
|
||
|
}
|
||
|
|
||
|
send_leds();
|
||
|
}
|
||
|
|
||
|
#endif // !_leds_h
|