Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

SmsToolset Library for Sending SMS over GSM Network using PDU Format

5.00/5 (3 votes)
2 May 2016CPOL5 min read 21.8K   600  
How to use the SmsToolset library to send SMS over GSM network by using PDU format
SmsToolset is a library which aims to help create applications of sending and receiving text messages in PDU format over GSM network.

Source code is also available in github repository: https://github.com/atmdevnet/SmsToolset.git

Nuget package (targets .NET Standard 2.0) is available at: https://www.nuget.org/packages/SmsToolset/

Introduction

SmsToolset is .NET library written in C# which aims to help create applications of sending and receiving text messages in PDU format over GSM network.

The original key concept of this library is the PDU profile which is an object that determines structure of transmitted PDU packet. Basic part of PDU profile object is settings object driven by text file in well known JSON format. Parameters of profile defined in JSON file are loaded into settings object which initialize the PDU profile object. The essential task of profile is to create PDU packets. Another essential part of library is PDU profile manager that helps create and manage many different profiles.

In general, the library consists of three main parts responsible for:

  • creating and managing PDU profiles
  • creating commands for communications equipment (GSM modem)
  • sending commands to and receiving response from communications equipment

Library also contains basic implementation of tools that help with tasks of:

  • authentication by pin
  • handling service center number
  • sending and reading text messages

Background

The structure of the library consists of three namespaces. The first namespace SmsTools.PduProfile is the heart of the library. There are two major interfaces: IPduProfile and IPduProfileSettings, and PduProfileManager class. IPduProfileSettings represents the settings object loaded from the JSON file, which is then initialized profile object that implements the interface IPduProfile. Object of PduProfileManager class is used to manage profiles. In the library, there are implementations of these interfaces, respectively PduDefaultProfileSettings responsible for profile setting, and PduDefaultProfile class which deals with the creation of the profile. Why are these classes so important? Because this profile object is responsible for creating the PDU package, which will be sent over the GSM network. The structure and contents of the PDU package defines the IPduProfileSettings contract and the associated JSON file. As a consequence of applying the given settings object is determined form of the package and its elements:

  • the number of Service Center,
  • the destination number,
  • protocol used,
  • data coding scheme,
  • the validity period of the package,
  • packet header information such as reply path, user header, status report, validity format, duplicates rejection and message type.

Another namespace is the SmsTools.Commands which contains interfaces representing AT commands understood by communications equipment (DCE: GSM modem). The main task of the object representing the AT command is the formation of a string passed to the DCE, in particular PDU packet, and interpretation of the response received from the DCE. To implement this concept, IATCommand and ICommandParameter interfaces are used which represent the command and its parameters respectively. The implementation of the command was divided into three parts. SimpleATCommand class is responsible for creating a command not taking any parameters. ParamATCommand allows you to create a command taking a single parameter while StepwiseATCommand is used in case of passing to command multiple parameters depending on the result of passing the previous parameter. An example of such a command is a command sending text message.

The last namespace SmsTools.Operations contains the interface representing the DCE and its implementation. Its primary and only purpose is to send commands to DCE and receive response. The IPortPlug object is used by commands for their execution by the DCE.

All of the above concepts are realized in Authentication, ServiceCenter and PduSms classes. Authentication is used to authenticate user by pin. Using the ServiceCenter class can be read and set service center number. PduSms allows you to send text messages in the form of a PDU package.

Using the Code

Let's see the simplest example of sending SMS using built-in default settings and default profile.

One of the default settings of built-in default PDU profile (when using PduSms class) are as follows:

  • service center number type: not set,
  • service center number: not set,
  • PDU header: 0x11, which means: 
    • reply path: no setting,
    • user data segment contains only contents of the message,
    • status report not required,
    • validity period field is valid and the format is relative,
    • not reject duplicates,
    • message type: SMS-SUBMIT.
  • destination number type: default (doesn't require prefix),
  • destination number: not set,
  • protocol identifier: sms,
  • data coding scheme: UCS2,
  • validity period: 0xFF (maximum),
  • message: not set.
C#
var ports = SerialPortPlug.AvailablePorts();
if (ports.Any())
{
    var config = SerialPortConfig.CreateDefault();
    config.Name = ports.First();

    using (var modem = new SerialPortPlug(config))
    {
        if (!modem.IsOpen)
            return;

        var destination = 888123456;
        var message = "hello";

        var sms = new PduSms();
        bool isSent = await sms.Send(modem, destination, message);
    }
}

How to authenticate user by pin:

C#
var auth = new Authentication();
bool isAuthenticated = await auth.IsAuthenticated(modem);
if (!isAuthenticated)
{
    isAuthenticated = await auth.Authenticate(modem, 1234);
}

If you want to, you can set service center number in this way:

C#
var sca = new ServiceCenter();
var defined = await sca.IsDefined(modem);
if (defined)
{
    bool international = await sca.HasInternationalFormat(modem);
    var address = await sca.GetAddress(modem);
}
else
{
    bool success = await sca.SetAddress(modem, 48601000310, true);
}

Now, let's do the same thing (as in first sample) in a slightly more complicated way. :)

First, create JSON file with profile settings. The settings are as follows:

  • service center number type: international,
  • service center number: +48 601 000 310,
  • PDU header: 0x11, which means: 
    • reply path: no setting,
    • user data segment contains only contents of the message,
    • status report not required,
    • validity period field is valid and the format is relative,
    • not reject duplicates,
    • message type: SMS-SUBMIT.
  • destination number type: international,
  • destination number: not set,
  • protocol identifier: sms,
  • data coding scheme: UCS2,
  • validity period: 0xFF (maximum),
  • message: not set.

Content of JSON file:

JavaScript
{
  "sca": {
    "type": 145,
    "value": 48601000310
  },
  "pdu-header": {
    "value": 17
  },
  "mr": {
    "value": 0
  },
  "da": {
    "type": 145,
    "value": 0
  },
  "pid": {
    "value": 0
  },
  "dcs": {
    "value": 8
  },
  "vp": {
    "value": 255
  },
  "ud": {
    "value": ""
  }
}

Data contract that match structure of JSON file is defined in PduDefaultProfileSettings class, so we can create settings object using this class and next create profile based on loaded settings:

C#
var manager = new PduProfileManager();

using (var file = Assembly.GetExecutingAssembly().GetManifestResourceStream("profile.json"))
{
    var settings = manager.CreateProfileSettings<PduDefaultProfileSettings>(file);

    var profile = manager.CreateDefaultProfile(settings, "my_profile");
}

Having PDU profile, we can create PDU packet that will be send over GSM network:

C#
int length = 0;
string packet = string.Empty;

long destination = 48888123456;
string message = "华为";

packet = profile.GetPacket(destination, message, out length);

Before we send our message as PDU packet, we must set message format as PDU:

C#
string commandParameterValue = Constants.MessageFormat.Pdu.ToValueString();
string successfulResponsePattern = Constants.BasicSuccessfulResponse;

var commandParameter = new CommandParameter(commandParameterValue, successfulResponsePattern);

string atCommand = ATCommand.MessageFormat.Command();

var command = new ParamATCommand(atCommand, commandParameter);
await command.ExecuteAsync(modem);
bool succeeded = command.Succeeded();

At last, we can send our message:

C#
var lengthStep = new CommandParameter($"{length}{Constants.CR}", 
                                      Constants.ContinueResponse, false);
var packetStep = new CommandParameter($"{packet}{Constants.SUB}", 
                                      Constants.BasicSuccessfulResponse);

var sendCommand = new StepwiseATCommand(ATCommand.MessageSend.Command(), 
                  new ICommandParameter[] { lengthStep, packetStep });
await sendCommand.ExecuteAsync(modem);
bool succeeded = sendCommand.Succeeded();

Points of Interest

I hope you enjoy the idea of using PDU profile for sending SMS in PDU message format.

History

This is the first version of the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)