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:
Code: Untitled.cpp Select all
void loop()
{
CreateMessageAndAddToQueue();
SendMessages();
}Code: Untitled.cpp Select all
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.
Code: Untitled.cpp Select all
#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...