Click here to Skip to main content
15,887,294 members
Articles / Programming Languages / C#
Article

RS232 Modem Wrapper

Rate me:
Please Sign up or sign in to vote.
3.73/5 (9 votes)
29 Nov 2007GPL32 min read 62.2K   2.8K   48   2
An article about creating a class which wraps the serial port and modem communication logic.

modem access form

Introduction

After a bit of search on CodeProject.com, I still could not find any article on wrapping the SerialPort class and modem functionality. So, I decided to write a base class which wraps RS232 communications with a modem. Also, I've written two subclasses for demonstration purposes - to simulate different behaviors of different modem models. In general, I think this article should be useful for somebody who is trying to implement classes which hold communication logic with any RS232 device.

Background

I have used some general AT modem commands in this sample. A good compilation of the general AT commands is available in this site. Also, some knowledge about thread-safe calls is required, because the SerialPort class operates in a different thread than the GUI.

Using the code

There are three classes implemented here. Below is the UML class diagram, drawn with a freeware tool bouml.

The basic class for communication with the modem is modem. The other two classes, ModemModel1 and ModemModel2, are inherited from the base class for demonstrating the idea that different types of modems can support different command sets and/or have different implementations of the same AT command (in theory). For example, a GSM modem can receive and send SMS; non-GSM compatible modems can't do this. Because I use only one modem, I just simulated different modems by implementing different modem behavior in subclasses by overriding the base class methods. Let's assume that the property DefaultBoudrate and the methods InitializeModem(), GetManufacturer(), and GetProductId() behave differently for different modem models. For this reason, they should be overridden in the sublases of modem. Like this:

C#
public class ModemModel1 : Modem
{
    #region constructors

    public ModemModel1() : base() { }
    public ModemModel1(SerialPort prt, SetCallback c) : base(prt,c) { }
    public ModemModel1(SerialPort prt, string prtnum, SetCallback c) :
                                               base(prt, prtnum, c) { }

    #endregion

    #region overriden properties

    // Will be other DefaultBoudrate than in base class

    public override int DefaultBoudrate
    {
        get {return 19200;}
    }

    #endregion

    #region overriden methods

    // Other modem initialization than in base class

    protected override void InitializeModem()
    {
        base.SendCommandToModem("ATE1L2S3?\r");
    }
    // Other command for geting manufacturer. Actually command is the

    // same - I4, but for simulating other behavior, just added additional

    // command I1.

    public override void GetManufacturer()
    {
        base.SendCommandToModem("ATI4I1\r");
    }
    // Also overriden command for getting modem product Id.

    // Added aditional command I3.

    public override void GetProductId()
    {
        base.SendCommandToModem("ATI0I3\r");
    }

    #endregion
}

One interesting note. I wanted the modem to be initialized in the object construction phase. That is, in the modem class constructor. And when the modem initializes, it sends a response back. I wanted to show that response in a form in the initialization textbox. At first, I thought that the initialization event will do the trick. But... it doesn't. Because the event handler can be attached to an already constructed object, and we need to fire the initialization event before the object is finally constructed. The solution was to use a delegate. That is, to pass a delegate into the modem class constructor. Like this:

C#
public ModemModel1(SerialPort prt, string prtnum, SetCallback c) : 
                                      base(prt, prtnum, c) { }

In general, using the created classes is simple, like this:

C#
mod = new Modem(new SerialPort(), this.cmbPortas.Text, this.call);

After that, we can query the modem manufacturer with mod.GetManufacturer(). Also, we have the modem class static method FirstAttachedModem(), which returns the COM port on which the modem is connected and also the modem manufacturer and the chipset version. That is why on the form show event, the modem is automatically detected (if it exists, of course :-)).

Finally, about thread-safe calls. This is achieved by the Modem.SetCallback delegate. The approach is more general - not to pass the modem answer / text to the GUI thread, but instead to pass the whole Modem object like this:

C#
public void TakeControl(Modem modcall).
{
    if (this.InvokeRequired)
    {
        Modem.SetCallback d = new Modem.SetCallback(TakeControl);
        this.Invoke(d,new object[] {modcall});
    }
    else
    {
        if (this.init) 
            this.txtInicializavimas.Text = modcall.ModemAnswer;
        else 
            this.txtAtsakymas.Text = modcall.ModemAnswer;
    }
}

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Lithuania Lithuania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralTypo Pin
Thomas Kjørnes5-Aug-10 15:56
Thomas Kjørnes5-Aug-10 15:56 
GeneralVery nice article Pin
iceteatwo10-Dec-09 1:35
iceteatwo10-Dec-09 1:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.