X.Y.E.A.H.net平台手机管理软件开发

用过西门子手机的都知道西门子手机在人性化设计方面做得比较好,但是让笔者失望的是电脑端上使用的官方软件SDS,其缺点是操作不方便,速度比较慢,感觉人性化设计不到位。后来官方推出了用于65系列的MobilePhoneManager,界面很好看,但安装后大于120MB的容量及其较慢的速度又让人大跌眼镜。

GhostMobile(简称GM)是我用过的国产非官方软件里面比较好的一款,但经常出现传输中一直等待的情况。估计作者并没有超时设计。另外GM文件传输速度很慢,短信管理不方便,后来也由于作者使用了新的手机,也就放弃了GM。后来又找到一款SiemensMobileControl,简称SiMoCo,是国外的非官方软件。800多kb的身躯及其速度、功能方面都超过了官方及GM,令人刮目相看,一度成为我最喜欢的软件。但用后发现一些问题,软件过于专业,选项太多,对中文的支持不好。

所以最终的目的就是做一款能够实现文件传输、短信、便签、任务、重要记事管理的软件。

(三)准备工作

2004的暑假我已经做了一部分,实现了基本的文件传输和短信功能,当时取名叫作M55FileTransferTool。后来在东北手机网上公开了,有一些GM无法连接的手机我的软件都可以连接,所以到现在为止有些网友还在使用我的这个软件。但由于知识不够,做得不是很理想,经常出现问题。

短信部分是官方网站下载的ATC_Command_Set_For_L55_Platform,详细地讲述了55平台上的AT指令集。其实SMS部分的AT指令各大手机厂商都是通用的,已基本上属于同一的指令集了。但是发现文件传输是OBEX却不是那么简单。

这条线索给我了极大的鼓舞,因为后来,顺藤摸瓜找到了红外线传输协议,意外地发现了IrOBEX的描述协议竟然和监视到的HEX代码的结构一样。随后经过仔细的研究发现就是OBEX协议,此协议可以作为上层协议用在红外线协议、蓝牙协议等。此过程大约经历了2个多月。其实现在看来这个问题简单了,手机的工厂模式的串口监视里面就会显示当前使用的协议。当数据传输开始时,会自动从GIPSY变为OBEX。但那个时候哪知道呢?

跨越了OBEX协议的障碍以后我写了一个OBEX-Multithread类,写得很垃圾,把十六进制转换成字符串,然后再转回来在发送。中间使用了string作字符串操作,速度很慢,测试以后只能勉强超过GM的传输速度。

后来借着SerialMonitor监视GM读取手机通讯薄的原理,发现通讯薄是在\telecom\pb目录里面,但是这个目录在手机里面是隐藏的,无法直接访问。由于原来写得OBEX库很糟糕,只能对应文件传输,对于这个特殊文件夹里面的文件都无法操作。修改了之后效果不好,遂放弃了OBEX-Multithread。

由于学习的原因,中途也只得停下来准备期末考试和六级。中途无聊的时候研究IrMC里面的vCard、vNote、vCalc格式,基本弄懂了如何同步通讯薄、便签、日历。2005年1月14日,放假回家了就正式开始动工,把所有的东西都重新写,对我来说,这是一个巨大的挑战。

(四)AT指令简介

AT指令在当代手机通讯中起着重要的作用,能够通过AT指令控制手机的许多行为,包括拨叫号码、按键控制、传真、GPRS等。西门子M55手机为我提供了很多的AT指令,网络上关于AT指令的资料也很多,我这里提取一些比较重要的做个简单解释。其他的手机也基本上通用,更详细的资料请查阅手机生产商的资料。

欲使用AT命令,可以安装微软的超级终端程序,选择好端口连接速度以后就可以正常使用了。

AT指令用法

注:并不是所有的AT指令都支持1和2。

常用基本AT指令

以上这些指令都用于与手机连接的时候初始化用。取得手机IMEI及IMSI可以给使程序支持更多的手机连接并且保持数据独立。

短信部分

以上命令是短消息部分最经常使用的命令。具体条目及使用方法会在后面讲解。

(五)OBEX介绍

一、什么是OBEX,它有什么用途?

OBEX全称为ObjectExchange,中文对象交换,所以称之为对象交换协议。它在此软件当中有着核心地位,文件传输和IrMC同步都会使用到它。

OBEX协议构建在IrDA架构的上层.

OBEX协议定义了一种柔性的概念——objects。也即是对象。这些对象可以包括文件,诊断信息,电子商务卡片,银行的存款等等。Objects在这里没有高级的技术含义,而是视你的应用而定。

OBEX能够具有以下几个特点:

1、友好的应用——可实现快速开发。

2、紧缩——可用在资源有限的小型设备上。

3、跨平台

4、柔性的数据支持。

5、方便的作为其他Internet传输协议的上层协议。

6、可扩展性——提供了对未来需求的扩充支持而不影响以存在的实现。例如可扩展安全,数据压缩等。

7、可测试可调试。

更为具体的关于OBEX的介绍请查阅IrOBEX协议。

二、OBEX对象模型

关于Headers

对象模型回答了对象是如何在OBEX协议描述的。这个模型必须包括被传输的对象和对对象的描述。为了做到这点,OBEX定义了Headers的概念。

Headers的构成

Headers简单的由和组成,简称为和。

HI由一个字节组成,指出了Header包含的内容以及它的格式。HV包含了一个或者多个字节,其结构由HI所决定。

所有的Header都是可选的,取决于设备的类型和事务的种类。你可以使用所有的Header,或者一些,或者没有。ID可以使Header可解析以及与传输顺序无关,也可以使不支持的Header被忽略掉。

HI又可以分为两部分,高2位和低6位。高2位确定了HI的编码方式(见表二),低6位确定了HI的意义(见表三)。两个表都是我从IrOBEX中的表摘抄并部分翻译过来的。

表二

HI的第8和第7位

意义

Byte块,2个字节的无符号整数前缀。

1Byte容量。

11(0xC0)

4Byte容量,以高位先传输为原则。

表三

HI

Header名称

描述

0xC0

Count

连接中用于指名对象的数量。

Name

对象的名字。一般为文件名。

Type

对象的类型。例如text,html,binary,manufacturespecific

0xC4

Time

Description

对对象的文本描述

Target

操作的目的服务名

HTTP

一个HTTP1.x头

Body

对象的一部分

Endofbody

对象的最后一部分

Who

OBEXApplication标识,用于表明是否是同一个应用。

0xCB

ConnectionID

用于OBEX多路连接的标识

App.Parameters

扩展的应用层请求和回复信息

Auth.Challenge

Authenticationdigest-challenge

Auth.Response

Authenticationdigest-response

ObjectClass

对象的OBEX对象类

Reserved

保留

Userdefined

用户自定义的。

关于常用Header的更详尽的解释,更详尽信息请参考IrOBEX

2、LengthLength描述了对象的大小,由4个字节组成。如果Length事先知道,这个Header应该被用到。这样可以让接受者迅速的知道需要分配多少空间,可使处理更为迅速。但这也不是必须的,有些情况下长度无法确认,但设备可以通过End-BodyHeader知道什么时候结束。

3、Time

BodyHeader由HI、一个2Byte长度的描述和整个的对象本身。End-of-Body组成和Body组成一样,但标识了这是对象的最后一部分。如果对象本来就很小,就直接使用End-of-Body。

三、请求(Request)和回应(Response)

OBEX使用Request和Response作为最基本的操作。请求的每个Request必然有一个Response,否则可认为Request失败。

Request由一个或多个的Packet(包)组成,每个包的结构如下表

Request数据包结构

Byte0

Byte1,2

Byte3ton

操作码(opcode)

PacketLength(包长度)

Headers或请求信息

由于每个Request可能有多个Packet,opcode的最高位称为Finalbit。如果被设置为1,那么说明这是Request的最后一个Packet。例如:当用PUT操作发送一个大文件时,会有几个Packet作为一个Request。那么只有最后一个Packet的FinalBit设置为1。

Response也由一个或多个Packet组成,每个包的结构如下表

Response数据包结构

ResponseCode(返回值)

ResponseLength(回应长度)

ResponseData回应的数据

同样的ResponseCode的最高位也叫做FinalBit。ResponseData可能包含对象和Header,或者其它信息。

下表列出了了常见的opcode和responseCode,更详尽的请参考IrOBEX1.2文档。

opcode

Opcode(w/highbitset)

定义

Connect

连接

Disconnect

断开连接

Put

发送一个对象

Get

取得一个对象

保留的

SetPath

设置路径

0xFF*

Abort

取消当前的操作

作为扩展保留

Userdefinable

用户自定义的

*总是设置FinalBit

ResponseCode

Continue(继续)

OK,Success

BadRequest(服务端不明白Request)

Fobidden(禁止——服务器明白Request,但拒绝)

NotFound(未找到)

四、说明。

1、Connect(连接)

此操作初始化会话然后设置参数。其Request格式为

Byte3

Byte4

Byte5,6

Byte7ton

包长度

OBEX版本

标志

最大OBEX包长度

可选Header

注:OBEX版本现在为1.0。

Response格式为:

对于更多关于Connect的说明请参考IrOBEX

2、Disconnect(断开当前会话)

此操作断开OBEX会话。例如断开当前FolderListingService,然后使用Connect连接到IrMCSyncService实现同步通讯薄等功能。

Disconnect格式为:

Bytes1,2

Bytes3ton

成功的断开会返回0Xa0,拒绝会返回0xD3

3、Put操作

Put操作从客户端发送一个对象到服务端。一般至少含有Name和Length两个Header。对于文件而言有可能还有Date/TimeHeader。

Put操作的格式如下:

PacketLength包长度

一组Header

回应格式如下:

关于Put操作的更详细的用法将在文件传输部分作解释。

4、Get操作

Get操作从服务端返回一个对象。

Get操作的格式如下:

关于Get操作更详细的用法将在文件传输部分作解释。

5、Abort操作

Abort操作中断一个多包操作(例如发送一个大文件)。Abort操作可以包含描述中断原因的DescriptionHeader。

Abort操作的格式如下:

0xFF

