Getting a speed-bottleneck in data-communication when using anonymous pipes - c#

I have a program setup where a MCU sends me sensor data via USART to a C# windows forms application. That application upon receiving the data via the serialdatareceived event sends it to a managed c++ application using anonymous pipes. As soon as the data is received it is plotted in an OpenGL 3d enviroment.
My problem is that the 3D application only refreshes a few times per second and the animation is quite slow and not smooth enough. I did my best to improve the USART speed but the result is the same. I believe the animations speed is bottlenecked by the anonymous pipes speed. I was wondering if anyone else encountered this problem before and possibly found ways to speed upthe anonymous pipes data transfer.
So my problem is the low data transfer speed between the two applications. Ideally I would want 20+ messages a second but at the very least the bottleneck of the data transfer should be the USART interface and not the anonymous pipes. I am running a BAUD-rate of 19200 and am transferring the command "get_angle" and receiving data back fairly fast (~20 ms for calculation of data on the MCU), the data received is ~12 chars.
My anonymous pipe client in managed c++ (in WinMain):
try
{
String^ args = gcnew String(lpCmdLine);
PipeStream^ pipeClient = gcnew AnonymousPipeClientStream(PipeDirection::In, args);
StreamReader^ sr = gcnew StreamReader(pipeClient);
String^ temp;
fullscreen = FALSE;
if (!CreateGLWindow("OpenGL Test", 640, 480, 16, fullscreen))
{
return 0; // Quit If Window Was Not Created
}
while (!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message == WM_QUIT) // Was the message a quit message?
{
done = TRUE; // Set Flag to execute program
}
else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
temp = sr->ReadLine(); // Read text from pipeline
if (temp != "") // Make sure message is not empty/New message has been received
{
try
{
x_an = FLOAT::Parse(temp->Substring(0, 5)); // Parse X value from string to float
y_an = FLOAT::Parse(temp->Substring(7, 12)); // Parse Y value from string to float
}
catch (Exception^)
{
MessageBox(NULL, "Error parsing string to float", "Fatal error", MB_OK);
}
}
if ((!done)&& (1))
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if ((active && !DrawGLScene()) || keys[VK_ESCAPE]) // Active? Was There A Quit Received?
{
done = TRUE; // ESC or DrawGLScene Signalled A Quit
}
else // Not Time To Quit, Update Screen
{
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
}
}
}
// Shutdown
sr->Close();
pipeClient->Close();
KillGLWindow(); // Kill The Window
return (msg.wParam); // Exit The Program
}
catch (Exception^)
{
MessageBox(NULL, "Pipe connection error", "Fatal error", MB_OK);
return 0x01;
}
My code for the C# anonymous pipes server part:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (Ready_To_Receive)
{
if (Setup_Pipe)
{
try
{
pipeClient.StartInfo.FileName = "client.exe";
pipeClient.StartInfo.Arguments =
pipeServer.GetClientHandleAsString();
pipeClient.StartInfo.UseShellExecute = false;
pipeClient.Start();
pipeServer.DisposeLocalCopyOfClientHandle();
sw = new System.IO.StreamWriter(pipeServer);
sw.AutoFlush = true;
Setup_Pipe = false;
}
catch
{
MessageBox.Show("Error setting up pipeserver.");
button2_Click(this, null); // Resets application
}
}
Debug_String = serialPort1.ReadExisting();
Debug_String = Debug_String.Replace(serialPort1.NewLine, ""); // Delete newline character so all that remains are numbers
if (!(Debug_String == "")) // String is not empty
{
DataReceived = true;
try
{
sw.WriteLine(Debug_String);
}
catch (Exception)
{
MessageBox.Show("Connection to Pipe Client lost.");
button2_Click(this, null);
}
}
}
else if (Shutting_Down)
{
pipeClient.Close();
}
else
{
serialPort1.ReadExisting(); // Flush the data buffer
DataReceived = true;
}
}

