12/18
18:10
现在市面上大多数的GSM模块发送消息都支持Text和PDU两种编码方式Text方式发送短信特简单,但缺点是不能发送中文 <-废话
于是就写了这篇文章记录一下PDU的构造方式
随便Google一下就能查到,PDU编码大概长这样
A:B+C的长度,1Byte
B:SMSC地址类型,1Byte
C:SMSC地址
D:基本参数(TP-MTI/VFP),1Byte
E:信息类型(TP-MR),1Byte
F:目标号码长度,1Byte
G:被叫号码类型,1Byte
H:被叫号码,长度由F中的数据决定
I:协议标识(TP-PID),1Byte
J:数据编码(TP-DCS),1Byte
K:有效期(TP-VP),1Byte
L:用户数据长度(TP-UDL),1Byte 所以说短信长度限制就是这玩意的锅么(雾)
M:用户数据
先说说A,B,C三块数据,这是关于SMSC(短信中心的),F,G,H三块数据也用同样的方法处理,不再重复,但是注意F块长度不包含F字符长度和B块长度
注:如果你不知道SMSC地址,使用AT+CSCA?
就能读出来(除非SIM模块坏了或者你手贱设置了错误的SMSC数据)
数据块C:
- 将SMSC地址前面的+号去掉
smsc=smsc.lstrip('+');
- 用F将SMSC地址的长度补全为偶数
smsc=smsc.ljust(int(round(len(smsc)/2.0))*2,'F');
- 将SMSC地址的奇偶位交换
smsc=list(smsc); for k in range(len(smsc)/2): smsc[k*2],smsc[k*2+1]=smsc[k*2+1],smsc[k*2]; smsc=''.join(smsc);
数据块B:
一般来说,直接使用91就行了(国际格式号码),如果你要发到小灵通就用81
数据块A:
就是B+C的长度啦,但是B和C都是Hex数据,所以算出来要/2并转成Hex
'%02X'%(len(smsc)/2+1)
数据块D:
这是基本参数数据块,暂时不写吧
数据块E:
信息类型,固定00即可
数据块I:
协议标识,固定00即可(普通GSM类型,点到点)
数据块J:
数据编码,建议UCS2(Unicode编码),值是08
数据块K:
信息有效期,一般写00,五分钟
最后是数据块L,M,这两个数据块就是信息内容
因为上面数据块J写的是08,使用UCS2编码,直接将数据转为UTF8编码的Hex数据即可作为M数据块<-实际上麻烦死了
同样求出长度放到最前面就能作为L数据块,直接贴代码吧…Python的%真的很好用
同样求出长度放到最前面就能作为L数据块,直接贴代码吧…Python的%真的很好用
def ucs2_encode(text): result=''; for b in map(ord,text): result=result+'%02X%02X' % (b >> 8,b & 0xFF); return '%02X%s' % (len(result)/2,result);
注:使用时需要传入unicode对象,如u'poi'
数据块全部弄好后,将所有数据加一起就可以传入GSM模块啦
最后送上完整代码(只求保留作者;w;)
def pdu_build(smsc,dest_address,content): if(len(content)>70): raise Exception('Content too long!'); def phone_process(phone,includeF=True): phone=phone.lstrip('+'); length=len(phone); print(length,phone); phone=phone.ljust(int(round(len(phone)/2.0))*2,'F'); phone=list(phone); for k in range(len(phone)/2): phone[k*2],phone[k*2+1]=phone[k*2+1],phone[k*2]; print phone; if(includeF): length=len(phone)/2+1; return '%02X91%s'%(length,''.join(phone)); ucs2=''; for b in map(ord,content): ucs2=ucs2+'%02X%02X' % (b >> 8,b & 0xFF); return '%s1100%s000800%02X%s' % (phone_process(smsc),phone_process(dest_address,False),len(ucs2)/2,ucs2);