Application wide serial port utilisation - c#

I am developing a WPF application in C# and am communicating with a serial device. Currently in the main window of my application I am displaying some information that I obtain by periodically reading lines from the serial device.
Sometimes I need to constantly receive and save data from the serial device to a file. I stop other methods that are utilizing the serial port (like the one that is periodically reading lines to display on the main window) so that the recording process is not interfered with. It can be cumbersome to manage access to the serial port across the application and so "System.UnauthorizedAccessException" is not uncommon.
In each method or window within the application that utilizes the serial device I define a new serial port, open it, read lines and then close and dispose it. I have read though that it is good practice to open the serial port when the application launches and close it when the application closes and I can see why this would be helpful with where I am getting to with this application. I have some questions though:
Where should I define the serial port object?
If I am calling the serial port object from more than one window or method am I creating more than one instance of the serial port object? Can you have more than one instance of a serial port object for just one physical serial port?
If I had SerialPort.ReadLine() being called from two different methods (on two different threads), would one line go to one method and then the next line to the other method and repeat like that? How could I make all serial data go to both?

You should create a separate class to manage the SerialPort connection. It should have its own thread that reads from the serial port. It can then distribute the information it reads to the other places in your application. One good way to do this is using Rx. Make a singleton from this class and inject it into anywhere else in the application that needs it.
Using Rx you can subscribe to messages from the serial port as many times as you need to.
Create a class to manage the serial port:
public class SerialPortManager
{
private SerialPort;
private string comPort;
Subject<string> messageBus = new Subject<string>();
public IObservable<string> MessageBus => messageBus;
private CancellationTokenSource cts = new CancellationTokenSource();
public SerialPortManager(string comPort)
{
this.comport = comport;
}
public void Start()
{
ThreadStart ts = new ThreadStart(SerialDeviceThread);
Thread t = new Thread(ts);
t.IsBackground = true;
t.Name = this.Name;
t.Start();
}
private void SerialDeviceThread()
{
this.serialPort = new SerialPort(this.comPort, ...);
while (true)
{
string line = this.serialPort.ReadLine();
this.messageBus.OnNext(line);
}
}
}
Create a singelton of this class somewhere:
public static Lazy<SerialPortManager> SerialPortManager =
new Lazy<SerialPortManager>(x => {
var sm = new SerialPortManager("COM2");
sm.Start();
return sm;
});
and elsewhere
SerialPortManager.Value.MessageBus.Subscribe( ...)
[This is still greatly simplified, I would have logic around the serial port to catch failures and recreate the port when it disconnects. I'd also use a dependency injection container (e.g. Autofac) rather than a static value.]

It sounds like what you need is an object managing access to your serial port. This object would set up the port object once and start a new thread that would read lines continuously from the serial port, and fire an event when it has read the line. Then your other application objects would attach delegates to that event when they want to be notified of data coming in from the serial port. In that way, data from the serial port would always be broadcast to those who were interested. Depending on your UI, you will have to use the Invoke() method on Dispatcher (for WPF) or on a Windows form object (for Windows forms) to make sure the event is fired from the UI thread so it can invoke UI methods correctly.

Related

Correct way of managing threads

I'm building a C# Socket Server. My code currently works but I am not sure if this is the correct way to do it.
When a TcpClient is connected I put it in a new object with the following Methods, I then call Init() to start checking if data is available, when data is available I call an event that I listen on to start reading the buffer using methods I created like ReadInt32(), ReadByte(), ReadString() ReadObject<T>()
public void Init()
{
ThreadPool.QueueUserWorkItem(Read);
}
private void Read(object state)
{
if (IsClientConnected())
{
if (_connected.Available > 0)
{
OnDataAvailable(_connected.Available);
}
Init();
}
}
Should I use a While loop here or should I restart the Init() like I am currently doing? Then should I use a BackgroundWorker, Thread, or Task instead of ThreadPool?
I also was thinking of changing Init() to BeginWait(some sort of callback here) and removing the Init() inside the Read() and then just call BeginWait again where needed
My purpose is to listen to commands and reply on commands. With an x number of clients connected at the same time.
So the scenario is as follow:
I have an application that connects to the server.
The server then Initializes a new object with TcpClient as a parameter in the constructor. The server then adds the connected client to a room with another client. This room listens on each of the client's events DataAvailable look at following
private void Client_DataAvailable(ClientWrapper sender, int data)
{
var command = (Commands)Client.ReadByte();
switch (command)
{
case Commands.RequestConnectId: // 1
var buffer = new WriteBuffer(Commands.RequestConnectId);
buffer.WriteInt32(sender.ConnectId);
sender.Reply(buffer);
break;
case Commands.WriteText: //2
var buffer = new WriteBuffer(Commands.WriteText);
buffer.WriteString(sender.ReadString());
BroadCast(sender.ConnectId,buffer);//Send to the other client
break;
}
}
The correct way to read a socket is to just read from it. The call will not complete until data is ready. There is no need for events. The Available property almost always is a bug so don't use that.
Just execute:
var command = (Commands)Client.ReadByte();
immediately. It is fine to run that on a background thread (as opposed to what was suggested in the comments). Threads become a problem once you have too many of them. If you maintain a few dozen socket connections only there is no issue with that.
You also could use async IO preferably with await. The same idea applies: Just read.
If you want to process a stream of command simply wrap this in a loop:
while (true) {
ReadCommand();
WriteResponse();
}

Can a TCP c# client receive and send continuously/consecutively without sleep?

This is to a degree a "basics of TCP" question, yet at the same time I have yet to find a convincing answer elsewhere and believe i have a ok/good understanding of the basics of TCP. I am not sure if the combination of questions (or the one questions and while i'm at it the request for confirmation of a couple of points) is against the rules. Hope not.
I am trying to write a C# implementation of a TCP client, that communicates with an existing app containing a TCP server (I don't have access to its code, so no WCF). How do I connect to it, send and receive as needed as new info comes in or out, and ultimately disconnect. Using the following MSDN code as an example where they list "Send" and "Receive" asynchronous methods (or just TcpClient), and ignoring the connect and disconnect as trivial, how can I best go about continuously checking for new packets received and at the same time send when needed?
I initially used TCPClient and GetStream(), and the msdn code still seems to require the loop and sleep described in a bit (counter intuitively), where I run the receive method in a loop in a separate thread with a sleep(10) milliseconds, and Send in the main (or third) thread as needed. This allows me to send fine, and the receive method effectively polls at regular intervals to find new packets. The received packets are then added to a queue.
Is this really the best solution? Shouldn't there be a DataAvailable event equivalent (or something i'm missing in the msdn code) that allows us to receive when, and only when, there is new data available?
As an afterthought I noticed that the socket could be cut from the other side without the client becoming aware till the next botched send. To clarify then, the client is obliged to send regular keepalives (and receive isn't sufficient, only send) to determine if the socket is still alive. And the frequency of the keepalive determines how soon I will know that link is down. Is that correct? I tried Poll, socket.connected etc only to discover why each just doesn't help.
Lastly, to confirm (i believe not but good to make sure), in the above scenario of sending on demand and receiving if tcpclient.DataAvailable every ten seconds, can there be data loss if sending and receiving at the same time? If at the same time I am receiving I try and send will one fail, overwrite the other or any other such unwanted behaviour?
There's nothing wrong necessarily with grouping questions together, but it does make answering the question more challenging... :)
The MSDN article you linked shows how to do a one-and-done TCP communication, that is, one send and one receive. You'll also notice it uses the Socket class directly where most people, including myself, will suggest using the TcpClient class instead. You can always get the underlying Socket via the Client property should you need to configure a certain socket for example (e.g., SetSocketOption()).
The other aspect about the example to note is that while it uses threads to execute the AsyncCallback delegates for both BeginSend() and BeginReceive(), it is essentially a single-threaded example because of how the ManualResetEvent objects are used. For repeated exchange between a client and server, this is not what you want.
Alright, so you want to use TcpClient. Connecting to the server (e.g., TcpListener) should be straightforward - use Connect() if you want a blocking operation or BeginConnect() if you want a non-blocking operation. Once the connection is establish, use the GetStream() method to get the NetworkStream object to use for reading and writing. Use the Read()/Write() operations for blocking I/O and the BeginRead()/BeginWrite() operations for non-blocking I/O. Note that the BeginRead() and BeginWrite() use the same AsyncCallback mechanism employed by the BeginReceive() and BeginSend() methods of the Socket class.
One of the key things to note at this point is this little blurb in the MSDN documentation for NetworkStream:
Read and write operations can be performed simultaneously on an
instance of the NetworkStream class without the need for
synchronization. As long as there is one unique thread for the write
operations and one unique thread for the read operations, there will
be no cross-interference between read and write threads and no
synchronization is required.
In short, because you plan to read and write from the same TcpClient instance, you'll need two threads for doing this. Using separate threads will ensure that no data is lost while receiving data at the same time someone is trying to send. The way I've approached this in my projects is to create a top-level object, say Client, that wraps the TcpClient and its underlying NetworkStream. This class also creates and manages two Thread objects, passing the NetworkStream object to each during construction. The first thread is the Sender thread. Anyone wanting to send data does so via a public SendData() method on the Client, which routes the data to the Sender for transmission. The second thread is the Receiver thread. This thread publishes all received data to interested parties via a public event exposed by the Client. It looks something like this:
Client.cs
public sealed partial class Client : IDisposable
{
// Called by producers to send data over the socket.
public void SendData(byte[] data)
{
_sender.SendData(data);
}
// Consumers register to receive data.
public event EventHandler<DataReceivedEventArgs> DataReceived;
public Client()
{
_client = new TcpClient(...);
_stream = _client.GetStream();
_receiver = new Receiver(_stream);
_sender = new Sender(_stream);
_receiver.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
Client.Receiver.cs
private sealed partial class Client
{
private sealed class Receiver
{
internal event EventHandler<DataReceivedEventArgs> DataReceived;
internal Receiver(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for receiving data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Client.Sender.cs
private sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
// transition the data to the thread and send it...
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// main thread loop for sending data...
}
private NetworkStream _stream;
private Thread _thread;
}
}
Notice that these are three separate .cs files but define different aspects of the same Client class. I use the Visual Studio trick described here to nest the respective Receiver and Sender files under the Client file. In a nutshell, that's the way I do it.
Regarding the NetworkStream.DataAvailable/Thread.Sleep() question. I would agree that an event would be nice, but you can effectively achieve this by using the Read() method in combination with an infinite ReadTimeout. This will have no adverse impact on the rest of your application (e.g., UI) since it's running in its own thread. However, this complicates shutting down the thread (e.g., when the application closes), so you'd probably want to use something more reasonable, say 10 milliseconds. But then you're back to polling, which is what we're trying to avoid in the first place. Here's how I do it, with comments for explanation:
private sealed class Receiver
{
private void Run()
{
try
{
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutdownEvent.WaitOne(0))
{
try
{
// We could use the ReadTimeout property and let Read()
// block. However, if no data is received prior to the
// timeout period expiring, an IOException occurs.
// While this can be handled, it leads to problems when
// debugging if we are wanting to break when exceptions
// are thrown (unless we explicitly ignore IOException,
// which I always forget to do).
if (!_stream.DataAvailable)
{
// Give up the remaining time slice.
Thread.Sleep(1);
}
else if (_stream.Read(_data, 0, _data.Length) > 0)
{
// Raise the DataReceived event w/ data...
}
else
{
// The connection has closed gracefully, so stop the
// thread.
ShutdownEvent.Set();
}
}
catch (IOException ex)
{
// Handle the exception...
}
}
}
catch (Exception ex)
{
// Handle the exception...
}
finally
{
_stream.Close();
}
}
}
As far as 'keepalives' are concerned, there is unfortunately not a way around the problem of knowing when the other side has exited the connection silently except to try sending some data. In my case, since I control both the sending and receiving sides, I've added a tiny KeepAlive message (8 bytes) to my protocol. This is sent every five seconds from both sides of the TCP connection unless other data is already being sent.
I think I've addressed all the facets that you touched on. I hope you find this helpful.

Reading from two serial ports at the same

I have a C# program that reads from two serial ports at the same time. The serial port device is a Prolific USD to 4 serial ports adapter and I plug the two hardware on separate ports of the adapter. The problem is when I read from each port one at a time, everything works fine but when I try to read from both ports at the same time, one of the port is not responding. To troubleshoot the problem, I started two instances of the application and was able to read from the two ports at a time (one from each instance of the application). Does anyone know how to read from two separate serial ports in one application at the same time? Thank you.
Adding some codes:
Port 1:
// button to start or stop reading from port 1. Because the hardware requires me to write to it before reading the response, the writing is done in the timer
private void buttonPort1_Click(object sender, EventArgs e)
{
if (buttonPort1.Text == "Start Recording")
{
if (!port1.IsOpen)
{
port1.Open();
}
timerPort1.Start();
buttonPort1.Text = "Stop Recording";
}
else
{
timerPort1.Stop();
buttonPort1.Text = "Start Recording";
}
}
// Write "D" to the hardware each time to receive back the response
private void timerPort1_Tick(object sender, EventArgs e)
{
port1.Write("D");
}
void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string result = port1.ReadLine();
oneParamDelegate dg = PHandCondResult; // send back the result to the main thread
this.Invoke(dg, result);
}
catch
{
}
}
Port 2
The code for the second port is similar to the above really, the difference being different port, datareceived event and timer.
I'll try the multiple thread options suggested by Grant Thomas: I didn't try this before because I thought serial ports are already working on separate threads: the datareceived event doesn't block the main thread and you can't access controls created on the main thread but I'll still give it a go using background worker and revert back later. Thank you all for the quick response.
You're going to need to do some reading, specifically on Threading.
If you have, say, some code that looks like this:
ReadDataFromSomePort();
ReadDataFromSomeOtherPort();
Then the first will execute synchronously (blocking) and then the latter. This happens on the same thread, the main application thread. When you want to do asynchronous things, including just doing one thing while keeping a UI interactive/responsive, then you need to delegate work to other threads.
So, you end up with something like this:
var thread1 = new Thread(ReadDataFromSomePort);
var thread2 = new Thread(ReadDataFromSomeOtherPort);
thread1.Start();
thread2.Start();
There's more to it than this, rest assured, so I recommend some research on the concept before proceeding.
MSDN has a tutorial/programming reference for threading that should get you started.
Creating two different objects of SerialPort and different DataReceived events for both should work.

How to Read Device Data From serial port

I have one device which sends data on COM port say on COM13. Now i want to read that data and display it in the RichTextBox or in any text control.
I have written the application with the help of IO and IO.Ports but comport.DataRecived event does not fire, even though device is sending data on that port.
I have some software on which i define the port number and it successfully display data, which insure me that data is receiving on the Port but i am unable to receive.
Is there any way i can read data?
comm.Parity = cboParity.Text;//None
comm.StopBits = cboStop.Text;//One
comm.DataBits = cboData.Text;//8
comm.BaudRate = cboBaud.Text;//9600
comm.DisplayWindow = rtbDisplay;//Null
comm.PortName = "COM13";
comm.OpenPort();
cmdOpen.Enabled = false;
cmdClose.Enabled = true;
cmdSend.Enabled = true;
public bool OpenPort()
{
if (comPort.IsOpen)
{
comPort.Close();
}
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
comPort.PortName = _portName;
comPort.Open();return true;
}
This normally comes from a wrong configuration of a serial port. It is not enough to simple open a serial port and waiting for some data to come in. You have also to set all the SerialPort.Properties to a correct value for your wanted connection.
Some of the common ones are BaudRate, DataBits or Parity, but to be really sure you have to set all of them. Even such things as RtsEnable or ReadTimeout.
You have to set the all, cause the configuration state will be saved from the port itself. So if one application opens such a port, makes some changes to the configuration and closes it, the next application that opens the port starts with this configuration, till it change it.
Update
Seems to be a problem i can't see from here. ;-))
The only advice i can give you is to use a Monitor tool, to better understand what your other application really does and what comes on the wire. Additionally you can set up two virtual com ports to test reading and writing on one machine (even within the same application), to have a better control about when will which data be send.
Have you read the documentation for the DataReceived event?
From MSDN:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
The snippet you've posted is quite rough, but I'd set the ReceivedBytesThreshold property to one. This ensures the event firing when at least one byte is present in the incoming buffer.
Cheers
Use PortMon to capture the working software, and then capture your software; then compare the traces. Pay particularly close attention to all the configuration parameters, making sure they are the same (as Oliver mentioned).

Sharing a COM port over TCP

What would be a simple design pattern for sharing a COM port over TCP to multiple clients?
For example, a local GPS device that could transmit co-ordinates to remote hosts in realtime.
So I need a program that would open the serial port and accept multiple TCP connections like:
class Program
{
public static void Main(string[] args)
{
SerialPort sp = new SerialPort("COM4", 19200, Parity.None, 8, StopBits.One);
Socket srv = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
srv.Bind(new IPEndPoint(IPAddress.Any, 8000));
srv.Listen(20);
while (true)
{
Socket soc = srv.Accept();
new Connection(soc);
}
}
}
I would then need a class to handle the communication between connected clients, allowing them all to see the data and keeping it synchronized so client commands are received in sequence:
class Connection
{
static object lck = new object();
static List<Connection> cons = new List<Connection>();
public Socket socket;
public StreamReader reader;
public StreamWriter writer;
public Connection(Socket soc)
{
this.socket = soc;
this.reader = new StreamReader(new NetworkStream(soc, false));
this.writer = new StreamWriter(new NetworkStream(soc, true));
new Thread(ClientLoop).Start();
}
void ClientLoop()
{
lock (lck)
{
connections.Add(this);
}
while (true)
{
lock (lck)
{
string line = reader.ReadLine();
if (String.IsNullOrEmpty(line))
break;
foreach (Connection con in cons)
con.writer.WriteLine(line);
}
}
lock (lck)
{
cons.Remove(this);
socket.Close();
}
}
}
The problem I'm struggling to resolve is how to facilitate communication between the SerialPort instance and the threads.
I'm not certain that the above code is the best way forward, so does anybody have another solution (the simpler the better)?
Why write at such a low-level (sockets)? Why not use WCF as the communication between the clients and the server and present a cleaner, strongly-typed interface instead of raw access to the GPS device?
Devices like this are often best managed independently from the clients calling in - i.e. you have your own separate thread that talks to the GPS device, polling it at the appropriate interval and populating shared data structures with the current location - while the clients make service calls and are supplied with data from the shared data structures. All error handling and recovery for the sometimes unreliable device connection is handled by the GPS thread and the clients don't need to each get involved with such nastiness. They can make non-blocking calls to get status updates and those updates might include a status 'position unavailable' while the GPS thread is frantically trying to re-establish communication.
So I would create a service that abstracts the particulars of dealing with this specific device and provides a clean interface to the clients. It might for example offer a services like GetPosition() which returns some class like "GeoCoordinate". That way if you ever need to support other location sensing devices you can add them without making any changes to the client code.
GPS <--Serial--> Server <--WCF--> Clients
I have a system that communicates with hundreds of different devices, many over serial ports and other semi-reliable connections and this is the approach I use. See http://blog.abodit.com.
----- per your additional requirement to use TELNET: maybe something like:
Create a thread that handles all communication with the device itself.
Create a class that encapsulates a single WorkItem - what to send, the response, and a WaitHandle.
Use a Queue to queue up requests from clients. Each client waits on the WaitHandle for its response to be ready.
Let the single communication thread pull work items off that queue, send them to the GPS device, get the response, store the response in the WorkItem (or set a flag for failures), and then set the wait handle to say that the WorkItem is done.
If the requests come in faster than the GPS can handle, add code so it can return cached values for requests coming within a small time window from the last successful request to the device.
In effect you are now presenting a virtual GPS device to all the clients but internally you are serializing all their requests (on a Queue) and managing communication with the GPS device on a single thread so you can do the Request-Response cycle easily without interference.
This also allows you to time-out nicely (on the wait handle) to inform a client that no response is currently available.
you have socat and ser2net and other programs but my experience is very bad... not working properly. I've done this small python program, can be useful. Update port, baudrate... then use any tcp client. Remove first line if don't want to use is as auto executable script
#!/usr/bin/python
import socket
import sys
import serial
#open serial port
ser = serial.Serial('/dev/ttyAMA0', 115200, timeout=0)
#create socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
#bond to the port. Don't use localhost to accept external connections
server_address = ('', 2105)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
#listen
sock.listen(1)
#loop
while True:
#waits for a new connection
print('waiting for a connection')
connection, client_address = sock.accept()
try:
print('connection from', client_address)
#continously send from serial port to tcp and viceversa
connection.settimeout(0.1)
while True:
try:
data = connection.recv(16)
if data == '': break
ser.write(data)
except KeyboardInterrupt:
connection.close()
sys.exit()
except Exception as e:
pass
received_data = ser.read(ser.inWaiting())
connection.sendall(received_data)
except Exception as e:
print e
finally:
#clean up connection
connection.close()

Categories