Related

Reading data from serial Port is loosing packages

Hello i created a program which reads serial data from a scoreboard, then depending on the string the program separates the data into different boxes on the form and then to different txt files.The purpose of this, is to use those txt files for livestreaming purposes in basketball games.
It's the first time i work with serial data and i am not a very experienced programmer.
My problem, as the title of this post suggests is that every now and then without any reason i am loosing some packages. This is happening randomly , for example in 10 second period i could 1 package while the next one none or 4.
private void ReadData()
{
Thread MyThread = null;
{
try
{
ThreadStart ThreadMethod = new ThreadStart(ReadFromPort);
MyThread = new Thread(ThreadMethod);
}
catch (Exception e)
{
Console.WriteLine("Failed to create thread! " + e.Message);
return;
}
try
{
MyThread.Start();
}
catch (Exception e)
{
Console.WriteLine("The thread failed to start! " + e.Message);
}
}
}
//Recieves data and write them on textbox (optionally on a txt)
private void ReadFromPort()
{
while (Receiver == true)
{
try
{
int count = ComPort.BytesToRead;
System.Windows.Forms.Application.DoEvents();
byte[] data = new byte[count];
ComPort.Read(data, 0, data.Length);
currentMessage = Combine(currentMessage, data);
ReceivedData = (BitConverter.ToString(data));
if (count > 0)
{
if (chBoxUpdate.Checked)
{
DataType = count;
tempData = ReceivedData;
this.Invoke(new EventHandler(DisplayText));
if (chboxTxt.Checked)
{
this.Invoke(new EventHandler(ExportData));
}
}
else if (chBoxPrevious.Checked)
{
DataType = count;
tempData = ReceivedData;
this.Invoke(new EventHandler(ClearData));
this.Invoke(new EventHandler(DisplayText));
if (chboxTxt.Checked)
{
this.Invoke(new EventHandler(ExportData));
}
}
}
}
catch (Exception e)
{
}
}
}
//Displays Text
private void DisplayText(object sender, EventArgs e)
{
string temp;
Console.WriteLine(tempData+ " (" + tempData.Length.ToString() + ")");
try
{
if (tempData.Length == 38)// && ReceivedData.Substring(12, 5) == "03-02")
{
if (tempData.Substring(12, 5) == "03-02")
{
DataText.AppendText(tempData.Substring(24, 8));
DataText.AppendText("\n");
Blink.Text = "Reading...";
timer1.Start();
timer1.Enabled = true;
}
}
else
if (tempData.Length == 35)
{
if (tempData.Substring(12, 5) == "45-02")
{
AttackTime.AppendText(tempData.Substring(24, 5));
Blink.Text = "Reading...";
AttackTime.AppendText("\n");
timer1.Start();
timer1.Enabled = true;
}
}
else
if (tempData.Length == 29)
{
if (tempData.Substring(12, 5) == "03-36")
{
HomeScore.AppendText(tempData.Substring(21, 2));
Blink.Text = "Reading...";
HomeScore.AppendText("\n");
timer1.Start();
timer1.Enabled = true;
}
else
if (tempData.Substring(12, 5) == "03-46")
{
AwayScore.AppendText(tempData.Substring(21, 2));
Blink.Text = "Reading...";
AwayScore.AppendText("\n");
timer1.Start();
timer1.Enabled = true;
}
}
}
catch (ArgumentOutOfRangeException)
{
}
}
Keep in mind that tempData and ReceivedData are the same here and as the programs appears now there's not any particular reason to set tempData=ReceivedData.This is a part of a different,older code i used in the begining which i never changed but it doesn't effect the program.
At first i am using a thread to enable the ReadFromPort then if the program finds that there are available data in line it displays them with the DisplayText and it's using the ExportData to export the data to a txt.I think the problem is somewhere there but as i am not very experienced i can't tell where.
Are there any suggestions on how to improve my code? If you more details or information i can provide them.
You are using Invoke, this blocks the caller thread until the event has been processed, and since you are updating the UI this can take some time. This probably causes some buffer to overflow and data to be discarded. So you should do as little work as possible on the reading thread.
There are a few alternatives
Put the data on a concurrentQueue, and let the UI thread have a timer that periodically triggers a method that reads from the queue and updates the UI.
Put the data on a concurrentQueue, wrapped in a blocking collection, have another background thread iterate over the blocking collection, using GetConsumingEnumerable, and post the result to the main thread once done. This would be suitable if there is significant processing to be done.
Use BeginInvoke to post the received data to the main-thread, this does not wait for the call to complete, but probably have slightly higher overhead that the previous alternatives. I would recommend not accessing any UI properties from the background thread, since by default no property of a UI class is threadsafe. Even if you might get away with it if you are only reading, I would not take the chance.

How to append text into textbox form from seperate class?

I am fairly new to programming, and am not sure I'm doing this the correct way.
I've created a button on my main form that calls a separate class and appends the return to a richtextbox. This other class pings a machine and returns the text I want (obviously).
---Here is the main form and the button within it--
public void Btn_Ping_Click_1(object sender, EventArgs e)
{
Class1 pingClass = new Class1();
if (Btn_Ping.Text == "Ping")
{
Btn_Ping.Text = "Stop Ping";
}
else if (Btn_Ping.Text == "Stop Ping")
{
Btn_Ping.Text = "Ping";
}
while (Btn_Ping.Text == "Stop Ping")
{
richTextBox1.AppendText(pingClass.PingHost(Txt_Main.Text));
}
}
---Here is the seperate class that pings the machine and returns text--
namespace HelpDeskTools.Service.Classes
{
class Class1
{
HelpdeskTools_MainInterface mainForm = new HelpdeskTools_MainInterface();
public string PingHost(string host)
{
//string to hold our return messge
string returnMessage = string.Empty;
//IPAddress instance for holding the returned host
var address = Dns.GetHostEntry(host).AddressList.First();
//set the ping options, TTL 128
PingOptions pingOptions = new PingOptions(128, true);
//create a new ping instance
Ping ping = new Ping();
//32 byte buffer (create empty)
byte[] buffer = new byte[32];
var HasConnection = NetworkInterface.GetIsNetworkAvailable();
//first make sure we actually have an internet connection
if (HasConnection)
{
try
{
//send the ping 4 times to the host and record the returned data.
//The Send() method expects 3 items:
//1) The IPAddress we are pinging
//2) The timeout value
//3) A buffer (our byte array)
PingReply pingReply = ping.Send(address, 1000, buffer, pingOptions);
//make sure we dont have a null reply
if (!(pingReply == null))
{
switch (pingReply.Status)
{
case IPStatus.Success:
returnMessage = string.Format("Reply from host: bytes={0} Response Time={1}ms ", pingReply.Buffer.Length, pingReply.RoundtripTime);
break;
case IPStatus.TimedOut:
returnMessage = "Connection has timed out...";
break;
default:
returnMessage = string.Format("Ping failed: {0}", pingReply.Status.ToString());
break;
}
}
else
returnMessage = "Connection failed for an unknown reason...";
}
catch (PingException ex)
{
returnMessage = string.Format("Connection Error: {0}", ex.Message);
}
catch (SocketException ex)
{
returnMessage = string.Format("Connection Error: {0}", ex.Message);
}
}
else
returnMessage = "No Internet connection found...";
//return the message
return returnMessage;
} } }
The main problem with my code, is that the while loop runs in the main form infinitely (it does correctly append the text) but freezes the program (I want to be able to press the button again and stop the while loop) - I realize I didnt code the logic to stop the while loop in yet, because it freezes the program instantly and I need to address that first anwyay. I also dont know the best way to do this.
Is there a better way to run the while loop in the class and instead of returning a string, and actually append the text to the richtextbox1 WITHIN the class (is that even possible?) Right now its calling the function over and over, and to me that seems wrong.
Or am I doing this the right way but need to separate the function call into a different process somehow? (I have no idea how).
You must run your loop in another thread with async and await -> https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
And for your label you can try this -> How do I update the GUI from another thread?
Hope it helps

My multi-thread online Server gets too slow when multiple clients connect, C#

I'm trying to develop an online game just for fun, with a server and at least 2 clients playing in a single "room". My logic goes as follow, first have the server wait for a client to connect, after the client connects to the server I create a thread for this client (so the client can send messages to the server when it interacts with the main screen). After this if the client wants to play he clicks a button that says "start match" and if another client does the same both goes inside another Thread to play the game only between them. So I create a Thread for each client that connects and a Thread for every 2 clients that want to play.
Now, when i have 2 players playing the game everything goes smooth, the problem is when another 2 players want to play the game the server standalone stops responding (but you can still connect to the server and send messages) and the game gets really slow for the clients.I'm trying to learn about multi-threading that's why i'm doing this project so maybe i'm missing something. I should be creating only 2 threads for each client (when they are actually in game if not only 1) and with 4 clients that's at max 8 Threads, so why is my server getting so slow and crashing?.
This is where I accept my clients:
private void AcceptTcpClient(IAsyncResult ar)
{
TcpListener listener = (TcpListener)ar.AsyncState;
ServerClient sc = new ServerClient(listener.EndAcceptTcpClient(ar));
sc.SetisInGame(false); // not in game, just in the main menu
clients.Add(sc);
new Thread(() => MainPanelRoomThread(sc)).Start();
StartListening();
}
This is my Thread when a client connects:
private void MainPanelRoomThread(ServerClient scThread)
{
while (true)
{
if (!serverStarted)
return;
if (!scThread.GetisInGame()) //check if its not in game so it can receive data
{
NetworkStream stream = scThread.tcp.GetStream();
if (stream.DataAvailable)
{
StreamReader streamReader = new StreamReader(stream, true);
string data = streamReader.ReadLine();
if (data != null)
OnIncomingData(scThread, data); // waiting for that from the client
}
}
}
}
In the OnIncomingData function I wait for a Message saying that the client wants to enter a game so i can start the other thread:
private void OnIncomingData(ServerClient c, string data)
{
Debug.Log("Server = " + data);
string[] aData = data.Split('|');
switch (aData[0])
{
case "CMATCH":
if (aData[1].Contains("true"))
{
queueClients.Enqueue(c);
if (queueClients.Count == 2)
new Thread(new ThreadStart(RoomThread)).Start(); //start the Game only if 2 players are waiting for the game to start.
else
BroadCast("SMATCH|false", c);
}else if (aData[1].Contains("false"))
{
queueClients.Dequeue();
BroadCast("SMATCH|true", c);
}
break;
}
}
Finally the in Game room:
private void RoomThread()
{
string msg = "";
List<ServerClient> players = new List<ServerClient>();
List<ServerClient> disconnected = new List<ServerClient>();
int tamanoCola = queueClients.Count;
for(int i = 0; i < tamanoCola; i++)
{
players.Add(queueClients.Dequeue());
msg = players[i].clientName + "|";
players[i].isMainPlayer = (i == 0);
players[i].SetisInGame(true); //its in game
BroadCast("SWHO|" + msg + ((players[i].isMainPlayer) ? 1 : 0).ToString(), players[i]);
}
while (true)
{
if (!serverStarted)
return;
foreach (ServerClient c in players)
{
//check if client is still playing (either because the connection died or someone won)
if (!IsConnected(c.tcp))
{
c.tcp.Close();
disconnected.Add(c);
continue;
}
else
{
NetworkStream stream = c.tcp.GetStream();
if (stream.DataAvailable)
{
StreamReader streamReader = new StreamReader(stream, true);
string data = streamReader.ReadLine();
if (data != null)
OnIncomingData(c, data, players);
}
}
}
if (disconnected.Count >= 1)
return;
}
}
Any help is really appreciated.

Cannot read data from Arduino bluetooth serial data in WinRT

I am using Arduino UNO connected with bluetooth module. I have this below code in Arduino, which listen to specific input and glow the LED.
int LED= 13;
char input;
void setup()
{
Serial.begin(9600);
pinMode(LED, OUTPUT);
Serial.println(">> START<<");
Serial.flush();
}
void loop()
{
Serial.flush();
if(Serial.available()>0)
{
input= Serial.read();
if(input=='1')
{
Serial.write(1);
Serial.println('a');
digitalWrite(LED, HIGH);
}
else if(input=='0')
{
Serial.println("OFF");
digitalWrite(LED, LOW);
}
else
{
Serial.println("NO INPUT");
Serial.println(input);
}
}
}
From Windows 8.1 (XAML/C#) application I am sending data through bluetooth. And it works perfectly as expected. But I am also trying to read data from Arduino. For that I have below code in C#.
socket = new StreamSocket();
connectAction = socket.ConnectAsync(rfcommService.ConnectionHostName, rfcommService.ConnectionServiceName, SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
await connectAction;//to make it cancellable
writer = new DataWriter(socket.OutputStream);
reader = new DataReader(socket.InputStream);
Task.Run(() =>
{
ListenForMessagesAsync();
});
The ListenForMessagesAsync method supposed to keep listening the dataReader. But it just waiting for infinite time and never returns.
private async Task ListenForMessagesAsync()
{
while (reader != null)
{
try
{
uint sizeFieldCount = await reader.LoadAsync(1);// taskLoadLength.GetResults();
if (sizeFieldCount != 1)
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Read the message.
uint messageLength = reader.ReadByte();
uint actualMessageLength = await reader.LoadAsync(messageLength);
if (messageLength != actualMessageLength)
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Read the message and process it.
string message = reader.ReadString(actualMessageLength);
}
catch (Exception ex)
{
}
}
}
What am I doing wrong here?
You need a return after a successful ReadString and of course you need to do something with the message.

TCP Connection freezes while waiting for answer

I recently startet .NET programming and tried to do a small network game.
The Connection is set up properly and messages get mostly written and read at normal behaviour. But at some random point on runtime, the reading stream doesn't recognize the incoming message.
The Connection is set up via Tcp listener and the corresponding stream.
//Get the network Stream
stream = client.GetStream();
w = new BinaryWriter(stream);
r = new BinaryReader(stream);
As I said before, the communication is working, but seems to freeze at a random time ingame at the following point:
//Waiting for enemy to attack
public int ready()
{
try
{
while (r.ReadString() != ClientMessages.ATTACK) { }
Thread.Sleep(20);
return r.Read();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
throw new Exception("Dead");
}
}
It's always the same, that it get stuck within the while-loop. The Binary Reader doesn't seem to notice any further client messages no matter how many times I send the "Attack" order.
But the program is not somewhere in no man's land... if I shut down the connection, the method throws its "connection lost exception" just as normal.
At first I thought that I had screwed up something in this method, but in the following example, where I do almost the same, everything's perfect (or at least seems to be.. got never stuck at this point)
//Waiting for feedback
public int waitforfeedback()
{
try
{
while (r.ReadString() != ClientMessages.HIT) { }
Thread.Sleep(10);
return r.Read();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
throw new Exception("Dead");
}
}
Is it possible, that the problem is caused by a backgroundworker (which I use to call the network methods)?
What should I do to handle this problem?
EDIT :
As requested, the Backgroundworker code:
private void waiting()
{
bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
setter = true;
button.Content = "Waiting";
this.IsEnabled = false;
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
int hit = network.ready();
e.Result = hit;
}

Categories

Resources