reading from a serial/com port with C#

GeX

GeX

Soldato
Joined
17 Dec 2002
Posts
6,981
Location
Manchester
Hi all.

Am working on application that uses a mobile phone. It communicates with the phone via a com port and controls the phone using standard AT Commands.

It is currently very basic, and has no error checking in the code. It can currently communicate with the phone and send an SMS message / dial numbers. I want to be able to read data back from the serial port to check that it is working correctly.

This command;

Code:
serialPort1.Write("AT\r");

provokes a response of 'OK' from the phone when issued via Hyper Terminal. I want to be able to use this as a basic test that the phone is correctly connected.

I do not know how to read data back from the port though.

Whenever I try it, i just get the same data back from it that i initially sent to it.

Can anyone point me in the right direction?
 
If you could post the code you are using it would be a lot more useful. I've done serial reading and writing using Java which should be quite similar.
 
Code:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.IO.Ports;

namespace smsHandler
{
    /// <summary>
    /// Summary description for Service1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]

    public class Service1 : System.Web.Services.WebService
    {
        public SerialPort serialPort1 = new SerialPort();
        public string connectStatus;
        public int readTest;
        

        //public event SerialDataReceivedEventHandler DataReceived;
       // public int ReadChar();

        [WebMethod] //get list valid COM ports

        public string[] getPorts()
        {
            string[] portList = new string[10];
            portList = System.IO.Ports.SerialPort.GetPortNames();
            return portList; 
        }


        [WebMethod] //send SMS

        public int sendSMS(string port, string number, string text)
        {
                   
    
            try
            {

                if (!serialPort1.IsOpen)
                
                {
                    serialPort1.PortName = port;
                    serialPort1.Open();
                    serialPort1.BaudRate = 9600;
                    serialPort1.DataBits = 8;
                    serialPort1.StopBits = System.IO.Ports.StopBits.One;
                    serialPort1.Parity = System.IO.Ports.Parity.None;
                    serialPort1.Handshake = System.IO.Ports.Handshake.None;

                    connectStatus = "Connected to port";
                }

                else
                
                {
                    connectStatus = "Already Conencted to port";                
                }
            }

            catch
            
            {
               connectStatus = "Something went wrong";
            }

          
          //test phone number  serialPort1.Write("ATD=" + "00000" + ";\r\n");

            if (serialPort1.IsOpen)
            {
                
                serialPort1.BaseStream.Flush();

                string cb = char.ConvertFromUtf32(26); //return character

                System.Threading.Thread.Sleep(2000);

                serialPort1.Write("AT\r"); //AT Test, should reply OK

                //serialPort1.Write("AT+CMGF=1\r"); //set message type
                //serialPort1.Write("AT+CMGS=\"" + number + "\"\r\n"); //set SMS number
                //serialPort1.Write(text + cb); //set SMS text


     
            }

            else
            {
                connectStatus = "Port not open";
            }

            serialPort1.Close(); //close port, tidy tidy
            //return connectStatus;
            return readTest;



        }

       
    }
}

okie. code attached.
 
Last edited:
Just a quick little optimisation here, there is no need to allocate a local variable let alone initialise it to something when it gets reallocated on the next line.

Code:
        public string[] getPorts()
        {
            string[] portList = new string[10];
            portList = System.IO.Ports.SerialPort.GetPortNames();
            return portList; 
        }

Code:
        public string[] getPorts()
        {
            return System.IO.Ports.SerialPort.GetPortNames();
        }

As for the main problem, have you tried using:

Code:
Console.WriteLine(serialPort1.ReadLine());
 
Ta. Will rewrite that bit.

Have tried readline but it just returns what I have written to the port.

ok tried, creating a char[] and returning the buffer as that, and just a got an array full of 0;

Code:
serialPort1.Read(buffer, 0, (int)buffer.Length);
 
Last edited:
Are certain that the program manages to actually write to the serial port successfully? Does the phone provide any sort of feedback?

You could do with a loopback cable connected between two serial ports on your computer, you could then open a terminal on one end and simulate the communication.
 
i know the program is talking to the phone perfectly;

