implemented animation on xTask
parent
32705f0f50
commit
bfcf343447
93
main/leds.h
93
main/leds.h
|
@ -7,6 +7,7 @@
|
||||||
#ifndef _potion_leds_h
|
#ifndef _potion_leds_h
|
||||||
#define _potion_leds_h
|
#define _potion_leds_h
|
||||||
|
|
||||||
|
#include <FreeRTOS.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -16,6 +17,12 @@
|
||||||
#include "rom/ets_sys.h"
|
#include "rom/ets_sys.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
|
enum leds_send_state_t {
|
||||||
|
LEDS_SEND_WAITING,
|
||||||
|
LEDS_SEND_REQUESTED,
|
||||||
|
LEDS_SENDING,
|
||||||
|
};
|
||||||
|
|
||||||
// pack the struct to match exactly 8 * 4 = 32bits
|
// pack the struct to match exactly 8 * 4 = 32bits
|
||||||
struct __attribute__((__packed__)) led_components_t {
|
struct __attribute__((__packed__)) led_components_t {
|
||||||
// RGB component values
|
// RGB component values
|
||||||
|
@ -47,13 +54,17 @@ struct gradient_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
// buffer that will be written out to the led strip over serial
|
// buffer that will be written out to the led strip over serial
|
||||||
uint32_t g_serial_out_buffer[62];
|
uint32_t g_serial_out_buffer[122];
|
||||||
// 60-long slice of the out buffer that represents the first few leds
|
// 120-long slice of the out buffer that represents the first few leds
|
||||||
union led_t* g_leds = ((union led_t*)g_serial_out_buffer + 1);
|
union led_t* g_leds = ((union led_t*)g_serial_out_buffer + 1);
|
||||||
|
|
||||||
struct gradient_t g_default_gradient;
|
struct gradient_t g_default_gradient;
|
||||||
struct gradient_t g_current_gradient;
|
struct gradient_t g_current_gradient;
|
||||||
int g_leds_are_default = 1;
|
int g_leds_are_default = 1;
|
||||||
|
enum leds_send_state_t g_leds_send_state = LEDS_SEND_WAITING;
|
||||||
|
|
||||||
|
SemaphoreHandle_t g_led_mutex; // mutex governing access to data for leds
|
||||||
|
// use for all global data defined in this header
|
||||||
|
|
||||||
#define CLOCK 4
|
#define CLOCK 4
|
||||||
#define DATA 5
|
#define DATA 5
|
||||||
|
@ -78,26 +89,21 @@ void serial_write(int high) {
|
||||||
// write bit to data out
|
// write bit to data out
|
||||||
gpio_set_level(DATA, high);
|
gpio_set_level(DATA, high);
|
||||||
|
|
||||||
os_delay_us(2);
|
ets_delay_us(1);
|
||||||
|
|
||||||
// set clock to low, triggering a falling edge, shifting the LEDs shift register
|
// set clock to low, triggering a falling edge, shifting the LEDs shift register
|
||||||
gpio_set_level(CLOCK, 0);
|
gpio_set_level(CLOCK, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void send_leds() {
|
void send_leds() {
|
||||||
LOGLN("entering send_leds()");
|
|
||||||
// index of the bit being written
|
// index of the bit being written
|
||||||
// fixed point number where the first 5 bits are the bit of a 32bit integger, and the rest is the integer
|
// fixed point number where the first 5 bits are the bit of a 32bit integger, and the rest is the integer
|
||||||
int write_bit = 0;
|
int write_bit = 0;
|
||||||
int write_next = 0;
|
int write_next = 0;
|
||||||
|
|
||||||
|
|
||||||
LOGLN("Setting clock low");
|
|
||||||
|
|
||||||
gpio_set_level(CLOCK, 0);
|
gpio_set_level(CLOCK, 0);
|
||||||
|
|
||||||
LOGLN("Writing to leds");
|
|
||||||
|
|
||||||
while(write_bit < sizeof(g_serial_out_buffer) * 8) {
|
while(write_bit < sizeof(g_serial_out_buffer) * 8) {
|
||||||
// fetch the bit being addressed
|
// fetch the bit being addressed
|
||||||
write_next = 0x1 & (g_serial_out_buffer[write_bit >> 5] >> (32 - (write_bit & 0x1F)));
|
write_next = 0x1 & (g_serial_out_buffer[write_bit >> 5] >> (32 - (write_bit & 0x1F)));
|
||||||
|
@ -160,7 +166,7 @@ void leds_set_current_gradient(const struct gradient_t* gradient, int defer_send
|
||||||
struct gradient_point_t to;
|
struct gradient_point_t to;
|
||||||
|
|
||||||
set_led_range(0, gradient->points[0].offset, gradient->points[0].led);
|
set_led_range(0, gradient->points[0].offset, gradient->points[0].led);
|
||||||
set_led_range(gradient->points[gradient->points_len-1].offset, 60, gradient->points[gradient->points_len-1].led);
|
set_led_range(gradient->points[gradient->points_len-1].offset, 120, gradient->points[gradient->points_len-1].led);
|
||||||
|
|
||||||
g_current_gradient = *gradient;
|
g_current_gradient = *gradient;
|
||||||
|
|
||||||
|
@ -175,11 +181,71 @@ void leds_set_current_gradient(const struct gradient_t* gradient, int defer_send
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void memswap(void* d, void* s, size_t n) {
|
||||||
|
void* tmp = malloc(n);
|
||||||
|
memcpy(tmp, s, n);
|
||||||
|
memcpy(s, d, n);
|
||||||
|
memcpy(d, tmp, n);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void leds_animate() {
|
||||||
|
for(size_t i = 0; i < g_current_gradient.points_len; ++i) {
|
||||||
|
struct gradient_point_t* point = g_current_gradient.points + i;
|
||||||
|
if(point->movement > 0) {
|
||||||
|
point->offset = min(point->offset + 1, 120);
|
||||||
|
LOGLN("move result %i", point->offset);
|
||||||
|
LOGLN("next %d", (point+1)->offset);
|
||||||
|
|
||||||
|
if(point->offset > (point+1)->offset) {
|
||||||
|
memswap(point, point+1, sizeof(struct gradient_point_t));
|
||||||
|
LOGLN("swap down");
|
||||||
|
}
|
||||||
|
} else if(point->movement < 0) {
|
||||||
|
point->offset = max(0, point->offset - 1);
|
||||||
|
LOGLN("move result %i", point->offset);
|
||||||
|
LOGLN("next %d", (point-1)->offset);
|
||||||
|
|
||||||
|
if(point->offset < (point-1)->offset) {
|
||||||
|
memswap(point, point-1, sizeof(struct gradient_point_t));
|
||||||
|
LOGLN("swap up");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leds_set_current_gradient(&g_current_gradient, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct led_thread_data_t {
|
||||||
|
TaskHandle_t task;
|
||||||
|
TaskFunction_t func;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void leds_thread();
|
||||||
|
|
||||||
|
static struct led_thread_data_t _thread_data = {
|
||||||
|
.task = 0,
|
||||||
|
.func = &leds_thread
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
void leds_thread() {
|
||||||
|
send_leds();
|
||||||
|
for(;;) {
|
||||||
|
vTaskDelay(10);
|
||||||
|
xSemaphoreTake(g_led_mutex, portMAX_DELAY);
|
||||||
|
send_leds();
|
||||||
|
leds_animate();
|
||||||
|
xSemaphoreGive(g_led_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void leds_init() {
|
void leds_init() {
|
||||||
g_serial_out_buffer[0] = 0u;
|
g_serial_out_buffer[0] = 0u;
|
||||||
g_serial_out_buffer[61] = ~0u;
|
g_serial_out_buffer[61] = ~0u;
|
||||||
set_led_range(0, 60,
|
set_led_range(0, 120,
|
||||||
(union led_t){.components =
|
(union led_t){.components =
|
||||||
(struct led_components_t) {
|
(struct led_components_t) {
|
||||||
.red = 0,
|
.red = 0,
|
||||||
|
@ -189,6 +255,11 @@ void leds_init() {
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
g_led_mutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
|
xTaskCreate(_thread_data.func, "Leds", 1024, NULL, 1, &_thread_data.task);
|
||||||
|
|
||||||
|
// initialize mutex for leds data
|
||||||
leds_config_gpio();
|
leds_config_gpio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,39 +30,51 @@ void TEST_leds() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
set_led_range(0, 60, led);
|
set_led_range(0, 120, led);
|
||||||
led.components.blue = 255;
|
led.components.blue = 255;
|
||||||
set_led_range(30, 60, led);
|
set_led_range(60, 120, led);
|
||||||
send_leds();
|
send_leds();
|
||||||
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
struct gradient_point_t points[3];
|
struct gradient_t gradient;
|
||||||
points[0].offset = 0;
|
gradient.points_len = 4;
|
||||||
points[0].led.components = (struct led_components_t) {
|
|
||||||
.global = GLOBAL(10),
|
gradient.points[0].offset = 0;
|
||||||
.red = 200,
|
gradient.points[0].movement = 0;
|
||||||
|
gradient.points[0].led.components = (struct led_components_t) {
|
||||||
|
.global = GLOBAL(0),
|
||||||
|
.red = 0,
|
||||||
.green = 0,
|
.green = 0,
|
||||||
.blue = 40,
|
.blue = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
points[1].offset = 30;
|
gradient.points[1].offset = 59;
|
||||||
points[1].led.components = (struct led_components_t){
|
gradient.points[1].movement = -1;
|
||||||
|
gradient.points[1].led.components = (struct led_components_t){
|
||||||
.global = GLOBAL(10),
|
.global = GLOBAL(10),
|
||||||
.red = 40,
|
.red = 40,
|
||||||
.green = 30,
|
.green = 200,
|
||||||
.blue = 40,
|
.blue = 40,
|
||||||
};
|
};
|
||||||
|
gradient.points[2].offset = 61;
|
||||||
points[2].offset = 60;
|
gradient.points[2].movement = 1;
|
||||||
points[2].led.components = (struct led_components_t){
|
gradient.points[2].led.components = (struct led_components_t){
|
||||||
.global = GLOBAL(10),
|
.global = GLOBAL(10),
|
||||||
.red = 200,
|
.red = 40,
|
||||||
.green = 255,
|
.green = 200,
|
||||||
.blue = 255,
|
.blue = 40,
|
||||||
|
};
|
||||||
|
gradient.points[3].offset = 120;
|
||||||
|
gradient.points[3].movement = 0;
|
||||||
|
gradient.points[3].led.components = (struct led_components_t){
|
||||||
|
.global = GLOBAL(0),
|
||||||
|
.red = 0,
|
||||||
|
.green = 0,
|
||||||
|
.blue = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
leds_set_gradient(points, 3, 1);
|
leds_set_current_gradient(&gradient, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void) {
|
void app_main(void) {
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
///
|
///
|
||||||
//
|
|
||||||
// server.h
|
// server.h
|
||||||
// Call server_init() to start up an http webserver.
|
// Call server_init() to start up an http webserver.
|
||||||
// listens on '/' for GET queries with a url query format like
|
// Listens on '/' for GET queries with a url query format like
|
||||||
// ?l=*&r0=*&g0=*&b0=*&a0=*&t0=* ... &rl=*&gl=*&bl=*&al=*&tl=*
|
// ?l=*&r0=*&g0=*&b0=*&a0=*&t0=* ... &rl=*&gl=*&bl=*&al=*&tl=*
|
||||||
// Where l is the number of points on a gradient. And each point of the gradient has a r* g* b* a* and t* where * is the index.
|
// Where l is the number of points on a gradient. And each point of the gradient has a r* g* b* a* and t* where * is the index.
|
||||||
// r g and b are the red green and blue 8-bit colour components of a point on the gradient. A is the 5-bit global component of the led at that point.
|
// r g and b are the red green and blue 8-bit colour components of a point on the gradient. A is the 5-bit global component of the led at that point.
|
||||||
// t is the offset from the start measured in leds.
|
// t is the offset from the start measured in leds.
|
||||||
// Each point also has an optional &m argument for movement. &m should be either -1, +1 or 0 and represents the movement per frame or the point.
|
// Each point also has an optional &m 'movement' argument. &m should be either -1, +1 or 0 and represents the movement per frame or the point.
|
||||||
// &m arguments are only valid if the global &d variable is also defined.
|
// A point on the gradient can have an &m parameter, and has to have a &r, &g, &b, &a, and &t.
|
||||||
// So if &d is defined (say, &d=3) a point on the gradient will have &r, &g, &b, &a, &t, and &m. And the global variables will be &l and &d
|
// The whole gradient can have a duration &d parameter and must have a length &l
|
||||||
//
|
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef _potion_party_server_h
|
#ifndef _potion_party_server_h
|
||||||
|
@ -99,11 +97,11 @@ struct parse_error_t parse_leds_query(char* query_string, size_t query_size) {
|
||||||
.error = "ERROR: Point missing alpha component &a."
|
.error = "ERROR: Point missing alpha component &a."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Get the time of the gradient as a number ranging from 0 - 60.
|
// Get the time of the gradient as a number ranging from 0 - 120.
|
||||||
// Interpreted as an integer offset from the first led to the last
|
// Interpreted as an integer offset from the first led to the last
|
||||||
sprintf(query_key, "t%d", point);
|
sprintf(query_key, "t%d", point);
|
||||||
if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) {
|
if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) {
|
||||||
gradient.points[point].offset = clamp(0, 60, atoi(query_value));
|
gradient.points[point].offset = clamp(0, 120, atoi(query_value));
|
||||||
} else {
|
} else {
|
||||||
return (struct parse_error_t) {
|
return (struct parse_error_t) {
|
||||||
.error = "ERROR: Point missing time component &t."
|
.error = "ERROR: Point missing time component &t."
|
||||||
|
@ -124,10 +122,17 @@ struct parse_error_t parse_leds_query(char* query_string, size_t query_size) {
|
||||||
LOGLN(" g %d", gradient.points[point].led.components.green);
|
LOGLN(" g %d", gradient.points[point].led.components.green);
|
||||||
LOGLN(" b %d", gradient.points[point].led.components.blue);
|
LOGLN(" b %d", gradient.points[point].led.components.blue);
|
||||||
LOGLN(" global %d", gradient.points[point].led.components.global >> 3);
|
LOGLN(" global %d", gradient.points[point].led.components.global >> 3);
|
||||||
LOGLN(" t %zu", gradient.points[point].offset);
|
// may show up as a compile error on modern computers,
|
||||||
|
// x86_64 size_t is usually an unsigned long int, on the ESP8266 it is an unsigned int
|
||||||
|
LOGLN(" t %u", gradient.points[point].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xSemaphoreTake(g_led_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
leds_set_current_gradient(&gradient, 0);
|
leds_set_current_gradient(&gradient, 0);
|
||||||
|
|
||||||
|
xSemaphoreGive(g_led_mutex);
|
||||||
|
|
||||||
return (struct parse_error_t) { .error = NULL };
|
return (struct parse_error_t) { .error = NULL };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue