博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Using VB.NET to Encode SMS and EMS
阅读量:5834 次
发布时间:2019-06-18

本文共 10139 字,大约阅读时间需要 33 分钟。

我发表在Codeproject上的文章,直接粘贴过来了。此文被评为Prize Winner

PDUEncoder.jpg

Introduction

Hi, we're back again to generate the PDU code while we have known . But at first, sorry for the late publishing of my PDU encoder as I was busy for a long time. These classes are written for my own program, but they can be easily implemented in your project. And this tiny demo program can be used to get the correct PDU code from your setting so as to convince your AT command test work. I'll show how to do this later in this article.

Background

It was last year that I did some work on SMS and EMS PDU code encoding and decoding. And I wrote my PDU Decoder to help me get the PDU strings returned from the mobile. That article has been read by more than twenty thousands people all over the world. Some one pointed out the bugs hidden in my decoder and they helped me to improve my decoder.

But my encoder, although I have done it in February this year, I have it shown to the world in the hot summer. I'm sorry again for this.

Like the decoder, this encoder also was created according to GSM 03.40. But I use 3GPP TS 23.040 V6.5.0 for reference. The link to these documents can be found at the end of this article.

OK. Here we start, I'll introduce my encoder step by step and hope it will give you a hand when designing an encoder.

The architecture of this encoder

The most important parts, public class SMS and ConcatenatedShortMessage, are under the namespace SMS and Encoder. Figure 1 shows this.

PDUEncoder1.gif

The SMS class is foundation of SMS and EMS. It has the basic elements required for SMS. Figure 2 shows you the SMS class. I'll explain how this class works in detail later.

Please note that I have set a group of protected variables prefixed with TP. These variables' names can be easily found in 3GPP or GSM documents. And there're also a set of properties, e.g. ServiceCenterNumber, TP_Status_Report_Request. When you set these properties, they prepare the correct PDU string and store them in protected variables for future use.

This class implements one function GetSMSPDUCode() to generate PDU code. This function simply joins the protected variables in a certain order to get a PDU code. Another function FirstOctet() contains the first octet data in PDU code. We can use it in some particular occasions.

We know that EMS is composed of several SMSs. Each SMS has TP_UserDataHeader set which is different from simple SMS. We can easily inherent from SMS to create the base of EMS. And please note the Concatenated Short Message is only part of EMS, which allows you to send messages containing more than 160 ASCII characters or 70 Unicode characters. You can inherent the SMS class and build another portion of EMS.

From figure 2 you can see an Integer variable named TotalMessages. It tells you how many SMS PDU Codes are generated. And note the GetEMSPDUCode(), it returns a number of SMS PDU codes. I'll explain this later.

PDUEncoder2.gif

How it really works?

In order to demonstrate and explain the details about how this encoder works, let us open my demo program in Visual Studio.

First, please find function GetPDU() in the Form and make a checkpoint. We will trace it down.

Then build and start this program. Fill the blanks according to the picture shown at the beginning of this article and then click Get PDU Code button.

The program stops at the checkpoint. Let's trace down the code. It first check the coding scheme and user data length to ensure if EMS will be used. Please note that the SMSObject is an object type. It will be blind to a specific type of SMS or EMS. Going down the code, we see it sets ServiceCenterNumber and other properties.

Please trace into ServiceCenterNumber property and you can see it prepares PDU code from your setting. The final result is stored in a protected variable SC_Number. Similar process happen to all the properties.

Then, according to the type of SMSObject, we use GetSMSPDUCode() or GetEMSPDUCode() to get PDU codes.

Function details

Let's look into the detail of the GetSMSPDUCode function:

ExpandedBlockStart.gif
ContractedBlock.gif
Public
 
Overridable
 
Function GetSMSPDUCode()
Function GetSMSPDUCode() As String
InBlock.gif    
Dim PDUCode As String
InBlock.gif    
'Check User Data Length
InBlock.gif
    If TP_DCS = ENUM_TP_DCS.DefaultAlphabet Then
InBlock.gif        
If TP_UD.Length > 280 Then 
InBlock.gif            
Throw New Exception("User Data is TOO LONG for SMS")
InBlock.gif    
End If
InBlock.gif    
If TP_DCS = ENUM_TP_DCS.UCS2 Then
InBlock.gif        
If TP_UD.Length > 280 Then 
InBlock.gif            
Throw New Exception("User Data is TOO LONG for SMS")
InBlock.gif    
End If
InBlock.gif    
'Make PDUCode
InBlock.gif
    PDUCode = SC_Number
