AT指令编程相关技术问题

AT编程常见问题 1. 如何与GSM MODEM建立通信联系
2. 不能与GSM MODEM进行正常的通信或总是在仿真终端上出现乱码
3. 如何才能知道错误代码
4. 发送短消息后,收到出错信息+CMS ERROR 512
5. 发送短消息后,收到出错信息+CMS ERROR 513
6. 发送短消息后,收到出错信息+CMS ERROR 514
7. 发送短消息后,收到出错信息+CMS ERROR 515
8. 如何才能知道您发送的短消息已被送达目的号码
9. 如何发送中文短消息
10.如何建立一个话音呼叫
11.如何建立一个数据呼叫
12.当GSM MODEM作被叫时,如何显示主叫的电话号码
13.当GSM MODEM作被叫时,如何判别主叫发起的是话音、数据或传真呼叫
14.当GSM MODEM作被叫时,如何使其自动应答或不能自动应答
15.如何不通过SIM卡直接读或写短消息
1. 如何与GSM MODEM建立通信联系
您可用诸如Windows下的超级终端或Pcomm等终端仿真软件,将计算机的串行口与GSM MODEM的串行口用电缆直接连接。
2. 不能与GSM MODEM进行正常的通信或总是在仿真终端上出现乱码
检查您的串口是否保证正常连接,计算机的串口引线与GSM MODEM的串口引线应是一一对应的。GSM MODEM与仿真终端应设置相同的通信速率。
但您初次使用GSM MODEM时,请在仿真终端上设置为通信速率9600bps、8位数据位、无较验位、1位停止位。
3. 如果您想在出错后得到错误代码号,需将GSM Modem作如下设置:
AT+CMEE=1
4. 发送短消息后,收到出错信息+CMS ERROR 512
表示您的GSM MODEM在发送短消息的同时它收到了新的短消息,发送短消息被拒绝,您需要重新发送此条短消息。
5. 发送短消息后,收到出错信息+CMS ERROR 513
您遇上了下面问题中的一种:
a) 您的GSM MODEM失去了无线链路连接;
b) 在发送完短消息后的28秒内,您的GSM MODEM没有收到短消息中心送来的接收确认+CMGS:〈顺序号〉;
c) 在送出请求建立发送短消息的控制信道指令后的42秒内,您的GSM MODEM没有收到基站送来的确认〉。
6. 发送短消息后,收到出错信息+CMS ERROR 514
您遇上了下面问题中的一种:
a) 您设置的短消息中心的号码是错误的;
b) 短消息将要送达的目的号码是错误的;
c) 您发送的短消息被短消息中心拒绝(一般为目的号码不存在或目的号码被禁用)。
7. 发送短消息后,收到出错信息+CMS ERROR 515
如果您的GSM MODEM在初始化期间或在指令执行过程当中GSM MODEM又接受新的指令,将会出现此错误。您必须等到初始化完成或指令执行完毕。
8. 如何才能知道您发送的短消息已被送达目的号码
a) 采用文本格式发送
在您采用文本格式发送短消息时,您的GSM MODEM须作以下的设置:
at+csmp=49,〈X〉,〈X〉,〈X〉
at+cnmi=〈X〉,〈X〉,〈X〉,1,〈X〉
〈X〉代表根据您的需要您所选择的合适的参数。
当您发送完短消息后,您将收到来自短消息中心的以下两种确认中的一种:
+CDS:〈X〉,〈顺序号〉,"电话号码","发送时间","接收时间",0
或:
+CDS:〈X〉,〈顺序号〉,"电话号码","发送时间","接收时间",48
确认中的最后个数代表了此短消息的传输状态。(0表示已经送达目的号码,48表示不可能将此送达目的号码)
b) 采用PDU格式发送
在您采用PDU格式发送短消息时,您的GSM MODEM须作以下的设置:
at+cnmi=〈X〉,〈X〉,〈X〉,1,〈X〉
〈X〉代表根据您的需要您所选择的合适的参数。
在您所要发送的PDU格式的短消息中,您须将短消息中心号码后的第一个字节设成31
在发送完短消息后,您将收到来自短消息中心的以下确认:
+CDS:〈长度〉00〈PDU格式的确认信息〉
注意:在收到的PDU格式的确认中,顺序号和传输状态标志都是以16进制数存在的,您可将其直接转成10进制数而无需将其倒置后再转换。
9. 如何发送中文短消息
采用现有的GSM MODEM发送中文短消息,都必须先将准备发送的中文短消息转换成16位的Unicode编码。
A) 采用文本方式发送
在您采用文本格式发送Unicode编码中文短消息时,您的GSM MODEM须作的设置:
at+csmp=〈X〉,〈X〉,〈X〉,8
〈X〉代表根据您的需要您所选择的合适的参数。
然后您就可将转换好的Unicode编码中文短消息按照发送普通文本短消息的方法发送出去。
B) 采用PDU方式发送
您只须在您的PDU格式的短消息中,将目的号码字符串后的第二个字节设成08,将转
换好的Unicode编码中文短消息作为PDU中的发送内容一齐发送。
10. 如何建立一个话音呼叫
向GSM MODEM的串口送指令ATD〈电话号码〉;〈回车〉必须确认电话号码是一个话音号码而非传真或数据号码。
11. 如何建立一个数据呼叫
先将您的GSM MODEM作如下设置:
at+ipr=9600
at+ifc=2,2
at+cbst=0,0,1
向GSM MODEM的串口送指令ATD〈电话号码〉〈回车〉
必须确认电话号码是一个数据号码而非传真或话音号码,同时必须确认您的SIM卡已开通数据通信的服务。
12.当GSM MODEM作被叫时,如何显示主叫的电话号码
将您的GSM MODEM作如下设置:
at+clip=1
13.当GSM MODEM作被叫时,如何判别主叫发起的是话音、数据或传真呼叫
将您的GSM MODEM作如下设置:
at+crc=1
14.当GSM MODEM作被叫时,如何使其自动应答或不能自动应答
如果您想让您的GSM MODEM自动应答,将您的GSM MODEM作如下设置:
ats0=〈N〉 N是代表GSM MODEM震铃的次数的一个整数,即GSM MODEM在N 次 震铃后将自动应答。
如果您想让您的GSM MODEM不能自动应答,将您的GSM MODEM作如下设置:
ats0=0
15.如何不通过SIM卡直接读或写短消息
因为SIM卡只有1万到10万次的读写次数和10-15条短消息的存储空间,还涉及到SIM卡上短消息读写需要一定的时间才能完成。这些因素影响了许多应用,这些应用需要通过GSM网络进行大量的数据交换,为保证流程的顺利进行,SIM卡要完成大量的读、写和删除***作,SIM卡的寿命周期很快就会达到,此外,SIM卡完成这些工作所耗费的时间比外界要求的要多。为解决这些问题,有必要在终端上作一些软件设置,使短消息不通过SIM卡进行读写***作。
以下的描述介绍了如何采用这种方法在Falcom A2系列和数据终端MT4002之间不通过SIM卡交换数据,这种方法也可用与2个MT4002之间。
a) 串口上的从终端来的RTS信号可用来指示数据交换时隙是否忙,串口准备好接收数据
b) 如果终端双方都可用来接收和发送短消息,在设置时双方都要设同样的命令和常数。
在接收端,设命令AT+CNMI=2,2,0,0,0
在发送端,设命令AT+CSMP=17,167,0,240 (当使用PDU格式发送时,240改成字符串DCS(F0))
c) 当程序发现短消息以前缀+CMT后跟所传送的数据这种格式时,立即将此短消息捕获并将其分发到原定的地址。
d) 当发送端如果没有设置CSMP=17,167,0,240时,捕获到的短消息应有前缀+CMTI,此时用命令AT+CMGR=n读取并分发到原定的地址,随后用命令AT+CMGD=n将此短消息删除以保证SIM卡有足够多的空间。

Q:请问什么是STK,FALCOM A2D系列有没有这项功能?怎么用STK? 多谢.
A:STK (SIM Tool Kit)卡预先储存一些移动网络可提供的一些服务的数据资料,如短消息中心号码、信息服务代码等,目前中国移动即将推出的手机银行业务即需要STK卡来支持。使用STK卡的手机在屏幕上可显示普通SIM卡不具备的菜单,如"全球通服务"。通过调用这一菜单,可进入下一级和在下一级菜单。用户通过选择可进行新闻股票信息查询、银行转帐股票委托等移动电子商务等多项移动信息服务,***作上类似于internet网页的分级链接。STK (SIM Tool Kit)卡由SIM卡厂家提供。
Q:STK程序如何开发,工具及帮助文档?
A:目前中国移动网络的STK (SIM Tool Kit)卡由SIM卡厂家提供技术支持,负责提供STK开发系统,负责STK的编程和制作,并保证消息加密方式的先进性和密钥的安全性应用层协议格式有网络运营,业务提供,SIM卡厂家,短消息厂家四方共同制定。 Q:发SMS的时候,是怎么实现能自动判断接受手机的语言,发中文SMS给中文机,英文SMS给英文机.
A:发送短消息时,无法自动判断接受手机的语言,必须预先知道接受手机所能支持的语言,再选择语言种类编码发送。以小区广播为例,无论发送中文还是英文信息小区内的手机都将同时收到,不支持该发语种的手机收到的将是乱码。 Q:GSM MODEM有没有提供SMS编程的API或者其他资料
A:GSM Modem的使用及开发资料请参看A2D-1。对于FalcomA2D-A(B,C)和A2D-3我们提供配套的开发工具,请参看相关类别的资料说明。 Q:SMS的格式如何规定的?
A:请在我们网站上下载Falcom A2D用户手册上面有关于短消息通信的相关指令.
Q:我买了一个nokia data suite想通过它发at命令来实现发中文短讯 但是不支持"at * c" "send " 请问如何处理?
A:不知您提到的"at * c" 是否在GSM规范07.07和07.05中? Q:从哪能得到GSM规范07.07和07.05?谢谢!
A:您在我们网站上可以下载相关文档,里面有关于GSM规范AT指令的详细说明。或者您可以到ETSI的官方网站上去找。 Q:我也用数据套件(Nokia DataSuite2.0)发过消息,但只能发英文,发不了中文.怎么办?
A:中英文短消息的编码格式不一样. Q:我可以确定我是用Unicode格式发送的中文,怎么还不好使? 如果想发中文,你说该怎办? Email:[email protected]
A:"Nokia DataSuite2.0"的数据格式和定义我们不了解. Falcom A2D可以实现中文短信. Q:AT+CMGS如何发送命令?本人想通过超级连接发送中文(手机不支持中文发送),应如何写命令格式? 望大虾指点.
at+cmgf=0
ok
at+cmgs="683106316070F60008050034192242308007400650073007"
Error
如何解决? 求助大虾!
A:假设有一个消息ab须发送,则:
at+cmgs=16
>0891(短消息中心号码)11000D91(目的号码)00F2A7024121(ctrl+Z结束) Q:Re: AT+CMGS如何发送命令?
A:先设at+cmgf=0,再发at+cmgs="LEHGTH"
"LENGTH'代表发送字节长度短消息中心号码和目的号码包含其中中文用unicode编码,如不明白与我联系发信给我 Q:我就是用unicode编码,但是在pdu格式下,在对方手机上显示不出来
A:Falcom A2D可以实现中文短信. Q:请教PDU数据格式以及SMS-AT命令中的发送数据格式
A:"PDU数据格式"见GSM03.40和GSM03.41,"SMS-AT命令中的发送数据格式"见GSM07.05和GSM07.07.上述规范可到http://www.etsi.org/ 下载。 Q:falcom的A2D系列产品可否与WAP、GPRS兼容?
A:WAP是一种简化的浏览器协议,与传输通路没有关系只要您的终端上有WAP或类似的浏览器,您就可支持WAP,所以,falcom的A2D是可以通过的只要您在上建立了数据链路。 支持的A2D将在今年第三季度推出,现有的内核是支持的只不过现在未开放。 Q:请问A2D的内核支持WAP,是否直接内置WAP浏览器,如果是的话,A2D是否等于WAP手机。
A:A2D本身没有WAP浏览器,须在A2D中加入WAP浏览器和显示屏及键盘才能成为手机 Q:贵公司有GPS receiver 的代理和A2D-GPS的相关中文的资料吗?
A:我公司不代理单独的GPS,不过我可推荐此代理给您. A2D-GPS目前没有中文资料,抱歉 Q:可以发以份报价表给我吗?EMAIL:SEAGATE@163。NET 希望可以得到贵公司的最新的代理产品和公司产品。谢谢!
A:请在'联系方式'下填写用户信息我们将电邮给您 Q:Nokia手机的NDS收发短信息也是用AT命令吗?有没有手机和电脑通讯的规范呢?本人也非常想知道有关PC和手机通讯的规范。当TE 和 ME (未经 TA)相连时,手机端所采用的通讯规范是哪一种?
A:NDS代表什么?请参考本网站a2dman.pdf.请参考ETSI相关规范。http://www.etsi.org/ Q:本人已查看过 ETSI 关于GSM的规范,如GSM07.01 GSM 07.07 GSM 07.05 等,但仍未搞明白,在此特请教先生,涉及手机编程问题的具体规范.
A:有关Falcom GSM 产品的开发问题请直接与我公司联系。其他产品我们因不了解无法提供进一步解答,请见谅.欢迎各位同仁提供信息和指教。 Q:Can I find any papers published on IEEE and how? Thanks.
A:http://www.ieee.org/ Q:MODEM如何设置自动应答?请教AT命令集?
A:ats0=1 Q:用什么指令可以让手机收到的短信息不存储在手机内部而直接发送到数据终端(如计算机)?如果广泛使用短消息,势必造成接收短消息那台手机的flash或sim卡eeprom的损坏,用什么at指令可以让手机收到的短消息直接从串行口发送出来而不存储?
A:请下载simcn.doc文件 Q:我用PDU方式,对字符进行8bit编码,发送英文字符正常,但发送汉字在手机上显示不出来?SMS对汉字怎样编码才能被手机识别并显示出来?
A:请参考本论坛以前讨论内容。 Q:但是还是不能解决问题啊,怎样编码才能让普通手机收到后显示出来?
A:您的手机是否支持中文? Q:Re: AT+CMGS如何发送命令?
我就是用unicode编码,但是在pdu格式下,在对方手机上显示不出来
A:Falcom A2D可以实现中文短信.
Q:请教
内容:
我在接收中文短信时,接收到的是UNICODE原码,但它的正文个数好象是按普通的ASC码算的,比如:
我发的是"一一一一"收到的是"4E004EOO4E004E",后面的还有的"00"没有;
当我发"一一一乙"时,收到的还是"4E004E004E004E"
请教一下这是为什么?
A:但是这不是unicode原码,是手机自己的编码!
Q: 请教一下,GPRS是什么单词的缩写。
A:GPRS的全称是"通用分组无线业务"(General Packet Radio Service),它是ETSI组织制定的一套标准,以实现移动分组数据业务。
· 实现方式:在GSM网络上增加分组数据服务设备,并对GSM无线网络设备进行升级,从而利用现有的GSM无线覆盖提供分组数据业务。
· 特点:
· 传输速度快:最高可达171kbps(初期9-50kHz)
· 可灵活支持多种数据应用
· 网络接入速度快
· 可长时间在线连接
· 计费更加合理(按数据流量计费)
· 高效利用网络资源,降低通信成本
· 利用现有无线网络覆盖,提高网络建设速度,降低建设成本
· GPRS的核心网络顺应通信网络的发展趋势,为GSM网向第三代演进打下基础
· 进展情况:商用系统计划2000年推出 Q:使用ISDN的适配器向手机发送短消息
有pc的串口发送AT命令,ISDN适配器使手机收到短消息可以实现吗?
A:只要您的ISDN适配器可与短消息中心正常通信就可向手机发送短消息
"与短消息中心正常通信"是指向ISDN的适配器发送标准贺氏指令即可,短消息中心一定会接受。还是指要经过短信息中心授权,短信息中心给出一套自己定义的标准指令。与短消息中心正常通信"是指向ISDN的适配器发送标准贺氏指令即可,短消息中心一定会接受。还是指要经过短信息中心授权,短信息中心给出一套自己定义的标准指令。 AT指令既可 Q:A2D设备发送SMS是否大材小用,因为从兼容AT指令的MODEM发送AT即可.
A:A2D是GSM Modem,针对于基于GSM无线网络的系统应用。
Q:A2D模块是否支持16位的短消息传输内容:也就是说如何实现中文短消息.烦请举一个例子说明。谢谢!
A:Falcom A2D模块支持16位的短消息传输。具体应用请与我们联系。
Q:Re: 如何用falcom发送广播消息?
A:Falcom GSM Modem/Module 完全符合GSM规范,通过FTA认证。发送广播消息应该需要短消息中心具备这种功能。 Q:Re: 请问如何用PDU格式发送短信?
A:有关Falcom GSM Modem/Module开发应用请直接与我们联系或参看本网站所列资料。