Abort对应的应该是一个成功的操作(0xA0),指明这个操作已被接收并且服务端已经重新与客户端同步。如果返回的另外的值,客户端应该Disconnect。

6、SetPath

SetPath操作用于切换对方的路径。通常使用一个NameHeader用于指定对方路径名称。如果为空,则返回默认目录,通常为根目录

SetPath操作格式如下:

(六)OBEX应用——文件传输部分

在手机数据传输方面基本OBEX应用分为

l文件传输

lIrMC同步

文件传输又可以细分为以下基本操作

l初始化连接

l断开连接

l设置路径

l取得目录信息

l创建目录

l上传下载文件

l删除文件或空目录

在笔者的软件当中设计了OBEX这个类,里面包含了以上所有的基本操作。另外针对M55的服务端的特殊性又设计了更名、取得磁盘空间信息、移动、拷贝文件的功能。具体请参考源代码。

下面具体讲述各个操作的细节。

初始化连接包括了使手机进入OBEX状态再到发送Connect指令的一系列过程。具体流程参考下图。

其中AT^SQWE=0和AT^SQWE=3是西门子特有的隐藏的AT指令,甚至在官方的AT指令集里面都没有提到。其作用是初始化手机到OBEX模式。

发送Connect指令收到手机回复以后确定MaxPacketLength等参数。最后连接到Folder-ListingService进行文件操作。如果需要IrMC同步的话,在Connect后直接连接到IrMCSyncService即可,手机立刻进入同步模式,所有的应用程序退出。

在笔者的程序中当中首先使用AT指令确定手机当前的工作,如果超时,尝试发送+++并等待1秒钟以便手机从不正常的OBEX状态中退出。然后在此发送AT,成功后即进行文件操作,否则引发一个错误。

程序中使用SetPath操作设置路径。需要注意的是,可以设计两种风格的过程:一种使用绝对路径,另一种使用相对路径。

对于手机而言,经笔者实践证明,使用绝对路径要比使用相对路径方便,而且更准确,但效率上稍逊,特别是在多层目录的情况下。由于手机没有能够返回当前路径的方法,所以相对路径总难以控制,只有通过程序控制,极容易出现错误。所以建议使用绝对路径。

如果使用绝对路径,那么路径名将呈现\path1\path2这种形式。首先回到根目录,然后一级一级的到达目的。在笔者的OBEX类当中,可以看到BacktoRoot这个过程。其作用就是把当前程序路径切换到根目录以免引起混乱。

要取得一个目录的文件信息可以用发送Get指令。该Get指令需要一个TypeHeader,其值为x-obex/folder-listing

当SetPath的Flags的Bit1设为1并且无法找到目录时,服务端会创建这个目录并进入。

请注意,再次使用SetPath并将Flags的Bit0设为1返回上层目录,否则容易引起混乱。

使用Put和Get命令可以实现上传和下载文件。注意所有的文件操作都在SetPath所指定的目录下进行。

使用Put命令实现上传时,至少需要提供NameHeader,BodyHeader,一般还要提供LengthHeader,DateTimeHeader。大文件传输需要正确处理BodyHeader,不能超出了服务端最大所能接收的Packet的大小,否则会出现错误。

需要注意的是如果当前文件存在,那么Put命令不会覆盖已有的文件而是追加,导致错误。传输文件之前需要首先删除同名文件。

使用Get命令实现下载时,只需要提供NameHeader即可。具体例子参考上一节。

使用Put命令,其NameHeader指定为文件名或目录名并将BodyHeader设置为空即可。

非空目录无法删除,会返回错误。

(七)IrMC简介

要实现通讯薄、日历、便签的同步,需要用到IrDA协议里面的IrMC部分。

下面主要讲述我在开发当中所用到的部分以及实现方法。更为详细的资料请参考IrMC协议。

Phonebook

在手机软件桌面端通讯薄的管理是整个软件的必备功能之一,利用其信息可以方便的和Outlook等软件实现同步,实现更强大的功能。

通讯薄的管理分为读取、删除、增添、修改。通过这几个功能的组合可以实现更为强大的同步功能。下面分条概述。

l读取

1.读取指定LUID的Entry使用OBEX的GET命令取得\telecom\pb\luid\xxxx.vcf,其中xxxx代表了LUID号码。得到的依然是一个vCard文件,只不过只包含特定LUID号码的vCard信息。可以简单的通过Outlook查看vCard所包含的信息。

l删除欲删除一个Entry

2.得到ChangeCount

4.使用OBEX的PUT命令,传输一个xxxx.vcf(xxxx指LUID)空文件到\telecom\pb\luid覆盖即可。

l添加欲添加一个文件:

1.连接到IrMC_Sync_Service

l修改修改过程与添加过程相似,只是将文件名改为欲修改的vCard的LUID.vcf就行了。

Notes

便签是大多数手机都提供的功能,能够方便的记录简短的信息。在我的M55手机上能够储存150Byte的信息,也就是150个英文或者75个汉字。软件通过管理便签可以与Outlook等软件同步,实现更高级的功能。

管理Notes的方法和Phonebook类似。得到全部Notes的vNote只需要获取\telecom\nt.vnt即可。删除、添加、修改只需要把\telecom\pb\luid改为\telecom\nt\luid即可。在此不再赘述。