InBlock.gif    PDUCode 
+= FirstOctet()
InBlock.gif    PDUCode 
+= Format(TP_MR, "X2")
InBlock.gif    PDUCode 
+= TP_DA
InBlock.gif    PDUCode 
+= Format(TP_PID, "X2")
InBlock.gif    PDUCode 
+= Format(TP_DCS, "X2")
InBlock.gif    PDUCode 
+= Format(TP_VP, "X2")
InBlock.gif    PDUCode 
+= Format(TP_UDL, "X2")
InBlock.gif    PDUCode 
+= TP_UD
InBlock.gif    
Return PDUCode
ExpandedBlockEnd.gif
End Function
None.gif

This function first checks the coding and determines if the length of user data is longer than the maximum size. Then every prepared PDU code is added to the variable PDUCode. Note the PDU codes are added by a certain order. So it is an easy task to modify the order or add some more PDU codes simply by changing the order or adding the other PDU codes to PDUCode. This gives my class flexibility and extensibility.

Here are also two core functions: Encode7Bit() and EncodeUCS2(). You can treat UCS2 as Unicode and use AscW function to get Unicode character.

But Encode7Bit is much more complex. In order to ease this encoding, I use several help functions such as BitsToHex, CharTo7Bits and so on. First I convert hex number to binary and join them together, then I split them into 8 bits. Please refer to GSM documents for detailed information about 7 bit encoding.

Let us take a look at GetEMSPDUCode():

ExpandedBlockStart.gif
ContractedBlock.gif
Public
 
