Arduino can't process serial fast enough - c#

So my Arduino is taking almost 200ms processing a total of 128 bytes. The whole process without writing over the serial port is only taking 25ms.
Why is my Arduino bottlenecking so much?
Arduino
setColor is simply setting the color of the ledstrip using the FastLED library.
void loop() {
if(Serial.available() == 4){
int led = Serial.read();
int r = Serial.read();
int g = Serial.read();
int b = Serial.read();
setColor(led, r, g, b);
Serial.write(1);
if(Serial.available() > 0) Serial.read();
}
}
C#
In a loop I am doing the following to write the data:
attempt:
if (Port.isReady) {
strip.Send(new byte[] { id, c.R, c.G, c.B });
Port.isReady = false;
} else {
goto attempt;
}
public void Send(byte[] bytes) {
port.Write(bytes, 0, bytes.Length);
}
And I read the Arduino response using:
private const int DONE = 1;
public void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e) {
Console.WriteLine("- Serial port data received -");
Console.WriteLine("Nr. of bytes: {0}", port.BytesToRead);
if (port.ReadByte() == DONE) {
isReady = true;
}
port.DiscardInBuffer();
}

Well it all depends on your baudrate. If your baudrate are 9600 you can receive 9600 bit per second, thats 1200 bytes.
So 128/1200 = 0.1066 = 107 ms spend on receiving 128 bytes.
Higher baudrates will give shorter readtime.
Well why is it then taking 200ms you then ask?
My guess is that it is because of the many calls to setColor()
You are calling that once for every 4 bytes so that is 32 times.
I don't know the execution time on that function, but if it's something like 2-3ms you'r hitting that 200ms fast.

Related

How to close read function on Com Port

I'm trying to communicate on a com port on a single wire UART(Half Duplex). It's a C# Application with 8 bit MCU.
Here, Application is the master and MCU is a slave. On the MCU the RX is disabled while TX is sending.
The requirement is to make the com port disable the read function while I send data from the Application.
To do this, I tried to pull out from the buffer of RX after it transmits the number of bytes it transmits, but the MCU responds too fast and the last bytes of TX get in between with the response of the MCU.
Note: I can't change anything in the MCU
Here is my CODE:
public int serialRX()
{
int b;
if (serialPort.IsOpen && (serialPort.BytesToRead > 0))
{
try
{
b = serialPort.ReadByte();
}
catch (TimeoutException)
{
b = -1;
}
return b;
}
else
{
return -1;
}
}
public void serialTX(byte[] data)
{
if (serialPort.IsOpen)
{
serialPort.Write(data, 0, data.Length);
byte i = 0;
int read = -1;
while (i < data.Length)
{
while (read == -1)
{
read = serialRX();
}
read = -1;
i++;
}
}
}

C#: I have 100 clients to thread separately, what is the most effective way to send/receive data?

