From 9aa8af017f1d4cad6c3494e4a724c9da1099fcac Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 18 Sep 2023 22:41:46 +0200 Subject: [PATCH] implemented most of the leds --- main/leds.h | 131 ++++++++++++++++++++++++++++++++++++++++++++ main/network.h | 1 - main/potion_party.c | 31 ++++++++--- main/server.h | 115 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 264 insertions(+), 14 deletions(-) create mode 100644 main/leds.h diff --git a/main/leds.h b/main/leds.h new file mode 100644 index 0000000..c4f30e0 --- /dev/null +++ b/main/leds.h @@ -0,0 +1,131 @@ +#ifndef _potion_leds_h +#define _potion_leds_h + +#include +#include +#include +#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 diff --git a/main/network.h b/main/network.h index cf7b269..ae1fa27 100644 --- a/main/network.h +++ b/main/network.h @@ -33,7 +33,6 @@ void wifi_init() { LOGLN("Configuring WIFI"); // init tcp/ip stack tcpip_adapter_init(); - ESP_ERROR_CHECK(esp_event_loop_create_default()); // initialize wifi wifi_init_config_t wifi_startup = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&wifi_startup)); diff --git a/main/potion_party.c b/main/potion_party.c index f4bff7a..29b2d6e 100644 --- a/main/potion_party.c +++ b/main/potion_party.c @@ -1,18 +1,31 @@ +#include "leds.h" #include "shared.h" #include "network.h" +#include "server.h" #include "rom/ets_sys.h" #include #include -#include - -void app_main() { - LOGLN("starting {"); - - wifi_init(); - softap_init(); - - LOGLN("}"); +static +void init_esp(void) { + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); +} + +void app_main(void) { + LOGLN("---- starting"); + + init_esp(); + leds_init(); + send_leds(); + wifi_init(); + softap_init(); + server_init(); + + os_delay_us(10000); + send_leds(); + + LOGLN("---- finished setting up"); } diff --git a/main/server.h b/main/server.h index 1bf7187..ab81581 100644 --- a/main/server.h +++ b/main/server.h @@ -1,7 +1,114 @@ -#ifndef _server_h -#define _server_h +#ifndef _potion_party_server_h +#define _potion_party_server_h -void server_init() { +#include +#include +#include +#include "shared.h" +#include "leds.h" +#include "esp_http_server.h" +#include "esp_system.h" +#include "esp_netif.h" + +static +httpd_handle_t g_http_server = NULL; + +static +void parse_leds_query(char* query_string, size_t query_size) { + char query_value[16]; + char query_key[3]; + size_t gradient_point_count = 0; + + if(httpd_query_key_value(query_string, "l", query_value, sizeof(query_value)) == ESP_OK) { + gradient_point_count = atoi(query_value); + } else { + return; + } + + struct gradient_point_t* points = malloc(gradient_point_count * sizeof(union led_t)); + + for(int point = 0; point < gradient_point_count; ++point) { + 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); + } + 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); + } + 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); + } + 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 = atoi(query_value) | 0xE0; + } + 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); + } + + 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); + LOGLN(" t %d", (int)points[point].offset); + + } + + leds_set_gradient(points, gradient_point_count); } -#endif // !_server_h +static +esp_err_t on_http_post(httpd_req_t* request) { + LOGLN("POST received on '/'."); + + char* buffer; + size_t buffer_len; + + 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) { + LOGLN("Received query."); + parse_leds_query(buffer, buffer_len); + } + } + + const char* response = "OK!"; + httpd_resp_send(request, response, strlen(response)); + + return ESP_OK; +} + +httpd_uri_t post = { + .uri="/", + .method=HTTP_POST, + .handler=&on_http_post, + .user_ctx = NULL +}; + +static +httpd_handle_t start_webserver(void) { + httpd_handle_t server = NULL; + httpd_config_t server_config = HTTPD_DEFAULT_CONFIG(); + + LOGLN("Starting HTTPd server ':%d'.", server_config.server_port); + if(httpd_start(&server, &server_config) == ESP_OK) { + httpd_register_uri_handler(server, &post); + return server; + } + + LOGLN("Failed to start HTTPd server."); + return NULL; +} + +static +void server_init(void) { + g_http_server = start_webserver(); +} + +#endif // !_potion_party_server_h