Well, first I discovered mutex and and how important that is. And then I got told about xQueue and how I should implement that instead of creating my own solution.
This works just fine:
- void loop()
- {
- CreateMessageAndAddToQueue();
- SendMessages();
- }
- void setup()
- {
- //more setup before this...
- xTaskCreatePinnedToCore(
- Core0Loop, /* Function to implement the task */
- "Task1", /* Name of the task */
- 10000, /* Stack size in bytes */
- NULL, /* Task input parameter */
- 5, /* Priority of the task */
- NULL, /* Task handle. */
- 1); /* Core where the task should run */
- xTaskCreatePinnedToCore(
- Core1Loop, /* Function to implement the task */
- "Task1", /* Name of the task */
- 10000, /* Stack size in bytes */
- NULL, /* Task input parameter */
- 5, /* Priority of the task */
- NULL, /* Task handle. */
- 1); /* Core where the task should run */
- }
- void Core0Loop(void *parameter)
- {
- while (true)
- {
- CreateDataAndAddToxQueue();
- }
- }
- void Core1Loop(void *parameter)
- {
- while (true)
- {
- UploadxQueueAsJson();
- }
- }
- //Data generation
- int id = 0;
- void CreateMessageAndAddToQueue()
- {
- if (IsConfigured)
- {
- Serial.print("#");
- // Generate test messages in the loop
- Message messageToSend;
- messageToSend.id = 4000 + id;
- messageToSend.mdate = modem.getUnixTime();
- messageToSend.LpA = random(0, 100); // Random LpA between 0 and 10
- messageToSend.LpC = random(0, 100); // Random LpC between 0 and 10
- messageToSend.Battery = random(30, 50); // Random Battery between 3.0 and 5.0
- // Send the message to the queue
- if (xQueueSend(messageQueue, &messageToSend, portMAX_DELAY) != pdPASS)
- {
- Serial.println("Failed to send message to the queue");
- }
- // Delay before generating the next test message
- id++;
- }
- vTaskDelay(pdMS_TO_TICKS(newDataInterval));
- }
If I put them on different cores which should give the functions plenty of resources, I get watchdog errors:
[Codebox]
E (29125) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (29125) task_wdt: - IDLE (CPU 0)
E (29125) task_wdt: Tasks currently running:
E (29125) task_wdt: CPU 0: Task1
E (29125) task_wdt: CPU 1: Task1
E (29125) task_wdt: Aborting.
[/Codebox]
Googling that "watchdog got triggered" gives plenty of responses. But it seems the answer is often "do less in one of your functions", but that's not an option for me. Uploading takes time, and there's nothing I can do to prevent that.
The complete code as it looks right now is shown below. The lte_post(jsonString) uses the A76XX library (https://github.com/gasagna/A76XX/) to upload code.
- #include <Arduino.h>
- #include "lte_upload.h"
- #include <ArduinoJson.h>
- #include <esp_task_wdt.h>
- const uint64_t NodeID = ESP.getEfuseMac();
- unsigned long lastSendTime = 0;
- const unsigned long sendInterval = 2000; // milliseconds
- unsigned long lastNewDataTime = 0;
- const unsigned long newDataInterval = 500; // milliseconds
- typedef struct Message
- {
- uint64_t id;
- uint32_t mdate;
- double LpA;
- double LpC;
- double Battery;
- } Message;
- // Create a queue to store messages
- QueueHandle_t messageQueue;
- const int maxMessageCount = 20; // Adjust as needed
- Message *messageBuffer = nullptr;
- void SendMessagesTask(void *parameter);
- void loopTask(void *parameter);
- bool IsConfigured = false;
- const TickType_t xMaxBlockTime = pdMS_TO_TICKS(sendInterval); // Maximum block time for waiting in milliseconds
- void setup()
- {
- // begin serial port
- Serial.begin(115200);
- setCpuFrequencyMhz(240);
- Serial.println("Starting setup()...");
- // Setup the LTE modem
- if (!IsConfigured)
- {
- lte_setup();
- IsConfigured = true;
- // Create the message queue
- messageQueue = xQueueCreate(maxMessageCount, sizeof(Message)); // Adjust the size as needed
- // Allocate memory for the message buffer
- messageBuffer = (Message *)malloc(maxMessageCount * sizeof(Message));
- if (messageBuffer == nullptr)
- {
- Serial.println("Failed to allocate memory for message buffer");
- while (true)
- {
- };
- }
- // Start a task to send messages
- xTaskCreatePinnedToCore(loopTask, "MyLoopTask", 1024 * 8, NULL, 1, NULL, 1); // CORE0
- //xTaskCreate(loopTask, "MyLoopTask", 1024 * 8, NULL, 1, NULL);
- // xTaskCreatePinnedToCore(SendMessagesTask, "MyMessageTask", 1024 * 8, NULL, 1, NULL, 0); // CORE1
- }
- Serial.println("setup() done!");
- }
- int id = 0;
- void CreateMessageAndAddToQueue()
- {
- if (IsConfigured)
- {
- Serial.print("#");
- // Generate test messages in the loop
- Message messageToSend;
- messageToSend.id = 4000 + id;
- messageToSend.mdate = modem.getUnixTime();
- messageToSend.LpA = random(0, 100); // Random LpA between 0 and 10
- messageToSend.LpC = random(0, 100); // Random LpC between 0 and 10
- messageToSend.Battery = random(30, 50); // Random Battery between 3.0 and 5.0
- // Send the message to the queue
- if (xQueueSend(messageQueue, &messageToSend, portMAX_DELAY) != pdPASS)
- {
- Serial.println("Failed to send message to the queue");
- }
- // Delay before generating the next test message
- id++;
- }
- vTaskDelay(pdMS_TO_TICKS(newDataInterval));
- }
- void loopTask()
- {
- while (true)
- {
- CreateMessageAndAddToQueue();
- }
- }
- void SendMessages()
- {
- // for(int i = 0; i<3;i++)
- // {
- // CreateMessageAndAddToQueue();
- // }
- // Collect all messages
- int messageCount = 0;
- id = 0;
- TickType_t xStartTime = xTaskGetTickCount(); // Record the start time
- while (xTaskGetTickCount() - xStartTime < pdMS_TO_TICKS(sendInterval))
- { // Collect for the last X seconds
- TickType_t xStartNow = xTaskGetTickCount(); // Record the start time
- Message receivedMessage;
- if (xQueueReceive(messageQueue, &receivedMessage, xMaxBlockTime))
- {
- // Store the received message
- if (messageCount < maxMessageCount)
- {
- messageBuffer[messageCount] = receivedMessage;
- messageCount++;
- }
- }
- }
- Serial.print("Message count: ");
- Serial.println(messageCount);
- // Create a JSON array for the collected messages
- DynamicJsonDocument doc(1024); // Adjust the size as needed
- JsonObject root = doc.to<JsonObject>(); // Create the outermost JSON object
- root["mm_apikey"] = "myKey";
- root["data"]["station_id"] = NodeID;
- root["data"]["station_unixtime"] = modem.getUnixTime();
- // Create the "values" array
- JsonArray values = root["data"]["values"].to<JsonArray>();
- for (int i = 0; i < messageCount; i++)
- {
- JsonObject messageObject = values.createNestedObject();
- messageObject["id_node"] = messageBuffer[i].id;
- messageObject["mdate"] = messageBuffer[i].mdate;
- messageObject["lpa"] = messageBuffer[i].LpA;
- messageObject["lpa"] = messageBuffer[i].LpC;
- messageObject["battery"] = messageBuffer[i].Battery;
- }
- // Convert the JSON document to a string
- String jsonString;
- serializeJson(doc, jsonString);
- // Send the JSON string (replace this with your actual sending logic)
- Serial.println("Sending JSON: ");
- Serial.println(jsonString);
- esp_task_wdt_reset();
- // Sending the json string
- lte_post(jsonString);
- // Wait for a while before collecting and sending the next batch
- TickType_t xEndTime = xTaskGetTickCount(); // Record the end time
- vTaskDelay(pdMS_TO_TICKS(sendInterval));
- }
- bool initTask = false;
- void loop()
- {
- if (!initTask)
- {
- esp_task_wdt_init(120, true);
- esp_task_wdt_add(NULL);
- initTask = true;
- }
- SendMessages();
- }
- void SendMessagesTask(void *parameter)
- {
- (void)parameter;
- esp_task_wdt_init(120, true);
- esp_task_wdt_add(NULL);
- while (true)
- {
- SendMessages();
- }
- }
I might be missing some basics here, but I don't really know where to start...