Skip to content

Commit 785a046

Browse files
committed
send_P, sendContent_P, and FPSTR
This allows for the content of server response to be stored in flash memory.
1 parent c4667ff commit 785a046

File tree

4 files changed

+99
-26
lines changed

4 files changed

+99
-26
lines changed

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,27 @@ Both ```Serial``` and ```Serial1``` objects support 5, 6, 7, 8 data bits, odd (O
9191

9292
The Program memory features work much the same way as on a regular Arduino; placing read only data and strings in read only memory and freeing heap for your application.
9393
The important difference is that on the esp8266 the literal strings are not pooled. This means that the same literal string defined inside a ```F("")``` and/or ```PSTR("")``` will take up space for each instance in the code. So you will need to manage the duplicate strings yourself.
94+
There is one additional helper macro to make it easier to pass ```const PROGMEM``` strings to methods that take a ```__FlashStringHelper``` called ```FPSTR()```. The use of this will help make it easier to pool strings.
95+
Not pooling strings...
96+
```
97+
String response1;
98+
response1 += F("http:");
99+
...
100+
String response2;
101+
response2 += F("http:");
102+
```
103+
using FPSTR would become...
104+
```
105+
const char HTTP[] PROGMEM = "http:";
106+
...
107+
{
108+
String response1;
109+
response1 += FPSTR(HTTP);
110+
...
111+
String response2;
112+
response2 += FPSTR(HTTP);
113+
}
114+
```
94115

95116
#### WiFi(ESP8266WiFi library) ####
96117

hardware/esp8266com/esp8266/cores/esp8266/WString.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ class StringSumHelper;
3535
// an abstract class used as a means to proide a unique pointer type
3636
// but really has no body
3737
class __FlashStringHelper;
38-
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
39-
38+
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
39+
#define F(string_literal) (FPSTR(PSTR(string_literal)))
4040

4141
// The string class
4242
class String {

hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp

+72-23
Original file line numberDiff line numberDiff line change
@@ -129,30 +129,51 @@ void ESP8266WebServer::sendHeader(const String& name, const String& value, bool
129129
}
130130
}
131131

132+
133+
void ESP8266WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
134+
response = "HTTP/1.1 ";
135+
response += String(code);
136+
response += " ";
137+
response += _responseCodeToString(code);
138+
response += "\r\n";
139+
140+
if (!content_type)
141+
content_type = "text/html";
142+
143+
sendHeader("Content-Type", content_type, true);
144+
if (_contentLength != CONTENT_LENGTH_UNKNOWN && _contentLength != CONTENT_LENGTH_NOT_SET) {
145+
sendHeader("Content-Length", String(_contentLength).c_str());
146+
}
147+
else if (contentLength > 0){
148+
sendHeader("Content-Length", String(contentLength).c_str());
149+
}
150+
sendHeader("Connection", "close");
151+
sendHeader("Access-Control-Allow-Origin", "*");
152+
153+
response += _responseHeaders;
154+
response += "\r\n";
155+
_responseHeaders = String();
156+
}
157+
132158
void ESP8266WebServer::send(int code, const char* content_type, const String& content) {
133-
String response = "HTTP/1.1 ";
134-
response += String(code);
135-
response += " ";
136-
response += _responseCodeToString(code);
137-
response += "\r\n";
138-
139-
if (!content_type)
140-
content_type = "text/html";
141-
142-
sendHeader("Content-Type", content_type, true);
143-
if (_contentLength != CONTENT_LENGTH_UNKNOWN && _contentLength != CONTENT_LENGTH_NOT_SET) {
144-
sendHeader("Content-Length", String(_contentLength).c_str());
145-
} else if(content.length() > 0){
146-
sendHeader("Content-Length", String(content.length()).c_str());
147-
}
148-
sendHeader("Connection", "close");
149-
sendHeader("Access-Control-Allow-Origin", "*");
150-
151-
response += _responseHeaders;
152-
response += "\r\n";
153-
response += content;
154-
_responseHeaders = String();
155-
sendContent(response);
159+
String header;
160+
_prepareHeader(header, code, content_type, content.length());
161+
sendContent(header);
162+
163+
sendContent(content);
164+
}
165+
166+
void ESP8266WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
167+
size_t contentLength = 0;
168+
169+
if (content != NULL) {
170+
contentLength = strlen_P(content);
171+
}
172+
173+
String header;
174+
_prepareHeader(header, code, String(FPSTR(content_type)).c_str(), contentLength);
175+
sendContent(header);
176+
sendContent_P(content);
156177
}
157178

158179
void ESP8266WebServer::send(int code, char* content_type, const String& content) {
@@ -178,6 +199,34 @@ void ESP8266WebServer::sendContent(const String& content) {
178199
}
179200
}
180201

202+
void ESP8266WebServer::sendContent_P(PGM_P content) {
203+
char contentUnit[HTTP_DOWNLOAD_UNIT_SIZE + 1];
204+
205+
contentUnit[HTTP_DOWNLOAD_UNIT_SIZE] = '\0';
206+
207+
while (content != NULL) {
208+
size_t contentUnitLen;
209+
PGM_P contentNext;
210+
211+
// due to the memccpy signature, lots of casts are needed
212+
contentNext = (PGM_P)memccpy_P((void*)contentUnit, (PGM_VOID_P)content, 0, HTTP_DOWNLOAD_UNIT_SIZE);
213+
214+
if (contentNext == NULL) {
215+
// no terminator, more data available
216+
content += HTTP_DOWNLOAD_UNIT_SIZE;
217+
contentUnitLen = HTTP_DOWNLOAD_UNIT_SIZE;
218+
}
219+
else {
220+
// reached terminator
221+
contentUnitLen = contentNext - content;
222+
content = NULL;
223+
}
224+
225+
// write is so overloaded, had to use the cast to get it pick the right one
226+
_currentClient.write((const char*)contentUnit, contentUnitLen);
227+
}
228+
}
229+
181230
String ESP8266WebServer::arg(const char* name) {
182231
for (int i = 0; i < _currentArgCount; ++i) {
183232
if (_currentArgs[i].key == name)

hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ class ESP8266WebServer
8080
void send(int code, const char* content_type = NULL, const String& content = String(""));
8181
void send(int code, char* content_type, const String& content);
8282
void send(int code, const String& content_type, const String& content);
83+
void send_P(int code, PGM_P content_type, PGM_P content);
8384

8485
void setContentLength(size_t contentLength) { _contentLength = contentLength; }
8586
void sendHeader(const String& name, const String& value, bool first = false);
8687
void sendContent(const String& content);
88+
void sendContent_P(PGM_P content);
8789

8890
template<typename T> size_t streamFile(T &file, const String& contentType){
8991
setContentLength(file.size());
@@ -104,7 +106,8 @@ template<typename T> size_t streamFile(T &file, const String& contentType){
104106
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
105107
void _uploadWriteByte(uint8_t b);
106108
uint8_t _uploadReadByte(WiFiClient& client);
107-
109+
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
110+
108111
struct RequestHandler;
109112
struct RequestArgument {
110113
String key;

0 commit comments

Comments
 (0)