1、绪论
SMS提供了在GSM移动站台(MS)与一个短消息实体(SME)之间通过服务中心(SC)传送短消息的方法
。SC提供了在MS与SME之间消息传送的相互联系和转播的功能。
SMS采用存储转发模式,短消息被发送出去之后,不是直接地发送给接收方,而是先存储在SMS(
短消息服务中心),然后再由SMC将其转发给接收方。如果接收方当时关机或不在服务区内,SMC
会自动保存该短消息,排队并尝试再次发送给接收方。
点到点短消息服务包含两个基本服务:
Þ SM MT(点到点短消息移动接收)
Þ SM MO(点到点短消息移动发送)
通过 SM MT 或 SM MO 方法传送的文本消息包含 140 个八位位组(最大 160 个拉丁字母字符、
70个双字节字符)。
本文仅仅给出了简单地一些AT指令及SMS PDU模式的描述。更多的详细资料,请参看下列标准:
GSM 03.04
GSM 03.38
GSM 03.41
GSM 07.05
GSM 07.07
2、缩写词
缩写 全称 说明
MS: Mobile-Station 移动站台
负责系统交换管理,控制来自或发往其他电话或数据系统的
通信
SME: Short-Message-Entity 短消息实体
负责接收和发送短消息。可以位于固话系统、移动基站或
其他服务中心内
SMSC: Short Message Service Center 短消息服务中心
负责在移动基站和SME之间中继、存储或转发短消息
PDUs: Protocol Data Units 协议数据单元
PDU Type: Protocol Data Unit Type 协议数据单元类型
MR: Message Reference 消息参考
OA: Originator Adress 发送方地址
DA: Destination Adress 接收方地址
PID: Protocol Identifier 协议标识
DCS: Data Coding Scheme 数据编码方案
SCTS: Service Center Time Stamp 服务中心的时间戳
VP: Validity Period 消息有效期
UDL: User Data Length 用户数据长度
UD: User Data 用户数据
RP: Reply Path 应答路径
UDHI: User Data Header Indicator 用户数据头标识
SRI: Status Report Indication 状态报告指示
SRR: Status Report Request 请示状态报告
VPF: Validity Period Format 有效期格式
MMS: More Messages to Send 有更多的信息需要发送
RD: Reject Duplicate 拒绝复本
MTI: Message Type Indicator 消息类型指示
ME: Mobile Equipment 移动设备
TE: Terminal Equipment 终端设备
SIM: Subscriber Identity Modul
SC: Service-Center 服务中心
SCA: Service Center Address 服务中心地址
SM MT: Short Message Mobile Terminated Point-to-Point 点到点短消息移动接收
SM MO: Short Message Mobile Originaed Point-to-Point 点到点短消息移动发送
3、设置指令
3.1 服务中心号码 (+CSCA)
服务中心(SC)负责转播和存储转发SME和MS之间的短消息。如果MS支持SMS-MO(短消息服务移动
发送),为了使用SMS,必须在MS中设置SMSC(短消息服务中心,SCA)。
使用指令 “AT+CSCA?” 可以查看存储在SIM卡中的当前服务中心地址。
使用AT指令 “AT+CSCA=[,]” 加入短消息服务号码。
句法:
输入 执行 注释
AT+CSCA? 查询当前服务中心地址(SCA)设置(从SIM卡中读取)
响应
+CSCA: “”
OK
AT+CSCA=“” 定义服务中心地址(SCA) (存储到SIM卡)
参数:
服务中心地址(字符型)
服务中心地址的类型设置(编码方式)
示例:
AT+CSCA=“+8613800250500” 以国际号格式定义服务中心地址(SCA)
AT+CSCA=“+13800250500” 以国内号格式定义服务中心地址(SCA)
注意:
Þ 为了避免漫游时出现问题,推荐国际号码格式存储所有地址(以“+”和国家代码开头
)。
Þ 向你本地的网络提供商询问正确的短消息服务中心号码
Þ SC地址是SMS的一部分!当任何一个SMS被存储到SIM卡上时,SC地址也同时该SMS中。
3.2 选择消息服务 (+CSMS)
这个指令用于选择消息服务。
句法:
输入 执行 注释
AT+CSMS? 返回当前的服务类型及ME支持的信息
AT+CSMS=? 返回所有支持的服务类型
AT+CSMS= 选择消息服务
响应
+ CSMS: ,,,
OK
参数:
消息服务
接收短消息
发送短消息
接收小区广播消息
示例:
读取指令
输入 执行 注释
AT+CSMS? 返回当前的服务类型及ME支持的信息
响应
+ CSMS: 0,1,1,1
OK
指令返回当前的消息服务和移动设备支持的服务选项
设置指令
输入 执行 注释
AT+CSMS=1 设置支持的消息类型
响应
+ CSMS: 0,1,1,1
OK
返回移动设备支持的服务选项
参数:
参数 值 描述
0 SMS AT 指令的句法兼容 GSM Phase 2
1 SMS AT 指令的句法兼容 GSM Phase 2+
2...127 保留
128 厂商自定义
,, 0 不支持
1 支持
3.3 选择消息格式 (+CMGF)
这个指令用于选择短消息格式。它的参数指示发送、列取、读取和写入的消息所使用的格式。
句法:
输入 执行 注释
AT+CMGF? 返回当前的SMS格式
AT+CMGF =? 返回所有支持的SMS格式
AT+CMGF= 选择SMS格式
响应
OK
支持的值:
含义
0 PDU模式(默认的)
1 Text模式
示例:
读取指令
输入
执行
注释
AT+CMGF?
返回当前的SMS格式
响应
+ CMGF: 0
OK
返回当前的SMS格式
设置指令
输入
执行
注释
AT+CMGF=1
设置SMS类型为Text
4、SMS文本模式
略
5、SMS PDU模式
一个完整的SMS消息所包含的所有报头信息被以二进制字符串格式传送。这个二进制串由十六进
制格式的IA5 字符组合而成。
使用AT指令”AT+CMGF=0”切换到协议数据模式,之后所有的SMS输入与显示将以PDU格式执行。
5.1 发送方SMS-Submit (Mobile Originated)
SMS-SUBMIT的意思就是GSM-Molbile传送一条SMS到服务中心。
5.1.1 向SIM卡存储区写入一条SMS (+CMGW)
执行指令”AT+CMGW”用于存储一条消息在SIM卡的存储区中。命令返回消息被存储的索引号。
句法:
*)
/
**)
响应
+CMGW:
OK
如果命令正确执行,返回消息存储位置的索引号
参数:
给定的TP层数据单元的八位位组代码数目(不包含服务中心地址的八位位组数目)
除存储未发送的状态之外的状态值
在PDU模式下该值为整型(默认值为0)
在文本模式下该值为字符型(默认值为”REC UNREAD”)
PDU数据
存储位置
支持的值:
含义
0 “REC UNREAD”
已接收未读的消息(例如新消息)
1 “REC READ”
已接收已读的消息
2 “STO UNSENT”
已存储未发送的消息
3 “STO SENT”
已存储已发送的消息
4 “ALL”
所有的消息(仅适用于 +CMGL命令)
注:
*) 符号”>”是的移动终端设置返回而产生的
**) +执行命令;不保存/发送、直接退出执行
5.1.2 发送SIM卡存储区中的一条SMS (+CMSS)
AT指令”AT+CMSS=[,[,]]”将SIM卡消息存储区中索引位置的消息发
送到网络中(SMS-SUBMIT)。如果指定新的接收地址,它将代替原消息中存储的接收地址。
如果消息传送成功,消息参考值将返回到终端设备(TE)。通常(当+CSMS值为1
,并且网络支持时),同时返回服务中心时间戳。
句法:
输入
执行
注释
AT+CMSS=
响应
+CMSS: [,]
OK
参数:
SIM卡内存位置索引
消息参考
服务中心时间戳
示例:
输入
执行
注释
AT+CMSS=1
SIM卡中存储位置1的消息将被发送到服务中心
响应
+CMSS: 255
OK
SMS被发送到服务中心,消息参考为255
5.1.3 直接从终端设置发送SMS (+CMGS)
这个指令用于从一个终端向网络中发送消息(SMS-SUBMIT),而不会在SIM卡中保存所发送的SMS
消息。
如果消息传送成功,消息参考值将返回到终端设备(TE)。通常(当+CSMS值为1
,并且网络支持时),同时返回服务中心时间戳。
句法:
输入
执行
注释
AT+CMGS=
转换SMS输入模式,SMS将会被以“未发送”状态保存。命令后所跟的PDU字串的长度必须在这个
*)
/
**)
直接从终端中发送一条SMS,而不将其保存到SIM卡。
响应
+CMGS: [,]
OK
如果发送成功将返回消息参考
参数:
给定的TP层数据单元的八位位组代码数目(不包含服务中心地址的八位位组数目)
PDU数据
消息参考
服务中心时间戳
注:
*) 符号”>”是的移动终端设备返回而产生的
**) +执行命令;不保存/发送、直接退出执行
5.2 接收方 SMS-DELIVER (Mobile Terminated)
SMS-DELIVER意味着终端设置从服务中心接收到一条SMS消息。
5.2.1 列取消息 (+CMGL)
句法:
输入 执行 注释
AT+CMGL=
列取内存中指定类型的SMS
响应
+CMGL: [,],
[...]
]
AT+CMGL=? 查看设备支持的类型
参数:
参数 描述
在PDU模式下该值为整型(默认值为0)
在文本模式下该值为字符型(默认值为”REC UNREAD”)
指示内存中消息的状态
定义的值:
0 “REC UNREAD” 已接收未读的消息(例如新消息)
1 “REC READ” 已接收已读的消息
2 “STO UNSENT” 已存储未发送的消息
3 “STO SENT” 已存储已发送的消息
4 “ALL” 所有类型的消息
5.2.2 读取消息 (+CMGR)
句法:
输入 执行 注释
AT+CMGR=
读取内存中指定索引位置的SMS
响应
+CMGR: [,],
OK
参数:
参数 描述
在PDU模式下该值为整型(默认值为0)
在文本模式下该值为字符型(默认值为”REC UNREAD”)
指示内存中消息的状态
定义的值
0 “REC UNREAD”
已接收未读的消息(例如新消息)
1 “REC READ”
已接收已读的消息
2 “STO UNSENT”
已存储未发送的消息
3 “STO SENT”
已存储已发送的消息
以字符型的数字文字表示的,在SIM电话薄中找到的相应条目
给定的TP层数据单元的八位位组代码数目(不包含服务中心地址的八位位组)
PDU数据
注意:
Þ 切不可直接提交一个DELIVER-SMS!因为它的PDU数据中头信息是与用于提交的PDU不一
样的!
Þ在内存(SIM)中至少有最后一个空闲空间,以保证能接收到新的SMS!
5.2.3 删除消息 (+CMGD)
句法:
输入
执行
注释
AT+CMGD=
删除在SIM卡中索引位置的SMS
响应
OK
6、SMS PDU 基本组成元素
下列元素是用于SMS-SUBMIT和SMS-DELIVER中的部分。
元素 名称 长度 描述
SCA Service Center Adress 1-12 服务中心的电话号码
PDU-Type Protocol Data Unit Type 1 协议数据单元类型
MR Message Reference 1 所有成功的SMS-SUBMIT参考数目
(0..255)
OA Originator Adress 2-12 发送方SME的地址
DA Destination Adress 2-12 接收方SME的地址
PID Protocol Identifier 1 参数显示SMSC以何种方式处理SM (比
如FAX,、Voice等)
DCS Data Coding Scheme 1 参数表示用户数据(UD)采用什么编码
方案
SCTS Service Center Time Stamp 7 参数表示SMSC接收到消息时的时间戳
VP Validity Period 0,1,7 参数表示消息在SMSC中不再有效的时
长
UDL User Data Length 1 用户数据段长度
UD User Data 0-140 SM数据
6.1 发送方PDU格式SMS-SUBMIT-PDU (Mobile Originated)
SCA PDUType MR DA PID DCS VP UDL UD
1-12 1 1 2-12 1 1 0,1,7 1 0-140
示例:
向13851724908发送一条SMS,消息内容为:“Test”
0031000D91683158714209F80000A704D4F29C0E
向13851724908发送一条SMS,消息内容为:“测试”
0031000B813158714209F80008A7046D4B8BD5
SCA PDUType MR DA PID DCS VP UDL UD
1-12 1 1 2-12 1 1 0,1,7 1 0-140
00 31 00 0D91683158714209F8 00 00 A7 04 D4F29C0E
00 31 00 0B813158714209F8 00 18 A7 04 6D4B8BD5
6.2 接受方PDU格式 SMS-DELIVER-PDU (Mobile Terminated)
SCA PDUType OA PID DCS SCTS UDL UD
1-12 1 2-12 1 1 7 1 0-140
示例:
从13851724908接收到一条SMS,消息内容为:“Test”
0891683108200505F0240D91683158714209F800004001528035350004D4F29C0E
从13851724908接收到一条SMS,消息内容为:“测试”
0891683108200505F0240D91683158714209F8000840015280452400046D4B8BD5
SCA
PDUType
OA
PID
DCS
SCTS
UDL
UD
1-12
1
2-12
1
1
7
1
0-140
0891683108200505F0
24
0D91683158714209F8
00
00
40015280353500
04
D4F29C0E
0891683108200505F0
24
0D91683158714209F8
00
08
40015280452400
04
6D4B8BD5
6.3 SCA 短消息服务中心地址格式
服务中心地址包含三个部分:
SCA组成:1-12个八位位组
例:0891683108200505F0
1 Octet
0-1 Octet
0-10 Octets
Len
Type
Addr
SCA长度
SCA类型
SCA地址
08
91
683108200505F0
Len:短消息中心地址长度。指(91)+(68 31 08 20 05 05 F0)的八位位组数目。如果Len被
设置为00&h,并不提供后面的部分,那么终端设备将读取SIM中设置的SCA填充到SMS-PUD中,通
过“AT+CSCA=xxxxx”指令可以设置SIM卡中存储的SCA值。
Type:短消息中心地址的类型,是国际的号码还是国内的号码(81&h表示国内,91&h表示国际的
)。91&h是TON/NPI遵守International/E.164标准,指在号码前需加‘+’号;此外还有其它数
值,但91&h最常用。
例:91 &h = 1001 0001 &b
Bit No.
7
6
5
4
3
2
1
0
1
数据类型
号码鉴别
第7位永远置为1
数值类型(Type of Number):
000—未知,001—国际(以 + 开始的地址),010—国内,111—留作扩展;
号码鉴别(Numbering plan identification):
0000—未知,0001—ISDN/电话号码(E.164/E.163),1111—留作扩展;
Add:依照ISDN编号方式的短消息中心地址。
示例:
服务中心号码
PDU格式编码
+8613800250500
08 91 86 31 08 20 05 05 F0
13800512500
07 81 31 08 50 21 05 F0
123456
04 81 21 43 65
注:
指令AT+CMGW和AT+CMGS的参数是从PDUType部分开始计算PDU的长度,不包括SCA的长度
。所以:
输入:
AT+CMGS=19
输出:
AT+CMGS=19>
输入:
0891863108200505F031000D91683158714209F80000A704D4F29C0E
输出:
0891863108200505F031000D91683158714209F80000A704D4F29C0E+CMGS:
111OK
SCA = 0891863108200505F0
输入:
AT+CMGS=19
输出:
AT+CMGS=19>
输入:
0031000D91683158714209F80008A7046D4B8BD5
输出:
0031000D91683158714209F80008A7046D4B8BD5+CMGS:
112OK
SCA = 00
= 0D&h
= 0A&h
= 1A&h
6.4 PDU Type(第一个八位位组)
PDUType是SMS-SUBMIT、SMS-DELIVER的第一个八位位组。它分别由下面几个部分组成:
PDUType组成:1个八位位组
发送方:SMS-SUBMIT
例:31&h = 0011 0001&b
Bit No.
7
6
5
4
3
2
1
0
RP
UDHI
SRR
VPF
RD
MTI
0
0
1
1
0
0
0
1
接收方:SMS-DELIVER
例:04&h = 0000 0100&b
Bit No.
7
6
5
4
3
2
1
0
RP
UDHI
SRI
MMS
MTI
0
0
0
0
0
1
0
0
RP: 应答路径(Reply Paht),
0 – 未设置;
1 – 设置
UDHI: 用户数据头标识(User Data Header Indicator),
0 – 用户数据(UD)部分不包含头信息;
1 – 用户数据(UD)开始部分包含用户头信息
SRR: 请求状态报告(Status Report Request),
0 – 不需要报告;
1 – 需要报告
SRI: 状态报告指示(Status Report Indication),此值仅被短消息服务中心
(SMSC)设置
0 – 状态报告将不会返回给短消息实体(SME)
1 – 状态报告将返回给短消息实体(SME)
VPF: 有效期格式(Validity Period Format),
00 – VP 段没有提供(长度为 0 ),
01 – 保留,
10 – VP 段以整型形式提供(相对的),
11 – VP 段以8位组的一半(semi-octet)形式提供(绝对的)
RD: 拒绝复本(Reject Duplicate),
0 – 通知 短消息服务中心(SMSC)接受一个SMS-SUBMIT,即使该消息
是先前已提交过的,并还存在于SMSC中未发送出去。MS重复的条件是:消息参考(MR)、接收方地
址(DA)及发送方地址(OA)相同
1 – 通知 SMSC 拒绝一个重复的 SMS
MMS: 有更多的信息需要发送(More Messages to Send),此值仅被 SMSC 设置
0 – 在 SMSC 中有更多的信息等待 MS
1 – 在 SMSC 中没有更多的信息等待 MS
MTI: 信息类型指示(Message Type Indicator)
00 – SMS-DELIVER(SMSCèMS)
00 – SMS-DELIVER REPORT(MS è SMSC)
当手机接收到 SMS-DELIVER 时自动产生
01 – SMS-SUBMIT(MS è SMSC)
01 – SMS- SUBMIT REPORT(SMSC è MS)
10 – SMS-STATUS REPORT (SMSC è MS)
10 – SMS-COMMAND(MS è SMSC)
11 – 保留
注:(粗体代表手机支持的类型,并不是所有的 PDU 类型均被服务中心支持)
注意:
PDUType是PDU的第一个八位位组,而并不是服务中心号码后的第一个字节!
6.5 MR 信息参考 (Message Reference)
设为 00 即可
6.6 DA/OA 接收方地址与发送方地址
OA与DA格式是一样的,如下所示:
DA组成:2-12个八位位组
例:0D91683158714209F8
1 Octet
0-1 Octet
0-10 Octets
Len
Type
Addr
长度
类型
地址
0D
91
683158714209F8
Len:地址长度。指8613851724908 的长度。这与SCA中的定义不一样!
Type:短消息中心地址的类型,是国际的号码还是国内的号码(81&h表示国内,91&h表示国际的
)。
Add:依照ISDN编号方式的短消息中心地址。
示例:
电话号码
PDU格式编码
+8613851724908
0D 91 86 31 58 71 42 09 F8
13851724908
0B 81 31 58 71 42 09 F8
106051268812345 *)
0F A1 01 06 15 62 88 21 43 F5
123456
06 81 21 43 65
*) 小灵通号码
6.7 PID 协议标识 (Protocol-Identifier)
对于标准情况下的下 MS-to-SC 短消息传送,只需设置 PID 为 00
6.8 DCS 数据编码方案 (DataCoding-Scheme)
Bit No.
7
6
5
4
3
2
1
0
描述
示例:
0
0
0
0
0
0
0
0
= 00&h 7 bit 数据编码 默认字符集
1
1
1
1
0
1
1
0
= F6&h 8 bit 数据编码 Class 1
0
0
0
0
1
0
0
0
= 08&h USC2(16bit)双字节字符集
Bit No.7与Bit No.6:
一般设置为 00;
Bit No.5:
0 – 文本未压缩,1 – 文本用GSM标准压缩算法压缩;
Bit No.4:
0 – 表示 Bit No.1、Bit No.0 为保留位,不含信息类型信息,
1 – 表示 Bit No.1、Bit No.0 含有信息类型信息;
Bit No.3与Bit No.2:
00 – 默认的字母表,每个字符占用 7 比特位,此时最大可以传送 160 字符
01 – 8bit,此时最大只能传送 140 个字符
10 – USC2(16bit), 传送双字节字符集
11 – 预留;
Bit No.1与Bit No.0:
00 – Class 0,短消息直接显示在屏幕上
01 – Class 1,
10 – Class 2(SIM卡特定信息),
11 – Class 3。
示例:
DSC
字符集
信息 Class
00
default (7-bit)
No Class
F0
default (7-bit)
Class 0 (immediate display)
F1
default (7-bit)
Class 1 (Mobile Equipment- specific)
F2
default (7-bit)
Class 2 (SIM specific message)
F3
default (7-bit)
Class 3 (Class3 Terminate Equipment- specific)
F4
8-bit
Class 0 (immediate display)
F5
8-bit
Class 1 (Mobile Equipment- specific)
F6
8-bit
Class 2 (SIM specific message)
F7
8-bit
Class 3 (Class3 Terminate Equipment- specific)
08
16-bit
No Class
18
16-bit
Class 0 (immediate display)
6.9 VP 信息有效期(Validity Period)
第一种情况(相对的): VPF = 10 VP = AA H (四天)
第二种情况(绝对的): VPF = 11
年
月
日
时
分
秒
时区
30
80
02
90
54
33
20
表示 03-08-20 09:45:33
VP 段以整型或半个8位组(semi-octet)形式提供。
第一种情况,VP为一个8位组,给定有效期的长度,
从 SMS-SUBMIT 被 SMSC 接受开始计算。
第二种情况,VP为七个8位组,给定有效期终止的绝对时间。
在第一种情况下,有效期表示格式如下所示:
VP
相应的有效期
00 – 8F
(VF+1)*5 分钟 从 5 分钟间隔到 12 个小时
90 – A7
12 小时 + (VF – 143)*30 分钟
A8 – C4
(VP – 166) * 1 天
C5 – FF
(VP – 192) * 1 周
第二种情况下的时间形式与 SCTS(Service Center TimeStamp)形式一致。
6.10 SCTS 服务中心时间戳(Service Center TimeStamp)
占用七个8位组,格式如 VP 的第二种情况所示
6.11 UDL 用户数据长度 (User-Data-Length (Amount of Characters))
UDL 以整型形式提供,表示后面用户数据段的数据长度。
数据格式有3种: 7bit,8bit,16bit。
其中7bit采用GSM字符集,8bit采用ASCII字符集,16bit采用Unicode字符集。
1 octet
0 .. 140 octets
UDL
UD
05
E8 32 9B FD 06
如:7bit数据 "Test"
UDL = 04, UD = D4 F2 9C 0E
又如:16bit数据 "Test"
UDL = 08, UD = 00 54 00 65 00 73 00 74
用户数据(UD)的编码方式请参考第9章SMS编码方案与编程实现
7、常用 AT 指令
AT 指令
功 能
AT+CMGC
Send an SMS command(发出一条短消息命令)
AT+CMGD
Delete SMS message(删除SIM卡内存的短消息)
AT+CMGF
Select SMS message formate(选择短消息信息格式:0-PDU;1-文本)
AT+CMGL
List SMS message from preferred store
(列出SIM卡中的短消息PDU/text
0/“REC UNREAD” -未读
1/“REC READ” -已读
2/“STO UNSENT” -待发
3/“STO SENT” -已发
4/“ALL” -全部的
)
AT+CMGR
Read SMS message(读短消息)
AT+CMGS
Send SMS message(发送短消息)
AT+CMGW
Write SMS message to memory(向SIM内存中写入待发的短消息)
AT+CMSS
Send SMS message from storage(从SIN|M内存中发送短消息)
AT+CNMI
New SMS message indications(显示新收到的短消息)
AT+CPMS
Preferred SMS message storage(选择短消息内存)
AT+CSCA
SMS service center address(短消息中心地址)
AT+CSCB
Select cell broadcast messages(选择蜂窝广播消息)
AT+CSMP
Set SMS text mode parameters(设置短消息文本模式参数)
AT+CSMS
Select Message Service(选择短消息服务)
8、PDU操作实例
8.1 准备工作
一台支持AT操作的手机或手机模块,建议使用SIEMENS的,我使用的是西门子2118。
一根串口数据线。
串口调试软件:
串口调试助手V2.2
RoaringWindStudio 啸峰工作室
用于通过串口发送和接收数据。
Portmon
Mark Russinovich
用于监听系统中正在使用中的串口或并口当前传送的数据。
西门子手机工作室
通过上面的监听程序分析它的动作,你可以学到很多。
8.2 连接手机
将数据线插在主机的COM1上,然后运行串口调试助手V2.2,设置串口为COM1,波特率为19200,
校验位为NONE,数据位为8,停止位为1。然后输入AT再加一个回车,之后点发送按钮,如果手机
应答 ATOK,则说明电脑已与手机正常连接!如下图所示:
8.3 发送PDU SMS
如前面所述,向号码为 +8613851724908手机发送一条内容为“Test”的SMS,PDU串是
0031000D91683158714209F80000A704D4F29C0E,它的长度是20个八位位组,而最左方的 00 位组
是PDU串中的短消息服务中心字段,AT+CMGS=指令的不将其计算在内,所以首
先应该发送AT+CMGS=19:
如上图所示,手机返回了
AT+CMGS=19
>
这是要尽快输入PDU串:0031000D91683158714209F80000A704D4F29C0E
正确输入了PDU串后,还需要输入一个控制字符 1A &h通过手机立即将它发送出去,或
输入 1B &h通过终端设备放弃。
手机返回
+CMGS: 111
OK
说明短消息发送成功!返回的消息参考是111,表示这是发送成功的第111条消息(服务中心不保
证该值绝对准确)。
9、SMS 编码方案与编程实现
a. 英文编码
参见表,设短信息内容为“Hello World!”。缺省的GSM 字符集为7位编码,可以简单地理解为
ASCII码(ASCII值小于80Hex,因此,Bit8被忽略),依次将下一7位编码的后几位逐次移至前面
,形成新的8位编码,参见表2箭头指示。GSM并非支持所有的ASCII字符显示。
下面是实现英文编码的部分Delphi 5代码:
function Encode1(var s: String): String;
var
i, j, len: Integer;
cur: Integer;
t: String;
begin
Result := '';
len := Length(s);
//j 用于移位计数
i := 1;
j := 0;
while i <= len do
begin
if i < len then
//数据变换
cur := (Ord(s[i]) shr j) or ((Ord(s[i+1]) shl (7-j)) and $ff)
else
cur := (Ord(s[i]) shr j) and $7f;
FmtStr(t, '%2.2X', [cur]);
Result := Result+t;
inc(i);
//移位计数达到7位的特别处理
j := (j+1) mod 7;
if j = 0 then
inc(i);
end;
end;
b. 中文编码
通过Delphi的WideString类型转换,可以巧妙地实现GB2312到Unicode的编码转换(注意代码页
和操作系统相关联)。下面是实现中文编码的部分
编号
字符
GB2312编码
GB2312 编码 BIN
Unicode 编码 BIN 代码页CP936
1
中
D6
1101 0110
0100 1110
D0
1101 0000
0010 1101
2
文
CE
1100 1110
0110 0101
C4
1100 0100
1000 0111
Delphi 5代码:
function Encode2(var s: WideString): String;
var
i, len: Integer;
cur: Integer;
t: String;
begin
Result := '';
len := Length(s);
i := 1;
while i <= len do
begin
cur := Ord(s[i]);
//BCD转换
FmtStr(t, '%4.4X', [cur]);
Result := Result+t;
inc(i);
end;
end;
附
Message service error
These are the error codes for +CMS ERROR.
0-127 GSM 04.11 Annex E-2 values
128-255 GSM 03.40 section 9.2.3.22 values
300 Phone failure
301 SMS service of phone reserved
302 Operation not allowed
303 Operation not supported
304 Invalid PDU mode parameter
305 Invalid text mode parameter
310 SIM not inserted
311 SIM PIN necessary
312 PH-SIM PIN necessary
313 SIM failure
314 SIM busy
315 SIM wrong
320 Memory failure
321 Invalid memory index
322 Memory full
330 SMSC (message service center) address unknown
331 No network service
332 Network timeout
500 Unknown error
512 Manufacturer specific
error codes:
0 phone failure
1 no connection to phone
2 Phone-adaptor link reserved
3 operation not allowed
4 operation not supported
5 PH-SIM PIN necessary
10 SIM not inserted
11 SIM PIN required
12 SIM PUK required
13 SIM failure
14 SIM busy
15 SIM wrong
16 incorrect password
20 memory full
21 invalid index
22 not found
23 memory failure
24 text string too long (+CPBW)
25 invalid characters in text string
26 dial string to long
27 invalid characters in dial string
30 no network service
31 network timeout
100 unknown
265 PUK for theft protection necessary
266 PUK2 for SIM necessary
267 PIN2 for SIM necessary
2006-4-13 11:11:21
发表评语»»»
2006-5-27 13:15:40 一、短消息收发的实现模式
计算机串口上连接GSM MODEM,用它向手机发送短消息,要求对AT 指令集和串口编程比较熟悉。
这种方法收发短消息又分三种模式:BLOCK 模式、TEXT 模式和PDU 模式。BLOCK 模式现在用的
很少了; TEXT 模式则只能发送ASCII 码,它不能发送中文的UNICODE码——确切地讲,从技术上
来说是可以用于发送中文短消息的,但是国内的手机基本上不支持;而PDU 模式开发起来则较为
复杂,它需要编写专门的函数来将文本转换为PDU 格式,但PDU 模式被所有手机支持,可以使用任
何字符集,它也是手机默认的编码方式。笔者在开发中正是选用的PDU 模式。
二、PDU 模式
用PDU 模式收发短消息可以使用三种编码: 7-bit 编码、8-bit 编码和UCS2 编码。7-bit
编码用于发送普通的ASCII 字符;8-bit 编码通常用于发送数据消息,如图片或铃声等;UCS2
编码用于发送Unicode 字符。由于笔者在系统中要实现中文短消息的发送,所以选择用UCS2
编码,即中文Unicode 码。
(一)UCS2 编码原理
所谓UCS2 编码,是将单个的字符(1-2 个字节)按ISO/IEC10646 的规定,转变为16 位
的Unicode 宽字符。即将单个的字符转换为由四位的‘0’-‘9’、‘A’-‘F’的数字和字
母组成的字符串。待发送的消息以UCS2 码的形式进行发送。
(二)发送PDU 串的编制分析
通过UCS2 编码我们得到中文Unicode 码,接着就可以进行发送PDU 串的编制了。从表
面上看,PDU 串是ASCII 码串,同样由‘0’-‘9’、‘A’-‘F’这些数字和字母组成。它
们是8 位字节的十六进制数,或者BCD 码十进制数。PDU 串除了包含所发送的消息本身外,还包
含很多其它参数信息,如服务中心号码、目标号码和编码方式等。现用一个实例说明发送PDU 串
的结构和编排方式。
例:08 91 683108100005F0 31 00 0D 91 683119109991F2 00 08 C2 06 60A8597DFF01
参照规范,具体分析:
分段含义解释说明
08 SMSC 地址信息的长度共8 个八位字节(包括91)
91 SMSC 地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 10 00 05 F0 SMSC 地址8613800100500,补‘F’凑成偶数个
31 基本参数(TP-MTI/VFP) 要求发送回复
00 消息基准值(TP-MR) 0
0D 目标地址数字个数共13 个十进制数
91 目标地址格式(TON/NPI)
A1:国内格式
91:国际格式
81:未知,+86 可带可不带。
683119109991F2 目标地址(TP-DA) 8613910199192,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM 类型,点到点方式
08
用户信息编码方式
(TP-DCS)
00:表示7-bit 编码, 08:表示UCS2 编码,
04:表示8-bit 编码。
C2 有效期(TP-VP) 5 分钟
06 用户信息长度(TP-UDL) 实际长度6 个字节
60 A8 59 7D FF 01 用户信息(TP-UD) “您好!”
这里需要注意的几点:
①.比较SMSC 地址分段:68 31 08 10 00 05 F0 与真实SMSC 地址8613800100500F(为
了凑足14 位,在末尾补F),不难发现只需将前者奇偶位对调即可得到后者。同样,目标地
址分段683119109991F2 与实际目标地址13910199192F 之间的关系也是如此。
②.若“SMSC 地址信息的长度”分段的值为00,则意味着SMSC 地址字符串的长度为零,
PDU 串的“SMSC 地址格式”段和“SMSC 地址”段将省去。且将使用SIM 卡设置的SMSC 地址。
上例中的PDU 串变为:
00 31 00 0D 91 683119109991F2 00 08 C2 06 60A8597DFF01
③. 对于用户信息长度,可通过VB 中的Len 函数求得,如“您好!”,用Len(“您好!”)
得到是3,那么3*2=6 即为用户信息长度06(这里要转换为16 进制,并且是两位)。
④.用户信息(TP-UD)段最大容量是140 字节,所以在UCS2 编码方式下,可发送短消息
的最大字符数是70 个。
(三)UCS2 解码
在接收消息时,可能不仅收到UCS2 格式编码的PDU 串,也可能是7bit 编码格式
(TP-DCS 为00)或8bit 编码格式(TP-DCS 为04)的PDU 串。对这两种情况,笔者也编了相应
的解码算法,且它们的算法要相对简单,由于着重介绍UCS2 解码,7bit 与8bit 解码就不再多
介绍了。
(四)接收PDU 串的编制分析
接收PDU 串和发送PDU 串结构是不完全相同的。通过一个实例来分析,假定收到的短消
息其PDU 串为:
08 91 68 31 08 10 00 05 F0 04 0D 91 68 31 19 10 99 91 F2 00 08 40 40 60 31 35 30
23 06 60 A8 59 7D FF 01
参照规范,具体分析:
分段含义解释说明
08 SMSC 地址信息的长度共8 个八位字节(包括91)
91 SMSC 地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 10 00 05 F0 SMSC 地址8613800100500,补‘F’凑成偶数个
84 基本参数(TP-MTI/MMS/RP) 接收,无更多消息,有回复地址
0D 回复地址数字个数共13 个十进制数(不包括91 和‘F’)
91 回复地址格式(TON/NPI) 国际格式
68 31 19 10 99 91 F2 回复地址(TP-RA) 8613910199192,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM 类型,点到点方式
08 用户信息编码方式(TP-DCS) UCS2 编码
40 90 10 31 35 30 23 服务时间戳(TP-SCTS) 2004-09-01 13:53:03
06 用户信息长度(TP-UDL) 实际长度6 个字节
60 A8 59 7D FF 01 用户信息(TP-UD) “您好!”
通过分析,我们可以获取其中的有用信息。如:短信服务中心号码是+8613800100500,
发送方号码是13910199192,发来的消息内容是“您好!”,以及发送时间是:2004-09-01
13:53:03。
2006-9-2 14:58:24 简单的短信源码简单的短信源码,使用了MSCOMM控件,代码写得
比较烂,但是发短信已经完全没有问题,供各位有兴趣的朋友参考。
简单的短信源码
Q 用串口连接GSM手机发送和接收短消息,在应用程序中如何编程实现?
Q 我们打算开发一个基于GSM短消息方式的GPS系统,如何利用SMS进行数据通信?
A 首先,我们要对由ESTI制订的SMS规范有所了解。与我们讨论的短消息收发有关的规范主要包
括GSM 03.38、GSM 03.40和GSM 07.05。前二者着重描述SMS的技术实现(含编码方式),后者则规
定了SMS的DTE-DCE接口标准(AT命令集)。
一共有三种方式来发送和接收SMS信息:Block Mode, Text Mode和PDU Mode。Block Mode已是昔
日黄花,目前很少用了。Text Mode是纯文本方式,可使用不同的字符集,从技术上说也可用于
发送中文短消息,但国内手机基本上不支持,主要用于欧美地区。PDU Mode被所有手机支持,可
以使用任何字符集,这也是手机默认的编码方式。Text Mode比较简单,而且不适合做自定义数
据传输,我们就不讨论了。下面介绍的内容,是在PDU Mode下发送和接收短消息的实现方法。
PDU串表面上是一串ASCII码,由‘0’-‘9’、 ‘A’-‘F’这些数字和字母组成。它们是8位字
节的十六进制数,或者BCD码十进制数。PDU串不仅包含可显示的消息本身,还包含很多其它信息
,如 SMS服务中心号码、目标号码、回复号码、编码方式和服务时间等。发送和接收的PDU串,
结构是不完全相同的。我们先用两个实际的例子说明PDU串的结构和编排方式。
例1 发送:SMSC号码是+8613800250500,对方号码是13851872468,消息内容是“Hello!”。从
手机发出的PDU串可以是
08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 58 81 27 64 F8 00 00 00 06 C8 32 9B FD
0E 01
对照规范,具体分析:
分段 含义 说明
08 SMSC地址信息的长度 共8个八位字节(包括91)
91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
11 基本参数(TP-MTI/VFP) 发送,TP-VP用相对格式
00 消息基准值(TP-MR) 0
0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
91 目标地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 58 81 27 64 F8 目标地址(TP-DA) 8613851872468,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM类型,点到点方式
00 用户信息编码方式(TP-DCS) 7-bit编码
00 有效期(TP-VP) 5分钟
06 用户信息长度(TP-UDL) 实际长度6个字节
C8 32 9B FD 0E 01 用户信息(TP-UD) “Hello!”
例2 接收:SMSC号码是+8613800250500,对方号码是13851872468,消息内容是“你好!”。手机
接收到的PDU串可以是
08 91 68 31 08 20 05 05 F0 84 0D 91 68 31 58 81 27 64 F8 00 08 30 30 21 80 63 54 80
06 4F 60 59 7D 00 21
对照规范,具体分析:
分段 含义 说明
08 地址信息的长度 个八位字节(包括91)
91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
84 基本参数(TP-MTI/MMS/RP) 接收,无更多消息,有回复地址
0D 回复地址数字个数 共13个十进制数(不包括91和‘F’)
91 回复地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
68 31 58 81 27 64 F8 回复地址(TP-RA) 8613851872468,补‘F’凑成偶数个
00 协议标识(TP-PID) 是普通GSM类型,点到点方式
08 用户信息编码方式(TP-DCS) UCS2编码
30 30 21 80 63 54 80 时间戳(TP-SCTS) 2003-3-12 08:36:45 +8时区
06 用户信息长度(TP-UDL) 实际长度6个字节
4F 60 59 7D 00 21 用户信息(TP-UD) “你好!”
若基本参数的最高位(TP-RP)为0,则没有回复地址的三个段。从Internet上发出的短消息常常是
这种情形。
注意号码和时间的表示方法,不是按正常顺序顺着来的,而且要以‘F’将奇数补成偶数。
Q 上面两例中已经出现了7-bit和UCS2编码,请详细介绍一下这些编码方式?
A 在PDU Mode中,可以采用三种编码方式来对发送的内容进行编码,它们是7-bit、8-bit和UCS2
编码。7-bit编码用于发送普通的ASCII字符,它将一串7-bit的字符(最高位为0)编码成8-bit的
数据,每8个字符可“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;而
UCS2编码用于发送Unicode字符。PDU串的用户信息(TP-UD)段最大容量是140字节,所以在这三种
编码方式下,可以发送的短消息的最大字符数分别是160、140和70。这里,将一个英文字母、一
个汉字和一个数据字节都视为一个字符。
需要注意的是,PDU串的用户信息长度(TP -UDL),在各种编码方式下意义有所不同。7-bit编码
时,指原始短消息的字符个数,而不是编码后的字节数。8-bit编码时,就是字节数。UCS2 编码
时,也是字节数,等于原始短消息的字符数的两倍。如果用户信息(TP-UD)中存在一个头(基本参
数的TP-UDHI为1),在所有编码方式下,用户信息长度(TP-UDL)都等于头长度与编码后字节数之
和。如果采用GSM 03.42所建议的压缩算法(TP-DCS的高3位为001),则该长度也是压缩编码后字
节数或头长度与压缩编码后字节数之和。
下面以一个具体的例子说明7-bit编码的过程。我们对英文短信“Hello!”进行编码:
7-bit解码
将源串每8个字符分为一组(这个例子中不满8个)进行编码,在组内字符间压缩,但每组之间是没
有什么联系的。
用C实现7-bit编码和解码的算法如下:
// 7-bit编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回: 目标编码串长度
int gsmEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
int nSrc; // 源字符串的计数值
int nDst; // 目标编码串的计数值
int nChar; // 当前正在处理的组内字符字节的序号,范围是0-7
unsigned char nLeft; // 上一字节残余的数据
// 计数值初始化
nSrc = 0;
nDst = 0;
// 将源串每8个字节分为一组,压缩成7个字节
// 循环该处理过程,直至源串被处理完
// 如果分组不到8字节,也能正确处理
while(nSrc {
// 取源字符串的计数值的最低3位
nChar = nSrc & 7;
// 处理源串的每个字节
if(nChar == 0)
{
// 组内第一个字节,只是保存起来,待处理下一个字节时使用
nLeft = *pSrc;
}
else
{
// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
*pDst = (*pSrc << (8-nChar)) | nLeft;
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft = *pSrc >> nChar;
// 修改目标串的指针和计数值 pDst++;
nDst++;
}
// 修改源串的指针和计数值
pSrc++; nSrc++;
}
// 返回目标串长度
return nDst;
}
// 7-bit解码
// pSrc: 源编码串指针
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回: 目标字符串长度
int gsmDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
int nSrc; // 源字符串的计数值
int nDst; // 目标解码串的计数值
int nByte; // 当前正在处理的组内字节的序号,范围是0-6
unsigned char nLeft; // 上一字节残余的数据
// 计数值初始化
nSrc = 0;
nDst = 0;
// 组内字节序号和残余数据初始化
nByte = 0;
nLeft = 0;
// 将源数据每7个字节分为一组,解压缩成8个字节
// 循环该处理过程,直至源数据被处理完
// 如果分组不到7字节,也能正确处理
while(nSrc {
// 将源字节右边部分与残余数据相加,去掉最高位,得到一个目标解码字节
*pDst = ((*pSrc << nByte) | nLeft) & 0x7f;
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft = *pSrc >> (7-nByte);
// 修改目标串的指针和计数值
pDst++;
nDst++;
// 修改字节计数值
nByte++;
// 到了一组的最后一个字节
if(nByte == 7)
{
// 额外得到一个目标解码字节
*pDst = nLeft;
// 修改目标串的指针和计数值
pDst++;
nDst++;
// 组内字节序号和残余数据初始化
nByte = 0;
nLeft = 0;
}
// 修改源串的指针和计数值
pSrc++;
nSrc++;
}
*pDst = 0;
// 返回目标串长度
return nDst;
}
需要指出的是,7-bit的字符集与ANSI标准字符集不完全一致,在0x20以下也排布了一些可打印
字符,但英文字母、阿拉伯数字和常用符号的位置两者是一样的。用上面介绍的算法收发纯英文
短消息,一般情况应该是够用了。如果是法语、德语、西班牙语等,含有 “?”、 “é”这一类
字符,则要按上面编码的输出去查表,请参阅GSM 03.38的规定。
8-bit编码其实没有规定什么具体的算法,不需要介绍.
UCS2编码是将每个字符(1-2个字节)按照ISO/IEC10646的规定,转变为16位的Unicode宽字符。在
Windows系统中,特别是在2000/XP中,可以简单地调用API 函数实现编码和解码。如果没有系统
的支持,比如用单片机控制手机模块收发短消息,只好用查表法解决了。
Windows环境下,用C实现UCS2编码和解码的算法如下:
// UCS2编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回: 目标编码串长度
int gsmEncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
int nDstLength; // UNICODE宽字符数目
WCHAR wchar[128]; // UNICODE串缓冲区
// 字符串-->UNICODE串
nDstLength = ::MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLength, wchar, 128);
// 高低字节对调,输出
for(int i=0; i {
// 先输出高位字节
*pDst++ = wchar[i] >> 8;
// 后输出低位字节
*pDst++ = wchar[i] & 0xff;
}
// 返回目标编码串长度
return nDstLength * 2;
}
// UCS2解码
// pSrc: 源编码串指针
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回: 目标字符串长度
int gsmDecodeUcs2(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
int nDstLength; // UNICODE宽字符数目
WCHAR wchar[128]; // UNICODE串缓冲区
// 高低字节对调,拼成UNICODE
for(int i=0; i {
// 先高位字节
wchar[i] = *pSrc++ << 8;
// 后低位字节
wchar[i] |= *pSrc++;
}
// UNICODE串-->字符串
nDstLength = ::WideCharToMultiByte(CP_ACP, 0, wchar, nSrcLength/2, pDst, 160,
NULL, NULL);
// 输出字符串加个结束符
pDst[nDstLength] = '\0';
// 返回目标字符串长度
return nDstLength;
}
用以上编码和解码模块,还不能将短消息字符串编码为PDU串需要的格式,也不能直接将PDU串中
的用户信息解码为短消息字符串,因为还差一个在可打印字符串和字节数据之间相互转换的环节
。可以循环调用sscanf和sprintf函数实现这种变换。下面提供不用这些函数的算法,它们也适
用于单片机、 DSP编程环境。
// 可打印字符串转换为字节数据
// 如:"C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01}
// pSrc: 源字符串指针
// pDst: 目标数据指针
// nSrcLength: 源字符串长度
// 返回: 目标数据长度
int gsmString2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
for(int i=0; i {
// 输出高4位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst = (*pSrc - '0') << 4;
}
else
{
*pDst = (*pSrc - 'A' + 10) << 4;
}
pSrc++;
// 输出低4位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst |= *pSrc - '0';
}
else
{
*pDst |= *pSrc - 'A' + 10;
}
pSrc++;
pDst++;
}
// 返回目标数据长度
returnnSrcLength / 2;
}
// 字节数据转换为可打印字符串
// 如:{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01"
// pSrc: 源数据指针
// pDst: 目标字符串指针
// nSrcLength: 源数据长度
// 返回: 目标字符串长度
int gsmBytes2String(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
const char tab[]="0123456789ABCDEF"; // 0x0-0xf的字符查找表
for(int i=0; i {
// 输出低4位
*pDst++ = tab[*pSrc >> 4];
// 输出高4位
*pDst++ = tab[*pSrc & 0x0f];
pSrc++;
}
// 输出字符串加个结束符
*pDst = '\0';
// 返回目标字符串长度
return nSrcLength * 2;
}
关于GSM 03.42中的压缩算法,至今还没有发现哪里用过,这里我们就不讨论了。有兴趣的话,
可深入研究一下。