Calendar日历功能提供了事件提醒功能,分为重要记事(vEvent)和任务(vTodo)。通过管理日历,同样可以实现和Outlook同步,实现电脑和手机的同步。

管理Calendar的方法和Phonebook类似。得到全部vCalendar只需要获取\telecom\cal.vcs。删除、添加、修改只需要把\telecom\pb\luid改为\telecom\cal\luid即可。在此不再赘述。

但值得注意的是vCalendar的结构

BEGIN:VCALENDAR

VERSION:1.0

BEGIN:VEVENT

END:VEVENT

BEGIN:VTODO

END:VTODO

END:VCALENDAR

完整的vCalender包含了至少一个vEvent或者一个vTodo,因此在添加、修改vEvent、vTodo时要将其补充为一个完整的vCalender结构,否则服务端会拒绝操作。

遇到的问题:

在实际操作中,遇到问题最多的地方在Phonebook部分。我的手机第一次同步的时候经常出现数据库被锁的情况,用SiMoCo读取也是一样,说明是手机拒绝写操作。这时候关闭手机再重新启动就好了。至于原因,我还没有搞清楚,希望能有高人指点

(八)vCard、vNote、vCalender格式简介

关于vCard、vNote、vCalender的.Net简单编码解码器请参阅SIEMENSSUPPORTTOOL源代码中的IrMC部分。

vCardObject(vCard对象)

vCardProperty(vCard属性)

vCard是一个或多个Property的集合。一个Property是唯一命名的值。一系列的Property可以在vCard中成为一组。

vCardProperty的格式如下:

注:

1、PropertyName及PropertyParameters不区分大小写。

2、PropertyParameters可选,可以为零个或多个,与ProperyName以分号相隔,与PropertyValue以冒号相隔。

3、vCard可以分多行呈现。由于在这个软件里面应用得不多,所以笔者也没有钻研具体实现方法。可以参考vCardSpecification。

例如TEL;HOME;+86111222333其PropertyName为TEL,PropertyParameters为HOME,PropertyValue为+86111222333。

Encoding(编码)

vCard默认的编码方式是7-Bit。默认编码方式可以使用ENCODING属性参数(Propertyparameter)改变。其值为可以为BASE64;QUOTED-PRINTABLE;8BIT。这个参数可以用在任何的Property里。

例如:

X-ESI-CATEGORIES;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=AE=B6=E4=BA=BA

例如ENCODING=QUOTED-PRINTABLE:Home=E5=AE=B6People=E4=BA=BA

CharacterSet(字符集)

默认的字符集是ASCII。可以通过CHARSET参数改变默认的字符集。其参数可取的值为所有IANA(InternetAssignedNumbersAuthority)注册的字符集。这个参数可以用于任何Property,但某些Property并不起作用。

vCard例子:

BEGIN:VCARD

VERSION:2.1

X-IRMC-LUID:1017646

N:test

ADR:;;Street;city;;610000;country

ORG:company

TEL;HOME:123456

TEL;WORK:123456

TEL;CELL:123456

TEL;FAX:123456

TEL;FAX;HOME:123456

EMAIL;INTERNET:a@a.ao

EMAIL;HOME;INTERNET:b@g

BDAY:1985-04-23

END:VCARD

(九)短信部分——PDU简介及其格式

PDU是大多数手机短信通讯的核心,仅有少数手机只支持Text模式(例如笔者的MOTOC330)。PDU模式比起Text模式可以提供能为强大的功能,但其编码较Text模式困难。无论哪种模式,我们都可以通过AT指令控制终端实现短信的发送、接收、删除等管理。下面主要介绍PDU的构成及编码解码。

PDU的构成

下面举一个发送和接收的例子。

1、手机发送的一个PDU串:

0891683108200805F011190D91683188902848F40008FF108FD9662F4E0067616D4B8BD577ED4FE

对比3GPP协议得到:(二进制代码从左到右依次为高位->低位)

短信中心地址字段

08地址长度:8个字节,包括其后的91

FirstOctet字段

11包含TP-MTI(2bit),TP-RD(1bit),TP-VPF(2bit),TP-RP(1bit),TP-UDHI(1bit),TP-SRR(1bit)

二进制表示形式:00010001

TP-MTI:01

TP-Message-Type-Indicator(消息类型指示符)

Bit1,0:01指示为SMS-SUBMIT类型TP-RD:0

TP-Reject-Duplicates(是否拒绝相同重复消息)

Bit2:0指示短消息中心接受未转发的具有相同TP-MR的消息。

TP-VPF:10

TP-Validity-Period-Format(有效期格式)

Bit4,3:10指示使用相对格式。

TP-SRR:0

TP-Status-Report-Request

Bit5:0指示不使用状态报告。

TP-UDHI:0TP-User-Data-Header-Indicator(用户数据头标示)Bit6:0指示这是一个SMS消息,没有用户数据头。EMS消息需要设置。

TP-RP:0TP-Reply-Path(回复路径)Bit7:0指示没有设置回复路径。

消息参考值TP-MR

19TP-Message-Reference

对方号码字段

0D91683188902848F4

