Introduction
Whenever there is an interaction between a PC and hardware, most of the time, we are communicating either through a serial port or a parallel port. Here we will see how serial communication is done in .NET 2003 using the Microsoft Communication control (MSComm). There are of course many ways by which we can communicate serially without using the MSComm control.
Communication in PCs happens through COM ports. We choose a COM port open it. Before we open the COM port, we set the COM properties like baud rate, parity bit, handshaking, input mode, etc.
The MSComm control allows you to establish a connection to a serial port and connect to another computer or modem, issue commands, and respond to various events.
Adding the MSComm control in .NET
Note: MSCOMM32.OCX is a registered Microsoft component that comes with Visual Basic 6.0.
- Go to Tools -> Add/Remove Items.
- Click on the COM Components tab.
- Click on Browse, then go to Windows - > System32 folder.
- Choose file type as COM components, choose MSCOMM32.OCX, click on Open.
- Click on the OK button of Customize Toolbox.
Setting MSComm properties before opening a COM port
Select and add the "Microsoft Communications Control, version 6.0" control (the Telephone control) onto your form. Set its name property to COM. Here is how we use the control:
private void InitComPort()
{
com.CommPort = 1;
com.RThreshold = 1;
com.Settings = "9600, n, 8, 1";
com.RTSEnable=true;
com.Handshaking = MSCommLib.HandshakeConstants.comNone;
com.InputMode = MSCommLib.InputModeConstants.comInputModeText;
com.InputLen = 0;
com.NullDiscard = false;
com.OnComm += new System.EventHandler(this.OnComm);
}
Call the InitComPort() method in form load or in the form's constructor after InitializeComponent(). Note: We can set the InputMode property to text mode or binary mode.
OnComm event
The OnComm event is used to handle the communication events. OnComm also handles communication errors.
In order to call the OnComm event of the MSComm component, we have to set the Rthreshold property to 1 and attach an event handler. We can either loop through the input buffer if input buffer count is greater than 0 and read data until some specified time is elapsed and then process the data, or you can use the OnComm events to receive output data from a hardware.
You can wait for characters to be received:
do
Application.DoEvents();
while com.InputBufferCount >= 5
Wait for five characters to receive and then you process the read data.
Properties of MSComm
Break: If the Break property is set to true the transmission of characters is suspended until you set it to false. If you want, you can place a timer where you can set some delay and set the Break property to false.
CTS: This is the clear-to-send property usually sent from the modem to the computer to indicate that the transmission can proceed. If the CTS property returns true when polled, you can send a command.
Comport: You can set the COM port value between 1 to 16. If the port doesn't exist, MSComm generates device error 68.
InBufferCount: Refers to the number of characters waiting in the buffer that you can read; if InBufferCount > 0, you can read the data.
CommEvent: Returns the most recent error or event occurred; to determine the actual event or error occurred, you must reference the commEvent property.
Communication errors:
comEventBreak - A break signal is received.
comEventFrame - Hardware detected a framing error.
comEventOverrun - A character was not read from the hardware before the next character arrived and was lost.
comEventRxOver - Received buffer overflow.
comEventRxParity - Hardware detected a parity error.
comEventTxFull - Transmit buffer full.
comEventDCB - Unexpected error retrieving device control block for the port.
Communication events:
comEvSend: There is fewer than SThreshold number of characters in the transmitting buffer.
comEvReceive: Received RThreshold number of characters. This event is generated continuously until you read the data from the receiving buffer.
comEvCTS: Change is clear to send line.
comEvDSR: Change in data set ready line; this event is generated only when DSR changes from 1 to 0.
comEvCD: Changes in carrier detect line.
comEvRing: Ring detected; note: some UARTs may not support this.
comEvEOF: End of file character received.
Syntax: object.Setting = <value>
The calue is composed of "BBBB, P, D, S", where:
- BBBB -> baud rate
- P -> parity bit
- D -> number of data bits
- S -> number of stop bits
The default value is "9600, N, 8, 1".
OutBufferCount: Returns the number of characters currently waiting in the transmitting buffer. You can also use this to clear the transmitting buffer by setting the OutBufferCount property to 0.
OutBufferSize: Returns the total size of the transmitting buffer; the default value is 512 bytes.
NullDiscard: If set to false, null characters are transferred from the port to the receiving buffer.
Handshaking: This property ensures that data is not lost due to buffer overrun. When the data from the hardware is received and directly read without moving into the receiving buffer, there may be chances of losing some characters because the characters may arrive too quickly. You can use this property and synchronize the communication.
InputMode: It determines how the data will be retrieved through the input property; you can read the data either as string or binary data in a byte array.
Using the code
Here we will see how you can serially communicate between two systems using GSM modems. The following things are done: Dial the GSM number from one system by clicking the Dial button. From the other system, send a command to accept the call (data). You will get a response CONNET 9600 when the connection is established between the two modems connected to the different systems. Once the data call is established, you can send data and it's received on the other end. Similarly, you can send data from another system. To send a message, type the message and click on the Send button. To disconnect, you can disconnect at any end just by closing the COM port. In the GUI, you should click on the Disconnect button.
Note: after connecting the GSM modem, dial from one system by clicking the Dial button; on the other system, you will get the response as a RING, RING. Now you can connect by specifying the command ATA\n and then send CONNECT 9600\n which will establish the connection.
Initialize the COM port by calling InitComPort():
public Form1()
{
InitializeComponent();
InitComPort();
}
The OnComm event shown below receives whenever there is a response from the hardware. Note: the input mode of the COM port is set to Text so that you can process the text read. Sleep for a while until you receive the full response, then read the response using com.Input. ProcessResponseText is used to display the response in a RichTextBox.
private void OnComm(object sender, EventArgs e)
{
Thread.Sleep(200);
if (com.InBufferCount > 0)
{
try
{
string response=(string)com.Input;
ProcessResponseText(response);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
}
}
}
The input string contains CONNECT 9600 when the connection is established from a GSM Modem. Note: while you communicate between two systems using GSM modems, say for example by using a WaveComm modem, the SIM must be enabled for making data calls. In such cases, after the connection is established, you can send data across the system.
If you receive text data as response:
private void ProcessResponseText(string input)
{
if( input.Trim().Equals("RING"))
{
Message.Text="Ring...";
}
else
if( input.Trim().Equals("CONNECT 9600"))
{
MessageBox.Show(input.Trim(), this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
}
else
{
MessageBox.Show(input.Trim(), this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
Message.Text=input.Trim();
}
rtfTerminal.AppendText(input + "\n");
}
When the user clicks on the Dial button, send the AT command to dial the other modem. The command for dialing is ATD\n.
private void btn_dial_Click(object sender, System.EventArgs e)
{
if( txt_phoneno.Text.Trim().Equals(""))
{
MessageBox.Show("Please Specify Phone Number", this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
txt_phoneno.Focus();
return;
}
if(! com.PortOpen )
com.PortOpen=true;
string gsm_command="ATD";
string phone_number=txt_phoneno.Text.Trim();
string command1=gsm_command + phone_number + "\n";
byte[]command_to_dial=System.Text.ASCIIEncoding.Default.GetBytes (command1);
com.Output=command_to_dial;
Message.Text="Dialing...";
}
To disconnect, the Disconnect button needs to be clicked which will set com.PortOpen to false.
private void btn_disconnect_Click(object sender, System.EventArgs e)
{
if( com.PortOpen )
{
com.PortOpen=false;
MessageBox.Show("Disconnected...", this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
Message.Text="";
rtfTerminal.Text="";
}
}
To send messages, click on the Send Button after typing some messages. If you are communicating using a GSM modem by sending commands, then you have to send a byte array. Or else you can send messages as plain text.
private void btn_sendmessage_Click(object sender, System.EventArgs e)
{
string msg="";
if( txt_sendmessage.Text.Trim().Equals(""))
{
MessageBox.Show("Please Specify Command", this.Text,
MessageBoxButtons.OK,MessageBoxIcon.Information);
txt_sendmessage.Focus();
return;
}
if(! com.PortOpen )
com.PortOpen=true;
msg=txt_sendmessage.Text.Trim() + "\n";
com.Output = System.Text.ASCIIEncoding.Default.GetBytes(msg);
Message.Text="Message Sent....";
}
Points of interest
Communicating through a serial port is a very interesting topic, that too using GSM modems. You can do a lot many things like you can programmatically send SMS, do remote communication etc.
Conclusion
It was nice playing with a serial port. This serial demo project wouldn't have been possible without the work by Noah Coad (noah@coad.net). I learnt about serial communication from his article, and worked on and modified his sample code to communicate with GSM modems.
Reference