un exemple de code avec un buffer de 3600 entiers et génération par chunks
je ne me suis pas cassé la tête pour les chunks, j'émets simplement un échantillon dans chaque chunk comme ça je ne m'ennuie pas à compter les octets qui rentrent dans le buffer; (Bien sûr, c'est plus long de générer le fichier comme cela car on n'optimise pas le buffer).
la subtilité vient du fait que sur l'ESP32 on a 2 processeurs et donc on ne peut pas se permettre que le callback web travaille sur le buffer qui sert aux acquisitions. Il y a donc une duplication protégée par un sémaphore (mutex) des 3600 valeurs et la fonction pour les chunks travaille sur la copie.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
const char* ssid = "xxx";
const char* password = "xxx";
AsyncWebServer server(80);
SemaphoreHandle_t mutex = NULL;
const char contenu[] PROGMEM = u8R"rawliteral(
<html>
<head>
<meta charset="UTF-8">
<title>Serveur de fichiers ESP32</title>
</head>
<body>
<h1>ACQUISITION DE DONNEES</h1>
<p><a href='/download'>Télécharger le fichier</a></p>
</body>
</html>
)rawliteral";
constexpr unsigned long nbMesures = 3600;
int mesures[nbMesures];
unsigned long indiceProchaineMesure = 0;
bool tableauPein = false;
int copieMesures[nbMesures];
unsigned long copieIndiceProchaineMesure = 0;
bool copieTableauPein = false;
void ajouterMesure(int valeur) {
mesures[indiceProchaineMesure] = valeur;
if (++indiceProchaineMesure >= nbMesures) {
tableauPein = true;
indiceProchaineMesure = 0;
}
}
void acquisition() {
static unsigned long chrono = -1000;
if (millis() - chrono >= 10) {
if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE) {
// OK pour être en section critique
// on rajoute un élément à 1Hz (ici un nombre aléatoire)
ajouterMesure(random(4096));
xSemaphoreGive(mutex);
chrono = millis();
}
}
}
size_t chunkedCallback(uint8_t *buffer, unsigned long maxLen, unsigned long index) {
// on ne se casse pas la tête on ajoute 1 seule ligne à la fois :)
static unsigned long nbEchantillonsEnvoyes = 0;
if (index == 0) { // c'est le debut d'un chunk
nbEchantillonsEnvoyes = 0;
snprintf((char*) buffer, maxLen, "Le tableau contient %lu échantillons\r\n", tableauPein ? nbMesures : copieIndiceProchaineMesure);
return strlen((const char*)buffer);
}
if (copieTableauPein) {
// on doit emettre toutes les valeurs, la plus vieille est à indiceProchaineMesure
if (nbEchantillonsEnvoyes >= nbMesures) return 0ul; // on a fini
} else {
// on emet de 0 à indiceProchaineMesure (non compris)
if (nbEchantillonsEnvoyes >= copieIndiceProchaineMesure) return 0ul; // on a fini
}
// sinon on emet une ligne
if (copieTableauPein) {
snprintf((char*) buffer, maxLen, "%lu\t%d\r\n", nbEchantillonsEnvoyes + 1, copieMesures[(copieIndiceProchaineMesure + nbEchantillonsEnvoyes) % nbMesures]);
} else {
snprintf((char*) buffer, maxLen, "%lu\t%d\r\n", nbEchantillonsEnvoyes + 1, copieMesures[nbEchantillonsEnvoyes]);
}
nbEchantillonsEnvoyes++;
return strlen((const char*)buffer);
}
void setup() {
mutex = xSemaphoreCreateMutex();
Serial.begin(115200);
// Se connecter au Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connexion au Wi-Fi en cours...");
while (WiFi.status() != WL_CONNECTED) {
Serial.write('.');
delay(500);
}
Serial.println(" => Connecté");
Serial.print("Joindre le serveur web sur http://");
Serial.println(WiFi.localIP());
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send_P(200, "text/html", contenu);
});
server.on("/download", HTTP_GET, [](AsyncWebServerRequest * request) {
// on attend le mutex et on fait une copie
while (xSemaphoreTake(mutex, portMAX_DELAY) != pdTRUE);
memcpy(copieMesures, mesures, sizeof mesures);
copieIndiceProchaineMesure = indiceProchaineMesure;
copieTableauPein = tableauPein;
xSemaphoreGive(mutex);
AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", chunkedCallback);
response->addHeader("Content-Disposition", "attachment; filename=fichier.txt");
request->send(response);
});
// Démarrer le serveur
server.begin();
}
void loop() {
acquisition();
}
Si vous voulez améliorer les performances, il faudrait mettre un maximum d'enregistrements dans le buffer pour limiter le nombre de chunks ➜ laissé au lecteur ![]()