其结构与短信中心号码字段部分类似,不再赘述。

协议标识TP-PID

00TP-Protocol-Identifier(上层协议指示),一般设置为00,表示普通GSM,点对点编码方法TP-DCS

08TP-Data-Coding-Scheme(数据编码设置),指示TP-UD的编码方式。08代表Unicode方式。00为7Bit编码

有效期TP-VP

FFTP-Validity-Period(有效期)。FF表示最大。

用户数据长度TP-UDL

10TP-User-Data-Length(用户数据长度)

用户数据TP-UD

2、手机接收的PDU串

0891683108200805F0040D91683188902848F4000850208151754500108FD9662F4E0067616D4B8BD577ED4FE1

0891683108200805F0:+861380280500

FirstOctet

04

其二进制代码:00000100

TP-MTI:00

TP-MMS(TP-More-Message-to-Send):1短信中心没有更多的消息发送

TP-SRI:0

TP-UDHI:0

TP-RP:0

发送方号码

0D91683188902848F4:+8613880982844

协议标识00TP-DCS点对点

编码方式

08TP-DCSUnicode编码

用户数据长度

10TP-DHL

用户数据

8FD9662F4E0067616D4B8BD577ED4FE1TP-UD

(十)短信部分——VB.NET解码PDU

解码器的构成

NameSpaceSMS

Decoder

MustInheritClassSMSBase

ClassEMS_RECEIVED

ClassEMS_SUBMIT

ClassSMS_RECEIVED

ClassSMS_STATUS_REPORT

ClassSMS_SUBMIT

ClassPDUDecoder

SMSBase部分

SMSBase包含了所有短信类型所共有的基本信息部分以及一个指示短信类型的枚举SMSType,继承的类扩展其特有的基本信息部分。

PublicTP_PIDAsByte

PublicTP_DCSAsByte

PublicTP_UDLAsByte

PublicTP_UDAsString

PublicTextAsString

PublicTypeAsSMSType

PublicUserDataAsString

PublicEnumSMSType

SMS_RECEIVED=0

SMS_STATUS_REPORT=2

SMS_SUBMIT=1

EMS_SUBMIT=65

EndEnum

SMSBase中定义了一个必须重写的过程GetOrignalData,其参数为PDUCode,目的是为了得到PDU的基本信息。不同的短信类型具有不同的解码过程,所以作为一个必须重写的函数。

PublicMustOverrideSubGetOrignalData(ByValPDUCodeAsString)

SMSBase中还有一系列的辅助函数,具体实现方法见源代码:

处理PDU代码的:

SharedFunctionGetByte(ByRefPDUCodeAsString)AsByte

SharedFunctionGetString(ByRefPDUCodeAsString,ByValLengthAsInteger)AsString

SharedFunctionGetDate(ByRefSCTSAsString)AsDate

SharedFunctionSwap(ByRefTwoBitStrAsString)AsString

SharedFunctionGetAddress(ByRefAddressAsString)AsString

SharedFunctionGetSMSType(ByValPDUCodeAsString)AsSMSBase.SMSType

TP-UD解码部分:

TP-UD的解码的任务主要集中在Unicode的解码和7BitCode的解码。其中Unicode的解码很方便,只需要将两个字节的PDUCode通过Val函数转换成为数字,在通过ChrW函数即可得到。

Byte1110101000xD4

Byte2111100100xF2

注:各字符二进制代码:

T:1010100e:1100101s:1110011t:1110100

从这个例子可以看出一个Byte包含了一个字符的ASCII码的二进制部分及后续字符的二进制部分的低位。这样8个字符可以压缩成为7个Byte,SMS中140Byte的TP-UD长度就可以容纳160个英文字母。

通过观察可以看出,只要我们从后到前把所有的二进制代码拼接到一块,就能够方便的处理,上面例子通过拼接后得到:

00001110100111001111001011010100

我们可以直接通过从后往前的按7个一组的原则进行截取在处理就可以得到解码后的代码。为了编程的方便,我设计了一个简单易懂的解码过程,比起通过做乘除法来进行运算的简单,但最终效率不及它。但我想在普通场合应用也绰绰有余了。

1、Decode7Bit得到一个PDU的TP-UD部分

2、InvertHexString反转十六进制代码:例如123456=〉563412

4、根据charCount所提供的字符数(来自TP_UDL)按7个一组从字符串位往前截取,并用Chr函数转换成ASCII码。

SharedFunctionDecodeUnicode(ByValstrUnicodeAsString)AsString

SharedFunctionInvertHexString(ByValHexStringAsString)AsString

SharedFunctionByteToBinary(ByValDecAsByte)AsString

SharedFunctionBinaryToInt(ByValBinaryAsString)AsInteger

SharedFunctionDecode7Bit(ByValstr7BitCodeAsString,ByValcharCountAsInteger)AsString

SMS_SUBMIT、SMS_RECEIVED、SMS_STATUS_REPORT

由于SMS_RECEIVED、SMS_STATUS_REPORT与SMS_SUBMIT比较相似,所以我重点讲讲SMS_SUBMIT。

参考协议知道SMS_SUBMIT比SMSBase多出以下部分:

PublicTP_MRAsByte