Code:
serialPort1.Write("AT+CMGF=1\r"); //set message type
serialPort1.Write("AT+CMGS=\"" + number + "\"\r\n"); //set SMS number
serialPort1.Write(text + cb); //set SMS text

succesfully sends a text message from the phone and;

Code:
serialPort1.Write("ATD=" + "000000" + ";\r\n");

makes it dial 000000
 
Slow things down a bit.. establish that you can communicate at all before you rush off and start dialling etc. :)

Code:
public bool SendCommandToPortWithReply(Stream port, string aString)
{
    var list = new List<byte>(Encoding.Default.GetBytes(aString));
    list.ForEach(port.WriteByte);
    var returnedBytes = new List<byte>();
    int anInt;
    while ((anInt = port.ReadByte()) > 0)
    {
        foreach (var aByte in BitConverter.GetBytes(anInt))
            returnedBytes.Add(aByte);
    }
    var returnedString = Encoding.Default.GetString(returnedBytes.ToArray());
    return returnedString.Length > 0;
}

P.S. it's a bit smart of ReadByte() to return an int :/
 
Last edited:
i CAN communicate, the phone DOES dial, and DOES send messages when called to.

Return values may not be as expected as this is a webservice, and it's responded with an XML document.
 
You've misunderstood.. you haven't yet established if the modem returns a value. You've also posted you have no error handling. If you don't know if the modem returns anything, how do you expect to handle errors (and data, as you've posted about)?
 
ah reet.

if i connect to it using Hyper Terminal, and issue the command AT, the phone responds with OK. That is what I am wanting to read.
 
You'll probably need to setup and asynchronous stream on the modem. It won't respond "instantly" so you'll need to fire an event when it does, so Read() ing won't work, but waiting for the modem to send data back will.

I'll post more on this tomorrow as I am too tired right now. :)
 
can you explain what you mean? I did find a way round this using an existing library, but it has major issues with bluetooth / virtual COM ports.
 
Serial devices do not reply immediately, in the context of a computer device. Ergo, you can't send a signal and expect an immediate response. Ergo, you can't do "SerialPortStream.Write("foo"); SerialPortStream.ReadLine();" as it just won't work.

They may not even respond at all.

So you have to have two operations. One to send signals, and another operation to listen for responses. This will need multi-threading or forking and some logic to make sense of the order.

The listening operation will need to trigger events (such as "responseReceivedEvent" or something)
 
ok, I have a public string called dataBack

I have this method setup.

Code:
private void port_DataReceived(object sender,SerialDataReceivedEventArgs e)
        {
            string dataBack = serialPort1.ReadExisting();
        }

and then running this method;

Code:
        public string dial(string port, string number)
        {
            connectPort(port);
            if (serialPort1.IsOpen)
            {

                serialPort1.BaseStream.Flush();
                string cb = char.ConvertFromUtf32(26); //return character
                System.Threading.Thread.Sleep(2000);
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                serialPort1.Write("AT\r"); //AT Test, should reply OK
             // serialPort1.Write("ATD=" + number + ";\r\n");
             }

            else
            {
                connectStatus = "Port not open";
            }
            serialPort1.Close(); //close port, tidy tidy

            return dataBack;
        }

I'm not getting anything back, and the code does not look right - but i do not understand why.

This is to do with threads isn't it, this is a new thing to me - any pointers?
 
Last edited:
ok, I have a public string called dataBack
Code:
private void port_DataReceived(object sender,SerialDataReceivedEventArgs e)
        {
            [COLOR="Red"]string [/COLOR]dataBack = serialPort1.ReadExisting();
        }

I understand what you are doing, attaching an event handler to the serial port that gets called whenever any data arrives. You handler is declaring a local variable called dataBack which lies in a different scope to that of the public variable also called dataBack so you will never get back anything. Remove the variable type declaration to make the handler use the public variable rather than declaring a new one in its own scope.
 
When you use Hyperterminal the reason you see the characters you type are because the modem echos them back, that is what your program will read first. Keep reading lines of text until you get an OK or ERROR.

Look at the ATE command if you wish to stop the modem echoing the characters you type
 
Back
Top Bottom