I'm doing a project with one Server and a Client for simulation purpose. The objective is to develop a single Server that can communicate with 100 clients at a same time using TCP and UDP. I am using TCPListener and UDPClient for both Server and Client. And I am using multi threading, creating an object class.
My code has 2 problems:
During the run, UDP packet gets lost, which freezes some of the threads.
The sending/receiving speed for UDP is immensely different (Thread 2 sent 2000 vs Thread 4 sent 900 etc)
Also, when I run 10 Threads, it will work perfectly fine. But when the number of threads increases, it will throw these problems.
I have the following bits of code ↓
Client (receiving function):
rpacket = new byte[1024];
//#0: UDP packet timeout
// is this necessary?? I could use while loop to measure waiting time.
net.tClient.Client.ReceiveTimeout = 1000;
net.client.Client.ReceiveTimeout = 1000;
//net.client.Client.SendTimeout = 2000;
// #1: message
_logIt(false, localThreadId, "started receivedata for threadid" + localThreadId);
// #2: number of received data recording
int nReceived = 0;
// #3: loop runs forever...
while (true)
{
// receiving data
bool recursion = false;
int recursionCount = 0;
int bytesReceived = 0;
// receiving data
bytesReceived = messageReceive(out recursion);
while (recursion == true)
{
// check if there are data 3 times
bytesReceived = messageReceive(out recursion);
recursionCount++;
if (recursionCount <= 3)
{
if (recursionCount == 1 && rIndex > 0)
{ rIndex--; }
// resend message
if (net.q[rIndex][1] == 0x00)
{
// sending data to PICS
// changed net.q[rIndex].Length - 1 to changed net.q[rIndex].Length - 2
try
{
int nBytesSend = net.client.Send(tempData, tempData.Length, net.ipEndPoint);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
// if 0x01, the protocl is TCP
else if (net.q[rIndex][1] == 0x01)
{
try {
int nBytesSend = net.tClient.Client.Send(tempData, tempData.Length, SocketFlags.None);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
else if (recursionCount == 4)
{
// hoot~ byebye
recursion = false;
Usage("hoot");
}
}
}
Client (sending function):
// if 0x00, the protocol is UDP
if (net.q[rIndex][1] == 0x00)
{
// sending data to PICS
// changed net.q[rIndex].Length - 1 to changed net.q[rIndex].Length - 2
int nBytesSend = net.client.Send(data, net.q[rIndex].Length - 2, net.ipEndPoint);
}
// if 0x01, the protocl is TCP
else if (net.q[rIndex][1] == 0x01)
{
int nBytesSend = net.tClient.Client.Send(data, net.q[rIndex].Length - 2, SocketFlags.None);
}
// June 1th, tempData is only used for failed messages
if (data.Length != 0)
{ tempData = data; }
Array.Resize(ref tempData, data.Length);
net.nSent++;
totalSent[localThreadId]++;
if (verbosity)
_logIt(false, localThreadId, "# of data sent: " + net.nSent);
// after sending, set the queue[][0] to 0x00
net.q[rIndex][0] = 0x00;
// setting queue[][1] is not neccessary...
rIndex++;
Message Receive(out recursion):
messageReceive(out bool audi)
{
int numBytes = 0;
audi = false;
// updated try and catch method, because there can be udp or tcp
try
{
rpacket = net.client.Receive(ref net.ipEndPoint);
numBytes = rpacket.Length;
}
catch (SocketException ex)
{
try
{
numBytes = net.tClient.Client.Receive(rpacket);
Array.Resize(ref rpacket, numBytes);
}
catch (Exception exc)
{
audi = true;
Console.WriteLine(exc.Message);
}
}
return numBytes;
}
Server side is same as the client.
FYI: there is a 2-D byte array called queue that stores all of the data that will be sent to the remote user. wIndex is a integer that is used for writing the reply data to the queue. rIndex is a integer that is used for reading the reply data from the queue and sends it to the remote user.
How can I fix my problems?
Warning Using multiple threads to send/receive with socket would lock the sockets and its I/O operation in your program.
When you are working with sockets it's better to work with async that sockets provide, like BeginRead and 'EndRead', because they make that the program will run over the same thread and it avoids the socket-client would get blocked. Also, don't use sleep into the socket-clients, they will block the socket.
Check this answer: C# High CPU usage on Listener thread, sleeping misses disconnect
In this answer i show how to use use the BeginRead and WriteRead.

Read serial data to winforms

Let's start off with that I have no idea what I'm doing. I've done some fancy C# stuff, but with the arduino I'm clueless. Luckily this is the last assignment I have to do with the arduino, so after this I'm done with it.
I have a Adafruit RFID/NFC shield, to, well, read RFIC/NFC tags. This works perfectly with the Adafruit examples. Now I have it logging the ID of the tag to the serial, and I want my C# program to react to it.
I've looked around on the web for examples, but there isn't really much useful stuff to find about this specific piece. Hence why I'm posting a question here. So far I've tried using the DataReceivedHandler, as well as some other solutions (port.ReadByte();, what is described here and here).
But none of it seems to be working correctly. None of the solutions pick up anything the arduino is returning. I'm using Visual Studio 2015 for both the C# and the Arduino. Fist of all, I can run the C# while another instance of VS is keeping the serial console occupied. It didn't result in an error of any kind, which it apparently should have. Yes, the COM port is the correct one (3 on this computer) and yes, the cable works perfectly.
For the arduino I use the following code:
#include <Wire.h>
#include <Adafruit_PN532.h>
#define IRQ (2)
#define RESET (3) // Not connected by default on the NFC Shield
int ledPin = 11;
uint8_t code[] = { 153, 220, 181, 78, 0, 0, 0 };
boolean firstTime = true;
boolean correct = true;
Adafruit_PN532 nfc(IRQ, RESET);
void setup(void) {
Serial.begin(115200);
Serial.println("Hello!");
pinMode(ledPin, OUTPUT);
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532.
nfc.setPassiveActivationRetries(0xFF);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A card");
}
void loop(void) {
boolean success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
if (success) {
if (firstTime) { Serial.println("First time. Writing shit"); }
Serial.println("Found a card!");
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print("UID Value: ");
for (uint8_t i=0; i < uidLength; i++)
{
Serial.print(" 0x");Serial.print(uid[i], HEX);
if (firstTime) {
//code[i] = uid[i], HEX;
};
}
/*Serial.println("");
for (uint8_t i = 0; i < uidLength; i++) {
Serial.println(uid[i], HEX);
uint8_t temp = uid[i], HEX;
String temp = "0x" + uid[i];
}-*/
firstTime = false;
Serial.println("");
Serial.println("Let's check it: ");
digitalWrite(ledPin, HIGH);
for (uint8_t i = 0; i < uidLength; i++) {
//Serial.print("Looking for: "); Serial.println(code[i], HEX);
Serial.print("Found: "); Serial.println(uid[i], HEX);
if (code[i] == uid[i]) {
Serial.println("Found match!");
correct = true;
}
else {
Serial.print("Wanted: "); Serial.println(code[i], HEX);
correct = false;
}
}
if (correct) {
Serial.println("Complete code is correct!");
}
// Wait 1 second before continuing
delay(1000);
}
else
{
// PN532 probably timed out waiting for a card
Serial.println("Timed out waiting for a card");
}
}
Yes, this is nearly identical to the adafruit test programs, and no, that doesn't matter. I just need to get this working before Tuesday. I still need to change that the arduino only passes the ID to the serial monitor, but that is something to do when it can communicate with the C#. It needs to communicate in both ways:
The ID needs to be picked up by the C#
The C# will return a bool, and the arduino needs to act based on that bool
But I can't get the C# to work with the SerialPort. Can someone help me with how I should approach the serial communication from both ends?
A friend just worked this out for me. It's dirty, but it gets the job done.
SerialPort serial;
public Form1()
{
InitializeComponent();
serial = new SerialPort();
serial.PortName = "COM4";
serial.BaudRate = 9600;
serial.DtrEnable = true;
serial.Open();
Timer timer = new Timer();
timer.Interval = 1000;
timer.Tick += new System.EventHandler(timer_Tick);
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
String dataFromArduino = serial.ReadLine().ToString();
}
Thanks for the -1 again :p

Get network bandwidth information

I use a timer to get bandwidth per second and place that information on a label The output is a large value like 419000KB/S and next tick it may be 0KB/S. Is it a problem related to thread or something? I guess it was bytes can not update properly, but I have no idea to fix it.
public partial class MainWindow : Window
{
static long bytes = 0;
static NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
static Label uploadLabel;
public MainWindow()
{
InitializeComponent();
uploadLabel = uploadBandwidth;
IPv4InterfaceStatistics statistics = adapters[0].GetIPv4Statistics();
bytes = statistics.BytesSent;
Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler(TimeUp);
myTimer.Interval = 1000;
myTimer.Start();
}
public void TimeUp(object source, ElapsedEventArgs e)
{
IPv4InterfaceStatistics statistics = adapters[0].GetIPv4Statistics();
bytes = statistics.BytesSent - bytes;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<Label>(SetValue), uploadLabel);
}
private void SetValue(Label upload)
{
upload.Content = ((int)bytes / 1024).ToString() + "KB/s";
}
}
Update:
The problem is I change the value bytes to statistics.BytesSent - bytes which is wrong.
Here is the function I modified:
public void TimeUp(object source, ElapsedEventArgs e)
{
IPv4InterfaceStatistics statistics = NetworkInterface.GetAllNetworkInterfaces()[0].GetIPv4Statistics();
long bytesPerSec = statistics.BytesReceived - bytes;
bytes = statistics.BytesReceived;
String speed = (bytesPerSec / 1024).ToString() + "KB/S";
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<Label, String>(SetValue), uploadLabel, speed);
}
private void SetValue(Label upload, String speed)
{
upload.Content = speed;
}
There's a problem with your logic.
At the beginning, you store the data sent so far in bytes:
uploadLabel = uploadBandwidth;
IPv4InterfaceStatistics statistics = adapters[0].GetIPv4Statistics();
bytes = statistics.BytesSent; // initialize bytes to amount already sent
And then on each event, you reset the value to contain BytesSent - bytes:
IPv4InterfaceStatistics statistics = adapters[0].GetIPv4Statistics();
bytes = statistics.BytesSent - bytes;
So assuming that you start with 15k sent and send 1kB every second, the variables will be as follows:
|| seconds elapsed | BytesSent | bytes ||
||=================|===========|=======||
|| 0 | 15000 | 15000 ||
|| 1 | 16000 | 1000 ||
|| 2 | 17000 | 16000 ||
|| 3 | 18000 | 2000 ||
So as you can see, the bytes value is alternating and not showing any legitimate value in any of the cases except for the first one.
In order to fix your problem, you'll either need to introduce a second state variable or pass the bytes value to the SetValue method in a correct manner similar to answer by #Sign:
public void TimeUp(object source, ElapsedEventArgs e)
{
IPv4InterfaceStatistics statistics = adapters[0].GetIPv4Statistics();
var sent = statistics.BytesSent - bytes;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action<Label>(SetValue), uploadLabel, sent);
bytes = statistics.BytesSent;
}

Using COM port in C# and not getting all sent data

Just to explain, I have a dev board that is, on command, shooting out 4 chars (Bytes). The terminal program (RealTerm) i'm using to debug this sees all 4 bytes. I've now moved on to writing the desktop software, and my program is only paying attention to 1 out of 4 bytes sent. TO clarify, i don't know which 1 of 4 bytes (first , last, middle two) but i can find out if its really necessary.
At first I thought the SerialPort.DataReceived event would fire for each byte that was received. This isn't true, I don't know what causes it to fire but its not the receiving of a singular Byte.
So I tried looping over SerialPort.BytesToRead, but this also only gets the first byte, even though it recognizes there are 3 bytes to read (why not 4??)
Its not essential for me to receive this data at the exact time it hits the port, but obviously I dot want to be loosing 3/4 of my data. However it wont always be 4 bytes, that's just what its doing now. I just want to get all bytes that are ready to be read.
Event Handler:
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (comPort.BytesToRead > 0)
{
RxString = comPort.ReadExisting();
RxByte = comPort.ReadByte();
byte[] myByte = new byte[6];
for (int i = 0; i < 6; i++)
{
myByte[i] = 0000000;
}
comPort.Read(myByte, 0, comPort.BytesToRead);
for (int i=0;i<6;i++)
{
if (myByte[i] != null)
{
thisBytes.Add(myByte[i]);
}
}
RxString = RxByte + "";
try
{
this.Invoke(new EventHandler(dealWithByte));
}
catch
{
}
}
}
private void dealWithByte(object sender, EventArgs e)
{
foreach (byte item in thisBytes)
{
RxByte = Convert.ToInt16(item);
string binary = Convert.ToString(RxByte, 2).PadLeft(8, '0');
//processTime(binary);
}
}
I am not a C# person but the code is pretty simple, pseudo code
numBytes As Int = SerialPort1.BytesToRead 'get # of bytes available
buf(numBytes - 1) As Byte 'allocate a buffer
br As Int = SerialPort1.Read(buf, 0, numBytes) 'read the bytes
If br <> numBytes {
Resize(buf, br) 'resize the buffer
}
at this point store the bytes into a list. This list can then be processed for messages.

Categories