Ich nutze FreeRTOS auf einer Datenlogger-Anwendung auf einem ESP32. Grob
erklärt kümmert sich die main-Task um das Erfassen der Daten, die andere
namesns Logger schickt diese periodisch per FTP an einen Server. Zur
Kommunikation zwischen den Tasks und als Zwischenspeicher wird ein
StreamBuffer verwendet, die Daten werden von der Main-Task in den Buffer
geschrieben, die Logger-Task liest diesen wieder aus, sobald sich
genügend Daten im Buffer angesammelt haben.
Zum Testen schreibe ich pro Sekunde eine 16-bit-Zahl in den
Streambuffer, die Zahl wird dabei jedesmal um eins hochgezählt. Sobald
300 Zahlen (600 Bytes) erreicht sind, wird der gesamte Block zum Server
geschickt.
Im Prinzip funktioniert das, die Daten werden korrekt auf dem Server
gespeichert. Allerdings wartet xStreamBufferReceive in seltenen Fällen
(ca. 2-5%) nicht bis 600 Bytes eingetrudelt sind, sondern kehrt sofort
mit nur 2 Bytes zurück. Das geschieht manchmal sogar kurz
hintereinander. Danach wartet er wieder korrekt auf die nächsten 600
Bytes. Der Timeout ist auf 360 Sekunden eingestellt, da die Schwelle von
600 Bytes aber schon nach 300 Sekunden erreicht ist, sollte der Timeout
eigentlich nie zuschlagen.
Im Prinzip ist das nicht wirklich schlimm, es gehen keine Daten
verloren. Allerdings führt das kleckerlesweise Schreiben zu einer hohen
Last auf dem Server, denn jedesmal wird die FTP-Verbindung auf- und
wieder abgebaut.
Interessanterweise liefert die Receive-Funktion manchmal auch nur 0
Bytes zurück, diese kann ich natürlich einfach ignorieren.
Es scheint so zu sein, als ob xStreamBufferReceive manchmal das
TriggerLevel missachtet, ich frage mich nur warum und wieso?
Anbei die vereinfachte Struktur des Programms, Infoausgaben und der
Austausch des data_buffer-Handles ist hier nicht dargestellt.
Erzeugen des Streambuffer und der Logger-Task
1 | #define BUFFER_SIZE 2000
|
2 | #define FTP_CHUNK_SIZE 600 //Trigger Level
|
3 | void app_main(void) {
|
4 | ...
|
5 | StreamBufferHandle_t dataBuffer;
|
6 | uint16_t c = 0;
|
7 |
|
8 | dataBuffer = xStreamBufferCreate(BUFFER_SIZE, FTP_CHUNK_SIZE);
|
9 | xTaskCreate(loggerTask, "Logger", 4096, NULL, 8, NULL);
|
10 | ...
|
11 | while (true) {
|
12 | xStreamBufferSend(dataBuffer,&c,2,pdMS_TO_TICKS(1000));
|
13 | c++;
|
14 | vTaskDelay(pdMS_TO_TICKS(1000)); // wait 1 second
|
15 | }
|
16 | }
|
Auslesen in der Logger-Task, die Funktion ftp_writer schreibt den
Datensatz über FTP in ein File.
1 | void loggerTask(void *pvParameters) {
|
2 | char* ftp_buffer;
|
3 | ftp_buffer = (char*)malloc(FTP_CHUNK_SIZE);
|
4 | ...
|
5 | while(true) {
|
6 | // wait until FTP_CHUNK_SIZE Bytes have arrived
|
7 | nData = xStreamBufferReceive(dataBuffer, ftp_buffer, FTP_CHUNK_SIZE,
|
8 | pdMS_TO_TICKS(600*FTP_CHUNK_SIZE));
|
9 | if (nData > 0) {
|
10 | ftp_writer(ftp_buffer, nData); // send the chunk via FTP to the server
|
11 | }
|
12 | }
|
13 | }
|