In my app I have simple webserver, which get measure from few ESP8266 and then send it to thingspeak. Everything works fine when I don't use task and after accept I call function which handle with request, but when I use task and after accept I create task which handle with request, I get Corrupt heap error.
Code: Select all
CORRUPT HEAP: multi_heap.c:395 detected at 0x3ffbf968
abort() was called at PC 0x40086955 on core 1
0x40086955: multi_heap_assert at C:/esp/msys32/esp/esp-idf/components/heap/multi_heap.c:615 (discriminator 1)
(inlined by) multi_heap_free_impl at C:/esp/msys32/esp/esp-idf/components/heap/multi_heap.c:395 (discriminator 1)
Backtrace: 0x40086f10:0x3ffc2f90 0x4008700f:0x3ffc2fb0 0x40086955:0x3ffc2fd0 0x4008285e:0x3ffc2ff0 0x40082c95:0x3ffc3010 0x4000bec7:
0x3ffc3030 0x400f43b9:0x3ffc3050 0x400f447b:0x3ffc3070 0x4011cae6:0x3ffc3090 0x4011d8cf:0x3ffc30c0 0x400fae31:0x3ffc30e0
0x40086f10: invoke_abort at C:/esp/msys32/esp/esp-idf/components/esp32/panic.c:553
0x4008700f: abort at C:/esp/msys32/esp/esp-idf/components/esp32/panic.c:553
0x40086955: multi_heap_assert at C:/esp/msys32/esp/esp-idf/components/heap/multi_heap.c:615 (discriminator 1)
(inlined by) multi_heap_free_impl at C:/esp/msys32/esp/esp-idf/components/heap/multi_heap.c:395 (discriminator 1)
0x4008285e: heap_caps_free at C:/esp/msys32/esp/esp-idf/components/heap/heap_caps.c:190
0x40082c95: _free_r at C:/esp/msys32/esp/esp-idf/components/newlib/syscalls.c:42
0x400f43b9: tcp_close_shutdown at C:/esp/msys32/esp/esp-idf/components/lwip/core/tcp.c:1641
0x400f447b: tcp_close at C:/esp/msys32/esp/esp-idf/components/lwip/core/tcp.c:1641
0x4011cae6: lwip_netconn_do_close_internal at C:/esp/msys32/esp/esp-idf/components/lwip/api/api_msg.c:1740 (discriminator 6)
0x4011d8cf: lwip_netconn_do_close at C:/esp/msys32/esp/esp-idf/components/lwip/api/api_msg.c:1806
0x400fae31: tcpip_thread at C:/esp/msys32/esp/esp-idf/components/lwip/api/tcpip.c:474
Code: Select all
#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "freertos/portmacro.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "tcpip_adapter.h"
#include "lwip/priv/api_msg.h"
#include "lwip/sockets.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/api.h"
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/netbuf.h"
#include "lwip/netifapi.h"
#include "lwip/pppapi.h"
#include "string.h"
#include "cJSON.h"
#define LWIP_NETCONN_FULLDUPLEX 1
#define LWIP_NETCONN_SEM_PER_THREAD 1
#define LWIP_TCPIP_TIMEOUT 1
#define WEB_SERVER "api.thingspeak.com"
#define WEB_PORT 80
static const char WEB_URL_1[] = "GET https://api.thingspeak.com/update?api_key=";
static const char *TAG = "example";
static const char REQUEST[] = "HTTP/1.0\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
SemaphoreHandle_t taskSemaphore = NULL;
char* json_unformatted;
static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
//static char* TAG = "app_main";
bool sta_is_configured = false;
char* ssid;
char* pwd;
struct connection
{
struct netconn conn;
bool available;
};
struct connection conn_array[5];
struct channel
{
char name[80];
char data_str[80];
int data_int;
char api[80];
};
struct channel channel_list[10];
#define delay(ms) (vTaskDelay(ms/portTICK_RATE_MS))
char* json_unformatted;
const static char http_html_hdr[] =
"HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
const static char http_index_hml[] = "<!DOCTYPE html>"
"<html>\n"
"<head>\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
" <style type=\"text/css\">\n"
" html, body, iframe { margin: 0; padding: 0; height: 100%; }\n"
" iframe { display: block; width: 100%; border: none; }\n"
" </style>\n"
"<title>HELLO ESP32</title>\n"
"</head>\n"
"<body>\n"
"<h1>Hello World, from ESP32!</h1>\n"
"</body>\n"
"</html>\n";
char http_index_hml_sta_config[] = "<!DOCTYPE html>"
"<html>\n"
"<head>\n"
"<title>HELLO ESP32</title>\n"
"</head>\n"
"<body>\n"
"<h1>Hello World, from ESP32!</h1>\n"
"<form name=\"myForm\" onsubmit=\"sendForm(); return false;\">\n"
"SSID:<br><input type=\"text\" name=\"ssid\" value=\"\"><br>\n"
"PASS:<br><input type=\"text\" name=\"pass\" value=\"\"><br>\n"
"<input type=\"submit\" value=\"Zapisz\">\n"
"</form><br>\n"
"<script>\n"
"function sendForm() {\n"
"var x = document.forms[\"myForm\"][\"ssid\"].value;\n"
"var y = document.forms[\"myForm\"][\"pass\"].value;\n"
"var xhttp = new XMLHttpRequest();\n"
"xhttp.onreadystatechange = function() {\n"
"if (this.readyState == 4 && this.status == 200) {\n"
"location.reload(true);\n"
"}\n"
"};\n"
"var url = \"?ssid=\"+x+\"&pass=\"+y;\n"
"xhttp.open(\"GET\", url, true);\n"
"xhttp.send();\n"
"document.forms[\"myForm\"].reset()};\n"
"</script>\n"
"</body>\n"
"</html>\n";
char http_index_hml_tmp[] = "<!DOCTYPE html>"
"<html style=\"height: 100%;\">\n"
"<body style=\"color:white; background:linear-gradient(141deg, #0fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);\">\n"
"<title>HELLO ESP32</title>\n"
"</head>\n"
"<body>\n"
"<h1>Hello World, from ESP32!</h1>\n"
"<form name=\"myForm\" onsubmit=\"sendForm(); return false;\">\n"
"Kanal:<br><input type=\"text\" name=\"channel_add\" value=\"\"><br>\n"
"Api:<br><input type=\"text\" name=\"api\" value=\"\"><br>\n"
"<input type=\"submit\" value=\"Dodaj kanal\">\n"
"</form><br>\n"
"<div style=\"float: left; width: 15%;\">\n"
"Kanal:\n"
"<ul id = \"channel\"> </ul>\n"
"</div>\n"
"<div style=\"float: left; width: 15%;\">\n"
"Pomiary:\n"
"<ul id = \"data\" style=\"list-style: none;\"> </ul>\n"
"</div>\n"
"<div style=\"float: left; width: 15%;\">\n"
"Usun kanal:\n"
"<ul id = \"delete_ch\" style=\"list-style: none;\"> </ul>\n"
"</div>\n"
"<script>\n"
"function jsonreq(){\n"
"var xhttp = new XMLHttpRequest();\n"
"xhttp.onreadystatechange = function() {\n"
"if (this.readyState == 4 && this.status == 200) {\n"
"obj = JSON.parse(this.responseText);\n"
"var outleft = \"\";\n"
"var outright = \"\";\n"
"var delete_ch = \"\";\n"
"var i;\n"
"for(i = 0; i < obj.length; i++) {\n"
"outleft += \"<li>\"+obj[i].Name +\"</li>\";\n"
"outright += \"<li>\"+obj[i].Data +\" \"+\"</li>\";\n"
"delete_ch += \"<li><button type=\\\"button\\\" onclick =\\\"deleteCh(this); return false;\\\" id=\\\"\"+obj[i].Name+\"\\\">Usun</button></li>\";\n"
"}\n"
"document.getElementById(\"channel\").innerHTML = outleft;\n"
"document.getElementById(\"data\").innerHTML = outright;\n"
"document.getElementById(\"delete_ch\").innerHTML = delete_ch;\n"
" }\n };\n"
"xhttp.open(\"GET\", \"&\", true);\n"
"xhttp.send();\n };"
"function deleteCh(elem) {\n"
"var x = elem.id\n"
"var xhttp = new XMLHttpRequest();\n"
"var url = \"?channel_del=\"+x\n"
"xhttp.onreadystatechange = function() {\n"
"if (this.readyState == 4 && this.status == 200) {\n"
"jsonreq();}}\n"
"xhttp.open(\"GET\", url, true);\n"
"xhttp.send();\n"
"};\n"
"function sendForm() {\n"
"var x = document.forms[\"myForm\"][\"channel_add\"].value;\n"
"var y = document.forms[\"myForm\"][\"api\"].value;\n"
"var xhttp = new XMLHttpRequest();\n"
"var url = \"?channel_add=\"+x+\"&api=\"+y;\n"
"document.forms[\"myForm\"].reset()\n"
"xhttp.onreadystatechange = function() {\n"
"if (this.readyState == 4 && this.status == 200) {\n"
"jsonreq(); }}\n"
"xhttp.open(\"GET\", url, true);\n"
"xhttp.send();\n"
"};\n"
"setInterval(jsonreq,10000);\n"
"</script>\n </body>\n </html>\n";
static void generate_json() {
cJSON *root, *d;
root = cJSON_CreateArray();
for(int i = 0;i<10;i++)
{
if(channel_list[i].name[0] != 0)
{
cJSON_AddItemToArray(root, d = cJSON_CreateObject());
cJSON_AddStringToObject(d, "Name", channel_list[i].name);
cJSON_AddStringToObject(d, "Data", channel_list[i].data_str);
}
}
json_unformatted = cJSON_PrintUnformatted(root);
printf("[len = %d] ", strlen(json_unformatted));
printf("%s\n", json_unformatted);
}
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
printf("got ip\n");
printf("ip: " IPSTR "\n", IP2STR(&event->event_info.got_ip.ip_info.ip));
printf("netmask: " IPSTR "\n", IP2STR(&event->event_info.got_ip.ip_info.netmask));
printf("gw: " IPSTR "\n", IP2STR(&event->event_info.got_ip.ip_info.gw));
printf("\n");
fflush(stdout);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
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) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_AP) );
wifi_config_t ap_config =
{
.ap =
{
.ssid = "czesc",
.password = "12345678",
.authmode = WIFI_AUTH_WPA_WPA2_PSK,
.ssid_len = 0,
.beacon_interval = 400,
.max_connection = 16,
}
};
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, &ap_config) );
//
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void wifi_apsta_start()
{
ESP_ERROR_CHECK( esp_wifi_stop() );
esp_wifi_deinit();
wifi_config_t ap_config =
{
.ap =
{
.ssid = "czesc",
.password = "12345678",
.authmode = WIFI_AUTH_WPA_WPA2_PSK,
.ssid_len = 0,
.max_connection = 16,
}
};
wifi_config_t sta_config =
{
.sta =
{
.ssid = "",
.password = "",
.bssid_set = false,
}
};
printf("ruraj123\n");
strcpy(&sta_config.sta.ssid,ssid);
strcpy(&sta_config.sta.password,pwd);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
printf("tutaj12\n");
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, &ap_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void http_get_task(int id)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
int s, r;
char recv_buf[64];
char request[256];
strcpy(request,WEB_URL_1);
strcat(request,channel_list[id].api);
strcat(request,"&field1=");
strcat(request,channel_list[id].data_str);
strcat(request,REQUEST);
while(1) {
/* Wait for the callback to set the CONNECTED_BIT in the
event group.
*/
int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
s = socket(res->ai_family, res->ai_socktype, 0);
if(s < 0) {
ESP_LOGE(TAG, "... Failed to allocate socket.");
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... allocated socket");
if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... connected");
freeaddrinfo(res);
if (write(s, request, strlen(request)) < 0) {
ESP_LOGE(TAG, "... socket send failed");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... socket send success");
struct timeval receiving_timeout;
receiving_timeout.tv_sec = 5;
receiving_timeout.tv_usec = 0;
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
sizeof(receiving_timeout)) < 0) {
ESP_LOGE(TAG, "... failed to set socket receiving timeout");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... set socket receiving timeout success");
/* Read HTTP response */
close(s);
break;
}
vTaskDelete(NULL);
}
static void
http_server_netconn_serve(struct netconn* newconn)
{
struct netconn conn_temp = *newconn;
struct netconn* conn = &conn_temp;
printf("%d\n", esp_get_free_heap_size());
struct netbuf *inbuf;
char *buf;
u16_t buflen;
char* buf_temp = malloc(sizeof(char)*80);
char* ChannelToAddMeasure = malloc(sizeof(char)*80);
/* Read the data from the port, blocking if nothing yet there.
We assume the request (the part we care about) is in one netbuf */
netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY);
if (netconn_recv(conn, &inbuf) == ERR_OK) {
netbuf_data(inbuf,(void**)&buf,&buflen);
/* Is this an HTTP GET command? (only check the first 5 chars, since
there are other formats for GET, and we're keeping it very simple )*/
printf("buffer = %s \n", buf);
printf("buflen = %d\n", buflen);
if (buflen>=5 && buf[0]=='G' && buf[1]=='E' && buf[2]=='T' && buf[3]==' ' && buf[4]=='/' && buf[5]=='&' )
{
generate_json();
printf("po funkcji\n");
netconn_write(conn, json_unformatted, strlen(json_unformatted), NETCONN_NOCOPY);
free(json_unformatted);
printf("po write\n");
printf("po free\n");
}
else if (buflen>=5 && buf[0]=='G' && buf[1]=='E' && buf[2]=='T' && buf[3]==' ' && buf[4]=='/' && buf[5]=='!' )
{
int HTTP_pos=6;
int measure_pos=0;
int liczba;
int ChannelToAddMeasurePos=0;
memset(buf_temp,0,sizeof(char)*80);
memset(ChannelToAddMeasure,0,sizeof(char)*80);
printf("tutaj\n");
while(buf[HTTP_pos]!='H')
{
HTTP_pos+=1;
}
printf("tutaj1\n");
strncpy(buf_temp,strstr(buf,"channel_add=")+sizeof(char)*12,sizeof(char)*(HTTP_pos-19));
printf("%s\n", buf_temp);
printf("tutaj2\n");
while(buf_temp[measure_pos]!=':')
{
measure_pos+=1;
}
strncpy(ChannelToAddMeasure,buf_temp,sizeof(char)*measure_pos);
printf("%s\n",ChannelToAddMeasure);
while(strcmp(channel_list[ChannelToAddMeasurePos].name,ChannelToAddMeasure)!=0)
{
ChannelToAddMeasurePos+=1;
if(ChannelToAddMeasurePos>10)
{
break;
}
}
if(ChannelToAddMeasurePos<10)
{
strcpy(ChannelToAddMeasure,buf_temp+measure_pos+1);
printf("%s\n", ChannelToAddMeasure);
liczba = strtol(ChannelToAddMeasure,NULL,10);
printf("liczba= %d\n", liczba-1);
strcpy(channel_list[ChannelToAddMeasurePos].data_str,ChannelToAddMeasure);
xTaskCreate(&http_get_task, "http_get_task", 4096, ChannelToAddMeasurePos, 1, NULL);
}
}
else if (buflen>=5 && buf[0]=='G' && buf[1]=='E' && buf[2]=='T' && buf[3]==' ' && buf[4]=='/' && buf[5]=='?' && sta_is_configured) {
int and_pos=6;
int HTTP_pos=6;
int FemptyPos=0;
memset(buf_temp,0,sizeof(char)*80);
printf("tutaj\n");
if(strstr(buf,"channel_add=") != NULL)
{
while(buf[and_pos] != '&')
{
and_pos+=1;
}
while(buf[HTTP_pos] != 'H')
{
HTTP_pos+=1;
}
strncpy(buf_temp,strstr(buf,"channel_add=")+sizeof(char)*12,sizeof(char)*(and_pos-18));
while(channel_list[FemptyPos].name[0] != 0 && strcmp(channel_list[FemptyPos].name,buf_temp) != 0)
{
FemptyPos+=1;
}
printf("slowo = %s\n", buf_temp);
printf("%d\n", FemptyPos);
strcpy(channel_list[FemptyPos].name ,buf_temp);
strncpy(channel_list[FemptyPos].api,strstr(buf,"api=")+sizeof(char)*4,sizeof(char)*(HTTP_pos-(and_pos+6)));
for(int k = 0;k<=FemptyPos;k++)
{
printf("%s\n",channel_list[k].name );
printf("%s\n",channel_list[k].api );
}
}
else if(strstr(buf,"channel_del=") != NULL)
{
printf("Jestem tutaj \n");
while(buf[HTTP_pos] != 'H')
{
HTTP_pos+=1;
}
strncpy(buf_temp,strstr(buf,"channel_del=")+sizeof(char)*12,sizeof(char)*(HTTP_pos-19));
printf("buffer %s\n", buf_temp);
while(strcmp(channel_list[FemptyPos].name,buf_temp) != 0)
{
FemptyPos+=1;
if(FemptyPos > 10)
{
break;
}
}
if(FemptyPos<10){
printf("slowo = %s\n", buf_temp);
printf("%d\n", FemptyPos);
memset(channel_list[FemptyPos].name,0,80);
memset(channel_list[FemptyPos].api,0,80);
netconn_write(conn, "usunieto", 8, NETCONN_NOCOPY);
}
}
}
else if (buflen>=5 && buf[0]=='G' && buf[1]=='E' && buf[2]=='T' && buf[3]==' ' && buf[4]=='/' && buf[5]=='?' && !sta_is_configured) {
int and_pos=6;
printf("tutaj");
int HTTP_pos = 0;
ssid = malloc(sizeof(char)*80);
pwd = malloc(sizeof(char)*80);
memset(ssid,0,sizeof(char)*80);
memset(pwd,0,sizeof(char)*80);
while(buf[and_pos] != '&')
{
and_pos+=1;
}
printf("tutaj1");
strncpy(ssid,strstr(buf,"ssid=")+sizeof(char)*5,sizeof(char)*(and_pos-11));
while(buf[HTTP_pos] != 'H')
{
HTTP_pos+=1;
}
printf("tutaj2");
strncpy(pwd,strstr(buf,"pass=")+sizeof(char)*5,sizeof(char)*(HTTP_pos-(and_pos+7)));
printf("ssid= %s\n", ssid);
printf("haslo= %s\n",pwd );
sta_is_configured = true;
wifi_apsta_start();
printf("po apppp\n");
free(ssid);
free(pwd);
}
else
{
if(!sta_is_configured) {netconn_write(conn, http_index_hml_sta_config, sizeof(http_index_hml_sta_config)-1, NETCONN_NOCOPY);}
else {netconn_write(conn, http_index_hml_tmp, sizeof(http_index_hml_tmp)-1, NETCONN_NOCOPY);}
}
}
printf("Przed close\n");
err_t err1;
// Close the connection (server closes in HTTP)
err1 = netconn_close(conn);
printf("Po close, err = %d\n",err1);
err1 = netconn_delete(conn);
printf("Po delete, err = %d\n",err1);
/* Delete the buffer (netconn_recv gives us ownership,
so we have to make sure to deallocate the buffer) */
//free(inbuf);
//netbuf_free(inbuf);
netbuf_delete(inbuf);
free(buf_temp);
free(ChannelToAddMeasure);
printf("%d\n", esp_get_free_heap_size());
vTaskDelete(NULL);
}
static void http_server(void *pvParameters)
{
struct netconn *conn, *newconn;
taskSemaphore = xSemaphoreCreateMutex();
err_t err;
conn = netconn_new(NETCONN_TCP);
netconn_bind(conn, NULL, 80);
netconn_listen(conn);
do {
err = netconn_accept(conn,&newconn);
newconn->recv_timeout = 100;
xTaskCreate(&http_server_netconn_serve,"http_server_netconn_serve",4096,newconn,5,NULL);
//free(newconn);
} while(err == ERR_OK);
netconn_close(conn);
netconn_delete(conn);
vTaskDelete(NULL);
}
int app_main(void)
{
nvs_flash_init();
esp_wifi_restore();
initialise_wifi();
for(int i = 0;i<5;i++)
{
conn_array[i].available=true;
}
xTaskCreate(&http_server, "http_server", 4096, NULL, 5, NULL);
return 0;
}
Thanks in advance