From 78ea77179fb3e66eafab69c5dc1b6269ad78eab8 Mon Sep 17 00:00:00 2001 From: Sara Date: Fri, 22 Sep 2023 12:30:29 +0200 Subject: [PATCH] Server can now parse &m* and &d parameters and will respond with more useful errors --- main/server.h | 127 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 30 deletions(-) diff --git a/main/server.h b/main/server.h index 60d6da5..8f5473b 100644 --- a/main/server.h +++ b/main/server.h @@ -7,6 +7,9 @@ // 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. // 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. +// &m arguments are only valid if the global &d variable is also defined. +// 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 // /// @@ -27,75 +30,139 @@ static httpd_handle_t g_http_server = NULL; +struct parse_error_t { + const char* error; +}; + // Parse a gradient query static -void parse_leds_query(char* query_string, size_t query_size) { +struct parse_error_t parse_leds_query(char* query_string, size_t query_size) { char query_value[16]; char query_key[3]; - size_t gradient_point_count = 0; + struct gradient_t gradient; + // Fetch the &l length parameter. + // Interpret as a positive integer number of points on the gradient. if(httpd_query_key_value(query_string, "l", query_value, sizeof(query_value)) == ESP_OK) { - gradient_point_count = atoi(query_value); + gradient.points_len = max(0, atoi(query_value)); } else { - return; + leds_set_current_gradient(&g_default_gradient, 0); + return (struct parse_error_t) { + .error = "ERROR: Failed to find length parameter &l" + }; } - struct gradient_point_t* points = malloc(gradient_point_count * sizeof(struct gradient_point_t)); + // Get the &d 'duration' parameter from the query. + // Interpreted as a floating point number of seconds before returning to default state. + if(httpd_query_key_value(query_string, "d", query_value, sizeof(query_value)) == ESP_OK) { + gradient.duration = atof(query_string); + } else { + gradient.duration = 0; + } - for(int point = 0; point < gradient_point_count; ++point) { + LOGLN("Reading %zu points of gradient query:", gradient.points_len); + LOGLN("duration: %f", gradient.duration); + + // Get the gradient point components for every point that was promised by the &l parameter + for(int point = 0; point < gradient.points_len; ++point) { + // Get the r, g, and b components as 8 bit integers sprintf(query_key, "r%d", point); if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_size)) == ESP_OK) { - points[point].led.components.red = atoi(query_value); + gradient.points[point].led.components.red = atoi(query_value); + } else { + return (struct parse_error_t) { + .error = "ERROR: Point missing red component &r." + }; } sprintf(query_key, "g%d", point); if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_size)) == ESP_OK) { - points[point].led.components.green = atoi(query_value); + gradient.points[point].led.components.green = atoi(query_value); + } else { + return (struct parse_error_t) { + .is_error = 1, + .error = "ERROR: Point missing green component &g." + }; } sprintf(query_key, "b%d", point); if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) { - points[point].led.components.blue = atoi(query_value); + gradient.points[point].led.components.blue = atoi(query_value); + } else { + return (struct parse_error_t) { + .error = "ERROR: Point missing blue component &b." + }; } + // Get the global variable, passed as alpha. Limited to 0-32 (a 5bit unsigned int) + // Make sure the most significant 3 bits are all ones sprintf(query_key, "a%d", point); if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) { - points[point].led.components.global = GLOBAL(atoi(query_value)); + gradient.points[point].led.components.global = GLOBAL((uint8_t)atoi(query_value)); + } else { + return (struct parse_error_t) { + .error = "ERROR: Point missing alpha component &a." + }; } + // Get the time of the gradient as a number ranging from 0 - 60. + // Interpreted as an integer offset from the first led to the last sprintf(query_key, "t%d", point); if(httpd_query_key_value(query_string, query_key, query_value, sizeof(query_value)) == ESP_OK) { - points[point].offset = atoi(query_value); + gradient.points[point].offset = clamp(0, 60, atoi(query_value)); + } else { + return (struct parse_error_t) { + .error = "ERROR: Point missing time component &t." + }; + } + // Get the movement variable &m. + // Interpreted as an integer number from -1 to +1 + 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) { + gradient.points[point].movement = clamp(-1, +1, atoi(query_value)); + } else { + gradient.points[point].movement = 0; } - LOGLN("led %d:", point); - LOGLN(" r %d", points[point].led.components.red); - LOGLN(" g %d", points[point].led.components.green); - LOGLN(" b %d", points[point].led.components.blue); - LOGLN(" global %d", points[point].led.components.global >> 3); - LOGLN(" t %d", (int)points[point].offset); - + // Log fetched fields + LOGLN("led[%d]:", point); + LOGLN(" r %d", gradient.points[point].led.components.red); + LOGLN(" g %d", gradient.points[point].led.components.green); + LOGLN(" b %d", gradient.points[point].led.components.blue); + LOGLN(" global %d", gradient.points[point].led.components.global >> 3); + LOGLN(" t %zu", gradient.points[point].offset); } - leds_set_gradient(points, gradient_point_count, 1); + leds_set_current_gradient(&gradient, 0); + return (struct parse_error_t) { .error = NULL }; } // receives HTTP GET requests on root static esp_err_t on_http_get_root(httpd_req_t* request) { + // Error mewsages for cases of good and bad + static const char* response_ok = "OK!"; + + const char* response_msg = response_ok; + LOGLN("POST received on '/'."); - char* buffer; - size_t buffer_len; + // buffer for query string + char* query_buffer; + size_t query_length = httpd_req_get_url_query_len(request) + 1; + struct parse_error_t result = { .error = NULL }; - buffer_len = httpd_req_get_url_query_len(request) + 1; - - if(buffer_len > 1) { - buffer = malloc(buffer_len * sizeof(char)); - if(httpd_req_get_url_query_str(request, buffer, buffer_len) == ESP_OK) { + if(query_length > 1) { + query_buffer = malloc(query_length * sizeof(char)); + if(httpd_req_get_url_query_str(request, query_buffer, query_length) == ESP_OK) { LOGLN("Received query."); - parse_leds_query(buffer, buffer_len); + result = parse_leds_query(query_buffer, query_length); } } - const char* response = "OK!"; - httpd_resp_send(request, response, strlen(response)); + // an error was returned, pass it on to the API caller + if(result.error != NULL) { + httpd_resp_set_status(request, "400 Bad Request"); + response_msg = result.error; + } + + httpd_resp_send(request, response_msg, strlen(response_msg)); return ESP_OK; } @@ -106,7 +173,7 @@ httpd_uri_t get_root_uri = { .user_ctx = NULL }; -// Configure and enable the http server. +// Configure server and enable the http handler. static httpd_handle_t start_webserver(void) { httpd_handle_t server = NULL;