Programming SMS with a GSM Modem

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Quite often, if you’re using a small device (such as something that may be used at the core of an IoT-enabled device) you may not always have a full standard TCP or UDP stack.

Many small devices are equipped with a simple GSM modem and a SIM card, and the only means you have of communicating with the outside world is via the SMS (Smart Messaging Service) that’s exposed on many of these devices.

If you’re programming on a Windows Embedded CE device, there are APIs in the operating system to help you with this, but if you’re running on a standard Linux system or on a regular Windows build, you’ll very likely need to open a serial COM port, or a USB device to get access to the GSM Modem itself.

A Little Bit of Modem History

Many of you who’ve been brought up in the broadband era might never have seen a modem (at least not in the classical sense of one, anyway), but if you ever have you simply can’t forget the classic squawking sound they used to make while dialling the remote node and connecting.

In order for a computer to connect to these devices, they contained a small bit of firmware called an “AT Command Interpreter.” This firmware would listen on some kind of interface and respond to “AT Commands” sent to it.

These commands were used to instruct the modem to dial numbers, negotiate connection speeds, and all sorts of other things.

Many modem manufacturers included “Extras” in their command set, so they could command their modems to do things that others couldn’t, but every modem had to have a CORE control set known as the “Hayes Standard AT Command set” named after the company that first set the standard.

As time marched on, the “classic modem” design that we all think about faded into obscurity, but the “AT Interpreter” continued to be used.

You may not realise, but the Mobile Smart phone you hold in your hand now will still have an “AT Command interface” buried deep within its operating system somewhere, and if you know how to access it, you may be able to use it in a manner shown in this post.

For my purposes in this post, I have a dedicated “GSM Modem” that looks like this:

SMS1
Figure 1: USB GSM Modem

And I’ll be accessing it using a serial port connection on my PC.

How you connect yours and access it will depend largely on what you’re using. It’s a safe bet, however, that 99% of them will expose some kind of serial COMS port.

I wrote about accessing COM ports in a previous post in this column. I’ll not repeat all the setting up stuff needed to get a serial port running; instead, I’ll concentrate on the AT commands needed to use SMS.

One thing to remember, however, is that the serial port stuff in the previous article, does all work on MONO.

That means that everything there can easily be used on Rasbian, for example, so you can use a RaspberryPi. The one thing you need to remember if you do, however, is that on a non-Windows device, serial ports may not be named the same way.

For example, on a Linux-based OS your “com1” will likely be “/dev/ttyS0” or something similar. Unfortunately, there are quite a lot of variations, so I can’t possibly tell you exactly what you do & don’t use. You’ll need to do a little bit of experimentation and reading.

AT Commands

Okay, so finally we get to the meat of this article.

If you want to experiment before writing some code, I’m using “Putty” to show command examples. You’ll have similar serial terminals on other platforms.

Once you figure out which port to connect to and how, you’ll likely see nothing but a blank screen. Try typing uppercase “AT” (without the quote marks) and press Return. If everything is working, you should see your modem respond with “OK.” Depending on your modem configuration, you may/may not see what you’re typing.

SMS2
Figure 2: My modem responding to “AT” with “OK”

If you can’t see what you’re typing, enter “ATE1” (again, without the quotes) and press Return.

“ATE1” means “Attention Echo 1.” Historically, the commands start with “AT” because you’re asking the modem to give you its attention.

After entering “ATE1,” you’ll have turned on the modem’s ability to echo everything you type, and thus be able to see what you’re typing.

Let’s try a few more commands:

SMS3
Figure 3: Various information commands and their responses

Here are the various commands and their descriptions:

  • “AT+CGMM” gets the device description
  • “AT+CGMI” gets the manufacturer information
  • “AT+CGMR” gets the manufacturer revision
  • “AT+CGSN” gets the modems IMEI number
  • “AT+CIMI” gets the sim/subscriber ‘IMSI’ number
  • “AT+CNUM” gets the cell/phone number attached to the SIM card

Depending on the manufacturer settings and things like pin security, you may not be able to read some items or even use the SIM, without first entering a pin code.

If you enter a ‘query’ command, for cpin.

"AT+CPIN?"

and press Return, you’ll get a status telling you the current pin status of the SIM.

SMS4
Figure 4: No pin on this device

If you get back a status of “READY,” the SIM card your using has no pin protection enabled. If you get back any other, then you’ll need to send

AT+CPIN="1234"

to enter a pin code for the device. The “1234” must be in quote marks, and must be the 4 digits of the code you wish to submit. A very BIG warning has to be heeded here, however. If you do need a pin code, make sure you get it right.

You will generally ONLY have three attempts and if you exhaust all three of those attempts, you WILL lock the SIM card and render in unusable. There will be no magic code, or special text message your phone operator can send you that will ‘Unblock’ it. You will have to ask your operator to send you a new SIM card.

If you have some old SIM cards, use those for experimentation. You may not be able to send SMS using them, but you can still go through the motions of issuing the commands to them to test your code.

Okay, so warnings aside, how exactly do we send an SMS?

Well, as with any other modem command, we use an AT command that’s defined by the GSM Standard, in this case “AT+CMGS”. Before I show you this, however, you need to know one more thing.

“SMS Modes”

When sending/receiving SMS on a GSM Modem, you can use either PDU mode or Plain Text mode.

I’m not going to cover PDU mode in this post, because in all honesty you need lots and lots of background information on how GSM networks operate. You WILL, however need, to use PDU mode if you want to do things like send Ringtones, Concatenated Messages, and things like WAP Push messages.

For this post, we just want to send simple, single text-based messages so we’re just going to concentrate on that.

To switch your modem to Plain text SMS input mode, you need to use “AT+CGMF.” This command takes a single parameter as follows:

AT+CGMF=0 : Switch to PDU input mode

AT+CGMF=1 : Switch to plain text input mode

This means that, before we can start inputting SMS text, we need to use the =1 version to switch to the appropriate mode:

SMS5
Figure 5: Programming SMS with a GSM Modem Setting and checking the SMS input mode

As you can see in Figure 5, I’ve set plain text input mode; then, I’ve used the same command in its query format to ask the modem which mode is set.

Once that’s done, we then can use “AT+CMGS” to send an SMS. The “AT+CMGS” command is slightly different to other commands, in that once you start entering your message you need to send a “Ctrl+z” or char code 26 to the modem to enter it rather than just pressing Return.

In my example that follows, I’m using a deactivated SIM card, so I’ll get an error when I try to send. For a working SIM, however, the steps are exactly the same.

First, you enter “AT+CMGS” in set mode, followed by the destination cell/phone number you wish to send to. The destination number MUST be in international format; for example, “+44….” For the UK, “+1….” For the USA, and so on. You will need to know your country’s dialling rules to do this correctly. In the UK, for example, we drop the leading 0 and add “+44” in front. Your national telecom’s regulator will have all the information you need, usually on their Web site.

Once you’ve entered the command and destination number, you press Return as normal. This then puts you into message entry mode, where you enter your message followed by char code 26 (Ctrl+z).

SMS6
Figure 6: Sending a test message

As I mentioned previously, I’ve got an error on mine due to it being a de-activated SIM card. Had this been a success, however, you would have gotten a reply like:

+CMGS: 123
OK

Where ‘123’ would be some kind of ID number assigned by your device/operator as a reference to the message you just sent.

So, how do we translate this into .NET, very easily?

Start a console mode project. Then, make sure your Program.cs file has the following code in:

using System;
using System.IO.Ports;
using System.Linq;

namespace GSMSMSsend
{
   class Program
   {
      // NOTE: Change this to the actual name of the port
      // where your modem is
      private const string SERIAL_PORT_NAME = "COM41";

      private static SerialPort _modemConnection;

      static void SendSms(string destination, string text)
      {
         // Turn off echo, we don't need it for this
         _modemConnection.WriteLine("ATE0");
         var response = _modemConnection.ReadExisting();

         // Set text mode
         _modemConnection.WriteLine("AT+CMGF=1");
         response = _modemConnection.ReadExisting();

         // Send the SMS
         _modemConnection.WriteLine(String.Format
            ("AT+CMGS=\"{0}\"", destination));
         response = _modemConnection.ReadExisting();

         _modemConnection.Write(text);
         _modemConnection.Write(new byte[]{26}, 0, 1);

         response = _modemConnection.ReadExisting();

         if(response.Contains("ERROR"))
         {
            Console.WriteLine("SMS Failed to send");
         }
         else
         {
            Console.WriteLine("SMS Sent");
            Console.WriteLine("Response: {0}", response);
          }
      }

      static void HelpText()
      {
         Console.WriteLine("ERROR: ");
         Console.WriteLine("\tUSage is GSMSMSSend <number>
            \"<message>\"");
         Console.WriteLine("");
         Console.WriteLine("Where <number> should be
            the phone number you wish to send to in
            international format");
         Console.WriteLine("and \"<message>\" is the text
            you wish to send (NOTE: you MUST surround it
            with quote marks)");
      }

      static void Main(string[] args)
      {
         if(args.Count() != 2)
         {
            HelpText();
            return;
         }

         var destinationNumber = args[0];
         var message = args[1];

         Console.WriteLine("About to send message to {0}",
            destinationNumber);

         _modemConnection = new SerialPort(SERIAL_PORT_NAME)
         {
            // 19200 baud, most modems will accept everything
            // from 9600 up to 115200
            BaudRate = 19200,
            // 99% of the time the port connection will be
            //8 Data bits
            DataBits = 8,
            // NO partiy
            Parity = Parity.None,
            // and 1 stop bit. Check your modem manual if
            // this doesn't work
            StopBits = StopBits.One
         };
         _modemConnection.Open();

         SendSms(destinationNumber, message);

         _modemConnection.Close();

      }

   }
}

As you can see, this forms a full program that should build a command line SMS sender.

Remember to use “SendLine” when sending data, because AT commands are line orientated and terminated by a carriage return.

You also can see that we turn off the line echo by using ATE. This is to prevent extra data coming back when sending commands, ensuring that all we get in return is the responses from the commands we send.

There is far more we can do with this, such as set it up to watch for message reception, and check to see if we have a signal and an operator connection.

With a valid SIM, you can even monitor the terminal, and see “RING” when someone calls that telephone number.

For now, however, if you want to dig into this more, you’ll need to start reading specification documents. Here in the UK and Europe most of our standards in this arena are governed by “ETSI” (European Telecommunications Standards Institute); for other areas of the world, you may need to do a little research.

For now, however, you can find out a lot of information bby using the ETSI GSM 07.07 Standards guide available from:

http://www.etsi.org/deliver/etsi_gts/07/0707/05.00.00_60/gsmts_0707v050000p.pdf

There are also a couple of good guides at:

https://www.sparkfun.com/datasheets/Cellular%20Modules/AT_Commands_Reference_Guide_r0.pdf

and

http://www.hughes.com/AT_Command_Reference.html

Please remember, however, only AT commands that are defined in the standard as “required” are expected to work on most modems. The definitive guide should always be any documentation you may have for your device.

Got a .NET problem you want to share, or just curious about how you might achieve a goal using the .NET framework? Feel free to shout me on Twitter as @shawty_ds and let’s see if I can rustle up a post on the subject.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read