added edge action argument

main
Sara 2023-09-28 16:58:44 +02:00
parent afb521f7a8
commit 46011ea8d9
4 changed files with 69 additions and 7 deletions

View File

@ -1,8 +1,21 @@
The server listens on '/' for GET queries with a url query format like The server 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 'movement' argument. &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.
A point on the gradient can have an &m parameter, and has to have a &r, &g, &b, &a, and &t. When no movement is set, 0 (no movement) is implied.
The whole gradient can have a duration &d parameter and must have a length &l
When movement is set, a &e 'edge' component can also be set for that point. &e defines what the point will do once it reaches an end of the strip.
Edge should be one of
w to wrap to the opposite end of the strip.
r to reverse direction
s to stop
If no &e is specified, s is implied.
A point on the gradient may have a movement &m and edge &e parameter, and has to have a &r, &g, &b, &a, and &t.
The whole gradient may have a duration &d parameter and must have a length &l

View File

@ -156,23 +156,49 @@ void memswap(void* d, void* s, size_t n) {
free(tmp); free(tmp);
} }
static
void led_check_edge(GradientPoint* point) {
int offset = clamp(point->offset, 0, 120);
switch(point->edge_action) {
default:
case LEDS_EDGE_WRAP:
if(point->offset < 0) {
point->offset += 120;
} else if(point->offset >= 120) {
point->offset %= 120;
}
break;
case LEDS_EDGE_REVERSE: {
if(offset != point->offset) {
point->offset = offset;
point->movement *= -1;
}
break;
}
case LEDS_EDGE_STOP:
point->offset = clamp(point->offset, 0, 120);
break;
}
}
void leds_animate() { void leds_animate() {
for(size_t i = 0; i < g_current_gradient.points_len; ++i) { for(size_t i = 0; i < g_current_gradient.points_len; ++i) {
// The gradient point at i // The gradient point at i
GradientPoint* point = g_current_gradient.points + i; GradientPoint* point = g_current_gradient.points + i;
// move towards end // move towards end
if(point->movement > 0) { if(point->movement > 0) {
++point->offset;
// without moving past it // without moving past it
point->offset = min(point->offset + 1, 120); led_check_edge(point);
// swap with next point if we pass it // swap with next point if we pass it
if(point->offset > (point+1)->offset) { if(point->offset > (point+1)->offset) {
memswap(point, point+1, sizeof(GradientPoint)); memswap(point, point+1, sizeof(GradientPoint));
} }
// move towards start // move towards start
} else if(point->movement < 0) { } else if(point->movement < 0) {
++point->offset;
// without passing it // without passing it
point->offset = max(0, point->offset - 1); led_check_edge(point);
// swap with previous point if we fall below it // swap with previous point if we fall below it
if(point->offset < (point-1)->offset) { if(point->offset < (point-1)->offset) {

View File

@ -18,6 +18,12 @@ typedef enum LedsSendStatus {
LEDS_SENDING, LEDS_SENDING,
} LedsSendStatus; } LedsSendStatus;
typedef enum MoveEdgeAction {
LEDS_EDGE_WRAP,
LEDS_EDGE_REVERSE,
LEDS_EDGE_STOP
} MoveEdgeAction;
// pack the struct to match exactly 8 * 4 = 32bits // pack the struct to match exactly 8 * 4 = 32bits
typedef struct __attribute__((__packed__)) LedComponents { typedef struct __attribute__((__packed__)) LedComponents {
// RGB component values // RGB component values
@ -37,8 +43,9 @@ typedef union Led {
// point on a gradient // point on a gradient
typedef struct GradientPoint { typedef struct GradientPoint {
union Led led; // value of the led at this point union Led led; // value of the led at this point
size_t offset; // offset (measured in leds) from the beginning int offset; // offset (measured in leds) from the beginning
short movement; // direction of movement over time short movement; // direction of movement over time
MoveEdgeAction edge_action; // what to do when movement hits an end of the strip
} GradientPoint; } GradientPoint;
typedef struct Gradient { typedef struct Gradient {

View File

@ -3,6 +3,16 @@
#include <string.h> #include <string.h>
#include <esp_http_server.h> #include <esp_http_server.h>
MoveEdgeAction strtoea(const char* str) {
if(strcmp(str, "w")) {
return LEDS_EDGE_WRAP;
} else if(strcmp(str, "r")) {
return LEDS_EDGE_REVERSE;
} else {
return LEDS_EDGE_STOP;
}
}
// parse a URL query as described in api-doc.txt into a valid Gradient struct. // parse a URL query as described in api-doc.txt into a valid Gradient struct.
// If the gradient is invalid, the is_ok flag on the return value will be set, and error will be set to a message describing the problem. // If the gradient is invalid, the is_ok flag on the return value will be set, and error will be set to a message describing the problem.
Result parse_leds_query(char* query_string, size_t query_size) { Result parse_leds_query(char* query_string, size_t query_size) {
@ -75,11 +85,17 @@ Result parse_leds_query(char* query_string, size_t query_size) {
// Get the movement variable &m. // Get the movement variable &m.
// Interpreted as an integer number from -1 to +1 // Interpreted as an integer number from -1 to +1
sprintf(query_key, "m%d", point); sprintf(query_key, "m%d", point);
if(gradient->duration > 0 && 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].movement = clamp(-1, +1, atoi(query_value)); gradient->points[point].movement = clamp(-1, +1, atoi(query_value));
} else { } else {
gradient->points[point].movement = 0; gradient->points[point].movement = 0;
} }
sprintf(query_key, "e%d", point);
if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) {
gradient->points[point].edge_action = strtoea(query_value);
} else {
gradient->points[point].edge_action = LEDS_EDGE_STOP;
}
// Log fetched fields // Log fetched fields
LOGLN("led[%d]:", point); LOGLN("led[%d]:", point);