Function GetEMSPDUCode()
Function GetEMSPDUCode() As String()
InBlock.gif    
Select Case tp_dcs
InBlock.gif        
Case ENUM_TP_DCS.UCS2
InBlock.gif            TotalMessages 
= (TP_UD.Length / 4\ 66 + ((TP_UD.Length / 4 Mod 66= 0)
InBlock.gif        
Case ENUM_TP_DCS.DefaultAlphabet
InBlock.gif            TotalMessages 
= (tp_ud.Length \ 266- ((tp_ud.Length Mod 266= 0)
InBlock.gif    
End Select
InBlock.gif
InBlock.gif    
Dim Result(TotalMessages) As String
InBlock.gif    
Dim tmpTP_UD As String
InBlock.gif    
Dim i As Integer
InBlock.gif    TP_UDHI 
= 2 ^ 6
InBlock.gif    
Dim Reference As Integer = Rnd(1* 65536
InBlock.gif    
'16bit Reference Number 'See 3GPP Document
InBlock.gif
    For i = 0 To TotalMessages
InBlock.gif        
Select Case tp_dcs
InBlock.gif            
Case ENUM_TP_DCS.UCS2
InBlock.gif                tmpTP_UD 
= Mid(TP_UD, i * 66 * 4 + 166 * 4)
InBlock.gif                
'When TP_UDL is odd, the max length of an Unicode string 
InBlock.gif
                'in PDU code is 66 Charactor.
InBlock.gif
                'See [3GPP TS 23.040 V6.5.0 (2004-09] 9.2.3.24.1
InBlock.gif
            Case ENUM_TP_DCS.DefaultAlphabet
InBlock.gif                tmpTP_UD 
= Mid(tp_ud, i * 133 * 2 + 1133 * 2)
InBlock.gif        
End Select
InBlock.gif        Result(i) 
= SC_Number
InBlock.gif        Result(i) 
+= FirstOctet()
InBlock.gif        Result(i) 
+= Format(TP_MR, "X2")
InBlock.gif        Result(i) 
+= TP_DA
InBlock.gif        Result(i) 
+= Format(TP_PID, "X2")
InBlock.gif        Result(i) 
+= Format(TP_DCS, "X2")
InBlock.gif        Result(i) 
+= Format(TP_VP, "X2")
InBlock.gif        
If tp_dcs = ENUM_TP_DCS.UCS2 Then
InBlock.gif            TP_UDL 
= tmpTP_UD.Length / 2 + 6 + 1 '6:IE
InBlock.gif
        End If
InBlock.gif        
If tp_dcs = ENUM_TP_DCS.DefaultAlphabet Then
InBlock.gif            TP_UDL 
= Fix((tmpTP_UD.Length + 7 * 2* 4 / 7'6:length of IE
InBlock.gif
        End If
InBlock.gif        Result(i) 
+= Format(TP_UDL, "X2")
InBlock.gif        Result(i) 
+= "060804" 'TP_UDHL and some of Concatenated message
InBlock.gif
        Result(i) += Format(Reference, "X4")
InBlock.gif        Result(i) 
+= Format(TotalMessages + 1"X2")
InBlock.gif        Result(i) 
+= Format(i + 1"X2")
InBlock.gif        Result(i) 
+= tmpTP_UD
InBlock.gif    
Next
InBlock.gif
Return Result
InBlock.gif

As you can see, the above code is similar to GetSMSPDUCode(). But you can also see TP_UDHI is set indicating that TP_UDH appears in TP_UD. Note TP_UDL is calculated during the loop process. As I mentioned in my source code, it also has problems treating TP_UDL while the TP_DCS is DefaultAlphabet. To get details on how EMS is created, please refer to 3GPP TS 23.040 V6.5.0.

Let us send an SMS!

I'm happy to show you that it's so easy to send an SMS to a certain number. In this demonstration, I'll show you how to get my account information using my PDU Encoder, Microsoft HyperTerminal and my PDU Decoder. My phone is Siemens M55, and note some AT commands may not work on your phone or GSM Modem.

First let's produce an SMS PDU Code. Start my program, and fill the Number, Options and User Data as shown in Figure 3. Then press "Get PDU Code" button to get PDU code and length for AT which will be used later. Press "Copy to Clipboard" to copy PDU Code to clipboard.

PDUEncoder3.jpg

Start HyperTerminal program. I give this session a name "Send SMS Demo" and I choose COM3 which is the port my phone is connected to. Then follow these instructions:

<CR> equals to Enter key of your keyboard.

Step 1: Type AT<CR> and ensure the device is ready.

Step 2: Type AT+CPMS="MT","MT","MT"<CR> to set preferred memory storage. Here I set it to Mobile Terminal.

Step 3: Type AT+CMGS=12<CR>. The number 12.

Step 4: Paste PDU code to HyperTerminal and press CTRL+Z to end the input. At this time your phone will send SMS to the number you specified. Here my destination number is 1861 from which I can get my account info.

Step 5: After a while I can see my phone receive a status report and my account info.

Step 6: Type AT+CMGL=1 to list the incoming message. Here it returns:

+CMGL: 1,1,,166    0891683108200805F0066104818116505013612455005050136124550000FFFFFFFFFFFFFFFFFFFF    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF    FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF    +CMGL: 2,1,,83    0891683108200805F00404A1811600085050136164350044672C67085DF24F7F75288BDD8D39003A    00350031002E00340037002052694F5998845B586B3E003A00350039002E0033003600204F1860E0    003A00370039002E00350031

Step 7: Use my PDU Decoder to decode above PDU codes. Note there're some Chinese characters.

SMS_STATUS_REPORT    Send time:2005-5-31 16:42:55 Receive time:2005-5-31 16:42:55 Status:Success    SMS_RECEIVED    From:1861 Time:2005-5-31 16:46:53    ±¾ÔÂÒÑʹÓû°·Ñ:51.47 Ê£ÓàÔ¤´æ¿î:59.36 ÓÅ»Ý:79.51

You can see that it's an easy task to manually send and receive SMSs though my tools and HyperTerminal. Be glad to use them to ease your test work!

Reference

Note

You can use and modify my code freely. If you find some bugs or improve my code, please contact me. This will help me to fix bugs and also it will help a lot of people all over the world! Thanks for reading my article and thanks again for using my code!

Contact me

  • Tencent QQ Number: 38288890

转载地址:http://mtucx.baihongyu.com/

你可能感兴趣的文章
EventSystem
查看>>
用WINSOCK API实现同步非阻塞方式的网络通讯
查看>>
玩一玩博客,嘿嘿
查看>>
Ubuntu设置python3为默认版本
查看>>
JsonCpp 的使用
查看>>
问题账户需求分析
查看>>
JavaSE-代码块
查看>>
爬取所有校园新闻
查看>>
32、SpringBoot-整合Dubbo
查看>>
python面向对象基础
查看>>
HDU 2044 一只小蜜蜂(递归)
查看>>
docker 下 安装rancher 笔记
查看>>
spring两大核心对象IOC和AOP(新手理解)
查看>>
数据分析相关
查看>>
Python LDAP中的时间戳转换为Linux下时间
查看>>
微信小程序蓝牙连接小票打印机
查看>>
C++_了解虚函数的概念
查看>>
全新jmeter视频已经上架
查看>>
Windows 8下如何删除无线配置文件
查看>>
oracle系列(五)高级DBA必知的Oracle的备份与恢复(全录收集)
查看>>