#include "http_server.h" #include #include #include "freertos/semphr.h" #include "param.h" #define TAG "httpd" #define STATE_PARAM(typ, attr, ...) \ static esp_err_t handle_set_##attr(httpd_req_t* req) \ { \ ESP_LOGI(TAG, "Handling [%s] (%s)", #attr, req->uri); \ ws_params_t* params = (ws_params_t*)req->user_ctx; \ httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); \ ws_state_t snapshot; \ if (xSemaphoreTake(params->state_lock, portMAX_DELAY) != pdTRUE) { \ httpd_resp_send_err( \ req, HTTPD_500_INTERNAL_SERVER_ERROR, "lock failed"); \ return ESP_FAIL; \ } \ http_handle(typ)(req, ¶ms->state.attr); \ snapshot = params->state; \ xSemaphoreGive(params->state_lock); \ ws_state_save(&snapshot); \ httpd_resp_send(req, NULL, 0); \ return ESP_OK; \ } \ static httpd_uri_t http_##attr##_handler = { \ .uri = "/" #attr, \ .method = HTTP_POST, \ .handler = handle_set_##attr, \ .user_ctx = NULL}; #include "state_params.i" #undef STATE_PARAM static esp_err_t handle_get_params(httpd_req_t* req) { httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); size_t len = NUMBER_PARAMS * 128; char out_buffer[len + 1]; out_buffer[len] = 0; char* out_ptr = out_buffer; ws_params_t* ws_params = (ws_params_t*)req->user_ctx; ws_state_t snapshot; if (xSemaphoreTake(ws_params->state_lock, portMAX_DELAY) != pdTRUE) { httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "lock failed"); return ESP_FAIL; } snapshot = ws_params->state; xSemaphoreGive(ws_params->state_lock); bool write_comma = false; httpd_resp_set_type(req, "application/json"); if (len > 1) { *out_ptr = '{'; out_ptr++; len--; } #define STATE_PARAM(typ, attr, display, ...) \ if (write_comma && len > 1) { \ *(out_ptr++) = ','; \ len--; \ } \ len = serialize_to_json(typ)(&out_ptr, len, #attr, display, snapshot.attr); \ write_comma = true; #include "state_params.i" #undef STATE_PARAM if (len > 3) { *(out_ptr++) = '}'; len--; *(out_ptr++) = '\r'; len--; *(out_ptr++) = '\n'; len--; } if (len > 1) { *(out_ptr++) = 0; len--; } httpd_resp_set_status(req, HTTPD_200); httpd_resp_send(req, out_buffer, strlen(out_buffer)); return ESP_OK; } static httpd_uri_t http_params_get_handler = { .uri = "/params", .method = HTTP_GET, .handler = handle_get_params, .user_ctx = NULL}; static esp_err_t handle_reset(httpd_req_t* req) { httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); ws_params_t* params = (ws_params_t*)req->user_ctx; ws_state_t snapshot; reset_parameters(params); if (xSemaphoreTake(params->state_lock, portMAX_DELAY) != pdTRUE) { httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "lock failed"); return ESP_FAIL; } snapshot = params->state; xSemaphoreGive(params->state_lock); ws_state_save(&snapshot); httpd_resp_send(req, NULL, 0); return ESP_OK; } static httpd_uri_t http_reset_handler = { .uri = "/reset", .method = HTTP_POST, .handler = handle_reset, .user_ctx = NULL}; httpd_handle_t start_webserver(ws_params_t* params) { httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.lru_purge_enable = true; config.max_uri_handlers = NUMBER_PARAMS + 2; ESP_LOGI(TAG, "Starting httpd server on port: '%d'", config.server_port); if (httpd_start(&server, &config) == ESP_OK) { http_params_get_handler.user_ctx = params; http_reset_handler.user_ctx = params; httpd_register_uri_handler(server, &http_params_get_handler); httpd_register_uri_handler(server, &http_reset_handler); #define STATE_PARAM(typ, attr, ...) \ ESP_LOGI(TAG, "Registering URI handler [%s]", #attr); \ http_##attr##_handler.user_ctx = params; \ httpd_register_uri_handler(server, &http_##attr##_handler); #include "state_params.i" #undef STATE_PARAM return server; } ESP_LOGI(TAG, "Error starting server!"); return NULL; }