PublicDesAddressLengthAsByte

PublicDesAddressTypeAsByte

PublicDesAddressValueAsString

PublicTP_VPAsByte

参考协议我们可以很方便的得到GetOrignalData函数的实现:

PublicOverridesSubGetOrignalData(ByValPDUCodeAsString)

SCAddressLength=GetByte(PDUCode)

SCAddressType=GetByte(PDUCode)

SCAddressValue=GetAddress((GetString(PDUCode,(SCAddressLength-1)*2)))

FirstOctet=GetByte(PDUCode)

TP_MR=GetByte(PDUCode)

DesAddressLength=GetByte(PDUCode)

DesAddressType=GetByte(PDUCode)

DesAddressLength+=DesAddressLengthMod2

DesAddressValue=GetAddress((GetString(PDUCode,DesAddressLength)))

TP_PID=GetByte(PDUCode)

TP_DCS=GetByte(PDUCode)

TP_VP=GetByte(PDUCode)

TP_UDL=GetByte(PDUCode)

TP_UD=GetString(PDUCode,TP_UDL*2)

EndSub

这就完成了整个解码过程,通过SMSBase的巧妙设计,此解码过程显得简单方便。

EMS_SUBMIT、EMS_RECEIVED

对于EMS(增强型短信),其基本结构和SMS类似,主要的区别就是InformationElement(IE)。所以EMS_SUBMIT继承了SMS_SUBMIT,EMS_RECEIVED继承了SMS_RECEIVED

参考3GPP协议EMS部分我们可以做出以下的结构和定义

PublicIdentifierAsByte

PublicLengthAsByte

PublicDataAsString

EndStructure

PublicTP_UDHLAsByte

为了得到IE我写了一个函数:

SharedFunctionGetIE(ByValIECodeAsString)AsInfoElem()

DimtmpAsString=IECode,tAsInteger=0

Dimresult()AsInfoElem

ReDimPreserveresult(t)

Withresult(t)

.Identifier=GetByte(IECode)

.Length=GetByte(IECode)

.Data=GetString(IECode,.Length*2)

EndWith

t+=1

Loop

Returnresult

EndFunction

然后参考协议可以写出GetOrignalData函数。具体就不再赘述。

PDUDecoder

这个类的由一个结构,一个重要的解码函数,组成。

结构定义了需要取得的基本信息,可以视需要修改。我这里提供一个范例

PublicStructureBaseInfo

PublicSourceNumberAsString

PublicDestinationNumberAsString

PublicReceivedDateAsDate

PublicTypeAsSMS.Decoder.SMSBase.SMSType

PublicEMSTotolPieceAsInteger

PublicEMSCurrentPieceAsInteger

PublicStatusFromReportAsSMS_STATUS_REPORT.EnumStatus

PublicDestinationReceivedDate

PublicSharedFunctionDecode(ByValPDUCodeAsString)AsBaseInfo

内部主要处理步骤如下(源代码请参考PDUDecoder)

1.根据SMSBase的GetSMSType函数得到短信类型SMSType

2.根据SMSType生成对应的类的实例

3.解码PDU,得到基本结构

4.通过基本结构得到BaseInfo结构里面需要的数据

5.通过decode7bit或者decodeUnicode函数得到TP_UD数据

PDU的编码器的工作原理是解码器的逆过程。根据需要编码器只需要编码发送的PDU代码,工作相对简单。本文讲解编码思路,具体代码请参考Blog中PDUEncoder部分

我把PDU的编码分为两部分,SMS和EMS。EMS部分我只提供了ConcatenatedShortMessage的编码器。这是超长短信的编码,用得最多。

SMS编码

编码一个SMS一般需要如下的信息:

TP_Data_Coding_SchemeTP_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/7*8),中文70个字符。

对于TP_UD的编码在解码器中也有说明,在此不再赘述。

我还设计了几个枚举变量:

ENUM_TP_DCS编码方式

ENUM_TP_SRI状态报告

ENUM_TP_VALID_PERIOD有效期

ENUM_TP_VPF有效期格式

这些枚举变量可以简化输入,也利于日后扩充。

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/4Mod66)=0)+1

如果为7bit,则为:

TotalMessages=(tp_ud.Length\266)-((tp_ud.LengthMod266)=0)+1

注意在程序中我为了简化以后的数组操作,就没有加一。

确定了短信条数以后通过一个循环就可以提取出每条短信的TP_UD。

SelectCasetp_dcs

CaseENUM_TP_DCS.UCS2

CaseENUM_TP_DCS.DefaultAlphabet

tmpTP_UD=Mid(tp_ud,i*133*2+1,133*2)

EndSelect

此后还需要编码IE部分,关键代码是确定TP_UDL的值。对于TP_DCS为7bit来说确定此值显得比较复杂,弄不好容易出现多一个少一个的错误。

Iftp_dcs=ENUM_TP_DCS.UCS2Then

EndIf

Iftp_dcs=ENUM_TP_DCS.DefaultAlphabetThen

然后根据3GPP里关于EMS的结构的说明就可以编写出EMSPDU的处理程序。详见原代码。

