However, plotting data using the myPlot.SendData() command is always the bottleneck since serial communication is typically the slowest link in the chain. So, I do a few things to eek out more speed:
1. Run separate threads for "run the experiment" code and "send the data to Meguno".
2. Use a message queue so the "run the experiment" code can quickly add new data to the stack
3. Bundle up data points into batches and send them using the batch send signature of myPlot.SendData(). This is a major speed booster.
As a result of the multithreading, I have to protect against simultaneous threads trying to write to Meguno. To do that, I use a simple mutex.
It would be awesome if all of this were wrapped in the SendData() command by default. So, that's my feature request.
Here's some not-quite-complete code showing the relevant sections and my approach. The speed boost here is sometimes 10x greater than just sending data inside my CaptureData() method.
Code: Select all
//MegunoLink
XYPlot myPlot;
InterfacePanel Panel;
std::mutex meglock;
TaskHandle_t messageTask;
class DataPoint {
public:
char* title;
int position;
float force;
DataPoint() {
title = "";
position = 0;
force = 0;
}
DataPoint(char* _title, int _position, float _force)
{
title = _title;
position = _position;
force = _force;
}
};
QList<DataPoint> mQueue;
setup()
{
//process the message queue on a different thread
xTaskCreatePinnedToCore(processMessageQueue, "processMessageQueue", 5000, NULL, 5, &messageTask, 1);
}
void processMessageQueue(void* pvParameters)
{
for (;;)
{
if (mQueue.length() > 0)
{
int l = mQueue.length();
int* positions = new int[1];
positions = (int*)malloc(l * sizeof(int));
float* forces = new float[1];
forces = (float*)malloc(l * sizeof(float));
char* title = mQueue.front().title;
for (int i = 0; i < l; i++)
{
DataPoint p = mQueue.front();
positions[i] = p.position;
forces[i] = p.force;
mQueue.pop_front();
}
if (meglock.try_lock())
{
myPlot.SendData(title, positions, forces, l, 0);
meglock.unlock();
}
}
vTaskDelay(75);
}
}
void CaptureData(){
//do some stuff
DataPoint pt("my test name", xValue, yValue);
mQueue.push_back(pt);
}