Skip to content
This repository was archived by the owner on Feb 4, 2023. It is now read-only.

Commit 9f7e380

Browse files
authored
v1.5.0 to save heap when sending large data
#### Releases v1.5.0 1. Support using `CString` to save heap to send `very large data`. Check [request->send(200, textPlainStr, jsonChartDataCharStr); - Without using String Class - to save heap #8](khoih-prog/Portenta_H7_AsyncWebServer#8) and [All memmove() removed - string no longer destroyed #11](khoih-prog/Portenta_H7_AsyncWebServer#11) 2. Add multiple examples to demo the new feature
1 parent b867b25 commit 9f7e380

36 files changed

+2496
-411
lines changed

CONTRIBUTING.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ Arduino IDE version: 1.8.19
3030
ESP8266_NODEMCU_ESP12E using ESP8266_W5500 Ethernet
3131
ESP8266 core v3.0.2
3232
OS: Ubuntu 20.04 LTS
33-
Linux xy-Inspiron-3593 5.13.0-39-generic #44~20.04.1-Ubuntu SMP Thu Mar 24 16:43:35 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
33+
Linux xy-Inspiron-3593 5.15.0-48-generic #54~20.04.1-Ubuntu SMP Thu Sep 1 16:17:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
3434
3535
Context:
36-
I encountered a crash while trying to use the Timer Interrupt.
36+
I encountered a crash while using this library
3737
3838
Steps to reproduce:
3939
1. ...

changelog.md

+6
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,19 @@
1111
## Table of contents
1212