如果需要扩展EMS以适应更多种类的EMS,可以参考3GPP写出更为强大的编码程序。但最关键的还是需要处理好IE以及TP_UDL。

(十二)短信部分——通过RS232发送和接收短信

通常,发送和接收短信的终端都是通过串行接口连接电脑,这类设备用得比较多的是GSMModem和手机。这类设备通常都支持PDU模式,但仍有少数设备只支持Text模式。

准备工作:

2、设置回显:(此步骤为了测试方便)ATE18

5、查询并设置SMS格式:查询:AT+CMGF=8返回:+CMGF:(0)0代表PDU模式。你的设备可能有其他的选项,请参考设备的AT指令集。设置:AT+CMGF=08

查询短信:

1、查询具有相同状态的所有短信指令:AT+CMGL=n其中n代表0-4的数字。0——未读得短信。执行命令以后自行变为已读取。1——已读短信。2——草稿。3——已发送短信。4——全部返回(例):+CMGL:76,3,,20

0891683108200805F011620D91683194041338F50000FF0530972D860376——序号

3——状态:发送

20——PDU串长度

2、查询特定序号的短信指令:AT+CMGR=n8其中n代表序号返回(例):+CMGR:3,,200891683108200805F011620D91683195041338F50000FF0530972D86033——状态:发送20——PDU串长度

注意:PDU串长度表示PDU中除去短信中心部分剩下的代码的长度的1/2。例如上述PDU中PDU长度部分为11620D91683195041338F50000FF0530972D8603,40个字符,表示20个字节。

储存PDU指令:AT+CMGW=[PDU长度]8>[PDU串]例如:AT+CMGW=208

返回:+CMGW:8585——序号

发送PDU串

1、发送输入的PDU串指令:AT+CMGS=[PDU长度]8>[PDU代码]

2、发送指定序号的PDU串指令:AT+CMSS=[序号]8

接收短信

接收刚收到的短信有两种方法:轮询终端;使用事件

轮询终端可以定期的使用AT+CMGL=0指令读取未读取得指令。方法简单,但许多时候都在做无用功,效率低下,一般不建议采用。下面主要讲解事件法:

指令:AT+CNMI=,,,,

参数:mode:

0——缓存在终端

1——直接发送到TE

mt:

0——接收到新的SMS不返回事件

1——如果接收到的SMS存储在ME,则返回+CMTI:,

2——除了Class2SMS,新的SMS直接发送到终端,返回:+CMT:

3——Class3SMS使用mt=2的方法返回,其他类型的使用mt=1的方法返回。

THE END
1.Studio谷歌当你在 Google I/O 大会上推出自家全新的官方安卓软件集成开发工具 Android Studio 就引起了一片欢呼。这是 Google 基于IntelliJ IDEA (一款优秀的 Java 开发工具) 二次开发修改而来。 谷歌称 Android Studio 能让开发者更具生产力!它完全免费,跨平台支持 Win / Mac / Linux,是替代 Eclipse 的最佳安卓开发https://www.iplaysoft.com/android-studio.html
2.开发工具(编程语言程序设计软件电脑编程)开发工具下载提供编程语言|程序设计软件|电脑编程等相关下载软件,开发工具用户热评软件排行,新鲜软件排行等向您推荐最受关注和最新的开发工具工具。更多开发工具尽在中关村在线下载频道。https://xiazai.zol.com.cn/download_cate_biancheng/biancheng_page_1.html
3.西安AS400软件开发招聘网猎聘2025年西安AS400软件开发招聘信息,海量高薪猎头职位等你来选,了解西安AS400软件开发岗位要求、薪资待遇等真实招聘信息,找高薪职位,上猎聘!https://www.liepin.com/city-xian/zpas400ruanjiankaifa/
4.什么是NortekWinADV?(NortekAS开发)最新版本: 2024 软件类别: 其它 软件子类别: 其它 操作系统: Windows软件概述诺泰克WinADV是由挪威公司诺泰克AS开发的速度测量软件。 ADV代表声学多普勒流速仪。它被用于捕获颗粒,水,和其他物质的速度的测量。它在科研用于研究在实验室或海洋急剧电流变化。最后发布的版本是在2007年就已经停产了。软件https://www.solvusoft.com/zh-cn/file-extensions/software/nortek-as/nortek-winadv/
5.[转]AS语言基础飞鸟无痕6.2.3 封装让整个软件开发的复杂度大大降低 模块化,降低复杂度才是封装这个思想产生的最真实的原因,代码易于修改、替换、复用等只是这一点附带的好处而已。 6.3 ActionScript3中封装的几个层次 包外-> 包 -> 类 -> 包外类 (由外层到内层的结构,越靠近内近,访问权限越严格) https://www.cnblogs.com/tianlanliao/archive/2012/03/30/2425475.html
6.软件开发工具软件开发工具 储存到myST Complex programmable silicon components require a full complementary Ecosystem. ST and its partners provide an extensive range of Software Development Tools that are increasingly becoming an important criterion in the selection of semiconductor devices. https://www.st.com/zh/development-tools/software-development-tools.html
7.引领“数智时代”发展,打通“智变质变”正循环迁移完成之后,在后续版本迭代及新功能开发过程中,通过ARM架构配套的开发工具,帮助开发人员便捷获取和使用ARM架构优势特性,开发出高性能软件,同时自动完成典型场景下的应用包构建和执行,提升开发效率和体验,引导开发人员持续基于ARM架构原生开发行业应用,深入构建行业软件生态。 https://developer.aliyun.com/article/1150750
8.PracticeITIL 4软件开发和管理中文版介绍 Practice_Software development and management ITIL 4软件开发和管理 中文版【初译】.pdf 一般信息 2.1 目的和描述 软件开发和管理实践专注于应用程序软件的开发和管理。但是,许多原理也适用于作为开发和管理应用程序的基础结构的一部分的软件。 https://www.itilchina.cn/achotsao/vip_doc/16881760.html
9.关于软件开发英语作文软件开发的英语翻译phpSoftware development is often translated into English as \"software engineering.\" This term refers to the systematic process of creating and maintaining software applications. It involves the use of programming languages, software tools, and databases to create applications that can meet the needs ofhttps://www.yyzq.team/post/342645.html
10.ASP.NETCore适用于.NET的开源Web框架.NET 是一个开发人员平台,由工具、编程语言、库组成,用于构建许多不同类型的应用程序。 ASP.NET Core 通过专门用于生成 web 应用的工具和库扩展了.NET 开发人员平台。 更深入发掘: 什么是 ASP.NET Core? 了解ASP.NET Core 通过我们的教程、视频课程和文档,了解 ASP.NET Core 提供的所有功能。 https://asp.net/
11.开放的软件合作开发社区,分享互动和群体智能成为软件开发的[translate] a出现各种各样开源、开放的软件合作开发社区,分享、互动和群体智能成为软件开发的常态。 Appears opens the source, the opening software cooperation development community variously, the share, the interaction and the community intelligence becomes the habit which the software develops. [translate] http://eyu.zaixian-fanyi.com/fan_yi_1615023
12.有限元软件开发致力于国产大型通用商业有限元计算软件的开发当很多年前很多人一直怀疑这样一个由一大群“散户”开发出来的操作系统值不值得信赖,linux本身却在无声无息中迅速发展。走自己的路,让别人去说,也是一个很好的诠释。博主一直有发展我们自己的国产有限元计算软件的想法,但是对于如何有效的开展工作,是一个大大的难题。对于我们为什么至今还拿不出一个像样的有限元分析https://cfem2nli.wordpress.com/
13.您需要软件检测GJB 438B-2009 军用软件开发文档通用要求 GJB 439A-2013 军用软件质量保证通用要求 GJB 2115A-2013 军用软件研制项目管理要求 GJB 2226.8-1994 舰载雷达情报系统通用要求 软件要求 GJB 2434-1995 军用软件测试与评估通用要求 GJB 3982.4-2001 电子对抗装备软件通用要求 第4部分:电子对抗专用计算机支撑平台软硬件要求 https://a.bjhgyjs.cn/xiangmu/other/248697.html
14.Top9汽车HMI设计及软件开发公司4.Intellias(https://www.intellias.com/) 位置:乌克兰里沃夫,基辅,奥德萨;德国柏林 成立时间:2002 公司规模:1100+ Intellias是乌克兰最好的软件外包公司之一,主要提供HMI软件开发服务。这家公司有一个知名的投资组合,因为当它进入汽车HMI设计开发领域时,创造了TopGear路测“最卓越的无压力导航软件”。Intellias的汽车https://www.yoojia.com/ask/17-11719584628157500369.html
15.DGUSV7624T5L屏开发软件DWINDGUSV7642资源"DGUS_V7624_T5L屏开发软件DWIN_"涉及的核心知识点是基于迪文科技(DWIN)的T5L液晶显示屏的开发,利用DWIN提供的专用开发工具进行屏幕设计和程序编写。这个软件适用于将T5L屏作为DGUS2系统的一部分来使用的情况。 中提到的"DWIN迪文T5L屏开发软件"是指DWIN公司为开发者设计的一款专业工具,用于创建和调试T5L显示屏的https://download.csdn.net/download/weixin_42681774/27255701
16.2024校园招聘思特沃克软件技术(西安)有限公司招聘软件开发工程师与业务分析师和质量分析师、设计师、项目经理等合作设计软件解决方案,为我们的客户带来有意义的改变。他们仔细聆听以了解业务问题的上下文,并编写干净且迭代的代码以提供强大的最终结果。通过平衡强烈的意见和寻找正确答案的意愿,软件开发人员为技术带来完整性,确保所有声音都能被听到。 我们的初级顾问的职业https://xyzp.haitou.cc/article/3143288.html
17.对vb软件系统进行CAD二次开发.doc对vb软件系统进行CAD二次开发 关键词:标准零件、AutoCADVBA语言、AutoCAD的二次开发计算机辅助制图是现代企业生产和设计的重要工具,AutoCAD是计算机辅助设计工具的一种,VB是AutoCAD软件的重要组成部分。它是AutoCAD软件二次开发的重要工具。它可使一些常用的机械零件能很快的调用,简捷方便,很大的提高了工作效率缩短了新产品https://m.renrendoc.com/paper/303026186.html