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:
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
public override int DefaultBoudrate
{
get {return 19200;}
}
#endregion
#region overriden methods
protected override void InitializeModem()
{
base.SendCommandToModem("ATE1L2S3?\r");
}
public override void GetManufacturer()
{
base.SendCommandToModem("ATI4I1\r");
}
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:
public ModemModel1(SerialPort prt, string prtnum, SetCallback c) :
base(prt, prtnum, c) { }
In general, using the created classes is simple, like this:
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:
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;
}
}
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.