将uniCode转化为中文的代码 以下是将uniCode转换为中文的代码。
function TfrmMain.ReadHex(AString: string): integer;
begin
Result:=StrToInt('$'+AString)
end;
function TfrmMain.UnicodeToAnsi(Unicode: string): string;
var
s:string;
i:integer;
j,k:string[2];
begin
i:=1;
s:='';
while i j:=Copy(Unicode,i+2,2);
k:=Copy(Unicode,i,2);
i:=i+4;
s:=s+Char(ReadHex(j))+Char(ReadHex(k));
end;
if s<>'' then
s:=WideCharToString(PWideChar(s+#0#0#0#0))
else
s:='';
Result:=s;
end;

如何在vb中将汉字转化成unicode A.发送中文例子:
发送中文有两种方法,一种是PDU,一种是UCS2文本
1.PDU方法:
at+cmgf=0
at+cmgs=24
>0891683108100005F011000B813109018759F10008A70A00650073007496484E30
信息内容为set陈丰
解释:此字符串传set陈丰五个字符,采用unicode编码。
0891固定格式不动,683108100005F0为短消息中心号码,
11固定格式不动代表PDU格式,
00代表是第几条短消息,
0B81固定格式不动,3109018759F1为目的号码,
00固定格式不动代表是短消息,
08代表8位unicode编码(中文必须用unicode编码),F0到F3为7编码,F4到F7为8位编码
A7代表此短消息在短消息中心存储的时间是24小时,最大FF为135周,
0A代表后有10个字节(有1个字节为01,2个为01,类推)
0065是s的unicode编码,0073是e的unicode编码,0074是t的unicode编码,
9648是陈的unicode编码,4E30是丰的unicode编码
0A后跟的就是所需发送的消息部分,全部采用unicode的编码。
unicode的编码转换可调用VB或VC中的函数直接得到。
at+cmgs=24中的24是14再加上消息长度10得出的.
2.USC2的文本方法
at+cmgf=1
at+csmp=??,??,??,8(问号代表自己根据需要选择合适的参数)
at+cmgs=手机号码(1390PQRABCD)
>00650073007496484E30
信息内容为set陈丰
当您用UCS2文本发送中文短消息时,要先将中文转成unicode编码,
再将中文短消息的unicode编码用文本方式发送.

B.编程例子:
Private Sub Command1_Click()
' 使用 COM3。
' 9600 波特,无奇偶校验,8 位数据,一个停止位。
MSComm1.Settings = "9600,N,8,1"
MSComm1.Handshaking = comRTS
' 打开端口。
' MSComm1.PortOpen = False
' MSComm1.PortOpen = True
' 将 at 命令送到调制解调器。
MSComm1.Output = "AT"
MSComm1.Output = Chr(13)
MSComm1.Output = "AT+CMGF=1"
MSComm1.Output = Chr(13)
MSComm1.Output = "AT+CMGS="
MSComm1.Output = Chr(34)
MSComm1.Output = "13901237885"
MSComm1.Output = Chr(34)
MSComm1.Output = Chr(13)
MSComm1.Output = "test OK "
MSComm1.Output = Chr(26)
End Sub
Private Sub Command3_Click()
MSComm1.CommPort = 2
MSComm1.PortOpen = True
End Sub
//将UNICODE转换中文
Public Function Unicode2AscII(ByVal s As String)
On Error Resume Next
Dim i As Integer
Dim r As String
For i = 1 To Len(s) Step 4
r = r + ChrB("&H" & Mid(s, i + 2, 2)) & ChrB("&H" & Mid(s, i, 2))
Next
Unicode2AscII = r
End Function
//将中文转换为UniCode,
function AnsiToUnicode(Ansi: string):string;
var
s:string;
i:integer;
j,k:string[2];
a:array [1..1000] of char;
begin
s:='';
StringToWideChar(Ansi,@(a[1]),500);
i:=1;
while ((a[i]<>#0) or (a[i+1]<>#0)) do begin
j:=IntToHex(Integer(a[i]),2);
k:=IntToHex(Integer(a[i+1]),2);
s:=s+k+j;
i:=i+2;
end;
Result:=s;
end;

 

posted @ 2010-06-29 09:38 hcmfys_lover 阅读(248) | 评论(0) | 编辑
AT指令发送PDU短信详解 (转载)

本文以一个实例来解说AT指令发送PDU短信的全过程,假如我要发送下面的短信:
接收号码:+8613602433649
短信内容:工作愉快!
短信中心号码:+8613800200500

一、短信中心号码处理:用字符串 addr 表示
1、将短信息中心号码去掉+号,看看长度是否为偶数,如果不是,最后添加F
即 addr = "+8613800200500"
=> addr = "8613800200500F"
2、将奇数位和偶数位交换。
=> addr = "683108200005F0"
3、将短信息中心号码前面加上字符91,91是国际化的意思
=> addr = "91683108200005F0"
4、算出 addr 长度,结果除2,格式化成2位的16进制字符串,16 / 2 = 8 => "08"
=> addr = "0891683108200005F0"

二、手机号码处理:用字符串 phone
1、将手机号码去掉+号,看看长度是否为偶数,如果不是,最后添加F
即 phone = "+8613602433649"
=> phone = "8613602433649F"
2、将手机号码奇数位和偶数位交换。
=> phone = "683106423346F9"

三、短信息部分处理:用字符串 msg 表示
1、转字符串转换为Unicode代码,例如“工作愉快!”的unicode代码为 5DE54F5C61095FEBFF01,
(转换函数见最后附录)
2、将 msg 长度除2,保留两位16进制数,即 5DE54F5C61095FEBFF01 = 20 / 2 => "0A",再加上 msg
=> msg = "0A5DE54F5C61095FEBFF01"

四、组合
1、手机号码前加上字符串 11000D91(1100:固定,0D:手机号码的长度,不算+号,十六进制表示,91:发送到手机为91,发送到小灵通为81),
即 phone = "11000D91" + phone
=> 11000D91683106423346F9
2、手机号码后加上 000800 和刚才的短信息内容,000800也写死就可以了
即 phone = phone + "000800" + msg
即 11000D91683106423346F9 + 000800 + 0A5DE54F5C61095FEBFF01
=> phone = 11000D91683106423346F90008000A5DE54F5C61095FEBFF01
3、phone 长度除以2,格式化成2位的十进制数
即 11000D91683106423346F90008000A5DE54F5C61095FEBFF01 => 50位 / 2 => 25

五、所以要发送的内容为
AT+CMGF=0 <回车>
OK
AT+CMGS=25<回车>
> addr+phone

六、如果返回不是ERROR,恭喜你,发送成功了^_^
 
//-----------------------------------------------------
// 7bit编码
// 输入: pSrc - 源字符串指针
//       nSrcLength - 源字符串长度
// 输出: pDst - 目标编码串指针
// 返回: 目标编码串长度
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 < nSrcLength)
 {
  // 取源字符串的计数值的最低3位
  nChar = nSrc & 7;
  // 处理源串的每个字节
  if(nChar == 0)
  {
   // 组内第一个字节,只是保存起来,待处理下一个字节时使用
   nLeft = *pSrc;
  }
  else
  {
   // 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
   *pDst = (*pSrc << (8-nChar)) | nLeft;
   // 将该字节剩下的左边部分,作为残余数据保存起来
   nLeft = *pSrc >> nChar;
   // 修改目标串的指针和计数值
   pDst++;
   nDst++;
  }
  // 修改源串的指针和计数值
  pSrc++;
  nSrc++;
 }
 // 返回目标串长度
 return nDst;
}
// 7bit解码
// 输入: pSrc - 源编码串指针
//       nSrcLength - 源编码串长度
// 输出: pDst - 目标字符串指针
// 返回: 目标字符串长度
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;
}


// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补'F'凑成偶数
// 如:"8613851872468" --> "683158812764F8"
// 输入: pSrc - 源字符串指针
//       nSrcLength - 源字符串长度
// 输出: pDst - 目标字符串指针
// 返回: 目标字符串长度
int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength)
{
 int nDstLength;  // 目标字符串长度
 char ch;   // 用于保存一个字符
 // 复制串长度
 nDstLength = nSrcLength;
 // 两两颠倒
 for(int i=0; i {
  ch = *pSrc++;  // 保存先出现的字符
  *pDst++ = *pSrc++; // 复制后出现的字符
  *pDst++ = ch;  // 复制先出现的字符
 }
 // 源串长度是奇数吗?
 if(nSrcLength & 1)
 {
  *(pDst-2) = 'F'; // 补'F'
  nDstLength++;  // 目标串长度加1
 }
 // 输出字符串加个结束符
 *pDst = '/0';
 // 返回目标字符串长度
 return nDstLength;
}

// PDU编码,用于编制、发送短消息
// 输入: pSrc - 源PDU参数指针
// 输出: pDst - 目标PDU串指针
// 返回: 目标PDU串长度
int gsmEncodePdu(const SM_PARAM* pSrc, char* pDst)
{
 int nLength;   // 内部用的串长度
 int nDstLength;   // 目标PDU串长度
 unsigned char buf[256]; // 内部用的缓冲区
 // SMSC地址信息段
 nLength = strlen(pSrc->SCA); // SMSC地址字符串的长度
 buf[0] = (char)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1; // SMSC地址信息长度
 buf[1] = 0x91;  // 固定: 用国际格式号码
 nDstLength = gsmBytes2String(buf, pDst, 2);  // 转换2个字节到目标PDU串
 nDstLength += gsmInvertNumbers(pSrc->SCA, &pDst[nDstLength], nLength); // 转换SMSC号码到目标PDU串
 // TPDU段基本参数、目标地址等
 nLength = strlen(pSrc->TPA); // TP-DA地址字符串的长度
 buf[0] = 0x11;     // 是发送短信(TP-MTI=01),TP-VP用相对格式(TP-VPF=10)
 buf[1] = 0;      // TP-MR=0
 buf[2] = (char)nLength;   // 目标地址数字个数(TP-DA地址字符串真实长度)
 buf[3] = 0x91;     // 固定: 用国际格式号码
 nDstLength += gsmBytes2String(buf, &pDst[nDstLength], 4);  // 转换4个字节到目标PDU串
 nDstLength += gsmInvertNumbers(pSrc->TPA, &pDst[nDstLength], nLength); // 转换TP-DA到目标PDU串
 // TPDU段协议标识、编码方式、用户信息等
 nLength = strlen(pSrc->TP_UD); // 用户信息字符串的长度
 buf[0] = pSrc->TP_PID;   // 协议标识(TP-PID)
 buf[1] = pSrc->TP_DCS;   // 用户信息编码方式(TP-DCS)
 buf[2] = 0;      // 有效期(TP-VP)为5分钟
 if(pSrc->TP_DCS == GSM_7BIT)
 {
  // 7-bit编码方式
  buf[3] = nLength;   // 编码前长度
  nLength = gsmEncode7bit(pSrc->TP_UD, &buf[4], nLength+1) + 4; // 转换TP-DA到目标PDU串
 }
 else if(pSrc->TP_DCS == GSM_UCS2)
 {
  // UCS2编码方式
  buf[3] = gsmEncodeUcs2(pSrc->TP_UD, &buf[4], nLength); // 转换TP-DA到目标PDU串
  nLength = buf[3] + 4;  // nLength等于该段数据长度
 }
 else
 {
  // 8-bit编码方式
  buf[3] = gsmEncode8bit(pSrc->TP_UD, &buf[4], nLength); // 转换TP-DA到目标PDU串
  nLength = buf[3] + 4;  // nLength等于该段数据长度
 }
 nDstLength += gsmBytes2String(buf, &pDst[nDstLength], nLength);  // 转换该段数据到目标PDU串
 // 返回目标字符串长度
 return nDstLength;
}

// 初始化GSM状态
BOOL gsmInit()
{
 char ans[128];  // 应答串
 // 测试GSM-MODEM的存在性
 WriteComm("AT/r", 3);
 ReadComm(ans, 128);
 if (strstr(ans, "OK") == NULL)  return FALSE;
 // ECHO OFF
 WriteComm("ATE0/r", 5);
 ReadComm(ans, 128);
 // PDU模式
 WriteComm("AT+CMGF=0/r", 10);
 ReadComm(ans, 128);
 return TRUE;
}
// 发送短消息,仅发送命令,不读取应答
// 输入: pSrc - 源PDU参数指针
int gsmSendMessage(SM_PARAM* pSrc)
{
 int nPduLength;  // PDU串长度
 unsigned char nSmscLength; // SMSC串长度
 int nLength;  // 串口收到的数据长度
 char cmd[16];  // 命令串
 char pdu[512];  // PDU串
 char ans[128];  // 应答串
 nPduLength = gsmEncodePdu(pSrc, pdu); // 根据PDU参数,编码PDU串
 strcat(pdu, "/x01a");  // 以Ctrl-Z结束
 gsmString2Bytes(pdu, &nSmscLength, 2); // 取PDU串中的SMSC信息长度
 nSmscLength++;  // 加上长度字节本身
 // 命令中的长度,不包括SMSC信息长度,以数据字节计
 sprintf(cmd, "AT+CMGS=%d/r", nPduLength / 2 - nSmscLength); // 生成命令
// TRACE("%s", cmd);
// TRACE("%s/n", pdu);
 WriteComm(cmd, strlen(cmd)); // 先输出命令串
 nLength = ReadComm(ans, 128); // 读应答数据
 // 根据能否找到"/r/n> "决定成功与否
 if(nLength == 4 && strncmp(ans, "/r/n> ", 4) == 0)
 {
  return WriteComm(pdu, strlen(pdu));  // 得到肯定回答,继续输出PDU串
 }
 return 0;
}

 

你可能感兴趣的:(AT指令编程相关技术问题)