I have created a program in C# to receive high speed data coming from my Teensy 4.1 uController. The controller is simply measuring voltages at two channels every 1 microsec and sends them over a USB along with a time stamp. The packet length for each reading is 18 Bytes: 4 Bytes (Preamble) + 1 Byte (Packet Length) + 1 Byte (Measurement type) + 12 Bytes (All the info: 4 bytes (time stamp), 4 bytes (voltages1), 4 bytes (voltage2).). Hence I am getting 18 MBps over the USB port. Teensy works at the speeds of a USB 2.0 hence the limit is 480 Mbps / 8 = 60 MBps- so this isnt an issue.
For now, I am only sending data for a short period of time, say 1 second.
In my C# program, I have two methods to display this data: Real-Time processing and passive mode.
In Real-Time processing, I am reading the data in one thread and processing it in another. In this method, I frequently miss data.
In passive mode, I first read data and store it in a memory and after the acquisition time is over, Which is 1 sec in this case, My code stops receiving and starts to process the data. In this method, the frequency of missing data is rather less and sometime no missing data.
I have detached serial port interrupt since then the data missing is much higher.
I have tried double buffering technique but still I am missing data.
I want to fix this issue of missing data. any help would be appreciated.
My code is:
Method to call the threads
// Global variables
int passiveMode = 0;
int serialReadFlag = 0;
BlockingCollection<byte> fifo_queue = null;
int TEENSYADC = 40;
int PREAMBLE = 85;
int PREAMBLE_COUNT=4;
//
private void requestResponse()
{
serialReadFlag = 1;
serialPortTeensy.DataReceived -= new SerialDataReceivedEventHandler(this.serialPortTeensy_DataReceived);
serialPortTeensy.DiscardInBuffer();
serialPortTeensy.DiscardOutBuffer();
fifo_queue = new BlockingCollection<byte>();
serialPortTeensy.WriteLine(RESPONSE + 1); //Request response from Teensy
passiveMode = 0; // change to 1 to enable passive mode
if (passiveMode == 0)
{
Thread readThread = new Thread(readTSnewDouble);
readThread.Priority = ThreadPriority.Highest;
readThread.Start();
Thread processThread = new Thread(processTSnewDouble);
processThread.Start();
}
else
{
Thread readThread = new Thread(readTSnewfast);
readThread.Priority = ThreadPriority.Highest;
readThread.Start();
}
}
private void readTSnew()
{
while (serialReadFlag > 0 || serialPortTeensy.BytesToRead > 0) // In Passive mode, a timer interrupt method will change the serialReadFlag to 0
{
try
{
int serialbytestoread = serialPortTeensy.BytesToRead;
byte[] buffer = new byte[serialbytestoread];
serialPortTeensy.Read(buffer, 0, buffer.Length);
lock (serialLock)
{
foreach (var b in buffer)
fifo_queue.Add(b);
}
}
catch
{
}
//Thread.Sleep(1); // If I turn this on, I miss much more data. Wanted to used this to accumulate more data in the serial buffer but then its somehow results in a loss of data.
}
if (passiveMode == 1) // Passive mode will process after full data is acquired.
{
Thread processThread = new Thread(processTSnew);
processThread.Start();
}
}
Method to Process the data
while (serialReadFlag > 0 || fifo_queue.Count > 0)
{
try
{
while (fifo_queue.Count > 0)
{
int incoming_byte = 0;
long message1 = 0;
long message2 = 0;
long message3 = 0;
if (preamble_count < PREAMBLE_COUNT)
{
incoming_byte = fifo_queue.Take();
}
if (incoming_byte == PREAMBLE && preamble_count < PREAMBLE_COUNT)
{
preamble_count++;
}
else if (fifo_queue.Count > 0 && preamble_count == PREAMBLE_COUNT)
{
int len = fifo_queue.ElementAt(0);
if (fifo_queue.Count > len - 1)
{
len = fifo_queue.Take();
int type = fifo_queue.Take();
switch (type)
{
case TEENSYADC:
if (len == 2)
{
abortReponse();
serialReadFlag = 0;
serialPortTeensy.DataReceived += new SerialDataReceivedEventHandler(this.serialPortTeensy_DataReceived);
break;
}
else
{
message1 = (long)fifo_queue.Take() << 24;
message1 |= (long)fifo_queue.Take() << 16;
message1 |= (long)fifo_queue.Take() << 8;
message1 |= (long)fifo_queue.Take();
message2 = (long)fifo_queue.Take() << 24;
message2 |= (long)fifo_queue.Take() << 16;
message2 |= (long)fifo_queue.Take() << 8;
message2 |= (long)fifo_queue.Take();
message3 = (long)fifo_queue.Take() << 24;
message3 |= (long)fifo_queue.Take() << 16;
message3 |= (long)fifo_queue.Take() << 8;
message3 |= (long)fifo_queue.Take();
servicepResponse(message1, message2, message3);
}
break;
default:
break;
}
}
preamble_count = 0;
}
else // not enough data received yet or garbage was received
{
}
}
}
catch
{ }
}
fifo_queue.Dispose();
In the images below, you will see that I have missed some data in the real-time mode but not in the passive mode. But keep in mind that the data is sometimes also missed in the passive mode but its less frequent.
plot for the data received in the real-time mode
plot for the data received in the passive mode
I have recently started programming in C# and I dont have much knowledge on performing thread-safe operations.