Me-no-dev wrote:change in between 2.3.0 and 2.4.0-pre is in the regular TCP client, which has nothing to do with Async TCP lib, therefore there should be no change at all.
I see. I thought the change was at a lower level used by both.
This change is kinda mix between async and sync and is causing issues with some libraries and is mixing the loop context with the system context (where async runs).
Since the regular TCP Client is almost blocking to send the data as fast as possible, I'm not surprised by the results. Running async does not force any delay on any other service / loop code running elsewhere.
Results also depend on what is your loop doing,
In these tests, there is nothing else running, so Async is not used at its best for sure.
how busy is your network with others
You mind sharing your test sketches?
I should have done it already, sorry. Here we go:
First, here is my custom version of the "sync" sketch. The main difference compared to the samples is that it's slightly optimized so that very small payloads are included in the same packet as the headers instead of requiring two packets.
It also uses the WifiManager lib so you don't have to hardcode credentials in the sketch.
A sample call is http://<ip>/variable?size=100000
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> // from lib https://github.com/tzapu/WiFiManager
#define LED_PIN 2
// Device name
#define DEVICE_NAME "SpeedTestDemo"
// AP & web servers configuration
#define CLIENT_CONFIG_SSID DEVICE_NAME"_CFG"
#define HTTP_PORT 80
String dummy1460 = "012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
ESP8266WebServer server(HTTP_PORT);
void handleVariable() {
if(server.args() == 0) return server.send(500, "text/plain", "Argument size=xxx is required");
int length = atoi(server.arg(0).c_str());
if(length == 0) return server.send(500, "text/plain", "Wrong size value in parameter");
WiFiClient client = server.client();
String header = "HTTP/1.0 200 OK\r\n";
//header += "Content-Type: text/plain\r\n";
header += "Content-Type: application/octet-stream\r\n";
header += "Content-Length: " + String(length) + "\r\n";
header += "Content-Disposition: attachment; filename=data_" + String(length) + ".dat\r\n";
header += "Connection: close\r\n";
header += "\r\n";
// Prepare 1st packet
long start=millis();
//Serial.println("Preparing first packet...");
String packet = header;
int remain = length;
while(remain > 0) {
int alreadyUsed = packet.length();
if (alreadyUsed + remain <= 1460) {
// remaining payload fits.
packet += dummy1460.substring(0, remain);
remain = 0;
}
else {
// remaining payload doesn't fit
packet += dummy1460.substring(0, 1460-alreadyUsed);
remain -= (1460-alreadyUsed);
}
//Serial.println(String("P= ") + packet.length() + ". R=" + remain);
client.write(packet.c_str(), packet.length());
packet = "";
}
long total=millis()-start;
Serial.println(String(length) + " bytes payload sent in " + total + "ms or " + (8000 * length)/total + "bps");
}
// *******************************************
// Main
// *******************************************
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.print("\n");
delay(1);
//WiFiManager
Serial.println();
Serial.println("Initializing Wi-Fi");
digitalWrite(LED_PIN, LOW); // Turn led ON by making voltage LOW to indicate start of wifi setup
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//fetches ssid and pass from eeprom and tries to connect
//if it does not connect it starts an access point with the specified name
//and goes into a blocking loop awaiting configuration
wifiManager.autoConnect(CLIENT_CONFIG_SSID);
//if you get here you have connected to the WiFi
Serial.println("Connected.");
digitalWrite(LED_PIN, HIGH); // Turn the LED off by making the voltage HIGH to indicate end of wifi setup
//////////////////////////
//SERVER INIT
server.on("/", [](){
server.send(200, "text/html", "<html><body>Follow <a href='/variable?size=1000'>/variable?size=xxx</a> to generate data</body></html>");
});
server.on("/variable", handleVariable);
//called when the url is not defined here
server.onNotFound([](){
server.send(404, "text/plain", "FileNotFound");
});
server.begin();
Serial.println("HTTP server started");
Serial.print("Ready. Please direct your browser to: http://");
Serial.println(WiFi.localIP());
}
void loop() {
// Respond to HTTP requests
server.handleClient();
}
And here is my sketch to test the AsyncWebServer. It's based on the Async FSBrowser sample where I added a handler for the "/variable" URL.
Please note that I couldn't use the WifiManager lib here due to a conflict (redefinition of HTTP_ANY etc due to the inclusion of ESPWebServer in WifiManager I guess). So credentials must be hardcoded in the sketch below.
It responds to the same URL
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <FS.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
const char* ssid = "********* ";
const char* password = "*********";
// WEB HANDLER IMPLEMENTATION
//File: edit.htm.gz, Size: 4143
#define edit_htm_gz_len 4143
const uint8_t edit_htm_gz[] PROGMEM = {
0x1F, 0x8B, 0x08, 0x08, 0xAE, 0x92, 0x90, 0x57, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68,
0x74, 0x6D, 0x00, 0xCD, 0x1B, 0x7B, 0x5F, 0xDB, 0xC8, 0xF1, 0x7F, 0x3E, 0x85, 0x4E, 0x69, 0x6B,
0xB9, 0x7E, 0x13, 0xC2, 0x25, 0x06, 0x93, 0xDA, 0xC6, 0x04, 0xC2, 0x1B, 0xDB, 0xC9, 0x41, 0x4A,
0xFB, 0x5B, 0x4B, 0x6B, 0x5B, 0xA0, 0xD7, 0x49, 0x32, 0x36, 0x49, 0xF9, 0xEE, 0x9D, 0xD9, 0x5D,
0x49, 0x2B, 0x59, 0x76, 0x20, 0x77, 0xD7, 0x5E, 0x1E, 0x48, 0xDA, 0x9D, 0x99, 0x9D, 0xD7, 0xCE,
0xCC, 0x3E, 0xD8, 0xFD, 0x69, 0xFF, 0xBC, 0x3B, 0xB8, 0xBE, 0xE8, 0x29, 0xD3, 0xD0, 0xB6, 0xF6,
0x36, 0x76, 0xF1, 0xA1, 0x58, 0xC4, 0x99, 0xB4, 0x54, 0xEA, 0xA8, 0xD8, 0x40, 0x89, 0x01, 0x8F,
0xD0, 0x0C, 0x2D, 0xBA, 0xD7, 0xEB, 0x5F, 0x28, 0x3D, 0xC3, 0x0C, 0x5D, 0x7F, 0xB7, 0xC6, 0x5B,
0x36, 0x76, 0x83, 0xF0, 0xD1, 0xA2, 0x4A, 0xF8, 0xE8, 0xD1, 0x96, 0x1A, 0xD2, 0x45, 0x58, 0xD3,
0x83, 0x40, 0x55, 0x6C, 0x6A, 0x98, 0xA4, 0xA5, 0x06, 0xBA, 0x4F, 0x19, 0x9D, 0xAA, 0x6E, 0x2B,
0xDF, 0x36, 0x14, 0xE5, 0x6B, 0xC5, 0x74, 0x0C, 0xBA, 0x68, 0x2A, 0xAF, 0xEB, 0xF5, 0x1D, 0xF8,
0xF6, 0xDC, 0xC0, 0x0C, 0x4D, 0xD7, 0x69, 0x2A, 0x64, 0x14, 0xB8, 0xD6, 0x2C, 0xA4, 0xD8, 0x6A,
0xD1, 0x71, 0xD8, 0x54, 0xDE, 0x78, 0x0B, 0xFC, 0x18, 0xB9, 0xBE, 0x41, 0xFD, 0xA6, 0xD2, 0xF0,
0x16, 0x0A, 0x80, 0x98, 0x86, 0xF2, 0x6A, 0x6B, 0x6B, 0x8B, 0xF5, 0x10, 0xFD, 0x7E, 0xE2, 0xBB,
0x33, 0xC7, 0xA8, 0xE8, 0xAE, 0xE5, 0x02, 0xCC, 0xAB, 0x83, 0x37, 0xF8, 0x17, 0x3B, 0x0D, 0x33,
0xF0, 0x2C, 0xF2, 0xD8, 0x54, 0x1C, 0xD7, 0xA1, 0x9C, 0xCE, 0xA2, 0x12, 0x4C, 0x89, 0xE1, 0xCE,
0x9B, 0x4A, 0x1D, 0xFE, 0x36, 0xEA, 0x40, 0xD0, 0x9F, 0x8C, 0x88, 0xA6, 0xD4, 0xCB, 0xE2, 0x5F,
0x75, 0x4B, 0x29, 0x22, 0xEC, 0xD8, 0x75, 0xC2, 0x4A, 0x60, 0x7E, 0xA5, 0x30, 0xEC, 0x26, 0x67,
0x83, 0x35, 0x8D, 0x89, 0x6D, 0x5A, 0x40, 0x33, 0x20, 0x4E, 0x50, 0x09, 0xA8, 0x6F, 0x8E, 0xE3,
0xAE, 0x39, 0x35, 0x27, 0xD3, 0xB0, 0x39, 0x72, 0x2D, 0x63, 0x67, 0xE3, 0x89, 0x09, 0x3C, 0xB3,
0x98, 0xCC, 0x96, 0x19, 0x00, 0x31, 0x54, 0x53, 0xC2, 0x4C, 0xE8, 0x7A, 0xC0, 0x45, 0x22, 0x2B,
0x7B, 0xB5, 0x89, 0x3F, 0x31, 0x1D, 0xF1, 0xE1, 0x11, 0xC3, 0x30, 0x9D, 0x09, 0xFB, 0xE2, 0xE4,
0x2C, 0x93, 0x91, 0x4B, 0x54, 0xE6, 0x53, 0x8B, 0x84, 0xE6, 0x03, 0x23, 0x68, 0x9B, 0x4E, 0x65,
0x6E, 0x1A, 0xE1, 0xB4, 0xA9, 0x6C, 0xD7, 0x39, 0xC7, 0xFA, 0xCC, 0x0F, 0x50, 0x29, 0x9E, 0x6B,
0x3A, 0x21, 0xF5, 0x23, 0x32, 0x81, 0x47, 0x1C, 0x46, 0x28, 0xD2, 0x99, 0xD0, 0x66, 0xAC, 0x30,
0xD3, 0xB1, 0x4C, 0x87, 0x56, 0x46, 0x96, 0xAB, 0xDF, 0xA7, 0x38, 0xD9, 0x46, 0xBA, 0x11, 0x2F,
0xCD, 0xA9, 0xFB, 0x40, 0x7D, 0xE5, 0x9B, 0x64, 0x05, 0x41, 0x4B, 0xC9, 0x80, 0xF0, 0x01, 0xE3,
0xE1, 0x7A, 0xBD, 0x1E, 0x03, 0x09, 0x1F, 0x66, 0xA0, 0x21, 0xD0, 0x39, 0xBE, 0x44, 0xB2, 0x49,
0x42, 0x67, 0xF4, 0xB1, 0xAC, 0x45, 0x41, 0xC3, 0x74, 0xBC, 0x59, 0x98, 0xD1, 0x8C, 0xEC, 0x4C,
0xAE, 0x47, 0x74, 0x33, 0x7C, 0x8C, 0x14, 0x89, 0x28, 0xDF, 0x84, 0xD1, 0x90, 0x92, 0x6F, 0x13,
0x8B, 0x19, 0x59, 0xF9, 0x44, 0x7D, 0x83, 0x38, 0xA4, 0xAC, 0xB4, 0x7D, 0x93, 0x00, 0x63, 0xFD,
0x94, 0x91, 0x2B, 0xB6, 0xFB, 0xB5, 0x32, 0x83, 0x4F, 0x68, 0xB2, 0xA8, 0x1E, 0x26, 0xB6, 0x04,
0xD3, 0x8F, 0xEE, 0xCD, 0x30, 0xBF, 0x33, 0xB7, 0x31, 0xA3, 0x79, 0xA6, 0xEE, 0x29, 0xF7, 0x1F,
0xA5, 0x11, 0x69, 0x19, 0x19, 0x8D, 0x6D, 0xC5, 0x55, 0x51, 0x19, 0xB9, 0x61, 0xE8, 0xDA, 0x4D,
0x31, 0x33, 0x12, 0x6D, 0x71, 0x87, 0x7E, 0xBB, 0xC2, 0xEE, 0x6B, 0x6C, 0x9B, 0x1E, 0x55, 0x51,
0xC0, 0x5E, 0xA1, 0xA9, 0x13, 0xAB, 0x42, 0x2C, 0x73, 0x02, 0x8A, 0xB4, 0x4D, 0xC3, 0xB0, 0x68,
0x7A, 0xB2, 0x35, 0x95, 0x99, 0x6F, 0x69, 0x05, 0x83, 0x84, 0xA4, 0x69, 0xDA, 0x64, 0x42, 0x6B,
0x9E, 0x33, 0xD9, 0x19, 0x91, 0x80, 0x6E, 0x6F, 0x95, 0xCD, 0x4F, 0x9D, 0xF3, 0xAB, 0x79, 0xFD,
0xF8, 0xC3, 0xC4, 0x6D, 0xC3, 0x9F, 0xB3, 0xFE, 0x70, 0xDA, 0x1B, 0x4E, 0xE0, 0xAD, 0x83, 0x9F,
0xED, 0xCB, 0x6E, 0xFB, 0x12, 0x1E, 0xDD, 0x46, 0xE9, 0x6E, 0xFC, 0x2B, 0x36, 0x74, 0x3E, 0x18,
0x9D, 0xC1, 0xB0, 0xD7, 0x6E, 0x1F, 0xD7, 0x8E, 0xCE, 0xE6, 0x9F, 0x8F, 0xB7, 0xB1, 0xBB, 0x63,
0xD5, 0xAF, 0x3E, 0x4D, 0xEB, 0xC3, 0xCD, 0x77, 0xB6, 0x71, 0x68, 0x4C, 0x75, 0x7B, 0xD8, 0xBE,
0xFC, 0x7C, 0xF5, 0x70, 0x6D, 0x0F, 0x27, 0xFD, 0xCF, 0x8D, 0xE9, 0xCD, 0xE6, 0xA7, 0xFE, 0xCD,
0xE7, 0x83, 0x7B, 0xFA, 0xCB, 0xE1, 0xC7, 0x9B, 0xC1, 0x1C, 0x10, 0xF6, 0xDD, 0xFE, 0xF0, 0xAA,
0xF3, 0xA9, 0x33, 0xB9, 0xE9, 0xE8, 0xBD, 0xC5, 0xC8, 0x3A, 0xEB, 0x7C, 0x68, 0x8F, 0xDA, 0x9B,
0x3A, 0xA5, 0x93, 0xC1, 0x55, 0x67, 0x76, 0x74, 0x7C, 0x3E, 0x31, 0xCD, 0x69, 0xFF, 0xE6, 0x6C,
0xA0, 0x77, 0xDF, 0x9C, 0x0C, 0x0F, 0xDB, 0xE6, 0xF4, 0xEC, 0xE3, 0x55, 0xFD, 0xFE, 0xC3, 0x71,
0x77, 0x5F, 0xBF, 0xFE, 0x78, 0xBD, 0xBD, 0xFF, 0xBA, 0xF6, 0xF3, 0xCF, 0xA7, 0xC6, 0xB9, 0xE9,
0x0C, 0x1E, 0xBE, 0xB6, 0x27, 0xDD, 0xF9, 0xDB, 0xC7, 0x60, 0x30, 0x3D, 0x7A, 0x70, 0x6A, 0x9F,
0xDC, 0xBB, 0xA3, 0xC7, 0x53, 0xF8, 0x7F, 0x71, 0x51, 0x1A, 0xF5, 0x1B, 0xC1, 0xF0, 0xF2, 0xE8,
0xD3, 0x66, 0xF0, 0xEE, 0x8D, 0xD7, 0xD9, 0xDF, 0x7F, 0xB0, 0x47, 0x17, 0x35, 0xDB, 0xB8, 0x1F,
0x87, 0x6F, 0x5F, 0x87, 0xDE, 0xF5, 0x64, 0x76, 0xF3, 0xEB, 0x9B, 0x8F, 0xD3, 0xDA, 0x39, 0x25,
0xD7, 0xD3, 0xD2, 0xE3, 0xD7, 0xC7, 0xB7, 0xD3, 0xC1, 0xE1, 0xC3, 0x99, 0x45, 0x16, 0x67, 0x67,
0xFA, 0x57, 0xBB, 0x64, 0x91, 0x77, 0xE7, 0x03, 0x8B, 0xF8, 0x8D, 0xA1, 0xD1, 0xAE, 0x95, 0xBA,
0x9B, 0xED, 0xAD, 0xD0, 0xBF, 0xEA, 0x3A, 0xFB, 0xAF, 0xEF, 0xFA, 0x6F, 0x3B, 0x9D, 0x86, 0x3B,
0xFA, 0x75, 0xF3, 0xC3, 0xFD, 0xF6, 0x87, 0xE1, 0xF6, 0xE5, 0xE8, 0xB2, 0xDD, 0xDF, 0xEA, 0x0C,
0xC9, 0x75, 0xFF, 0xB2, 0x3D, 0xDE, 0x1A, 0x4D, 0xA7, 0xC7, 0xC7, 0x83, 0x03, 0xA3, 0xFD, 0xD5,
0x6F, 0x9F, 0xCF, 0xDB, 0x8B, 0xDE, 0xB0, 0x7D, 0x58, 0x3A, 0xEE, 0x9D, 0xD6, 0x1B, 0xFD, 0xEB,
0xD7, 0x93, 0xD3, 0xED, 0x79, 0x27, 0xE8, 0xB5, 0x2F, 0x3B, 0xF5, 0xC9, 0xC7, 0x92, 0x4D, 0x6E,
0xDC, 0xEE, 0xEB, 0xC9, 0xD1, 0xB6, 0x79, 0x71, 0x4D, 0xDA, 0x47, 0x9D, 0x8F, 0x81, 0x79, 0x65,
0x1F, 0x0E, 0xEB, 0xED, 0xF6, 0xC9, 0x39, 0x3D, 0xE8, 0xBE, 0x26, 0xC7, 0x9B, 0xFA, 0x67, 0xD0,
0xFF, 0xF0, 0x17, 0xFA, 0x73, 0xA9, 0x3D, 0x3F, 0xAF, 0x5B, 0xFA, 0x3B, 0x3A, 0x38, 0xBC, 0x1E,
0x30, 0xEB, 0xF4, 0xAC, 0x83, 0xC1, 0x7D, 0x7F, 0x76, 0x69, 0x77, 0xBB, 0x85, 0x22, 0x78, 0x6B,
0xC5, 0xA7, 0x1E, 0x25, 0x61, 0x26, 0xD6, 0x26, 0xD3, 0x0C, 0x23, 0x68, 0x3D, 0xE3, 0xAE, 0x51,
0x5C, 0xC0, 0x20, 0x07, 0xE9, 0xA0, 0x62, 0x50, 0xDD, 0xF5, 0x09, 0x87, 0x07, 0x6C, 0xEA, 0xA3,
0x03, 0x22, 0xC6, 0x3F, 0x58, 0x8E, 0x50, 0x78, 0x8A, 0x50, 0x88, 0x63, 0x28, 0x5A, 0x34, 0x93,
0x30, 0x98, 0x19, 0xF4, 0xC1, 0xD4, 0x69, 0xC5, 0x33, 0x17, 0xD4, 0xAA, 0x30, 0x02, 0xCD, 0x7A,
0x11, 0xA9, 0xE2, 0x48, 0xF8, 0x4C, 0x26, 0x1E, 0x71, 0xC0, 0x0D, 0xF9, 0x08, 0x51, 0x8B, 0x71,
0x47, 0x74, 0x0A, 0x51, 0x19, 0x26, 0x9E, 0x8D, 0x4F, 0x3E, 0x03, 0x5D, 0xBF, 0x32, 0x9A, 0x4D,
0xC6, 0xE6, 0x02, 0xE6, 0xC1, 0xD8, 0x74, 0xCC, 0x90, 0x2A, 0x8D, 0x00, 0xA5, 0x7B, 0xDA, 0x80,
0x1F, 0xFF, 0x88, 0xE8, 0xDD, 0xD3, 0xC7, 0xB1, 0x4F, 0x6C, 0x1A, 0x3C, 0x9B, 0x1C, 0xE7, 0x67,
0xEC, 0xBB, 0x90, 0xE5, 0x14, 0xF6, 0x9E, 0x8D, 0x65, 0x30, 0x06, 0xEF, 0x08, 0xDD, 0x35, 0x20,
0x8C, 0x95, 0xA7, 0x8D, 0x57, 0x33, 0xCF, 0x72, 0x89, 0xC1, 0xC2, 0xEB, 0xCA, 0xB8, 0x96, 0xA4,
0x10, 0x9F, 0xCF, 0xE1, 0x6C, 0x3A, 0x11, 0x73, 0x7B, 0x53, 0x84, 0x85, 0x54, 0x94, 0xD9, 0xDC,
0x4A, 0x85, 0x90, 0x0A, 0x47, 0x6B, 0x88, 0xCC, 0x91, 0x93, 0x58, 0x45, 0xA8, 0xE2, 0x9F, 0x2C,
0x86, 0x23, 0x9F, 0x21, 0xD8, 0xEE, 0xBB, 0x3C, 0x46, 0x0C, 0x88, 0xE0, 0xB5, 0xC4, 0x27, 0x4F,
0x5B, 0x8D, 0x28, 0x6D, 0xC5, 0x4A, 0x79, 0xCB, 0x3D, 0xEB, 0x15, 0x65, 0x15, 0x47, 0x59, 0x79,
0xE5, 0xF9, 0xE0, 0x13, 0x74, 0xFE, 0xEC, 0x01, 0x65, 0xBD, 0xE4, 0x0C, 0x1E, 0x8F, 0xC8, 0x2B,
0x0C, 0xAE, 0x03, 0xA9, 0xCA, 0x88, 0x84, 0x8C, 0x87, 0xCD, 0xD7, 0x0C, 0x03, 0x4B, 0xD8, 0x7E,
0xC3, 0xB9, 0xDE, 0xAD, 0xB1, 0x5C, 0x85, 0x05, 0x92, 0xEE, 0x9B, 0x5E, 0xB8, 0xB7, 0x31, 0x9E,
0x39, 0x3A, 0x32, 0xAC, 0x80, 0xC3, 0x93, 0x90, 0x1E, 0x98, 0x16, 0x1D, 0x0A, 0x33, 0x6B, 0xC2,
0xAF, 0xCA, 0x0A, 0x2A, 0xB4, 0xAC, 0x70, 0x89, 0x99, 0xB7, 0x3F, 0x10, 0x5F, 0x59, 0xD8, 0xD6,
0x61, 0x18, 0x7A, 0x3B, 0xE2, 0x93, 0x27, 0xBC, 0x96, 0x62, 0xB8, 0xFA, 0x0C, 0xB1, 0xAA, 0x9C,
0x60, 0x8F, 0xD3, 0xD0, 0x54, 0xD6, 0xAF, 0xB2, 0x3A, 0x86, 0xBD, 0x56, 0xB1, 0x38, 0x03, 0x78,
0x75, 0x0C, 0x43, 0xAA, 0x49, 0xB3, 0x3D, 0xB3, 0x42, 0xD3, 0xB3, 0xB0, 0x6B, 0x4C, 0xAC, 0x80,
0x26, 0x3D, 0x0E, 0x38, 0x3F, 0x22, 0x60, 0x88, 0x67, 0x08, 0xF1, 0x50, 0x13, 0x1A, 0x8A, 0x71,
0x3A, 0x8F, 0x47, 0x46, 0xC4, 0x77, 0xB1, 0x4A, 0x3C, 0x8F, 0x3A, 0x46, 0x77, 0x6A, 0x5A, 0x86,
0xC6, 0x68, 0x14, 0x23, 0x6E, 0x3D, 0x12, 0x4E, 0x9F, 0xC7, 0x2C, 0x42, 0x56, 0x41, 0xF1, 0x30,
0x30, 0xF7, 0xFF, 0x0A, 0xB6, 0xA8, 0x71, 0x57, 0x24, 0x06, 0x86, 0x95, 0xA4, 0x35, 0xE2, 0x35,
0x0D, 0x6B, 0xD0, 0x31, 0x01, 0xF1, 0x3E, 0x11, 0x6B, 0xC6, 0x7A, 0x6B, 0x2F, 0x17, 0x03, 0xE9,
0xC4, 0x52, 0x8C, 0x66, 0xE0, 0x3E, 0xCE, 0x1A, 0x39, 0x38, 0x00, 0x17, 0x84, 0xBF, 0x57, 0x4D,
0xC7, 0xA1, 0xFE, 0xE1, 0xE0, 0xF4, 0x04, 0xD0, 0x0A, 0xDC, 0xD4, 0x85, 0x17, 0x73, 0xC1, 0x69,
0xC5, 0x7C, 0xD8, 0xF7, 0x68, 0xC4, 0x67, 0xF2, 0xC1, 0x81, 0xD3, 0x7C, 0x74, 0x19, 0xF8, 0xCB,
0xF9, 0xE0, 0xB4, 0x80, 0x2C, 0x96, 0x4E, 0x91, 0x27, 0x4F, 0xC1, 0x2B, 0x2F, 0xDC, 0x20, 0xBC,
0xF0, 0x5D, 0x9D, 0x06, 0xC1, 0x15, 0xFD, 0x75, 0x46, 0x83, 0x50, 0x2B, 0xF2, 0x70, 0x68, 0x8E,
0x15, 0x4D, 0xB8, 0x6E, 0x15, 0x46, 0x35, 0x1E, 0xFB, 0x21, 0x0C, 0xAD, 0xB4, 0x5A, 0xCA, 0x96,
0x80, 0x40, 0x98, 0x18, 0x24, 0x80, 0xDE, 0x59, 0xA0, 0xFC, 0xD4, 0x52, 0x36, 0xEB, 0xF5, 0xA2,
0x42, 0x2C, 0x28, 0x45, 0x34, 0xB5, 0x77, 0x75, 0x75, 0x7E, 0xF5, 0x45, 0x2D, 0xA5, 0xA1, 0x4A,
0xEA, 0x6D, 0x53, 0x49, 0x1A, 0x7D, 0x1A, 0x78, 0xAE, 0x13, 0xD0, 0x01, 0x78, 0x46, 0x71, 0x47,
0x90, 0xA6, 0xE0, 0xD2, 0x4A, 0x34, 0x8E, 0xC2, 0x66, 0x16, 0x00, 0x8E, 0x01, 0x76, 0x7A, 0x01,
0xA6, 0x65, 0xF6, 0xAD, 0x3E, 0xA0, 0x83, 0xC4, 0x28, 0x4F, 0x52, 0x14, 0x96, 0xC4, 0xE4, 0x2A,
0xE6, 0x48, 0x82, 0x73, 0x31, 0x32, 0x68, 0xD4, 0x81, 0xC8, 0xF0, 0xCB, 0xE9, 0x09, 0x7E, 0xC5,
0xF2, 0xEF, 0xC8, 0x30, 0x55, 0xD7, 0x61, 0xD2, 0x23, 0xE7, 0x54, 0x9F, 0xC2, 0xDA, 0x0A, 0xED,
0x97, 0xAF, 0x3A, 0x8E, 0x88, 0x86, 0x1E, 0x43, 0x61, 0xBA, 0x0F, 0xD3, 0x4F, 0x8C, 0x70, 0x20,
0x3E, 0x23, 0xDA, 0x51, 0xB7, 0xB0, 0x91, 0xC6, 0xDD, 0xBF, 0xAC, 0x78, 0xD9, 0xB1, 0xA1, 0x57,
0x53, 0x2F, 0x86, 0x03, 0xE8, 0x53, 0x6B, 0x18, 0x57, 0xD4, 0x0C, 0x44, 0x80, 0xE8, 0x11, 0xB9,
0xE2, 0x8E, 0x90, 0x3D, 0xF1, 0x1E, 0xD7, 0xD1, 0x2D, 0x53, 0xBF, 0xC7, 0x20, 0x21, 0xF4, 0xA1,
0xD1, 0xD8, 0xC0, 0x92, 0x12, 0xAB, 0x6C, 0x61, 0x77, 0x3E, 0xD6, 0xD4, 0xAA, 0x5A, 0x04, 0x23,
0xB7, 0x94, 0x4A, 0xA3, 0x08, 0x4B, 0x94, 0x70, 0xE6, 0x3B, 0x7C, 0x44, 0x59, 0x8D, 0x59, 0xDD,
0xF3, 0x88, 0x57, 0xC5, 0x39, 0x32, 0x84, 0xE2, 0x32, 0xD3, 0xFF, 0x24, 0xCD, 0xAA, 0xF5, 0xFC,
0xF0, 0xF8, 0x85, 0x8C, 0x07, 0x55, 0x8B, 0x3A, 0x13, 0x8C, 0x3D, 0xC0, 0x4A, 0x3D, 0x76, 0x38,
0x99, 0xA1, 0xA7, 0x3F, 0xA7, 0x29, 0x59, 0xD4, 0x2D, 0x2B, 0x92, 0x28, 0x5F, 0xEA, 0xB7, 0x65,
0x65, 0x49, 0x67, 0x19, 0x1B, 0x9F, 0xF7, 0x5F, 0x64, 0xE4, 0x24, 0xDA, 0x83, 0x46, 0x23, 0x51,
0x5E, 0xA4, 0xD2, 0x94, 0x2E, 0x99, 0xA0, 0x00, 0x23, 0xC2, 0x71, 0x9A, 0x79, 0x16, 0xA4, 0x13,
0x38, 0x98, 0xA5, 0x00, 0x52, 0xD3, 0xDE, 0x37, 0xFF, 0x59, 0xD5, 0xBE, 0xFC, 0xAB, 0x7A, 0x5B,
0x2A, 0x16, 0xDF, 0xFF, 0xA5, 0x56, 0xA5, 0x0B, 0xAA, 0x6B, 0x11, 0x91, 0xE2, 0x97, 0xC6, 0x6D,
0x82, 0x22, 0xC8, 0xD6, 0xB4, 0xEA, 0xDF, 0x8B, 0xFF, 0xAC, 0x32, 0x9C, 0xD5, 0x08, 0xC0, 0x34,
0xE6, 0x0A, 0x77, 0xCC, 0xD1, 0x7E, 0x02, 0x6E, 0xB1, 0xF2, 0x84, 0x8A, 0x8F, 0x1A, 0xB1, 0x23,
0x48, 0xCC, 0x26, 0xDC, 0x3D, 0x65, 0xF0, 0x91, 0xD3, 0x7C, 0x74, 0x80, 0x61, 0x62, 0x40, 0xA7,
0x8A, 0x9B, 0x26, 0xE0, 0xF3, 0x5C, 0x2C, 0xFC, 0x52, 0x53, 0x31, 0x48, 0x06, 0xBD, 0xF3, 0xE8,
0x24, 0x01, 0xBD, 0xF3, 0x26, 0x31, 0xA8, 0xC4, 0x4F, 0xFC, 0x5A, 0x52, 0x60, 0x32, 0xC1, 0x4F,
0x00, 0xCF, 0xF0, 0x97, 0x38, 0x03, 0xA7, 0x5B, 0x53, 0x95, 0xFF, 0xFC, 0x47, 0x72, 0x91, 0xAA,
0x45, 0x82, 0xF0, 0x28, 0x9A, 0x91, 0x35, 0x31, 0x23, 0x93, 0x69, 0x20, 0xE3, 0x23, 0x76, 0x29,
0x1A, 0x33, 0xAA, 0x55, 0x53, 0xD1, 0x33, 0x05, 0x2D, 0x0D, 0x12, 0xCC, 0x46, 0x41, 0xE8, 0x43,
0xD5, 0xA3, 0xD5, 0xCB, 0xEB, 0x06, 0x2F, 0x35, 0x8A, 0xD9, 0x01, 0xB8, 0x0B, 0x42, 0xDD, 0x9D,
0x89, 0xB2, 0x03, 0x08, 0xD3, 0x49, 0x39, 0x94, 0x29, 0x84, 0xA2, 0x4A, 0xAC, 0xB5, 0x32, 0x77,
0xA9, 0x02, 0x44, 0x8D, 0x33, 0x26, 0xC6, 0xFD, 0x2B, 0xD7, 0x5D, 0x57, 0x30, 0x19, 0xE6, 0x03,
0x87, 0x8F, 0x60, 0xAB, 0x3A, 0x48, 0x10, 0x9C, 0x89, 0xCA, 0x02, 0xD6, 0x1B, 0x2F, 0xAF, 0x1E,
0x22, 0x52, 0x99, 0x8C, 0x89, 0x01, 0x6E, 0xDF, 0x9D, 0x3B, 0xF8, 0xE4, 0x15, 0x06, 0xD7, 0xF1,
0x2A, 0xDA, 0x05, 0x43, 0x00, 0x57, 0xD8, 0x8A, 0xA4, 0x50, 0xAC, 0x06, 0xBE, 0x2E, 0x8C, 0x50,
0x52, 0xDF, 0x47, 0xBD, 0xAD, 0xD0, 0x9F, 0xF1, 0xD2, 0xEE, 0x69, 0x69, 0xB8, 0x0B, 0xAE, 0x91,
0xE7, 0x8C, 0xA6, 0x72, 0x7D, 0xAB, 0x30, 0x0A, 0x16, 0xAF, 0x55, 0xB1, 0x6D, 0x80, 0x4A, 0xC0,
0xAD, 0x0B, 0xE1, 0xAB, 0x42, 0xC5, 0xCB, 0x30, 0x6C, 0x57, 0x21, 0x03, 0x94, 0x2A, 0x3E, 0x76,
0x4D, 0x7B, 0xA2, 0x80, 0x00, 0x2D, 0xB5, 0x50, 0x62, 0x12, 0x14, 0xDE, 0xFF, 0x5B, 0x1F, 0xB5,
0x0A, 0x25, 0x08, 0x4B, 0xB4, 0xEA, 0xB8, 0x73, 0xAD, 0x58, 0x2A, 0xA8, 0x0A, 0x23, 0xDC, 0x52,
0x6D, 0xB2, 0x10, 0x5B, 0x5A, 0x8D, 0x7A, 0xFD, 0xAF, 0x3B, 0x0A, 0x7E, 0x8B, 0xF5, 0x4B, 0xD4,
0xC0, 0xF6, 0x87, 0xC8, 0x2C, 0x74, 0x77, 0xE2, 0x2D, 0x0E, 0xBE, 0xB5, 0xA1, 0x2A, 0xB5, 0xBD,
0xC2, 0xB2, 0x3E, 0xC0, 0x09, 0x2D, 0x2C, 0xBC, 0x4F, 0xA9, 0x33, 0x03, 0xBB, 0x71, 0xA7, 0x15,
0x4A, 0x41, 0x67, 0xC1, 0x4D, 0xA6, 0x35, 0x8E, 0x32, 0xB3, 0xA2, 0xC0, 0x4A, 0xAD, 0x94, 0xB5,
0x11, 0xAF, 0x98, 0x44, 0x2B, 0xC2, 0x47, 0x5B, 0x4D, 0xC8, 0x32, 0x23, 0x42, 0x88, 0x99, 0x22,
0xC5, 0x71, 0x8B, 0x71, 0x24, 0x33, 0x03, 0xAC, 0x6A, 0x90, 0x69, 0x6E, 0xC1, 0x78, 0x0A, 0x73,
0xC0, 0x94, 0x82, 0xD5, 0x5D, 0x5C, 0x81, 0xEF, 0xE1, 0x16, 0x2D, 0xAC, 0x3F, 0xF0, 0x35, 0x0E,
0x2F, 0x02, 0x7A, 0x4D, 0xF6, 0x5C, 0x91, 0x86, 0xE3, 0xE2, 0x88, 0x71, 0x13, 0x0B, 0x34, 0x72,
0x8D, 0x47, 0xC9, 0x7D, 0x82, 0xCE, 0x63, 0x37, 0x9A, 0x33, 0x5A, 0x41, 0xB7, 0xC1, 0x51, 0x45,
0xAE, 0xD8, 0xC3, 0x4C, 0x91, 0x46, 0xF3, 0xA9, 0xED, 0x3E, 0x50, 0x2E, 0x2E, 0xB5, 0x92, 0xEA,
0x2B, 0x15, 0x7B, 0x98, 0xE8, 0x47, 0xB8, 0xBD, 0xF4, 0x22, 0xD9, 0x85, 0xB7, 0xFF, 0x98, 0xF8,
0x4B, 0xD3, 0xE5, 0x7F, 0x2E, 0x7B, 0xEC, 0x42, 0xD1, 0xCC, 0xFE, 0x31, 0x27, 0x8A, 0xB0, 0x45,
0x7F, 0xF4, 0x99, 0xA7, 0xB0, 0x28, 0x1A, 0xA5, 0x35, 0x16, 0x63, 0xAC, 0xD5, 0xD8, 0x72, 0x34,
0x8B, 0xE4, 0xF9, 0x43, 0xD5, 0xF5, 0x94, 0xCC, 0x34, 0x83, 0xB2, 0xF9, 0xFC, 0x83, 0x5A, 0xE2,
0xC8, 0x91, 0x92, 0xF8, 0x57, 0xAE, 0x8E, 0x20, 0xC4, 0x87, 0x34, 0xA3, 0x21, 0x01, 0xBE, 0x56,
0x41, 0x58, 0x1A, 0x72, 0xE4, 0xFF, 0xB5, 0x7A, 0xD2, 0x71, 0x2F, 0x98, 0xBA, 0xF3, 0xAE, 0xEB,
0xE0, 0xCA, 0x99, 0x87, 0xBE, 0x07, 0x96, 0x5E, 0x91, 0x27, 0x28, 0x34, 0x03, 0xB6, 0xB4, 0x4B,
0xA2, 0x20, 0xE4, 0x43, 0x01, 0xFC, 0x9C, 0xA4, 0xC9, 0x71, 0x02, 0xDD, 0x77, 0x2D, 0x6B, 0xE0,
0x7A, 0x32, 0x0A, 0xE3, 0x31, 0xE9, 0x79, 0xBF, 0xB2, 0xA7, 0x99, 0xF4, 0x44, 0x2F, 0x62, 0xA0,
0x04, 0x28, 0x3B, 0xD6, 0x09, 0x1D, 0x87, 0x2B, 0x06, 0x63, 0x5D, 0xF9, 0xA3, 0xB1, 0xAE, 0xEF,
0x0E, 0x87, 0x50, 0xC9, 0x78, 0x16, 0x1F, 0x89, 0x29, 0x0D, 0x4A, 0x03, 0x13, 0x1E, 0xBF, 0x40,
0x55, 0x96, 0x07, 0x1A, 0x32, 0x05, 0xC8, 0x90, 0xD7, 0x31, 0x64, 0x2C, 0x43, 0xA2, 0xDF, 0x54,
0xA1, 0x81, 0xC6, 0x5E, 0x02, 0xC8, 0x26, 0xD9, 0x02, 0xCB, 0x6F, 0xAB, 0xE0, 0x04, 0xA7, 0xEC,
0x51, 0x52, 0x0A, 0xDE, 0x62, 0x15, 0x20, 0xE7, 0x13, 0x7F, 0xCA, 0x60, 0xA9, 0xF4, 0x98, 0xE0,
0x88, 0x34, 0x19, 0x45, 0x06, 0x59, 0xA9, 0xA9, 0xE9, 0x14, 0x23, 0x48, 0x7E, 0xC1, 0x12, 0x38,
0x9A, 0x29, 0xE1, 0xC0, 0x1D, 0x8F, 0x03, 0x1A, 0x7E, 0xC6, 0x8E, 0x04, 0x8E, 0x27, 0xF6, 0x3C,
0xC0, 0x43, 0xD6, 0xB3, 0x24, 0x87, 0xEB, 0xD8, 0xEE, 0x2C, 0xA0, 0x2E, 0xDB, 0x0A, 0xCB, 0x99,
0x7A, 0x58, 0x75, 0xC7, 0xC6, 0xDA, 0xE5, 0x2A, 0x81, 0x12, 0x39, 0x69, 0xDB, 0x53, 0x34, 0xA1,
0x27, 0xC6, 0x63, 0x51, 0xEE, 0xBD, 0x06, 0x0C, 0x54, 0x4E, 0xAA, 0x09, 0x10, 0xB8, 0xC2, 0x38,
0xAF, 0x45, 0x29, 0x71, 0xFC, 0x11, 0xF3, 0x79, 0x49, 0x9D, 0xF1, 0xFE, 0xC4, 0xF2, 0xFC, 0x4E,
0x6A, 0xE7, 0x13, 0x4A, 0xF8, 0xEA, 0xA0, 0xCC, 0x96, 0x35, 0x65, 0x05, 0x4F, 0x31, 0xE5, 0x0A,
0x07, 0xFA, 0x9F, 0x17, 0x2D, 0x01, 0x90, 0xEF, 0xC6, 0x69, 0x9A, 0xC6, 0x37, 0xF1, 0xD8, 0x4A,
0xA1, 0xF8, 0x5E, 0x55, 0x9B, 0xCC, 0x1F, 0x4A, 0xB8, 0x6E, 0x60, 0x2B, 0x2F, 0x69, 0xAA, 0x90,
0x11, 0xB5, 0xD6, 0xD0, 0xC7, 0x08, 0x1A, 0x8F, 0x80, 0xB0, 0xA9, 0x70, 0x9B, 0xAC, 0x0F, 0xD8,
0xE8, 0xA9, 0x0A, 0x0B, 0x81, 0x65, 0xD6, 0xD6, 0xC6, 0xDD, 0x74, 0xDD, 0x24, 0x44, 0x01, 0xA7,
0x3F, 0x71, 0xE7, 0xD4, 0xEF, 0x92, 0x80, 0x6A, 0xC5, 0xE2, 0xEA, 0xB2, 0x47, 0xC0, 0x27, 0x6A,
0xCF, 0xAD, 0x48, 0xBE, 0x4B, 0x55, 0xAE, 0x26, 0x96, 0x48, 0xCA, 0x89, 0x2C, 0x92, 0x87, 0x5B,
0x1B, 0x14, 0x35, 0xCB, 0x97, 0x8A, 0x56, 0xB1, 0xAA, 0x06, 0x3D, 0xEE, 0xF3, 0xDD, 0x4D, 0x2D,
0x26, 0x07, 0x4B, 0x31, 0x70, 0xCD, 0x0B, 0xDF, 0xF5, 0xC8, 0x84, 0x9D, 0x84, 0x24, 0x5D, 0x4B,
0xA1, 0xBF, 0x1C, 0x99, 0x16, 0x77, 0x9B, 0xE3, 0xCD, 0x04, 0xC1, 0x0A, 0x5F, 0xD2, 0x33, 0x88,
0x65, 0x2F, 0x23, 0x86, 0x71, 0x02, 0x39, 0x14, 0xBC, 0xC1, 0x97, 0xD3, 0x47, 0x48, 0xED, 0xE0,
0x47, 0x6A, 0x68, 0x4E, 0x66, 0x5D, 0x1D, 0x6D, 0xA1, 0x2B, 0x31, 0xFA, 0x62, 0xCE, 0xC4, 0x3B,
0x26, 0x1A, 0xDB, 0x08, 0x87, 0xDE, 0xFA, 0x0E, 0x3C, 0x60, 0x7A, 0x5B, 0xF0, 0x2C, 0x95, 0x52,
0x0E, 0x80, 0x78, 0x5F, 0xCC, 0x5B, 0xB1, 0x6F, 0xDC, 0x8A, 0x36, 0xC0, 0x8B, 0x89, 0x81, 0xB2,
0x05, 0x41, 0xEE, 0x34, 0x8A, 0xE9, 0xF0, 0xF9, 0x14, 0x7F, 0xB2, 0x89, 0x15, 0x69, 0x6F, 0x63,
0x49, 0x59, 0xD9, 0xBA, 0x3D, 0x51, 0xD0, 0xDA, 0xED, 0x0F, 0x06, 0x9B, 0xB3, 0x93, 0xB1, 0x7A,
0x27, 0x22, 0x98, 0x9B, 0xA1, 0x3E, 0xC5, 0x2D, 0x06, 0xC9, 0xF7, 0x74, 0xF0, 0x46, 0x58, 0xB9,
0x2E, 0x42, 0xB5, 0x99, 0x69, 0xC3, 0xED, 0x89, 0x9C, 0x36, 0x6B, 0xA9, 0xF1, 0x2E, 0x58, 0x6A,
0xD2, 0x97, 0x5B, 0x3C, 0x6F, 0xB9, 0x2D, 0x58, 0xC6, 0x5C, 0xA4, 0x06, 0x88, 0xFD, 0x0C, 0x1D,
0x70, 0x79, 0xF3, 0x35, 0xEE, 0x8E, 0x8F, 0x25, 0xB2, 0xAA, 0xCD, 0xAC, 0x0B, 0xFE, 0x1F, 0xBA,
0xF5, 0x9C, 0xC9, 0xB2, 0xCA, 0xBC, 0xE5, 0xB6, 0x89, 0x39, 0xFE, 0xCD, 0x92, 0x87, 0x53, 0x33,
0x90, 0xF7, 0xAE, 0xE5, 0xF0, 0x20, 0x29, 0x20, 0xDE, 0xBE, 0x90, 0xD3, 0x48, 0xB2, 0xA7, 0x81,
0x9F, 0x67, 0xAE, 0xC1, 0x76, 0xE4, 0x84, 0xDF, 0x62, 0x7D, 0xFA, 0x81, 0x86, 0x31, 0x50, 0x99,
0x45, 0x78, 0xB1, 0x3F, 0x28, 0xAB, 0x1C, 0xAA, 0xDD, 0xEE, 0x48, 0x1E, 0x2B, 0xE2, 0x33, 0x62,
0x43, 0x9A, 0x79, 0xDF, 0xDF, 0xF5, 0x5F, 0xB3, 0xEF, 0xFF, 0x4D, 0x52, 0xD5, 0x6F, 0x3E, 0x02,
0x58, 0xDA, 0xC8, 0xFA, 0x31, 0x2D, 0xF1, 0x3F, 0xAB, 0x75, 0x25, 0x5B, 0x31, 0x7D, 0x88, 0xB0,
0x91, 0x39, 0x2C, 0x11, 0x6B, 0x81, 0x78, 0xCB, 0x92, 0xF3, 0xF5, 0x9B, 0x77, 0xA0, 0xB9, 0x75,
0x62, 0xAA, 0xD2, 0x8E, 0xEC, 0x8F, 0x9D, 0x22, 0x64, 0x28, 0xA5, 0x37, 0x9A, 0xF7, 0x7B, 0x27,
0xBD, 0x41, 0xEF, 0x45, 0xE7, 0x09, 0xB2, 0x1A, 0xA0, 0x32, 0x62, 0x9E, 0x94, 0xA4, 0x90, 0x3F,
0xCA, 0xA3, 0x5A, 0xD1, 0x49, 0x52, 0x6E, 0xDA, 0xFA, 0xD8, 0x3F, 0x3F, 0xAB, 0x42, 0x13, 0x64,
0xED, 0x5C, 0x1F, 0xCA, 0x3D, 0x14, 0xCA, 0xDA, 0x13, 0xFD, 0x21, 0x47, 0x94, 0xB5, 0x06, 0x4D,
0xC1, 0x3F, 0xC3, 0xB8, 0x39, 0x0A, 0xCB, 0x33, 0xCB, 0x87, 0x1E, 0xDF, 0xFE, 0xC7, 0xA4, 0xF6,
0xDE, 0x30, 0xFD, 0x96, 0x5A, 0xE2, 0x82, 0x4A, 0x49, 0x3E, 0x65, 0x23, 0x67, 0x66, 0x59, 0x89,
0x7D, 0x56, 0x7B, 0x77, 0x14, 0xB0, 0x20, 0x06, 0xE5, 0x6D, 0xD8, 0xF2, 0xFB, 0x80, 0xC9, 0x96,
0x2D, 0xFA, 0x4E, 0x99, 0x5D, 0x21, 0x84, 0xA1, 0xA7, 0x14, 0x53, 0x26, 0x86, 0x59, 0xA6, 0x19,
0xD9, 0x09, 0x4E, 0x00, 0xE2, 0xC0, 0x77, 0xED, 0x03, 0xE1, 0x6B, 0xD9, 0x49, 0xC1, 0xAB, 0x49,
0x67, 0xC2, 0xCE, 0x76, 0x2D, 0x62, 0x3A, 0x6A, 0xE2, 0xD6, 0x2F, 0x3C, 0x40, 0xF8, 0x3D, 0xB2,
0x68, 0x96, 0x17, 0x65, 0x04, 0xD2, 0xDF, 0xEF, 0x64, 0x40, 0x59, 0x72, 0x8D, 0x41, 0x59, 0x5A,
0x5D, 0x01, 0x89, 0xD9, 0x35, 0x06, 0xBC, 0x23, 0x0F, 0x84, 0x5F, 0x13, 0x58, 0x05, 0xAE, 0x4B,
0xD0, 0xFA, 0xBF, 0x31, 0xEB, 0xAE, 0x02, 0xC4, 0x84, 0xFC, 0x4C, 0xD0, 0x9C, 0x3C, 0x1D, 0xE4,
0x35, 0x7A, 0xD3, 0xE5, 0x24, 0xBF, 0xA2, 0x64, 0x70, 0x9D, 0xEF, 0xA6, 0x7E, 0xC1, 0x5B, 0x7C,
0xA6, 0x91, 0x9B, 0xFF, 0x10, 0x28, 0xF6, 0xCD, 0xC4, 0x7E, 0xFC, 0xF0, 0x1B, 0x4B, 0xB9, 0xD8,
0x82, 0x6A, 0x51, 0xB4, 0x82, 0xC3, 0xB2, 0x23, 0xC8, 0x2A, 0x3F, 0x80, 0x49, 0xE1, 0xF1, 0x31,
0x33, 0x78, 0xDF, 0x36, 0x24, 0x76, 0x56, 0x79, 0x64, 0x31, 0x87, 0x0B, 0xE6, 0xD6, 0xCB, 0x6C,
0x88, 0x66, 0x7E, 0x41, 0xC1, 0x86, 0xA9, 0x91, 0xE5, 0x22, 0x29, 0x44, 0x97, 0xB8, 0x90, 0xEF,
0x36, 0xC0, 0xAA, 0x2A, 0x12, 0x9F, 0x61, 0x27, 0xCC, 0x73, 0x73, 0x16, 0xD3, 0xD0, 0xC9, 0xE4,
0x60, 0x6C, 0x4A, 0x17, 0x46, 0x30, 0xFE, 0xC0, 0x24, 0xDF, 0x11, 0xAD, 0x7C, 0x95, 0x03, 0x8D,
0x44, 0xA7, 0x55, 0xFC, 0x88, 0x4F, 0x2E, 0x76, 0xB2, 0x71, 0xED, 0x4F, 0x7A, 0xA8, 0xBF, 0x74,
0x32, 0x1F, 0xF1, 0x1A, 0x4F, 0xFA, 0xB2, 0x82, 0xA7, 0xA7, 0x52, 0xC8, 0xF9, 0xF3, 0x9E, 0xEF,
0x22, 0x6C, 0xC7, 0x72, 0x47, 0xDA, 0x17, 0x6C, 0xB8, 0x2D, 0x2B, 0xDF, 0x18, 0xD7, 0x4D, 0x6E,
0xDD, 0xA7, 0xE2, 0x77, 0xD2, 0xF0, 0x4B, 0xCF, 0x7B, 0x73, 0x52, 0xD7, 0x8F, 0x5B, 0xF8, 0xFB,
0xC7, 0x6F, 0x6B, 0x4F, 0x90, 0x7E, 0xE8, 0x04, 0x4A, 0x3E, 0x5D, 0x5A, 0x97, 0xEE, 0xC5, 0x62,
0x3E, 0xA0, 0xFC, 0xF6, 0x4F, 0x7E, 0x76, 0x8F, 0x17, 0xCE, 0x58, 0x1D, 0x66, 0x31, 0xD4, 0xA4,
0xAC, 0x13, 0x5D, 0x3A, 0x2C, 0x88, 0xFD, 0x3E, 0xBB, 0xF4, 0x27, 0x2D, 0xAE, 0x73, 0xDD, 0x91,
0x25, 0xD1, 0x29, 0x1D, 0xFA, 0x56, 0xAC, 0xAD, 0xE7, 0x78, 0xE0, 0x33, 0x7C, 0x70, 0xC9, 0x62,
0x4B, 0x98, 0x52, 0x21, 0xC0, 0x59, 0x48, 0x65, 0xFF, 0xB5, 0xF9, 0x3F, 0x8A, 0x33, 0x98, 0x1D,
0x45, 0x8E, 0x8B, 0x55, 0x09, 0x36, 0xEA, 0xC3, 0xA8, 0x4C, 0x72, 0xD4, 0xD2, 0x29, 0x94, 0xC7,
0x9A, 0x0A, 0x51, 0xA4, 0x66, 0xC3, 0x9B, 0x08, 0x57, 0x8C, 0x54, 0xA2, 0xC9, 0x01, 0x06, 0x43,
0x0E, 0xC4, 0xE2, 0x22, 0x40, 0xB1, 0xA7, 0x0C, 0xF6, 0x17, 0x66, 0xD2, 0x3E, 0xDB, 0x1C, 0x35,
0x59, 0x14, 0x3E, 0xE2, 0xD7, 0x32, 0x1F, 0x25, 0xA0, 0xEC, 0xE0, 0xC3, 0x80, 0xF6, 0xDD, 0x71,
0x38, 0x20, 0xA3, 0x40, 0x8B, 0x85, 0x5B, 0x01, 0x0B, 0x40, 0x7D, 0x58, 0xA5, 0x6B, 0x9B, 0x19,
0xE6, 0x0E, 0xCD, 0xC9, 0xD4, 0xC2, 0x3D, 0xBC, 0xB6, 0x8E, 0xF7, 0xE7, 0x4F, 0x20, 0x12, 0x2F,
0xD1, 0x02, 0xB0, 0xFE, 0xD4, 0x9D, 0x5F, 0xF8, 0xA6, 0x13, 0x9E, 0xB2, 0x83, 0x46, 0x8D, 0x2D,
0xCA, 0x64, 0x18, 0xDD, 0xB5, 0x6D, 0xE2, 0x18, 0x41, 0x15, 0x4A, 0xCC, 0x2E, 0x7F, 0xD7, 0x22,
0xA3, 0xE3, 0xC4, 0x6D, 0x2A, 0x85, 0x80, 0xC0, 0x12, 0x83, 0x77, 0x15, 0xCA, 0xA2, 0x6B, 0x04,
0x79, 0xEA, 0x98, 0x3E, 0x36, 0x95, 0x6F, 0x73, 0xBC, 0xDE, 0x5E, 0xE8, 0x86, 0xBE, 0x55, 0xE9,
0x17, 0xCA, 0x78, 0xCD, 0x5B, 0xC7, 0x6F, 0x0E, 0x0F, 0x4D, 0x4F, 0x11, 0x0A, 0x56, 0x36, 0x4D,
0x69, 0x4F, 0x88, 0x9F, 0x8B, 0x4B, 0xEB, 0x9A, 0x54, 0x24, 0x2C, 0x4B, 0x0A, 0xE1, 0x2E, 0x5D,
0x2C, 0xA9, 0xAA, 0x88, 0x8A, 0x71, 0xD6, 0x8D, 0x68, 0xA3, 0xBB, 0x9D, 0x3B, 0xF8, 0x6B, 0x0D,
0x4C, 0x40, 0xF4, 0x88, 0x17, 0x0A, 0x09, 0xE9, 0xCC, 0x7D, 0x96, 0x90, 0x37, 0xCB, 0x42, 0xDE,
0xBC, 0x40, 0xC8, 0x3C, 0x33, 0xC3, 0xC7, 0x10, 0x86, 0x3F, 0x25, 0x0E, 0x99, 0x50, 0x1F, 0x1A,
0x90, 0x19, 0xC9, 0x54, 0xBF, 0xB3, 0xA8, 0x3E, 0x7D, 0xA6, 0xA8, 0xFD, 0xA9, 0x39, 0x0E, 0xF3,
0x04, 0x8E, 0x3A, 0x7E, 0x67, 0xB1, 0x91, 0xB1, 0x97, 0x8A, 0x1D, 0xC5, 0xAB, 0xB8, 0xD0, 0x49,
0x6F, 0x84, 0xCA, 0xDB, 0x0C, 0x99, 0xEA, 0x5C, 0x94, 0x5C, 0xE9, 0x4B, 0x1D, 0xCF, 0x29, 0xA5,
0x9E, 0x51, 0xEA, 0xFC, 0xB6, 0x10, 0x94, 0x23, 0xD5, 0x93, 0xB4, 0x8C, 0xE1, 0xF4, 0x70, 0x21,
0x13, 0x47, 0x6D, 0xD7, 0xE9, 0xB8, 0xC6, 0xE3, 0x09, 0x9E, 0x61, 0xC6, 0x37, 0x4D, 0xE0, 0x3F,
0x64, 0x14, 0xE5, 0xDB, 0x53, 0x54, 0x3C, 0xC1, 0xFA, 0x2B, 0xC4, 0x16, 0xB0, 0xB0, 0xE1, 0xCE,
0x41, 0x43, 0x3A, 0xDB, 0x67, 0xAD, 0x4E, 0x7D, 0x3A, 0x06, 0xDD, 0x03, 0xBB, 0x3A, 0xD5, 0x6A,
0x5F, 0xDE, 0xFF, 0xED, 0xB6, 0x04, 0x2B, 0x92, 0x16, 0x3C, 0x8A, 0x2D, 0x78, 0xF9, 0xDB, 0xED,
0xDF, 0x8B, 0xB5, 0x89, 0x59, 0x4E, 0x14, 0x69, 0x97, 0xEF, 0xE9, 0x63, 0x99, 0xDF, 0xE3, 0x82,
0x94, 0x8F, 0x03, 0x7D, 0x81, 0x96, 0x5B, 0xA0, 0xCD, 0x1A, 0x77, 0x84, 0x6D, 0x52, 0x15, 0x5B,
0x6A, 0xA9, 0x15, 0xE5, 0xC8, 0x32, 0x43, 0xAE, 0xF2, 0x09, 0xCF, 0x5E, 0xF9, 0xAA, 0x8B, 0xBD,
0x26, 0xC1, 0x36, 0xBA, 0x04, 0x13, 0x93, 0x61, 0x57, 0x6C, 0x54, 0x6C, 0x52, 0xE3, 0x1B, 0x36,
0x08, 0x98, 0x73, 0x2F, 0x59, 0x8D, 0x2E, 0xA2, 0xAB, 0x99, 0xAB, 0xC9, 0xA0, 0xC0, 0x1D, 0xBC,
0xE3, 0x2C, 0xEE, 0x36, 0x8B, 0x4B, 0xCE, 0xFC, 0x6E, 0x07, 0xEA, 0x3F, 0x68, 0xD6, 0x6A, 0xBA,
0xE1, 0xDC, 0x05, 0x90, 0x3A, 0xDD, 0x99, 0x31, 0xB6, 0x60, 0xF9, 0x8A, 0xD3, 0xAB, 0x46, 0xEE,
0xC8, 0x02, 0xD6, 0xA8, 0xA3, 0xA0, 0x86, 0xC6, 0x6B, 0x54, 0x1B, 0xD5, 0x77, 0xF8, 0x56, 0x85,
0xF5, 0x90, 0xFC, 0x4B, 0x64, 0xD2, 0x8A, 0x48, 0x81, 0x24, 0x08, 0xAB, 0xF4, 0xB0, 0xA5, 0xCE,
0xC2, 0x71, 0xE5, 0xAD, 0xBA, 0x27, 0x0D, 0x5B, 0x13, 0xBF, 0x9E, 0x86, 0x87, 0x27, 0x60, 0x47,
0x76, 0x15, 0x46, 0x95, 0xED, 0xB9, 0xA3, 0xEE, 0x81, 0x64, 0xBB, 0x86, 0xF9, 0xA0, 0x98, 0xD0,
0x15, 0x8B, 0x03, 0x44, 0xA0, 0x2D, 0xD5, 0xC7, 0x14, 0x92, 0xD3, 0x2E, 0xB4, 0x9D, 0xD3, 0x13,
0x15, 0x3B, 0xD1, 0x85, 0x95, 0xE8, 0x0A, 0x0A, 0xFB, 0x35, 0x1F, 0x19, 0xC1, 0x64, 0x97, 0x77,
0x10, 0x27, 0x7D, 0x9D, 0x47, 0x20, 0x16, 0x52, 0x88, 0x05, 0x40, 0xE4, 0x08, 0x28, 0x20, 0x4A,
0xC6, 0x04, 0x65, 0xBF, 0x9F, 0xF7, 0x5F, 0xFE, 0x90, 0xAA, 0x9A, 0xB0, 0x37, 0x00, 0x00
};
String char1000 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
class SPIFFSEditor: public AsyncWebHandler {
private:
String _username;
String _password;
bool _authenticated;
uint32_t _startTime;
public:
SPIFFSEditor(String username=String(), String password=String()):_username(username),_password(password),_authenticated(false),_startTime(0){}
bool canHandle(AsyncWebServerRequest *request){
if(request->method() == HTTP_GET && request->url() == "/edit")
return true;
else if (request->method() == HTTP_GET && request->url() == "/list")
return true;
else if(request->method() == HTTP_GET && !(request->url().endsWith("/")) && request->hasParam("download"))
return true;
else if(request->method() == HTTP_POST && request->url() == "/edit")
return true;
else if(request->method() == HTTP_DELETE && request->url() == "/edit")
return true;
else if(request->method() == HTTP_PUT && request->url() == "/edit")
return true;
return false;
}
void handleRequest(AsyncWebServerRequest *request){
if(_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str()))
return request->requestAuthentication();
if(request->method() == HTTP_GET && request->url() == "/edit"){
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
} else if(request->method() == HTTP_GET && request->url() == "/list"){
if(request->hasParam("dir")){
String path = request->getParam("dir")->value();
Dir dir = SPIFFS.openDir(path);
path = String();
String output = "[";
while(dir.next()){
fs::File entry = dir.openFile("r");
if (output != "[") output += ',';
bool isDir = false;
output += "{\"type\":\"";
output += (isDir)?"dir":"file";
output += "\",\"name\":\"";
output += String(entry.name()).substring(1);
output += "\"}";
entry.close();
}
output += "]";
request->send(200, "text/json", output);
output = String();
}
else
request->send(400);
} else if(request->method() == HTTP_GET){
request->send(SPIFFS, request->url(), String(), true);
} else if(request->method() == HTTP_DELETE){
if(request->hasParam("path", true)){
SPIFFS.remove(request->getParam("path", true)->value());
request->send(200, "", "DELETE: "+request->getParam("path", true)->value());
} else
request->send(404);
} else if(request->method() == HTTP_POST){
if(request->hasParam("data", true, true) && SPIFFS.exists(request->getParam("data", true, true)->value()))
request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value());
else
request->send(500);
} else if(request->method() == HTTP_PUT){
if(request->hasParam("path", true)){
String filename = request->getParam("path", true)->value();
if(SPIFFS.exists(filename)){
request->send(200);
} else {
fs::File f = SPIFFS.open(filename, "w");
if(f){
f.write((uint8_t)0x00);
f.close();
request->send(200, "", "CREATE: "+filename);
} else {
request->send(500);
}
}
} else
request->send(400);
}
}
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
if(!index){
if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str())){
_authenticated = true;
request->_tempFile = SPIFFS.open(filename, "w");
_startTime = millis();
}
}
if(_authenticated && request->_tempFile){
if(len){
request->_tempFile.write(data,len);
}
if(final){
request->_tempFile.close();
uint32_t uploadTime = millis() - _startTime;
os_printf("upload: %s, %u B, %u ms\n", filename.c_str(), index+len, uploadTime);
}
}
}
};
// SKETCH BEGIN
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
AsyncEventSource events("/events");
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
if(type == WS_EVT_CONNECT){
os_printf("ws[%s][%u] connect\n", server->url(), client->id());
client->printf("Hello Client %u :)", client->id());
client->ping();
} else if(type == WS_EVT_DISCONNECT){
os_printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if(type == WS_EVT_ERROR){
os_printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
} else if(type == WS_EVT_PONG){
os_printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
} else if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
String msg = "";
if(info->final && info->index == 0 && info->len == len){
//the whole message is in a single frame and we got all of it's data
os_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
os_printf("%s\n",msg.c_str());
if(info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
} else {
//message is comprised of multiple frames or the frame is split into multiple packets
if(info->index == 0){
if(info->num == 0)
os_printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
os_printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
}
os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
}
}
os_printf("%s\n",msg.c_str());
if((info->index + len) == info->len){
os_printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
if(info->final){
os_printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
if(info->message_opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
}
void handleVariable(AsyncWebServerRequest *request) {
os_printf("variable\n");
if(!request->hasParam("size")){
request->send(500, "text/plain", "Argument 'size' is missing");
}
else {
int length = atoi(request->getParam("size")->value().c_str());
if(length == 0){
request->send(500, "text/plain", "Argument 'size' must be >= 0 ");
}
else {
//send generated reply of requested size
// (from AsyncWebServer documentation)
AsyncWebServerResponse *response = request->beginResponse("application/octet-stream", length, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
//Write up to "maxLen" bytes into "buffer" and return the amount written.
//index equals the amount of bytes that have been already sent
//You will not be asked for more bytes once the content length has been reached.
//Keep in mind that you can not delay or yield waiting for more data!
//Send what you currently have and you will be asked for more again
if (maxLen >= 1000) {
strcpy((char*)buffer, char1000.c_str());
return 1000;
}
else {
strncpy((char*)buffer, char1000.c_str(), maxLen);
return maxLen;
}
});
response->addHeader("Content-Disposition", "attachment; filename=data_" + String(length) + ".dat");
request->send(response);
}
}
}
const char* http_username = "admin";
const char* http_password = "admin";
void setup(){
Serial.begin(115200);
Serial.setDebugOutput(true);
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);
}
//Send OTA events to the browser
ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); });
ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
char p[32];
sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
events.send(p, "ota");
});
ArduinoOTA.onError([](ota_error_t error) {
if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota");
else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota");
else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota");
else if(error == OTA_END_ERROR) events.send("End Failed", "ota");
});
ArduinoOTA.begin();
SPIFFS.begin();
ws.onEvent(onWsEvent);
server.addHandler(&ws);
events.onConnect([](AsyncEventSourceClient *client){
client->send("hello!",NULL,millis(),1000);
});
server.addHandler(&events);
server.addHandler(new SPIFFSEditor(http_username,http_password));
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm");
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", String(ESP.getFreeHeap()));
});
server.on("/variable", HTTP_GET, handleVariable);
server.onNotFound([](AsyncWebServerRequest *request){
os_printf("NOT_FOUND: ");
if(request->method() == HTTP_GET)
os_printf("GET");
else if(request->method() == HTTP_POST)
os_printf("POST");
else if(request->method() == HTTP_DELETE)
os_printf("DELETE");
else if(request->method() == HTTP_PUT)
os_printf("PUT");
else if(request->method() == HTTP_PATCH)
os_printf("PATCH");
else if(request->method() == HTTP_HEAD)
os_printf("HEAD");
else if(request->method() == HTTP_OPTIONS)
os_printf("OPTIONS");
else
os_printf("UNKNOWN");
os_printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
if(request->contentLength()){
os_printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
os_printf("_CONTENT_LENGTH: %u\n", request->contentLength());
}
int headers = request->headers();
int i;
for(i=0;i<headers;i++){
AsyncWebHeader* h = request->getHeader(i);
os_printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
}
int params = request->params();
for(i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isFile()){
os_printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
} else if(p->isPost()){
os_printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
} else {
os_printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
}
request->send(404, "text/plain", "FileNotFound");
});
server.onFileUpload([](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
if(!index)
os_printf("UploadStart: %s\n", filename.c_str());
os_printf("%s", (const char*)data);
if(final)
os_printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
});
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
if(!index)
os_printf("BodyStart: %u\n", total);
os_printf("%s", (const char*)data);
if(index + len == total)
os_printf("BodyEnd: %u\n", total);
});
server.begin();
}
void loop(){
ArduinoOTA.handle();
}
For the sake of ompleteness, here are the batch files I used to perform the wget's:
in sequence (the time computation routine was found on the net. Sorry I forgot where so I cannot give due credit :-/ ):
@echo off
set start=%time%
wget -O test1 http://192.168.0.100/variable?size=100000
wget -O test2 http://192.168.0.100/variable?size=100000
wget -O test3 http://192.168.0.100/variable?size=100000
wget -O test4 http://192.168.0.100/variable?size=100000
set end=%time%
set options="tokens=1-4 delims=:.,"
for /f %options% %%a in ("%start%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100
for /f %options% %%a in ("%end%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100
set /a hours=%end_h%-%start_h%
set /a mins=%end_m%-%start_m%
set /a secs=%end_s%-%start_s%
set /a ms=%end_ms%-%start_ms%
if %hours% lss 0 set /a hours = 24%hours%
if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins%
if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs%
if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms%
if 1%ms% lss 100 set ms=0%ms%
:: mission accomplished
set /a totalsecs = %hours%*3600 + %mins%*60 + %secs%
echo Execution time: %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total)
pause
and in parallel (similarly, I found the "parallel in batch" code here. Kudos go to user benham for the technique):
@echo off
set start=%time%
setlocal enableDelayedExpansion
:: Display the output of each process if the /O option is used
:: else ignore the output of each process
if /i "%~1" equ "/O" (
set "lockHandle=1"
set "showOutput=1"
) else (
set "lockHandle=1^>nul 9"
set "showOutput="
)
:: List of commands goes here. Each command is prefixed with :::
::: wget -O test1 http://192.168.0.100/variable?size=100000
::: wget -O test2 http://192.168.0.100/variable?size=100000
::: wget -O test3 http://192.168.0.100/variable?size=100000
::: wget -O test4 http://192.168.0.100/variable?size=100000
:: Define the maximum number of parallel processes to run.
:: Each process number can optionally be assigned to a particular server
:: and/or cpu via psexec specs (untested).
set "maxProc=4"
:: Optional - Define CPU targets in terms of PSEXEC specs
:: (everything but the command)
::
:: If a cpu is not defined for a proc, then it will be run on the local machine.
:: I haven't tested this feature, but it seems like it should work.
::
:: set cpu1=psexec \\server1 ...
:: set cpu2=psexec \\server1 ...
:: set cpu3=psexec \\server2 ...
:: etc.
:: For this demo force all cpu specs to undefined (local machine)
for /l %%N in (1 1 %maxProc%) do set "cpu%%N="
:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
set "lock="
for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
set "lock=%%T"
goto :break
)
:break
set "lock=%temp%\lock%lock%_%random%_"
:: Initialize the counters
set /a "startCount=0, endCount=0"
:: Clear any existing end flags
for /l %%N in (1 1 %maxProc%) do set "endProc%%N="
:: Launch the commands in a loop
set launch=1
for /f "tokens=* delims=:" %%A in ('findstr /b ":::" "%~f0"') do (
if !startCount! lss %maxProc% (
set /a "startCount+=1, nextProc=startCount"
) else (
call :wait
)
set cmd!nextProc!=%%A
if defined showOutput echo -------------------------------------------------------------------------------
echo !time! - proc!nextProc!: starting %%A
2>nul del %lock%!nextProc!
%= Redirect the lock handle to the lock file. The CMD process will =%
%= maintain an exclusive lock on the lock file until the process ends. =%
start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! %%A
)
set "launch="
:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
:: redirect stderr to null to suppress any error message if redirection
:: within the loop fails.
for /l %%N in (1 1 %startCount%) do 2>nul (
%= Redirect an unused file handle to the lock file. If the process is =%
%= still running then redirection will fail and the IF body will not run =%
if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" (
%= Made it inside the IF body so the process must have finished =%
if defined showOutput echo ===============================================================================
echo !time! - proc%%N: finished !cmd%%N!
if defined showOutput type "%lock%%%N"
if defined launch (
set nextProc=%%N
exit /b
)
set /a "endCount+=1, endProc%%N=1"
)
)
if %endCount% lss %startCount% (
1>nul 2>nul ping /n 2 ::1
goto :wait
)
2>nul del %lock%*
if defined showOutput echo ===============================================================================
set end=%time%
set options="tokens=1-4 delims=:.,"
for /f %options% %%a in ("%start%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100
for /f %options% %%a in ("%end%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100
set /a hours=%end_h%-%start_h%
set /a mins=%end_m%-%start_m%
set /a secs=%end_s%-%start_s%
set /a ms=%end_ms%-%start_ms%
if %hours% lss 0 set /a hours = 24%hours%
if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins%
if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs%
if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms%
if 1%ms% lss 100 set ms=0%ms%
:: mission accomplished
set /a totalsecs = %hours%*3600 + %mins%*60 + %secs%
echo Execution time: %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total)
pause
The tests were performed in my holiday hotel room with my old netbook and a small dlink router at the other end of the room with no internet access (and only the netbook and the ESP were connected to it). In other words far from a workhorse setup, but sufficiently isolated to give meaningfulresults I think.
I admit I spent one hour diffing 2.3.0 and git's 2.4.0-pre and could not pinpoint the exact place where the boost comes from. I saw LWIP settings have changed, I saw much of the "packeting" logic which was in the upper layers has been moved down, but no real "that's the bug they fixed" or something along the lines.
Same for bbx10nde's original observation. I really don't get why that change boosted the transfers by a factor 10...
Do you think that even with an empty loop, the Async version could benefit from similar enhancements as the ESP8266WebServer ?
Kind regards,
Vicne