Saturday, December 20, 2008

Reading Serial Port with C#

Couple days ago my junior in college called. He was asking about how to read data from Serial Port. He is currently working with his final project to pursue his Bachelor Degree in Electrical Engineering.

In general, his project is creating an RFID reader which can be used to read the RFID tag. The data then will be sent to a PC through RS232 Serial Port. This unique ID then will used as primary key to save data to database.

Hmm... this is a kind of a new thing for me, because I'm never done it before. To give you a better overview of the project, you may want to read these sources before continue:
Ok, let's get back to our main focus of how to read data from Serial Port.

According to MSDN, starting from .NET 2.0, there is a class which can be used to read and write data from Serial Port easily. You can read the documentation here. By using this class, working with serial port is no more a nightmare. The class make us able to work with serial port, as if we were working with file. In sort, you just need to specify the port object, instantiate it, open it, and start working with it (read or write data).

Specifically to create a port reader, SerialPort has an event which will be trigerred when there is a data being sent to the port. The event handler is called DataReceived. What you need to do is creating a method to be executed when the event raised, and attach the method with a SerialDataReceivedEventHandler delegate to the event handler. Let's look at the class that I've created, I call it PortReader class.

This class has three properties which are Name - name of the port which will be read, Error - to hold error occured during the operation (if any), and Message - to hold the message from the port.



private string _name = string.Empty;
private string _error = string.Empty;
private string _msg = string.Empty;

...

public string Name
{
get { return _name; }
set { _port.PortName = value; }
}

public string Message
{
get { return _msg; }
set { _msg = value; }
}

public string Error
{
get { return _error; }
}


You need to specify several attributes of the port such as BaudRate, Parity, DataBits, and StopBits (and other properties as necessary). In this class I specify it in the constructor.



public PortReader()
{
_port = new SerialPort();

_port.BaudRate = 9600;
_port.Parity = Parity.None;
_port.DataBits = 8;
_port.StopBits = StopBits.One;
_port.DataReceived += new SerialDataReceivedEventHandler(PortReader_SerialDataReceived);

}


You may notice that I also specify a new instance of SerialDataReceivedEventHandler which then attached to DataReceived event of the object. I also create a new event for my class which wrap the DataReceived event - EndReadEvent. The codes is as the following:



public delegate void PortReaderEventHandler();
public event PortReaderEventHandler EndReadEvent;

...

private void PortReader_SerialDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!_port.IsOpen)
{
_error = "Can't read. Port is closed.";
return;
}

_msg = _port.ReadExisting();

//raise end read event
if (EndReadEvent != null) EndReadEvent();

}


PortReader_SerialDataReceived is a method which is used to handle the DataReceived event. It's simply read the port data and hold it in _msg variable. The method then raise its own EndReadEvent. This will allow user to do necessary action after the read operation.

Other methods are the DoOpen and DoClose method, which are as the following:




public bool DoOpen()
{
if (_port.PortName == "")
{
_error = "Please supply port name!";
return false;
}

if (_port.IsOpen)
{
_port.Close();
}

_port.Open();
return true;
}

public bool DoClose()
{
if (!_port.IsOpen)
{
_error = "Can't close port that is not in open state.";
return false;
}

_port.Close();
return true;
}


That's it. The complete codes of this class is as the following:



public class PortReader
{
private SerialPort _port;
private string _name = string.Empty;
private string _error = string.Empty;
private string _msg = string.Empty;

public delegate void PortReaderEventHandler();
public event PortReaderEventHandler EndReadEvent;

public string Name
{
get { return _name; }
set { _port.PortName = value; }
}

public string Message
{
get { return _msg; }
set { _msg = value; }
}

public string Error
{
get { return _error; }
}

public PortReader()
{
_port = new SerialPort();

_port.BaudRate = 9600;
_port.Parity = Parity.None;
_port.DataBits = 8;
_port.StopBits = StopBits.One;
_port.DataReceived += new SerialDataReceivedEventHandler(PortReader_SerialDataReceived);

}

private void PortReader_SerialDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!_port.IsOpen)
{
_error = "Can't read. Port is closed.";
return;
}

_msg = _port.ReadExisting();

//raise end read event
if (EndReadEvent != null) EndReadEvent();

}

public bool DoOpen()
{
if (_port.PortName == "")
{
_error = "Please supply port name!";
return false;
}

if (_port.IsOpen)
{
_port.Close();
}

_port.Open();
return true;
}

public bool DoClose()
{
if (!_port.IsOpen)
{
_error = "Can't close port that is not in open state.";
return false;
}

_port.Close();
return true;
}

}


Now to use the class, you only need to instantiate the object, specify the port name, open the port, and specifying the action when any read event occurred. Just place your action in OnPortReader_EndRead (you may change it with your own method). A simple example may look like the following:



PortReader myPort = new PortReader();
myPort.Name = "COM1";
myPort.EndReadEvent += new PortReader.PortReaderEventHandler(OnPortReader_EndRead);
myPort.DoOpen();


To test the application you might want to use a Virtual Serial Port Emulator. I use Virtual Serial Port Emulator form Softpedia. It's a nice application - very easy to use, very helpful, and it's free. The application will allow you to create a virtual ports as many as you want up to 255 ports.

Ok, that's all. Happy playing with the port. Any input, please welcome. :D

1 comment:

Gopi said...

yeah abt the coding which u gave am designing a RFID based tracking system and i need to be able to read the data from each tag can u pls tell me how to do this in c# the coding which u gave above is ok but where does the read data is stored or shown??? pls explain...