PDA Battery Info (VB.Net+.Net CF) Source Code
'====================================== |
PDA Battery Info (VB.Net+.Net CF) Source Code
'====================================== |
今天凌晨查询了6级成绩,66分,过了!女友也过了,很高兴。庆祝庆祝!
整个寒假完成了我预想的1-12,基本上达到了讲解基本知识的目的。马上就要上学了,所以正在准备上学的事情了。下学期的任务比较重,我会抽空把相关开发经验写出来的。希望大家继续关注。
(十二) **短信部分——通过RS232**发送和接收短信
通常,发送和接收短信的终端都是通过串行接口连接电脑,这类设备用得比较多的是GSM Modem和手机。这类设备通常都支持PDU模式,但仍有少数设备只支持Text模式。
设备硬件连接好以后可以通过发送AT指令测试设备是否连接正确能否正常通讯。在这里我使用Windows自带的“超级终端”工具进行通讯。此工具可以在程序——附件——通讯里面找到,如果没有请确认是否安装了此组件。或者在运行里面输入“hypertrm”也可以快速启动“超级终端”。
以下所有范例均以Siemens M55手机作为终端,有可能跟你设备返回的不同。具体参数清参阅设备相关AT指令集。本手机AT指令集在我主页上有下载。
准备工作:
. 测试连接:“AT8 ”测试终端是否连接正确。成功后返回“OK”。
. 设置回显:(此步骤为了测试方便)ATE18
. 查阅及设置字符集:
AT+CSCS=?8
+CSCS: (“GSM”,”UCS2”)
说明该终端支持GSM与UCS2两种字符集。一般对于中文环境设置为UCS2
AT+CSCS=”UCS2”8
. *取得短信中心号码:
*AT+CSCA? 8
+CSCA: “+8613800280500”,145
. 查询并设置SMS**格式:
**查询:AT+CMGF= 8
返回:+CMGF: (0)
0代表PDU模式。你的设备可能有其他的选项,请参考设备的AT指令集。
设置:AT+CMGF=08
. 查询并设置短信储存位置:
查询:AT+CPMS=?8
返回:+CPMS: (“MT”,”SM”,”ME”),(“MT”,”SM”,”ME”),(“MT”,”SM”,”ME”)
其中MT表示设备所有可用储存位置。SM代表SIM卡,ME代表机身。
一般设置为:AT+CPMS= “MT”,”MT”,”MT”8
查询短信:
. 查询具有相同状态的所有短信
**指令**:AT+CMGL=n
其中n代表0-4的数字。
0——未读得短信。执行命令以后自行变为已读取。
1——已读短信。
2——草稿。
3——已发送短信。
4——全部
*返回(例):
*+CMGL: 76,3,,20
0891683108200805F011620D91683194041338F50000FF0530972D8603
76——序号
3——状态:发送
20——PDU串长度
. 查询特定序号的短信
**指令**:AT+CMGR=n8
其中n代表序号
返回(例):
+CMGR: 3,,20
0891683108200805F011620D91683195041338F50000FF0530972D8603
3——状态:发送
20——PDU串长度
注意:PDU**串长度表示PDU中除去短信中心部分剩下的代码的长度的1/2。例如上述PDU中PDU长度部分为11620D91683195041338F50000FF0530972D8603,40个字符,表示20**个字节。
储存PDU
**指令**:
AT+CMGW=[PDU长度] 8
[PDU串]
例如: AT+CMGW=208
0891683108200805F011620D91683195041338F50000FF0530972D8603
注意,输入PDU后按“CTRL+Z”终止。程序中使用0x1A,0x1D作为终止。
返回:+CMGW: 85
85——序号
发送PDU**串**
. 发送输入的PDU串
指令:
AT+CMGS=[PDU长度] 8
[PDU代码]
. 发送指定序号的PDU串
*指令:
*AT+CMSS=[序号] 8
接收短信
接收刚收到的短信有两种方法:轮询终端;使用事件
轮询终端可以定期的使用AT+CMGL=0指令读取未读取得指令。方法简单,但许多时候都在做无用功,效率低下,一般不建议采用。下面主要讲解事件法:
*指令:
* AT+CNMI=
参数:
mode**:**
** 0**——缓存在终端
1**——直接发送到TE
mt:**
** 0**——接收到新的SMS不返回事件
** 1**——如果接收到的SMS存储在ME,则返回
+CMTI:
** 2**——除了Class2 SMS,新的SMS直接发送到终端,返回:
+CMT:
3**——Class3 SMS使用mt=2的方法返回,其他类型的使用mt=1的方法返回。
bm:**
** 0**——小区广播不通知
** 2**——新的小区广播通知,返回
+CBM:
3**——Class3格式的小区广播通知,使用bm=2格式
ds:**
** 0**——状态报告不通知
** 1**——新的状态报告通知,返回:
+CDS:
2**——如果新的状态报告存储到ME,则返回:
+CDSI:
brf
例:
一般我们使用AT+CNMI=1,1,0,2,1
当收到新的短信时终端返回:
+CMTI:ME,5
新的状态报告:
+CDSI:ME,6
程序可以通过判断返回值并使用AT+CMGR指令返回新到短信。
(十一) **短信部分——VB.NET**编码PDU
PDU的编码器的工作原理是解码器的逆过程。根据需要编码器只需要编码发送的PDU代码,工作相对简单。本文讲解编码思路,具体代码请参考Blog中PDUEncoder部分
我把PDU的编码分为两部分,SMS和EMS。EMS部分我只提供了ConcatenatedShortMessage的编码器。这是超长短信的编码,用得最多。
SMS**编码**
编码一个SMS一般需要如下的信息:
TP_Data_Coding_Scheme TP_UD编码方式
TP_Destination_Address 对方号码
TP_Message_Reference 参考号码
TP_Status_Report_Request 状态报告
TP_User_Data 用户信息
TP_Validity_Priod 有效期
ServiceCenterNumber 短信中心号码
所以在编码器中存在以上的属性,并在Set中加入了处理代码,将可读信息转换成对应的十六进制信息。
特别注意的是TP_User_Data属性,它可以根据用户数据编码自动设置TP_UDL。对于纯英文编码,TP_UDL为所有的字符数;对于Unicode编码,由于一个字符由两个字节表示,TP_UDL为所有的字符数2。注意检查TP_User_Data的长度,对于SMS来说编码后的TP_UD长度不能超过140字节。也就是说英文160个字符(140/78),中文70个字符。
对于TP_UD的编码在解码器中也有说明,在此不再赘述。
我还设计了几个枚举变量:
ENUM_TP_DCS 编码方式
ENUM_TP_SRI 状态报告
ENUM_TP_VALID_PERIOD 有效期
ENUM_TP_VPF 有效期格式
这些枚举变量可以简化输入,也利于日后扩充。
当以上内容设置好以后,基本上一个短信的架子就出来了。此时调用GetSMSPDUCode进行组合,简单的把十六进制拼接起来就形成了一个完整的PDU代码。
EMS**——ConcatenatedShortMessage**部分
编码EMS较SMS复杂,但每条EMS的基础还是SMS,所以我直接继承了SMS类。区别主要是要处理好TP_UD和IE。对于ConcatenatedShortMessage,由于其IE和TP_UDHL占据了TP_UD的部分空间,所以每条短信英文只能容纳133字符,中文66字符。我们可以通过此信息得到短信条数。
如果TP_DCS为Unicode编码,则短信条目为:
TotalMessages = (TP_UD.Length / 4) 66 + ((TP_UD.Length / 4 Mod 66) = 0)+1
如果为7bit,则为:
TotalMessages = (tp_ud.Length 266) - ((tp_ud.Length Mod 266) = 0)+1
注意在程序中我为了简化以后的数组操作,就没有加一。
确定了短信条数以后通过一个循环就可以提取出每条短信的TP_UD。
Select Case tp_dcs
Case ENUM_TP_DCS.UCS2
tmpTP_UD = Mid(TP_UD, i * 66 * 4 + 1, 66 * 4)’When TP_UDL is odd, the max length of an Unicode string in PDU code is 66 Charactor.See [3GPP TS 23.040 V6.5.0 (2004-09] 9.2.3.24.1
Case ENUM_TP_DCS.DefaultAlphabet
tmpTP_UD = Mid(tp_ud, i * 133 * 2 + 1, 133 * 2)
End Select
此后还需要编码IE部分,关键代码是确定TP_UDL的值。对于TP_DCS为7bit来说确定此值显得比较复杂,弄不好容易出现多一个少一个的错误。
If tp_dcs = ENUM_TP_DCS.UCS2 Then
TP_UDL = tmpTP_UD.Length / 2 + 6 + 1 ‘6: length of IE
End If
If tp_dcs = ENUM_TP_DCS.DefaultAlphabet Then
TP_UDL = Fix((tmpTP_UD.Length + 7 * 2) * 4 / 7) ‘6:length of IE
End If
然后根据3GPP里关于EMS的结构的说明就可以编写出EMS PDU的处理程序。详见原代码。
如果需要扩展EMS以适应更多种类的EMS,可以参考3GPP写出更为强大的编码程序。但最关键的还是需要处理好IE以及TP_UDL。