这一篇主要讲一下短信的接受部分。
短信被手机接受后可以有好几种处理方法,我只说三种:
ComMobile.WriteStr('AT+CNMI=2,2,0,0,0'+#13);
Sleep(2000);
ComMobile.ReadStr(buff, 22);
if Copy(buff, 21, 2) <> 'OK' then
begin
ShowMessage('初始化错误!');
Exit;
end;
ComMobileData.StopString := #13#10;
ComMobileData.ComPort := ComMobile;
这里使用了一个TComDataPacket控件ComMobileData用于处理接到的所有数据(使用#13#10进行自动包分割)。其处理代码如下
procedure TFormMain.ComMobileDataPacket(Sender: TObject; const Str: string);
begin
if Length(Str) = 0 then Exit;
lstLog.Items.Append(Str);
lstLog.ItemIndex := lstLog.Items.Count-1;
if Copy(Str, 1, 1) = '>' then Exit;
if Copy(Str, 1, 2) = 'OK' then Exit;
if Copy(Str, 1, 1) = '+' then Exit;
if Copy(Str, 1, 2) = 'AT' then Exit;
if Copy(Str, 1, 5) = 'ERROR' then
begin
ShowMessage('错误!');
Exit;
end;
PhraseSMS(Str);
end;
PhraseSMS是用于解码PDU包的,有如下注意事项:
英文短信的编码是0x00,使用压缩7bit方法编码,如要编码“hellohello”,方法如下:
这一部分我是用内嵌汇编实现的,好好体会一下就明白怎么实现的了。
至于中文的UCS2编码,只是做了简单的拼装,注意高低字节千万不要弄反了。
procedure TFormMain.PhraseSMS(msg: string);
var
num: string;
str: WideString;
wchar: WideChar;
t: TDateTime;
i, j, k: Integer;
b1, b2, r: Byte;
begin
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2*(i+2));
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 4);
num := '';
for j := 1 to ((i+1) div 2) do
begin
num := num+msg[2];
if (j < ((i+1) div 2)) or ((i mod 2) = 0) then num := num+msg[1];
Delete(msg, 1, 2);
end;
Delete(msg, 1, 2);
k := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2);
t := StrToDateTime('20'+msg[2]+msg[1]+'-'
+msg[4]+msg[3]+'-'
+msg[6]+msg[5]+'-'
+msg[8]+msg[7]+':'
+msg[10]+msg[9]+':'
+msg[12]+msg[11]);
Delete(msg, 1, 14);
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2);
str := '';
if k = 0 then
begin
j := 0;
b2 := 0;
r := 0;
while j < i do
begin
Inc(j);
Inc(b2);
b1 := StrToInt('0x'+Copy(msg, 1, 2));
asm
MOV AL,b1
MOV AH,0
MOV CL,b2
SHL AX,CL
SHR AL,1
OR AL,r
MOV r,AH
MOV b1,AL
end;
str := str+Chr(b1);
if (j+1) mod 8 = 0 then
begin
Inc(j);
str := str+Chr(r);
r := 0;
b2 := 0;
end;
Delete(msg, 1, 2);
end;
end;
if k = 8 then
begin
for j := 1 to (i div 2) do
begin
b1 := StrToInt('0x'+Copy(msg, 1, 2));
b2 := StrToInt('0x'+Copy(msg, 3, 2));
Delete(msg, 1, 4);
asm
MOV AH,b1
MOV AL,b2
MOV wchar,AX
end;
str := str+wchar;
end;
end;
Vote(num, str, t);
end;
后面就是做一些简单的投票处理了,都是简单的数据库操作,比如查看时候有重复投票等等……这里就不罗嗦了,也没什么技术含量,呵呵
短信被手机接受后可以有好几种处理方法,我只说三种:
- AT+CNMI=0,0,0,0,0
短信到来后不告知主机,需要要主机定时使用AT+CMGL轮讯新消息,这种方式显然是不可取的,效率太低,实时性也不好。 - AT+CNMI=2,1,0,0,0
短信到来后使用+CMTI告知主机新短信的存储位置以及序号,等待主机使用AT+CMGR读取该消息。由于短信投票会在短时间内收到大量数据,如果每一条短信都被存储在手机中再读出分析,这势必会影响处理的速度。 - AT+CNMI=2,2,0,0,0
短信到来后,直接用+CMT把PDU串发送给主机,手机不做任何保存操作,这种方法效率是最高的,但是要求主机要能准确无误的收到所有的数据包,否则就会丢包了。
ComMobile.WriteStr('AT+CNMI=2,2,0,0,0'+#13);
Sleep(2000);
ComMobile.ReadStr(buff, 22);
if Copy(buff, 21, 2) <> 'OK' then
begin
ShowMessage('初始化错误!');
Exit;
end;
ComMobileData.StopString := #13#10;
ComMobileData.ComPort := ComMobile;
这里使用了一个TComDataPacket控件ComMobileData用于处理接到的所有数据(使用#13#10进行自动包分割)。其处理代码如下
procedure TFormMain.ComMobileDataPacket(Sender: TObject; const Str: string);
begin
if Length(Str) = 0 then Exit;
lstLog.Items.Append(Str);
lstLog.ItemIndex := lstLog.Items.Count-1;
if Copy(Str, 1, 1) = '>' then Exit;
if Copy(Str, 1, 2) = 'OK' then Exit;
if Copy(Str, 1, 1) = '+' then Exit;
if Copy(Str, 1, 2) = 'AT' then Exit;
if Copy(Str, 1, 5) = 'ERROR' then
begin
ShowMessage('错误!');
Exit;
end;
PhraseSMS(Str);
end;
PhraseSMS是用于解码PDU包的,有如下注意事项:
英文短信的编码是0x00,使用压缩7bit方法编码,如要编码“hellohello”,方法如下:
h | e | l | l | o | h | e | l | l | o | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
104 | 101 | 108 | 108 | 111 | 104 | 101 | 108 | 108 | 111 | ||||||||||||||||||||
1101000 | 1100101 | 1101100 | 1101100 | 1101111 | 1101000 | 1100101 | 1101100 | 1101100 | 1101111 | ||||||||||||||||||||
|
|
|
|
|
|
|
|
|
| ||||||||||||||||||||
|
|
|
|
|
|
|
|
| |||||||||||||||||||||
E8 | 32 | 9B | FD | 46 | 97 | D9 |
| EC | 37 |
这一部分我是用内嵌汇编实现的,好好体会一下就明白怎么实现的了。
至于中文的UCS2编码,只是做了简单的拼装,注意高低字节千万不要弄反了。
procedure TFormMain.PhraseSMS(msg: string);
var
num: string;
str: WideString;
wchar: WideChar;
t: TDateTime;
i, j, k: Integer;
b1, b2, r: Byte;
begin
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2*(i+2));
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 4);
num := '';
for j := 1 to ((i+1) div 2) do
begin
num := num+msg[2];
if (j < ((i+1) div 2)) or ((i mod 2) = 0) then num := num+msg[1];
Delete(msg, 1, 2);
end;
Delete(msg, 1, 2);
k := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2);
t := StrToDateTime('20'+msg[2]+msg[1]+'-'
+msg[4]+msg[3]+'-'
+msg[6]+msg[5]+'-'
+msg[8]+msg[7]+':'
+msg[10]+msg[9]+':'
+msg[12]+msg[11]);
Delete(msg, 1, 14);
i := StrToInt('0x'+Copy(msg, 1, 2));
Delete(msg, 1, 2);
str := '';
if k = 0 then
begin
j := 0;
b2 := 0;
r := 0;
while j < i do
begin
Inc(j);
Inc(b2);
b1 := StrToInt('0x'+Copy(msg, 1, 2));
asm
MOV AL,b1
MOV AH,0
MOV CL,b2
SHL AX,CL
SHR AL,1
OR AL,r
MOV r,AH
MOV b1,AL
end;
str := str+Chr(b1);
if (j+1) mod 8 = 0 then
begin
Inc(j);
str := str+Chr(r);
r := 0;
b2 := 0;
end;
Delete(msg, 1, 2);
end;
end;
if k = 8 then
begin
for j := 1 to (i div 2) do
begin
b1 := StrToInt('0x'+Copy(msg, 1, 2));
b2 := StrToInt('0x'+Copy(msg, 3, 2));
Delete(msg, 1, 4);
asm
MOV AH,b1
MOV AL,b2
MOV wchar,AX
end;
str := str+wchar;
end;
end;
Vote(num, str, t);
end;
后面就是做一些简单的投票处理了,都是简单的数据库操作,比如查看时候有重复投票等等……这里就不罗嗦了,也没什么技术含量,呵呵