1313
* [Changelog](#changelog)
14+
* [Releases v1.5.0](#releases-v150)
1415
* [Releases v1.4.1](#releases-v141)
1516

1617
---
1718
---
1819

1920
## Changelog
2021

22+
#### Releases v1.5.0
23+
24+
1. Support using `CString` to save heap to send `very large data`. Check [request->send(200, textPlainStr, jsonChartDataCharStr); - Without using String Class - to save heap #8](https://github.com/khoih-prog/Portenta_H7_AsyncWebServer/pull/8) and [All memmove() removed - string no longer destroyed #11](https://github.com/khoih-prog/Portenta_H7_AsyncWebServer/pull/11)
25+
2. Add multiple examples to demo the new feature
26+
2127
#### Releases v1.4.1
2228

2329
1. Initial coding to port [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) to ESP8266 boards using W5x00 / ENC28J60 Ethernet.

examples/Async_AdvancedWebServer/defines.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030

3131
#include <SPI.h>
3232

33-
#define CSPIN 16 // 5
33+
// Using GPIO4, GPIO16, or GPIO5
34+
#define CSPIN 4 //16 // 5
3435

3536
#if USING_W5500
3637
#include "W5500lwIP.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/****************************************************************************************************************************
2+
Async_AdvancedWebServer_MemoryIssues_SendArduinoString.ino
3+
4+
For ESP8266 using W5x00/ENC8266 Ethernet
5+
6+
AsyncWebServer_Ethernet is a library for the Ethernet with lwIP_5100, lwIP_5500 or lwIP_enc28j60 library
7+
8+
Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer)
9+
Built by Khoi Hoang https://github.com/khoih-prog/AsyncWebServer_Ethernet
10+
Licensed under GPLv3 license
11+
12+
Copyright (c) 2015, Majenko Technologies
13+
All rights reserved.
14+
15+
Redistribution and use in source and binary forms, with or without modification,
16+
are permitted provided that the following conditions are met:
17+
18+
Redistributions of source code must retain the above copyright notice, this
19+
list of conditions and the following disclaimer.
20+
21+
Redistributions in binary form must reproduce the above copyright notice, this
22+
list of conditions and the following disclaimer in the documentation and/or
23+
other materials provided with the distribution.
24+
25+
Neither the name of Majenko Technologies nor the names of its
26+
contributors may be used to endorse or promote products derived from
27+
this software without specific prior written permission.
28+
29+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
33+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
36+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39+
*****************************************************************************************************************************/
40+
41+
#include "defines.h"
42+
43+
#include <AsyncWebServer_Ethernet.h>
44+
45+
// In bytes
46+
//#define STRING_SIZE 40000
47+
#define STRING_SIZE 12000
48+
49+
AsyncWebServer server(80);
50+
51+
int reqCount = 0; // number of requests received
52+
53+
#define BUFFER_SIZE 512
54+
char temp[BUFFER_SIZE];
55+
56+
void handleRoot(AsyncWebServerRequest *request)
57+
{
58+
digitalWrite(LED_BUILTIN, LED_ON);
59+
60+
int sec = millis() / 1000;
61+
int min = sec / 60;
62+
int hr = min / 60;
63+
int day = hr / 24;
64+
65+
snprintf(temp, BUFFER_SIZE - 1,
66+
"<html>\
67+
<head>\
68+
<meta http-equiv='refresh' content='5'/>\
69+
<title>AsyncWebServer-%s</title>\
70+
<style>\
71+
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
72+
</style>\
73+
</head>\
74+
<body>\
75+
<h2>AsyncWebServer_Ethernet!</h2>\
76+
<h3>running on %s</h3>\
77+
<p>Uptime: %d d %02d:%02d:%02d</p>\
78+
<img src=\"/test.svg\" />\
79+
</body>\
80+
</html>", BOARD_NAME, SHIELD_TYPE, day, hr % 24, min % 60, sec % 60);
81+
82+
request->send(200, "text/html", temp);
83+
84+
digitalWrite(LED_BUILTIN, LED_OFF);
85+
}
86+
87+
void handleNotFound(AsyncWebServerRequest *request)
88+
{
89+
digitalWrite(LED_BUILTIN, LED_ON);
90+
String message = "File Not Found\n\n";
91+
92+
message += "URI: ";
93+
message += request->url();
94+
message += "\nMethod: ";
95+
message += (request->method() == HTTP_GET) ? "GET" : "POST";
96+
message += "\nArguments: ";
97+
message += request->args();
98+
message += "\n";
99+
100+
for (uint8_t i = 0; i < request->args(); i++)
101+
{
102+
message += " " + request->argName(i) + ": " + request->arg(i) + "\n";
103+
}
104+
105+
request->send(404, "text/plain", message);
106+
digitalWrite(LED_BUILTIN, LED_OFF);
107+
}
108+
109+
void PrintHeapData(String hIn)
110+
{
111+
// cores/esp8266/Esp.cpp
112+
static uint32_t maxFreeHeap = 0xFFFFFFFF;
113+
114+
// Get once at the beginning for comparison only
115+
static uint32_t totalHeap = ESP.getFreeHeap();
116+
117+
uint32_t freeHeap = ESP.getFreeHeap();
118+
119+
// Print and update only when larger heap
120+
if (maxFreeHeap > freeHeap)
121+
{
122+
maxFreeHeap = freeHeap;
123+
124+
Serial.print("\nHEAP DATA - ");
125+
Serial.print(hIn);
126+
127+
Serial.print(" Free heap: ");
128+
Serial.print(freeHeap);
129+
Serial.print(" Used heap: ");
130+
Serial.println(totalHeap - freeHeap);
131+
}
132+
}
133+
134+
void PrintStringSize(String & out)
135+
{
136+
static uint32_t count = 0;
137+
138+
// Print only when cStr length too large and corrupting memory or every (20 * 5) s
139+
if ( (out.length() >= STRING_SIZE) || (++count > 20) )
140+
{
141+
Serial.print("\nOut String Length=");
142+
Serial.println(out.length());
143+
144+
count = 0;
145+
}
146+
}
147+
148+
void drawGraph(AsyncWebServerRequest *request)
149+
{
150+
String out;
151+
152+
out.reserve(STRING_SIZE);
153+
char temp[70];
154+
155+
out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1810\" height=\"150\">\n";
156+
out += "<rect width=\"1510\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"2\" stroke=\"rgb(0, 0, 0)\" />\n";
157+
out += "<g stroke=\"blue\">\n";
158+
int y = rand() % 130;
159+
160+
for (int x = 10; x < 1500; x += 10)
161+
{
162+
int y2 = rand() % 130;
163+
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"2\" />\n", x, 140 - y, x + 10, 140 - y2);
164+
out += temp;
165+
y = y2;
166+
}
167+
168+
out += "</g>\n</svg>\n";
169+
170+
PrintHeapData("Pre Send");
171+
172+
PrintStringSize(out);
173+
174+
request->send(200, "image/svg+xml", out);
175+
176+
PrintHeapData("Post Send");
177+
}
178+
179+
void initEthernet()
180+
{
181+
SPI.begin();
182+
SPI.setClockDivider(SPI_CLOCK_DIV4);
183+
SPI.setBitOrder(MSBFIRST);
184+
SPI.setDataMode(SPI_MODE0);
185+
186+
#if !USING_DHCP
187+
eth.config(localIP, gateway, netMask, gateway);
188+
#endif
189+
190+
eth.setDefault();
191+
192+
if (!eth.begin())
193+
{
194+
Serial.println("No Ethernet hardware ... Stop here");
195+
196+
while (true)
197+
{
198+
delay(1000);
199+
}
200+
}
201+
else
202+
{
203+
Serial.print("Connecting to network : ");
204+
205+
while (!eth.connected())
206+
{
207+
Serial.print(".");
208+
delay(1000);
209+
}
210+
}
211+
212+
Serial.println();
213+
214+
#if USING_DHCP
215+
Serial.print("Ethernet DHCP IP address: ");
216+
#else
217+
Serial.print("Ethernet Static IP address: ");
218+
#endif
219+
220+
Serial.println(eth.localIP());
221+
}
222+
223+
void setup()
224+
{
225+
pinMode(LED_BUILTIN, OUTPUT);
226+
digitalWrite(LED_BUILTIN, LED_OFF);
227+
228+
Serial.begin(115200);
229+
while (!Serial && millis() < 5000);
230+
231+
delay(200);
232+
233+
Serial.print("\nStart Async_AdvancedWebServer_MemoryIssues_SendArduinoString on "); Serial.print(BOARD_NAME);
234+
Serial.print(" with "); Serial.println(SHIELD_TYPE);
235+
Serial.println(ASYNC_WEBSERVER_ETHERNET_VERSION);
236+
237+
PrintHeapData("Start =>");
238+
239+
initEthernet();
240+
241+
///////////////////////////////////
242+
243+
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request)
244+
{
245+
handleRoot(request);
246+
});
247+
248+
server.on("/test.svg", HTTP_GET, [](AsyncWebServerRequest * request)
249+
{
250+
drawGraph(request);
251+
});
252+
253+
server.on("/inline", [](AsyncWebServerRequest * request)
254+
{
255+
request->send(200, "text/plain", "This works as well");
256+
});
257+
258+
server.onNotFound(handleNotFound);
259+
260+
server.begin();
261+
262+
Serial.print(F("HTTP EthernetWebServer is @ IP : "));
263+
Serial.println(eth.localIP());
264+
265+
PrintHeapData("Pre Create Arduino String");
266+
267+
}
268+
269+
void heartBeatPrint()
270+
{
271+
static int num = 1;
272+
273+
Serial.print(F("."));
274+
275+
if (num == 80)
276+
{
277+
Serial.println();
278+
num = 1;
279+
}
280+
else if (num++ % 10 == 0)
281+
{
282+
Serial.print(F(" "));
283+
}
284+
}
285+
286+
void check_status()
287+
{
288+
static unsigned long checkstatus_timeout = 0;
289+
290+
#define STATUS_CHECK_INTERVAL 10000L
291+
292+
// Send status report every STATUS_REPORT_INTERVAL (60) seconds: we don't need to send updates frequently if there is no status change.
293+
if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0))
294+
{
295+
heartBeatPrint();
296+
checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL;
297+
}
298+
}
299+
300+
void loop()
301+
{
302+
check_status();
303+
}

0 commit comments

Comments
 (0)