Okay, that's probably a good idea.
I made a stripped-down version of my application. The only thing in components.mk is the index.html file which is here.
Code: Select all
<!DOCTYPE html>
<head>
<title>Sample web server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>Dropdown Menu (this works)</h2>
<form id="dropdown_menu" method="post" action="">
<select class="element select medium" name="item-choice">
<option value="item1" >item 1</option>
<option value="item2" >item 2</option>
<option value="item3" >item 3</option>
<option value="item4" >item 4</option>
<option value="item5" >item 5</option>
</select>
<label for="item-choice">select an item</label> <BR><BR>
<input type="hidden" name="form_id" value="choices" />
<input id="saveForm" class="button_text" type="submit" name="submit" value="submit" />
</form>
<br/>
<hr/>
<h2>File Upload (this blows up)</h2>
<p>Select a file to upload and look what happens in the log</p>
<BR>
<form method="post" enctype="multipart/form-data">
<input type="file" name="name">
<input class="button" type="submit" value="Upload">
</form>
</body>
</html>
And the entire application in main.c is as follows. As you can see I started with the persistent sockets example, which seemed like a decent enough starting point. It uses the http-server library, which not all of the examples do. http-server provides some nice tools.
Code: Select all
/* Persistent Sockets Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <esp_wifi.h>
#include <esp_event_loop.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <string.h>
#include <esp_http_server.h>
#define CONFIGURE_AS_SOFT_AP 1
#if CONFIGURE_AS_SOFT_AP
#define EXAMPLE_WIFI_SSID "ESP32_WIFI"
#define EXAMPLE_WIFI_PASS "12345678"
#else
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#endif
static const char *TAG="APP";
/* embedded binary data */
extern const char index_html_start[] asm("_binary_index_html_start");
extern const char index_html_end[] asm("_binary_index_html_end");
const static char http_204[] = "HTTP/1.1 204 No Content\nContent-Length: 0\n\n";
esp_err_t index_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "retrieving index.html");
httpd_resp_send(req, index_html_start, index_html_end - index_html_start);
return ESP_OK;
}
esp_err_t index_post_handler(httpd_req_t *req)
{
char buf[256];
int ret;
char temp[64];
ESP_LOGI(TAG, "post handler for index.html");
(void) memset(buf, 0, sizeof(buf));
/* Read data received in the request */
ret = httpd_req_recv(req, buf, sizeof(buf));
if (ret <= 0)
{
if (ret == HTTPD_SOCK_ERR_TIMEOUT)
{
httpd_resp_send_408(req);
}
return ESP_FAIL;
}
ESP_LOGI(TAG, "I think what was posted was [%s]", buf);
(void) memset(temp, 0, sizeof(temp));
ret = httpd_query_key_value(buf, "submit", temp, sizeof(temp));
if (ret == ESP_OK)
{
/* subnmit method was used in the http post */
ESP_LOGI(TAG, "detected submit [%s]", temp);
ret = httpd_query_key_value(buf, "item-choice", temp, sizeof(temp));
if (ret == ESP_OK)
{
ESP_LOGI(TAG, "you have chosen [%s]", temp); /* This all works great... */
}
}
httpd_resp_set_status(req, HTTPD_204);
httpd_resp_send(req, http_204, sizeof(http_204));
return ESP_OK;
}
static unsigned visitors = 0; /* I don't know why the httpd_uti struct requires this.... */
httpd_uri_t index_get = { .uri = "/", .method = HTTP_GET, .handler = index_get_handler, .user_ctx = &visitors };
httpd_uri_t index_get2 = { .uri = "/index.html", .method = HTTP_GET, .handler = index_get_handler, .user_ctx = &visitors };
httpd_uri_t index_post = { .uri = "/", .method = HTTP_POST, .handler = index_post_handler, .user_ctx = &visitors };
httpd_handle_t start_webserver(void)
{
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
httpd_handle_t server;
if (httpd_start(&server, &config) == ESP_OK) {
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &index_get);
httpd_register_uri_handler(server, &index_get2);
httpd_register_uri_handler(server, &index_post);
return server;
}
ESP_LOGI(TAG, "Error starting server!");
return NULL;
}
void stop_webserver(httpd_handle_t server)
{
// Stop the httpd server
httpd_stop(server);
}
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
// httpd_handle_t *server = (httpd_handle_t *) ctx;
ESP_LOGI(TAG, "event_handler received id %d", event->event_id);
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
ESP_ERROR_CHECK(esp_wifi_connect());
break;
case SYSTEM_EVENT_STA_GOT_IP:
case SYSTEM_EVENT_AP_STAIPASSIGNED:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
ESP_LOGI(TAG, "Got IP: '%s'",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
ESP_ERROR_CHECK(esp_wifi_connect());
break;
default:
break;
}
return ESP_OK;
}
#if CONFIGURE_AS_SOFT_AP
static tcpip_adapter_ip_info_t info;
#endif
static void init_wifi_and_httpd(void *arg)
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, arg));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
#if CONFIGURE_AS_SOFT_AP
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
memset(&info, 0, sizeof(info));
IP4_ADDR(&info.ip, 192, 168, 1, 1);
IP4_ADDR(&info.gw, 192, 168, 1, 1);
IP4_ADDR(&info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info));
ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP));
ESP_ERROR_CHECK( esp_wifi_set_ps( WIFI_PS_NONE ) );
wifi_config_t wifi_config =
{
.ap =
{
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
.authmode = WIFI_AUTH_WPA2_PSK,
// .channel = 11,
.max_connection = 2,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.ap.ssid);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
#else
wifi_config_t wifi_config =
{
.sta =
{
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
#endif
ESP_ERROR_CHECK(esp_wifi_start());
// dns_server_start(); ---- TODO FIXIT need to figure out how to make DNS hijack work
(void) start_webserver();
}
void app_main()
{
static httpd_handle_t server = NULL;
ESP_ERROR_CHECK(nvs_flash_init());
init_wifi_and_httpd(&server);
}
At the top of the file you'll see the #define CONFIGURE_AS_SOFT_AP. If you set this to 1, the ESP32 will establish a hotspot with the login credentials below. If you set it to 0, it will attempt to connect to your hotspot using whatever login credentials you set up with "make menuconfig"
With this very simple index.html, I'm able to catch and decode things posted with the dropdown menu. I've kinda been doing this whole thing from the bottom up, and my next step was to figure out how to catch and decode a big file, and if I could figure that out, then figure out what I need to do to write those file chunks to flash and then finally figure out how to get the bootloader to launch into that code at the next reboot instead of what's currently running (i.e. ping pong bootloader).
But when the incoming file gets to be a certain size, the http server crashes before I can even take a look at whats being sent. And in the course of testing this stripped down version, I just realized that when configured as a Soft AP, it can accept much larger files before it crashes. Earlier today I had been testing my actual app with the esp32 logging into my home network just because that's a lot faster and easier. When set up in station mode it chokes on pretty small files. So that's a little mystery. But in any event, there is a point where when you try to upload a large enough file, the http server barfs on the html header with this message:
W (47506) httpd_parse: parse_block: response uri/header too big
W (47506) httpd_txrx: httpd_resp_send_err: 500 Server Error - Server has encountered an unexpected error
Once that happens, only a hard reboot recovers.