|
16 | 16 | #include "esp_netif.h"
|
17 | 17 | #include "esp_netif_ppp.h"
|
18 | 18 | #include "esp_check.h"
|
| 19 | +#include "esp_http_server.h" |
| 20 | +#include "esp_timer.h" |
19 | 21 |
|
20 | 22 | extern uint8_t g_at_cmd_port;
|
21 | 23 |
|
@@ -73,6 +75,7 @@ static uint8_t at_setup_cmd_test(uint8_t para_num)
|
73 | 75 |
|
74 | 76 | #define TAG "at_custom_cmd"
|
75 | 77 | static esp_netif_t *s_netif = NULL;
|
| 78 | +static httpd_handle_t http_server = NULL; |
76 | 79 |
|
77 | 80 | static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
78 | 81 | {
|
@@ -206,10 +209,202 @@ static uint8_t at_exe_cereg(uint8_t *cmd_name)
|
206 | 209 | return ESP_AT_RESULT_CODE_OK;
|
207 | 210 | }
|
208 | 211 |
|
| 212 | +/* HTTP Server handlers */ |
| 213 | +static esp_err_t hello_get_handler(httpd_req_t *req) |
| 214 | +{ |
| 215 | + const char* resp_str = "Hello from ESP-AT HTTP Server!"; |
| 216 | + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); |
| 217 | + return ESP_OK; |
| 218 | +} |
| 219 | + |
| 220 | +static esp_err_t root_get_handler(httpd_req_t *req) |
| 221 | +{ |
| 222 | + const char* resp_str = "ESP-AT HTTP Server is running"; |
| 223 | + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); |
| 224 | + return ESP_OK; |
| 225 | +} |
| 226 | + |
| 227 | +static esp_err_t test_get_handler(httpd_req_t *req) |
| 228 | +{ |
| 229 | + const char* resp_str = "{\"status\":\"success\",\"message\":\"Test endpoint working\",\"timestamp\":12345}"; |
| 230 | + httpd_resp_set_type(req, "application/json"); |
| 231 | + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); |
| 232 | + return ESP_OK; |
| 233 | +} |
| 234 | + |
| 235 | +static esp_err_t async_get_handler(httpd_req_t *req) |
| 236 | +{ |
| 237 | + printf("Starting async chunked response handler\r\n"); |
| 238 | + |
| 239 | + // Set content type for plain text response |
| 240 | + httpd_resp_set_type(req, "text/plain"); |
| 241 | + |
| 242 | + // Static counter to track requests |
| 243 | + static uint8_t req_count = 0; |
| 244 | + req_count++; |
| 245 | + |
| 246 | + // Send initial response with request count |
| 247 | + char buffer[256]; |
| 248 | + snprintf(buffer, sizeof(buffer), "=== Async Response #%d ===\r\n", req_count); |
| 249 | + httpd_resp_sendstr_chunk(req, buffer); |
| 250 | + |
| 251 | + // Long message broken into chunks |
| 252 | + const char* chunks[] = { |
| 253 | + "This is a simulated slow server response.\r\n", |
| 254 | + "Chunk 1: The ESP-AT HTTP server is demonstrating...\r\n", |
| 255 | + "Chunk 2: ...asynchronous chunked transfer encoding...\r\n", |
| 256 | + "Chunk 3: ...with artificial delays between chunks...\r\n", |
| 257 | + "Chunk 4: ...to simulate real-world network conditions.\r\n", |
| 258 | + "Chunk 5: Processing data... please wait...\r\n", |
| 259 | + "Chunk 6: Still processing... almost done...\r\n", |
| 260 | + "Chunk 7: Final chunk - transfer complete!\r\n", |
| 261 | + "=== END OF RESPONSE ===\r\n" |
| 262 | + }; |
| 263 | + |
| 264 | + int num_chunks = sizeof(chunks) / sizeof(chunks[0]); |
| 265 | + |
| 266 | + // Send each chunk with delays |
| 267 | + for (int i = 0; i < num_chunks; i++) { |
| 268 | + // Add a delay to simulate slow processing |
| 269 | + vTaskDelay(pdMS_TO_TICKS(1500)); // 1.5 second delay between chunks |
| 270 | + |
| 271 | + // Add chunk number and timestamp |
| 272 | + snprintf(buffer, sizeof(buffer), "[%d/%d] [%d ms] %s", |
| 273 | + i + 1, num_chunks, (int)(esp_timer_get_time() / 1000), chunks[i]); |
| 274 | + |
| 275 | + printf("Sending chunk %d: %s", i + 1, chunks[i]); |
| 276 | + httpd_resp_sendstr_chunk(req, buffer); |
| 277 | + } |
| 278 | + |
| 279 | + // Add final summary |
| 280 | + vTaskDelay(pdMS_TO_TICKS(500)); |
| 281 | + snprintf(buffer, sizeof(buffer), "\r\nTransfer completed in %d chunks with delays.\r\n", num_chunks); |
| 282 | + httpd_resp_sendstr_chunk(req, buffer); |
| 283 | + |
| 284 | + // Send NULL to signal end of chunked transfer |
| 285 | + httpd_resp_sendstr_chunk(req, NULL); |
| 286 | + |
| 287 | + printf("Async chunked response completed\r\n"); |
| 288 | + return ESP_OK; |
| 289 | +} |
| 290 | + |
| 291 | +static const httpd_uri_t hello = { |
| 292 | + .uri = "/hello", |
| 293 | + .method = HTTP_GET, |
| 294 | + .handler = hello_get_handler, |
| 295 | + .user_ctx = NULL |
| 296 | +}; |
| 297 | + |
| 298 | +static const httpd_uri_t root = { |
| 299 | + .uri = "/", |
| 300 | + .method = HTTP_GET, |
| 301 | + .handler = root_get_handler, |
| 302 | + .user_ctx = NULL |
| 303 | +}; |
| 304 | + |
| 305 | +static const httpd_uri_t test = { |
| 306 | + .uri = "/test", |
| 307 | + .method = HTTP_GET, |
| 308 | + .handler = test_get_handler, |
| 309 | + .user_ctx = NULL |
| 310 | +}; |
| 311 | + |
| 312 | +static const httpd_uri_t async_uri = { |
| 313 | + .uri = "/async", |
| 314 | + .method = HTTP_GET, |
| 315 | + .handler = async_get_handler, |
| 316 | + .user_ctx = NULL |
| 317 | +}; |
| 318 | + |
| 319 | +static esp_err_t start_http_server(void) |
| 320 | +{ |
| 321 | + if (http_server != NULL) { |
| 322 | + printf("HTTP server already running\r\n"); |
| 323 | + return ESP_OK; |
| 324 | + } |
| 325 | + |
| 326 | + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); |
| 327 | + config.server_port = 8080; |
| 328 | + config.lru_purge_enable = true; |
| 329 | + |
| 330 | + printf("Starting HTTP server on port: %d\r\n", config.server_port); |
| 331 | + if (httpd_start(&http_server, &config) == ESP_OK) { |
| 332 | + printf("Registering URI handlers\r\n"); |
| 333 | + httpd_register_uri_handler(http_server, &hello); |
| 334 | + httpd_register_uri_handler(http_server, &root); |
| 335 | + httpd_register_uri_handler(http_server, &test); |
| 336 | + httpd_register_uri_handler(http_server, &async_uri); |
| 337 | + return ESP_OK; |
| 338 | + } |
| 339 | + |
| 340 | + printf("Error starting HTTP server!\r\n"); |
| 341 | + return ESP_FAIL; |
| 342 | +} |
| 343 | + |
| 344 | +static esp_err_t stop_http_server(void) |
| 345 | +{ |
| 346 | + if (http_server != NULL) { |
| 347 | + httpd_stop(http_server); |
| 348 | + http_server = NULL; |
| 349 | + printf("HTTP server stopped\r\n"); |
| 350 | + return ESP_OK; |
| 351 | + } |
| 352 | + return ESP_OK; |
| 353 | +} |
| 354 | + |
| 355 | +/* HTTP Server AT Commands */ |
| 356 | +static uint8_t at_test_httpd(uint8_t *cmd_name) |
| 357 | +{ |
| 358 | + uint8_t buffer[64] = {0}; |
| 359 | + snprintf((char *)buffer, 64, "AT%s=<0/1> - Start/Stop HTTP server\r\n", cmd_name); |
| 360 | + esp_at_port_write_data(buffer, strlen((char *)buffer)); |
| 361 | + return ESP_AT_RESULT_CODE_OK; |
| 362 | +} |
| 363 | + |
| 364 | +static uint8_t at_query_httpd(uint8_t *cmd_name) |
| 365 | +{ |
| 366 | + uint8_t buffer[64] = {0}; |
| 367 | + snprintf((char *)buffer, 64, "+HTTPD:%d\r\n", http_server != NULL ? 1 : 0); |
| 368 | + esp_at_port_write_data(buffer, strlen((char *)buffer)); |
| 369 | + return ESP_AT_RESULT_CODE_OK; |
| 370 | +} |
| 371 | + |
| 372 | +static uint8_t at_setup_httpd(uint8_t para_num) |
| 373 | +{ |
| 374 | + int32_t action = 0; |
| 375 | + if (esp_at_get_para_as_digit(0, &action) != ESP_AT_PARA_PARSE_RESULT_OK) { |
| 376 | + return ESP_AT_RESULT_CODE_ERROR; |
| 377 | + } |
| 378 | + |
| 379 | + if (action == 1) { |
| 380 | + if (start_http_server() == ESP_OK) { |
| 381 | + printf("HTTP server started successfully\r\n"); |
| 382 | + return ESP_AT_RESULT_CODE_OK; |
| 383 | + } |
| 384 | + } else if (action == 0) { |
| 385 | + if (stop_http_server() == ESP_OK) { |
| 386 | + return ESP_AT_RESULT_CODE_OK; |
| 387 | + } |
| 388 | + } |
| 389 | + |
| 390 | + return ESP_AT_RESULT_CODE_ERROR; |
| 391 | +} |
| 392 | + |
| 393 | +static uint8_t at_exe_httpd(uint8_t *cmd_name) |
| 394 | +{ |
| 395 | + // Default action: start server |
| 396 | + if (start_http_server() == ESP_OK) { |
| 397 | + printf("HTTP server started via execute command\r\n"); |
| 398 | + return ESP_AT_RESULT_CODE_OK; |
| 399 | + } |
| 400 | + return ESP_AT_RESULT_CODE_ERROR; |
| 401 | +} |
| 402 | + |
209 | 403 |
|
210 | 404 | static const esp_at_cmd_struct at_custom_cmd[] = {
|
211 | 405 | {"+PPPD", at_test_cmd_test, at_query_cmd_test, at_setup_cmd_test, at_exe_cmd_test},
|
212 | 406 | {"+CEREG", at_test_cereg, at_query_cereg, at_setup_cereg, at_exe_cereg},
|
| 407 | + {"+HTTPD", at_test_httpd, at_query_httpd, at_setup_httpd, at_exe_httpd}, |
213 | 408 | /**
|
214 | 409 | * @brief You can define your own AT commands here.
|
215 | 410 | */
|
|
0 commit comments