Skip to content

Instantly share code, notes, and snippets.

@bblanchon
Forked from sticilface/ESP_asyncJSON.ino
Created January 26, 2016 12:40
Show Gist options
  • Save bblanchon/6fa7f275cb8438ca62e9 to your computer and use it in GitHub Desktop.
Save bblanchon/6fa7f275cb8438ca62e9 to your computer and use it in GitHub Desktop.
demonstrates crash with large JSONs
/*
*
* Demonstrates crash using chuncked print and large Json
* Requires
* https://github.com/me-no-dev/ESPAsyncWebServer
* https://github.com/me-no-dev/ESPAsyncTCP
* https://github.com/bblanchon/ArduinoJson
*
* use curl to make request...
* http://ip/json -> Will make request and send results async... causes crash. Works if lines are removed from json.. see addJson function
* http://ip/jsonprint -> sets flag in loop, then prints same json, async to serial. does not crash.
* http://ip/jsonsync -> uses an async method to print json back to client. Called from loop. Not working, not sure why
*/
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
static const char rubbish[] = "abcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefgeabcdefge";
//static const char rubbish[] = "abcdefgeabcdefgeabcde";
const char* ssid = "xx";
const char* password = "xx";
AsyncWebServerRequest *client = nullptr;
/*
* Json Response
* */
class AsyncJsonResponse: public AsyncAbstractResponse
{
private:
DynamicJsonBuffer _jsonBuffer;
JsonVariant _root;
bool _isValid;
class ChunkPrint : public Print
{
public:
ChunkPrint(uint8_t* destination, size_t from, size_t to)
: _destination(destination), _to_skip(from), _to_write(to - from), _pos{0} {}
size_t write(uint8_t c)
{
if (_to_skip > 0) {
_to_skip--;
} else if (_to_write > 0) {
_to_write--;
_destination[_pos++] = c;
return 1;
}
return 0;
}
private:
uint8_t* _destination;
size_t _to_skip;
size_t _to_write;
size_t _pos;
};
public:
AsyncJsonResponse() : _isValid{false}
{
_code = 200;
_contentType = "text/json";
}
~AsyncJsonResponse() {};
DynamicJsonBuffer & getBuffer() { return _jsonBuffer; }
bool _sourceValid() { return _isValid; }
void SetTarget( JsonVariant root)
{
_root = root;
_contentLength = _root.measureLength();
os_printf("[SetTarget] buffer size = %u\n", _root.size());
if (_contentLength) { _isValid = true; }
}
size_t _fillBuffer(uint8_t *data, size_t len)
{
os_printf("[_fillBuffer] heap = %u\n",ESP.getFreeHeap());
ChunkPrint dest(data, _sentLength, _sentLength + len );
return _root.printTo( dest ) ;
}
};
void addjson(JsonObject& root) {
JsonObject& sub1 = root.createNestedObject("nested1");
JsonObject& test = sub1.createNestedObject("nested2");
JsonArray& array = root.createNestedArray("array");
root["key1"] = rubbish;
sub1["key2"] = rubbish;
sub1["key3"] = rubbish;
sub1["key4"] = rubbish;
sub1["key5"] = rubbish;
sub1["key6"] = rubbish;
sub1["key7"] = rubbish;
sub1["key8"] = rubbish;
sub1["key9"] = rubbish;
sub1["key10"] = rubbish;
sub1["key11"] = rubbish;
sub1["key12"] = rubbish;
sub1["key13"] = rubbish;
sub1["key14"] = rubbish;
sub1["key15"] = rubbish;
sub1["key16"] = rubbish;
sub1["key17"] = rubbish;
sub1["key18"] = rubbish;
sub1["key19"] = rubbish;
sub1["key20"] = rubbish;
sub1["key21"] = rubbish;
sub1["key22"] = rubbish;
sub1["key23"] = rubbish;
sub1["key24"] = rubbish;
sub1["key25"] = rubbish;
sub1["key26"] = rubbish;
sub1["key27"] = rubbish;
sub1["key28"] = rubbish;
sub1["key29"] = rubbish;
test["akey1"] = rubbish;
test["akey2"] = rubbish;
test["akey3"] = rubbish;
test["akey4"] = rubbish;
test["akey5"] = rubbish;
test["akey6"] = rubbish;
test["akey7"] = rubbish;
test["akey8"] = rubbish;
test["akey9"] = rubbish;
test["akey10"] = rubbish;
test["akey11"] = rubbish;
test["akey12"] = rubbish;
//
// test["akey13"] = "straw that broke the camels back";
// test["akey14"] = "straw that broke the camels back";
// test["akey15"] = "straw that broke the camels back";
// test["akey16"] = "straw that broke the camels back";
}
void send_data() {
os_printf("[send_data]\n");
DynamicJsonBuffer buffer;
JsonObject& root = buffer.createObject();
addjson(root);
while (client != NULL) {
Serial.println("[send_data] Send Json");
AsyncResponseStream *stream = client->beginResponseStream("text/json", root.measureLength());
os_printf("[send_Data] root.length() = %u\n", root.measureLength());
root.printTo(*stream);
client = client->next;
}
}
// SKETCH BEGIN
AsyncWebServer HTTP(80);
bool flag = false;
// need these to debug during an inturrupt..
extern "C" void system_set_os_print(uint8 onoff);
extern "C" void ets_install_putc1(void* routine);
//Use the internal hardware buffer
static void _u0_putc(char c){
while(((U0S >> USTXC) & 0x7F) == 0x7F);
U0F = c;
}
void initSerial(){
Serial.begin(115200);
ets_install_putc1((void *) &_u0_putc);
system_set_os_print(1);
}
void setup(){
initSerial();
os_printf("\n\nJSON TEST");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("STA: Failed!\n");
WiFi.disconnect(false);
delay(1000);
WiFi.begin(ssid, password);
}
ArduinoOTA.begin();
ArduinoOTA.setHostname("json");
HTTP.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
Serial.println();
Serial.printf("New Json request: heap = %u\n", ESP.getFreeHeap());
AsyncJsonResponse * response = new AsyncJsonResponse();
DynamicJsonBuffer buffer = response->getBuffer();
JsonObject& root = buffer.createObject();
addjson(root);
response->SetTarget(root);
request->send(response);
});
HTTP.on("/jsonprint", HTTP_ANY, [](AsyncWebServerRequest * request) {
flag = true;
request->send(200);
});
HTTP.on("/jsonsync", HTTP_ANY, [](AsyncWebServerRequest * request) {
if (client == NULL) {
os_printf("[HTTP] client = request\n");
client = request;
} else {
os_printf("[HTTP] client already.... chaining....");
AsyncWebServerRequest *c = client;
while (c->next != NULL) c = c->next;
c->next = request;
}
});
HTTP.begin();
}
void loop(){
ArduinoOTA.handle();
if (flag) {
DynamicJsonBuffer buffer;
JsonObject& root = buffer.createObject();
addjson(root);
root.printTo(Serial);
flag = false;
}
if (client) {
send_data();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment