I'm working with a fingerprint sensor on Arduino, but sometimes, on runtime, my WPF app throws an exception on sp.Open() saying "COM3" Access denied"
Here's the code on c#:
public string ConfigPort()
{
SerialPort sp = new SerialPort();
sp.BaudRate = 9600;
sp.PortName = AutodetectArduinoPort();
sp.Open();
string s = "";
while (true)
{
s = sp.ReadLine();
Console.WriteLine(s);
return s;
}
}
Here's the AutodetectArduinoPort method:
public string AutodetectArduinoPort()
{
ManagementScope connectionScope = new ManagementScope();
SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);
try
{
foreach (ManagementObject item in searcher.Get())
{
string desc = item["Description"].ToString();
string deviceId = item["DeviceID"].ToString();
if (desc.Contains("Arduino"))
{
return deviceId;
}
}
}
catch (ManagementException e)
{
/* Do Nothing */
}
return null;
}
Any solution??
This happens quite a lot with Arduino, personally I think there's a problem with the FTDI driver....certainly wouldn't be the first issue with them. What I do when this happens is physically unplug the device from the USB port, wait for the notification sound from Windows and then plug it back in again. This seems to "reset" the port and force whatever is holding it open to release it, and you're good to go again. You may need to do this quite a bit over time, so the only other tip I have is to use a cheap USB hub so that you wind up wearing out the port pins on that rather than your expensive laptop/desktop.
The error you're getting means that the port is already open. Make sure that you only call ConfigPort() once, and after you're done processing data from the Arduino, close the port with sp.Close(). I would suggest converting sp into a global variable, and subscribing to the OnClosing event of your WPF window, so you can close the port when the user closes the application.
Related
Using VS2013, WPF 4.5, Caliburn Micro. I want to replace the old method for multithreading for tcp data listener on my working client app with the new "async await".
Since I am not familiar with them, I bought and read the book "Concurrency in C# cookbook" (Author: Mr. Stephen Cleary) and C# in Depth Third Edition (Author: Mr. Jon Skeet). Then I write a sample code (see below) first, because I don't want to mess up my client app that run on customer machines.
The problem: After I click the Connect-Button, the GUI is blocked/frozen. Click any button even the "x" button can't help. I need to kill the process using Task Manager.
What I have tried till now but still find no answer nor sample code that helps:
read the book of Mr. Cleary and also his blog for TCP Socket FAQ.
read the book of Mr. Skeet Part 5 Chapter 15.
contacted Mr. Cleary via E-Mail (get it from his blog), still no answer; maybe he is still busy.
Therefore I ask here. Please tell me how to solve the problem and feel free to modify my code. Thank you in advance
ShellViewModel
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Caliburn.Micro;
namespace TcpClientAsyncAwait.ViewModels
{
public class ShellViewModel : Conductor<Screen>
{
private const Int64 MAX_DATA_LENGTH = 1024;
private const String CRLF = "\r\n";
private TcpClient _client;
private List<String> _responseData;
private Boolean _shouldStop;
private NetworkStream _stream;
private String _cmdConnect = "<StartConnect/>";
public TcpClient Client
{
get { return _client; }
set
{
_client = value;
NotifyOfPropertyChange(() => Client);
}
}
public List<String> ResponseData
{
get { return _responseData; }
set
{
_responseData = value;
NotifyOfPropertyChange(() => ResponseData);
}
}
public ShellViewModel()
{
}
public void Connect()
{
var hostIp = "127.0.0.1";
var port = 16770;
_client = new TcpClient(hostIp, port);
var listenTask = StartListenerAsync();
SendCmd(_cmdConnect);
}
private async Task StartListenerAsync()
{
_shouldStop = false;
if (_client != null)
{
while (!_shouldStop)
{
await GetMessageAsync().ConfigureAwait(false);
}
}
}
private async Task GetMessageAsync()
{
try
{
if (_stream == null) _stream = _client.GetStream();
if (_stream.DataAvailable)
{
Byte[] buffer = new Byte[MAX_DATA_LENGTH];
Int32 readBytes = await _stream.ReadAsync(buffer, 0, buffer.Length);
var receivedData = UTF8Encoding.UTF8.GetString(buffer, 0, readBytes);
Trace.WriteLine(receivedData);
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
private async Task SendCmd(string cmd)
{
if (_client != null)
{
// Manipulate command to fulfill format, that can be accepted by server
Byte[] utf8Source = UTF8Encoding.UTF8.GetBytes(cmd);
Byte[] suffix = UTF8Encoding.UTF8.GetBytes(CRLF);
Byte[] utf8Result = new byte[utf8Source.Length + suffix.Length];
Buffer.BlockCopy(utf8Source, 0, utf8Result, 0, utf8Source.Length);
Buffer.BlockCopy(suffix, 0, utf8Result, utf8Source.Length, suffix.Length);
if (_stream == null) _stream = _client.GetStream();
using (var sw = new StreamWriter(_stream))
{
var data = UTF8Encoding.UTF8.GetString(utf8Result).ToCharArray();
await sw.WriteAsync(data, 0, utf8Result.Length).ConfigureAwait(false);
await sw.FlushAsync().ConfigureAwait(false);
}
}
}
public void Disconnect()
{
_shouldStop = true;
if (_client != null) _client.Close();
}
}
}
ShellView
<Window x:Class="TcpClientAsyncAwait.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid Width="300" Height="300">
<StackPanel Width="130" Height="120"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="Connect"
Width="120" Height="50" Margin="5"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="Connect" />
<Button x:Name="DisConnect"
Width="120" Height="50" Margin="5"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="Disconnect" />
</StackPanel>
</Grid>
</Window>
EDIT:
Sample code is edited by adding namespace to ViewModel and XAML header to View due to completeness.
EDIT1:
OK, I get a tcp server sample code from MSDN, that works as server for my client sample code. Here the steps to compile the server sample code.
Download the C# version of that project from the link.
Using VS2013: open the ClientApp.sln.
In Solution Explorer: open project ServerApp and open Form1.cs to edit.
Goto line 30 and edit the port 3000 to 16770. Save the change.
Make the project ServerApp as startup project.
Build and run it.
Now the steps how to create and compile my client sample code, so you can reproduce the problem I have. Please follow the steps exactly.
Open VS2013
Get "SideWaffle Template Pack" Extension from Visual Studio Gallery, install it and restart VS2013.
Create "New Project" - choose "Caliburn.Micro WPF Application" project from SideWafle (see here) Set the solution name as TcpClientAsyncAwait
Click "Tools - NuGet Package Manager - Package Manager Console". On the Window of Package Manage Console you will see a warning "Some NuGet packages are missing from this solution. Click to restore from your online package sources.". Just follow the instruction by clicking the Restore-Button
After the download is completed, build the solution (usually I press "F6").
In Solution Explorer: open "View" folder and open the ShellView.xaml. You will see ShellView.xaml.cs (the code behind). Just delete that file.
Open ShellView.xaml and delete all code in it. Now you can copy & paste my sample code ShellView.xaml completely there.
Open "ViewModels" folder and open ShellViewModel.cs to edit.
Delete all code in it and copy & paste my sample code ShellViewModel.cs there.
Build it.
Note: Please run the server before you run the client, because my sample code is so simple and has no reconnect and no "no-server" detection mechanism.
EDIT2:
According suggestion from TedyPranolo it seems the loop could be the problem.
If I remove the loop the await GetMessageAsync().ConfigureAwait(false); is executed only once then ends. When the server sends another message later time, the client doesn't get the message anymore.
Q1: Now I want to know how to keep GetMessageAsync alive and always be ready to listen incoming message from server all the time till the application is closed. of course still in context "async await"
Q2: Or maybe "async await" does not fit for such purpose at all?
I am glad to get some solution suggestions from you all. Thank you in advance.
Your UI thread might be stuck on the loop here. Since there's no delay within the loop and GetMessageAsync the thread is probably too busy to process anything else.
while (!_shouldStop)
{
await GetMessageAsync().ConfigureAwait(false);
}
You may want to try the approach in this SO thread on how to do async socket.
Here's the code in the answer by #spender, in case something happens with that thread
void Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
TcpListener listener = new TcpListener(IPAddress.Any, 6666);
try
{
listener.Start();
//just fire and forget. We break from the "forgotten" async loops
//in AcceptClientsAsync using a CancellationToken from `cts`
AcceptClientsAsync(listener, cts.Token);
Thread.Sleep(60000); //block here to hold open the server
}
finally
{
cts.Cancel();
listener.Stop();
}
}
async Task AcceptClientsAsync(TcpListener listener, CancellationToken ct)
{
var clientCounter = 0;
while (!ct.IsCancellationRequested)
{
TcpClient client = await listener.AcceptTcpClientAsync()
.ConfigureAwait(false);
clientCounter++;
//once again, just fire and forget, and use the CancellationToken
//to signal to the "forgotten" async invocation.
EchoAsync(client, clientCounter, ct);
}
}
async Task EchoAsync(TcpClient client,
int clientIndex,
CancellationToken ct)
{
Console.WriteLine("New client ({0}) connected", clientIndex);
using (client)
{
var buf = new byte[4096];
var stream = client.GetStream();
while (!ct.IsCancellationRequested)
{
//under some circumstances, it's not possible to detect
//a client disconnecting if there's no data being sent
//so it's a good idea to give them a timeout to ensure that
//we clean them up.
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
var amountReadTask = stream.ReadAsync(buf, 0, buf.Length, ct);
var completedTask = await Task.WhenAny(timeoutTask, amountReadTask)
.ConfigureAwait(false);
if (completedTask == timeoutTask)
{
var msg = Encoding.ASCII.GetBytes("Client timed out");
await stream.WriteAsync(msg, 0, msg.Length);
break;
}
//now we know that the amountTask is complete so
//we can ask for its Result without blocking
var amountRead = amountReadTask.Result;
if (amountRead == 0) break; //end of stream.
await stream.WriteAsync(buf, 0, amountRead, ct)
.ConfigureAwait(false);
}
}
Console.WriteLine("Client ({0}) disconnected", clientIndex);
}
Others already pointed that the code sample is missing some async and await here and there. Among all comments and body text of your question I got a little bit lost, but just to be sure I'll ask this:
have you checked that Connect() method (the one bound to button action) is marked as async void? That should be one of the few cases when async void is allowed.
EDIT after comment: make sure that method now looks similar to this:
public async void Connect()
{
var hostIp = "127.0.0.1";
var port = 16770;
_client = new TcpClient(hostIp, port);
await StartListenerAsync(); // no return value needed
await SendCmdAsync(_cmdConnect); // renamed for clarity & to adhere to conventions
}
Also, that while (!_shouldStop) sounds fishy. If you need to interrupt your async operation, you should create a TaskCancellationSource and pass that along the whole call chain where you need such interruption feature. E.g. if the following represents a call chain:
await YourMethodAsync(..., cancellationSource);
...
await YourSubMethodAsync(..., cancellationSource);
...
var result = await SomeDotNetMethodAsync(..., cancellationSource);
await SomeOtherDotNetMethodAsync(..., cancellationSource);
If your custom methods just invoke out-of-the-box async methods, that should be enough. If your custom methods perform lenghty operations, or if they invoke long blocking-methods - e.g. a huge Buffer.BlockCopy() - then it is up to your method to break the long blocking operation into some kind of loop of shorter ones and check the cancellationSource at every loop.
EDIT after further re-reading your points: it seems that the root of everything is that you want your client to be aware of when the server sends something to it. If this is the case, you're looking for a bidirectional communication between the two.
One raw, low-level way to do that is long polling: the client from time to time asks the server if anything is ready. This is similar to what you're doing, but the client cannot continuously ed exclusively keep on polling the server. It should do that every X seconds/minutes/... and in the meantime do something else. So at the very minimum you should go with:
private async Task StartListenerAsync()
{
_shouldStop = false;
if (_client != null)
{
while (!_shouldStop)
{
await GetMessageAsync().ConfigureAwait(false);
// non-blocking sleep equivalent
await Task.Delay(pauseIntervalInMillis);
}
}
}
But there are much better ways than handling such a bidirectional communication from scratch. You could use a ready-made, tested library for this. Have a look at this SO thread, where e.g. they mention SignalR. If your server side was on node.js + socket.io, client side you could go for something like SocketIoClientDotNet.
I have a policy file server up and running. For a while I was getting the AccessDenied because the policy file was not set properly. Now I no longer receive that error, so I know that's not the issue. I have a simple server running that simple loops on accepting client connections from any address. I also wrote a simple client, so I know the server works. In Silverlight I set my args and then call ConnectAsync. It return immedately on localhost (makes sense) and when I check the event args LastOperation is Connect and SocketError is Success. However, when I check my socket, it is not connected at all. Any ideas..? Been banging my head against a wall for hours over this.
A few other things I've tried. I moved the servers off my local box onto another server. Still didn't work. I did a packet capture and noticed that it is receiving the Poilcy File, but after that, there is no packet sent out by the browser to even attempt to connect to the other server.
public void Connect(string ip)
{
SocketAsyncEventArgs saea = new SocketAsyncEventArgs();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endpoint = new IPEndPoint(IPAddress.Parse(ip), 4502);
saea.UserToken = socket;
saea.RemoteEndPoint = endpoint;
saea.Completed += new EventHandler<SocketAsyncEventArgs>(AsyncEventComplete);
var completedSync = socket.ConnectAsync(saea);
if (completedSync)
{
AsyncEventComplete(null, saea);
}
Result = ip;
}
void AsyncEventComplete(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
MessageBox.Show("CONNECTED");
break;
case SocketAsyncOperation.Receive:
MessageBox.Show("DATA RECEIEVED");
// do stuff
break;
}
}
I think you should use e.SocketError and not e.LastOperation
You could also use e.ConnectSocket (in Silverlight only)
You should also add a "not" in this condition : if ( ! completedSync )
My app WP7 was not accepted because it fails to load if the internet is not available. I looked for a way to check it and found this command
NetworkInterface.GetIsNetworkAvailable()
But it isn't working on the emulator and I do not have any device to test it.
Could someone tell me if it returns false if the device is in Airplane mode? If not, how can I check for it?
Thanks,
Oscar
Edit: I also tried with this code:
try
{
wsClient.CurrenciesCompleted += new EventHandler<CurrencyConversion.CurrenciesCompletedEventArgs>(wsClient_CurrenciesCompleted);
wsClient.CurrenciesAsync(null);
}
catch
{
NetworkNotAvailable();
}
But I am not able to catch the exception, I also tried in the wsClient_CurrenciesCompleted method, but also no good.
Where could I test it?
Don't test for "the internet in general" - test for the service you'll actually be connecting to. Test for it by trying to connect to it - make some simple, non-destructive request on start-up. Yes, that will take a tiny bit of the user's data allowance, but:
You will be warming up the networking stack and making a connection which should end up being kept alive automatically, so future latency will be reduced.
You could warn the user that they may have limited functionality if the connection fails.
An Alternative to Jon's suggestion is to check which network interface is available. This is very handy in cases were you need to adjust which service you call based on network speed. For example the switch statement below could be modified to return an Enum to represent the quality of the network.
public class NetworkMonitorClass
{
private Timer timer;
private NetworkInterfaceType _currNetType = null;
private volatile bool _valueRetrieved = false;
public NetworkMonitorClass()
{
//using a timer to poll the network type.
timer = new Timer(new TimerCallBack((o)=>
{
//Copied comment from Microsoft Example:
// Checking the network type is not instantaneous
// so it is advised to always do it on a background thread.
_currNetType = Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType;
_valueRetrieved = true;
}), null, 200, 3000); // update the network type every 3 seconds.
}
public NetworkInterfaceType CurrentNetworkType
{
get
{
if(false == _valueRetrieved ) return NetworkInterfaceType.Unknown;
return _currNetType;
}
private set { ;}
}
public bool isNetworkReady()
{
if(false == _valueRetrieved ) return false;
switch (_currentNetworkType)
{
//Low speed networks
case NetworkInterfaceType.MobileBroadbandCdma:
case NetworkInterfaceType.MobileBroadbandGsm:
return true;
//High speed networks
case NetworkInterfaceType.Wireless80211:
case NetworkInterfaceType.Ethernet:
return true;
//No Network
case NetworkInterfaceType.None:
default:
return false;
}
}
}
See http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.networkinterface.networkinterfacetype(VS.92).aspx
GetIsNetworkAvailable() will always return true in the emulator. For testing in the emulator you'll need to work round this in code.
This can be a useful quick check but you also (as Jon pointed out) need to handle the scenario of not being able to connect to your specific server.
Handling this can be done by catching the WebException when you try and get the response in the callback.
private static void DownloadInfoCallback(IAsyncResult asynchronousResult)
{
try
{
var webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
// This will cause an error if the request failed
var webResponse = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
.....
}
catch (WebException exc)
{
// Handle error here
}
}
GetIsNetworkAvailable() works properly on device.
You can mock your handling of this for testing in the emulator using Microsoft.Devices.Environment.DeviceType.
I would be inclined to test both for avaiability of the internet and availability of your site through exception handling and provide feedback to the user of the app that indicates what the true reason is for features being unavailable.
I have an IPC problem. I have created into a windows service a NamedPipeServer:
serverPipe = new NamedPipeServerStream(Constants.PIPE_NAME, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
Thread thread = new Thread(new ThreadStart(pipeWork));
thread.Start();
where pipeWork is
private static void pipeWork()
{
try
{
byte[] buffer = new byte[1024];
while (true)
{
if (!serverPipe.IsConnected)
serverPipe.WaitForConnection();
int nr = serverPipe.Read(buffer, 0, buffer.Length);
String str=Encoding.Default.GetString(buffer);
…
}
}
catch (Exception ex)
{
}
}
and into a Windows forms I have the client
clientPipe = new NamedPipeClientStream(".", PhotoServiceClassLibrary.Constants.PIPE_NAME, PipeDirection.InOut,PipeOptions.Asynchronous);
clientPipe.Connect();
clientPipe.ReadMode = PipeTransmissionMode.Message;
pipeThread=new Thread(new ThreadStart(pipeWork));
pipeThread.Start();
where pipeWork is
private void pipeWork()
{
try
{
while (true)
{
using (StreamReader sr = new StreamReader(clientPipe))
{
string message;
while ((message = sr.ReadLine()) != null)
{
…
}
}
}
}
catch (Exception ex)
{
}
}
I want when the service begin an action to disable a ContextMenuStrip from the windows forms, for that the service writes a message into a StreamWriter sw:
StreamWriter write = null;
write = new StreamWriter(serverPipe);
if (serverPipe.IsConnected)
{
write.Write(message);
write.Flush();
}
The code is correct because I created for testing another windows forms which implements the same things like the windows service and the communication between
windows forms pipe server -> windows forms pipe client is working well.
The problem is that the windows form - client pipe doesn't receive the message from windows service - server pipe.
I know that WCF can be a better idea but i want to understand why is not working at low-level IPC. Why? I've seen an very strange behavior. My service interact 2 times with the windows forms:
1.My service is designed for downloading some photos. When he begin download he sends a message to the windows forms to announcing him that.
2.When i stop the service he sends a message to windows forms and he stops also.
i've just discovered that both messages arrive at windows agent only after the service is stoped. Can someone explain why?
I hope this isn't your real code. It's good that you've got try/catch blocks around the code of your ThreadStart handlers (otherwise an exception would just quietly delete the thread). However, if you're not logging the exception in the catch block, then it's really just as bad.
You've got a mystery (server doesn't receive message), and you're hiding information (an exception has occurred). If you weren't hiding information, you might have the answer for your mystery (server doesn't receive message because an exception has occurred).
I'm trying to implement the same thing.
I noticed you're passing the PipeTransmissionMode.Message enumeration in the NamedPipeServerStream (serverPipe) constructor. That means the stream will contain strings.
But in pipeWork, you're reading them in as an array of bytes.
Look in the example in this article on MSDN:
http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream.aspx
I'm new to Windows development.
I've developed a WinForm application that communicate with a serial device and plot data on a chart.
The application should run 24h a day 7/7. The code is executed correctly, but after some hours of execution the UI freeze with a non responsive OS (I have to turn off the pc and restart it).
Serial class (using System.IO.Ports) execute read and write operations on separate thread.
This scenario make me think to a non correct cross-thread call from my serial class to UI. Reading Microsoft documentation and other questions i think i fixed the error but no way, the app continue to freeze the OS.
Write operation send a request character every 100ms to the board via serial, i'm using System.Threading.Timer to do that cause this operation will not interact with UI.
//Initialization
WriteTimer = new Timer(Write, COMport.IsOpen, 5000, 100);
// callback function
public static void Write(object state)
{
if ((bool) state)
{
try
{
COMport.Write("^");
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now,exc.ToString());
}
}
}
The serial board reply to the request char with a string of 10 bytes, to read the message I'm using the DataReceived event handler form IO.Ports, that is also execute on a separated thread, the received data will be elaborated and than passed to UI with a event handler delegate with args declared on the main form class. I pass the form control to the serial class to make a safe thread call.
// FormControl is passed in the constructor of the serial class:
public Form1 FormControl;
private void COMport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort) sender;
byte[] buffer = new byte[10];
try
{
for (int i = 0; i < buffer.Length && buffer[i]!=3 ; i++)
{
buffer[i] = (byte) port.ReadByte();
}
SerialDataArgs args = checkDataReceived(buffer);
if (!args.error)
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(...));
}
else
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(0,0,true));
ErrorLogger.WriteTxtLog(DateTime.Now, "");
}
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now, exc.ToString());
}
}
UI thread (Form1 class):
SerialClass Serial = null;
public delegate void DataReceived(SerialDataArgs args);
public DataReceived drItem;
void ConnectCOM()
{
// COM READ
if (Serial == null)
{
Serial = new SerialClass(param.comName, this //this should be the FORM CONTROL);
if (Serial.Open)
{
...
drItem += HandleSeriaData;
}
else
{
...
}
}
}
//EventHandler
private void HandleSeriaData(SerialDataArgs args)
{
if (!args.error)
{
Work(args...); // in the work method i'll update labels, drawGraph,....
}
else
{
if (!Serial.Open) RecoverySerial();
}
}
Maybe the error is not here, but in front of Windows crashing it seems to me the only interested part. Sorry for my bad English, hope I made a correct/non duplicate question.
Use Control.BeginInvoke instead of Control.Invoke
From my experience, usually problems with System.IO.Ports.SerialPort cause only the UI to freeze, not the OS, and are caused by a deadlock when trying to update the UI from the SerialPort .DataReceived event using Control.Invoke and the UI thread itself tries to access the SerialPort object for example to close it. In this case there can be a deadlock when the UI thread is waiting for the SerialPort DataReceived thread to complete and the DataReceived thread is waiting for the UI thread to complete the Control.Invoke. To overcome these kinds of problems, it is better to use Control.BeginInvoke so the DataReceived thread does not wait for the UI thread.
Use lock to synchronize access to shared resources
When accessing the same object from different threads, use lock to synchronize data access. None synchronized data access can cause all different weird problems.
Check if the problem is with the serial port driver or connection
When the UI freezes and the OS becomes unresponsive, try to remove the serial-port device and see if the OS becomes responsive. If so, the problem may not be in the application but in the serial port driver or connection.
Hope this helps