📄 smscomm.pas
字号:
Open
else
Close;
end
else
FConnected := Value;
end;
// set buffer
procedure TComPort.SetBuffer(const Value: TComBuffer);
begin
FBuffer.Assign(Value);
ApplyBuffer;
end;
// set parity
procedure TComPort.SetParity(const Value: TComParity);
begin
FParity.Assign(Value);
ApplyDCB;
end;
// set timeouts
procedure TComPort.SetTimeouts(const Value: TComTimeouts);
begin
FTimeouts.Assign(Value);
ApplyTimeouts;
end;
(*****************************************
* TSMSComm componennt *
*****************************************)
// create component
constructor TSMSComm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// component cannot reside on inheritable forms
FComponentStyle := FComponentStyle - [csInheritable];
FEncodeStyle := esUnicode;
FDestPhoneStyle := psMobilePhone;
FInSync := False;
FDatalenMsg := 70;
FTaskCapacity := -1;
FShouldQuit := False;
if not (csDesigning in ComponentState) and not (csLoading in ComponentState) then begin
FWaitEvent := TEvent.Create(nil,true,False,'');
FSmartSMSThread := TSMSCommThread.Create(Self); //创建通讯线程
TaskList := TList.Create;
FDeleteSMSList := TStringList.Create;
FLock := TCriticalSection.Create;
end;
FComPort := TComPort.Create(Self);
FTimingDelSMS := TTimingDelSMS.Create(Self);
FCommQueue:= TCommQueue.Create(Self);
end;
// destroy component
destructor TSMSComm.Destroy;
begin
if not (csDesigning in ComponentState) and not (csLoading in ComponentState) then begin
FShouldQuit := True;
FWaitEvent.SetEvent;
FreeAndNil(FSmartSMSThread);
FWaitEvent.Free;
TaskList.Free;
FDeleteSMSList.Free;
FLock.Free;
end;
FComPort.Free;
FTimingDelSMS.Free;
FCommQueue.Free;
inherited Destroy;
end;
function TSMSComm.GSM_AT_W: Boolean;
var
aTAT_W_Task: TAT_W_Task;
begin
Result := False;
if not FActive then Exit;
if InCommThread or FInSync then begin
Result := _GSM_AT_W;
end
else begin
if FTaskCapacity>0 then begin
if TaskList.Count>=FTaskCapacity then Exit;
end;
aTAT_W_Task := TAT_W_Task.Create(ctBlocking);
try
AddTask(aTAT_W_Task, atInsert, 0);
while not aTAT_W_Task.Finish do Application.ProcessMessages;
Result := aTAT_W_Task.Success;
finally
FreeAndNil(aTAT_W_Task);
end;
end;
end;
// 存储modem参数
function TSMSComm._GSM_AT_W: Boolean;
var
S: string;
ReadOK: Boolean;
StartT,EndT: Single;
begin
Result := False;
FSmartSMSThread.TaskItem.FSuccess := False;
//if not FComPort.Connected then Exit;
if not FActive then Exit;
_DelayTimems(500);
//首先将串口读空
while FComPort.ReadStr(S,1) do begin
FCommQueue.AddByStr(S);
JudgeCMTI;
end;
//首先将串口读空再进行设置号码
FComPort.Clear;
S := 'AT&W' + #13; // 存储参数
if not FComPort.WriteStr(S) then Exit;
FillChar(FReceiveBuffer, FDATALEN, 0);
FCommQueue.Reset;
ReadOK:=False;
StartT:=(SysUtils.Time)*24*3600000;
repeat
EndT := (SysUtils.Time)*24*3600000;
if not FComPort.ReadStr(S,1) then Continue;
FCommQueue.AddByStr(S);
FCommQueue.GetOneByte(FReceiveBuffer[0],-1);
FCommQueue.GetOneByte(FReceiveBuffer[1],0);
if (FReceiveBuffer[0] = $34) and (FReceiveBuffer[1] = $0D) then
begin
ReadOK:=False;
Break;
end;
if (FReceiveBuffer[0] = $30) and (FReceiveBuffer[1] = $0D) then
begin
ReadOK:=True;
Break;
end;
//在2秒中内要读完
until (abs(EndT-StartT)>2000);
if ReadOK then begin
Result:=True;
FSmartSMSThread.TaskItem.FSuccess := True;
end;
end;
function TSMSComm.DecodeSCA(SCA: string; ProcessF: Boolean): string;
var
i, Len: integer;
begin
Result := '';
Len := Length(SCA);
if (Len=0) or ((Len mod 2)=1) then Exit; //为空或为奇数则不处理
if Copy(SCA,1,2) = '91' then begin
for i:=3 to (Len div 2) do Result := Result + SCA[i*2] + SCA[i*2-1];
if ProcessF then
if Result[Length(Result)]='F' then Delete(Result,Length(Result),1);
Result := '+86'+Result;
end
else begin
for i:=3 to (Len div 2) do Result := Result + SCA[i*2] + SCA[i*2-1];
if ProcessF and (Length(Result)>=Len) and (Result[Len]='F') then Delete(Result,Len,1);
end;
end;
// 处理来电号码
function TSMSComm.DecodeSourPhone(SourPhone: string; ProcessF: Boolean): string;
var
i, Len: integer;
begin
Result := '';
Len := Length(SourPhone);
if (Len=0) or ((Len mod 2)=1) then Exit; //为空或为奇数则不处理
if Copy(SourPhone,1,2) = '91' then begin
for i:=3 to (Len div 2) do Result := Result + SourPhone[i*2] + SourPhone[i*2-1];
end
else begin
for i:=2 to (Len div 2) do Result := Result + SourPhone[i*2] + SourPhone[i*2-1];
end;
if ProcessF and (Length(Result)>0) and (Result[Length(Result)]='F') then Delete(Result,Length(Result),1);
end;
// 处理由CMGR的短消息
function TSMSComm.ProcessSMSItemByCMGR(const Msg: string; const Index: Integer; var aSMSItem: TSMSItem): Boolean;
var
Index1, Index2, Position: integer;
TmpStr, TmpStr1: string;
begin
//'+CMGR: 0,,23'#$D#$A'0891683108701305F0040BA13116470960F4000850601232331220044F60597D'#$D#$A'0'#$D
Result := False;
FillChar(aSMSItem, SizeOf(TSMSItem), 0);
//第1步 获取消息的状态 +CMGR: 0,,23'#$D#$A 状态为0
Index1 := Pos(': ', Msg); Index2 := Pos(',', Msg);
if (Index1=0) or (Index2=0) then Exit;
TmpStr := Copy(Msg, Index1+2, Index2-Index1-2);
aSMSItem.SMSState := csNone;
case StrToInt(TmpStr) of
0: aSMSItem.SMSState := csRecUnRead;
1: aSMSItem.SMSState := csRecRead;
2: aSMSItem.SMSState := csStoUnSend;
3: aSMSItem.SMSState := csStoSend;
end;
//第2步 获取消息的长度 +CMGR: 0,,23'#$D#$A 长度为23
Index1 := Pos(',,', Msg); Index2 := Pos(#$0D#$0A, Msg);
if (Index1=0) or (Index2=0) then Exit;
TmpStr := Copy(Msg, Index1+2, Index2-Index1-2);
Position := Index2+2;
//第4步 抽取短信中心号码 例如0891683108701305F0
TmpStr1 := Copy(Msg, Position, 2);
TmpStr := Copy(Msg, Position+2, 2*StrToInt(TmpStr1));
aSMSItem.SCA := DecodeSCA(TmpStr, True);
Position := Position + 2 + 2*StrToInt(TmpStr1);
//第5步 处理FirstOctet一个字节
Position := Position + 2;
//第3步 抽取来电号码 例如:小灵通 0EA101061754637551 手机 BA13116470960F4
//同时可能还有另外一种格式 如:0D91683188902848F4
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
if (Index1 mod 2) = 1 then Index2 := Index1+3
else Index2 := Index1+2;
TmpStr := Copy(Msg, Position+2, Index2);
aSMSItem.SourPhone := DecodeSourPhone(TmpStr, True);
Position := Position + 2 + Index2;
//第6步 处理协议标识和编码方式两个字节 0008 08标识unicode编码
HexStrToInt(Copy(Msg, Position +2, 2), Cardinal(Index1));
case Index1 of
8: aSMSItem.CodedType := esUnicode;
4: aSMSItem.CodedType := esEightBit;
0,$F0..$F4: aSMSItem.CodedType := esSevenBit;
else
Exit;
end;
Position := Position + 4;
//第7步 处理7个字节的时间 50601232331220 05/06/21/ 23:33:21最有一个字节为时区
TmpStr := Copy(Msg, Position, 12);
TmpStr1 := '';
for Index1:=1 to 6 do TmpStr1 := TmpStr1 + TmpStr[Index1*2] + TmpStr[2*Index1-1];
Insert('-', TmpStr1,3); Insert('-',TmpStr1,6);
Insert(' ',TmpStr1,9);
Insert(':',TmpStr1,12); Insert(':',TmpStr1,15);
TryStrToDateTime(TmpStr1, aSMSItem.SMSTime);
// Result.SMSTime := StrToDateTime(TmpStr1);
Position := Position + 14;
//第8步 处理PUD格式的用户数据
if aSMSItem.CodedType = esSevenBit then begin
// 162858100683D96037580C0683C56030180C264C01 第1个字节为16进制长度(即十进制22)
// 但后面的实际字节数为20,这时因为用7bit编码时,每8个字节压缩为7字节,而22表示
// 的是实际解码后的字节数
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
Index1 := Index1 - (Index1 div 8);
TmpStr1 := Copy(Msg, Position+2, 2*Index1);
SetLength(TmpStr, Index1);
HexToBin(PChar(TmpStr1),PChar(TmpStr),Index1);
aSMSItem.Msg := DecodeSevenBit(TmpStr);
end
else begin
// 044F60597D 第1个字节为16进制长度,该字节表示的实际的字节数
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
TmpStr := Copy(Msg, Position+2, 2*Index1);
if aSMSItem.CodedType = esUnicode then aSMSItem.Msg := DecodeChinese(TmpStr)
else aSMSItem.Msg := TmpStr;
end;
Result := True;
end;
// 处理由CMGL的短消息
function TSMSComm.ProcessSMSItemByCMGL(const Msg: string; var aSMSItem: TSMSItem): Boolean;
var
Index1, Index2, Position: integer;
TmpStr, TmpStr1: string;
begin
//+CMGL: 1,1,,38'#$D#$A'0891683108200705F0240EA101061754637551000850608132808320124F60597D00214F60662F90A34F4D554A003F
Result := False;
FillChar(aSMSItem, SizeOf(TSMSItem), 0);
//第1步 获取消息的序号 +CMGL: 1,1,,38#$0D#$0A
Index1 := Pos(': ', Msg); Index2 := Pos(',', Msg);
if (Index1=0) or (Index2=0) then Exit;
TmpStr := Copy(Msg, Index1+2, Index2-Index1-2);
aSMSItem.SerialNo := StrToInt(TmpStr);
//第2步 获取消息的状态 +CMGL: 1,1,,38#$0D#$0A
Index1 := Pos(',', Msg); Index2 := Pos(',,', Msg);
if (Index1=0) or (Index2=0) then Exit;
TmpStr := Copy(Msg, Index1+1, Index2-Index1-1);
aSMSItem.SMSState := csNone;
case StrToInt(TmpStr) of
0: aSMSItem.SMSState := csRecUnRead;
1: aSMSItem.SMSState := csRecRead;
2: aSMSItem.SMSState := csStoUnSend;
3: aSMSItem.SMSState := csStoSend;
end;
//第3步 获取消息的长度 +CMGL: 1,1,,38#$0D#$0A
Index1 := Pos(',,', Msg); Index2 := Pos(#$0D#$0A, Msg);
if (Index1=0) or (Index2=0) then Exit;
TmpStr := Copy(Msg, Index1+2, Index2-Index1-2);
Position := Index2+2;
//第4步 抽取短信中心号码 例如0891683108200705F0
TmpStr1 := Copy(Msg, Position, 2);
TmpStr := Copy(Msg, Position+2, 2*StrToInt(TmpStr1));
aSMSItem.SCA := DecodeSCA(TmpStr, True);
Position := Position + 2 + 2*StrToInt(TmpStr1);
//第5步 处理FirstOctet一个字节
Position := Position + 2;
//第6步 抽取来电号码 例如:小灵通 0EA101061754637551 手机 0BA13175841540F6
//同时可能还有另外一种格式 如:0D91683188902848F4
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
if (Index1 mod 2) = 1 then Index2 := Index1+3
else Index2 := Index1+2;
TmpStr := Copy(Msg, Position+2, Index2);
aSMSItem.SourPhone := DecodeSourPhone(TmpStr, True);
Position := Position + 2 + Index2;
//第7步 处理协议标识和编码方式两个字节 0008 08标识unicode编码
HexStrToInt(Copy(Msg, Position+2, 2), Cardinal(Index1));
case Index1 of
8: aSMSItem.CodedType := esUnicode;
4: aSMSItem.CodedType := esEightBit;
0, $F0..$F4: aSMSItem.CodedType := esSevenBit;
else
Exit;
end;
Position := Position + 4;
//第8步 处理7个字节的时间 50608132808320 05/06/18/ 23:08:38最有一个字节为时区
TmpStr := Copy(Msg, Position, 12);
TmpStr1 := '';
for Index1:=1 to 6 do TmpStr1 := TmpStr1 + TmpStr[Index1*2] + TmpStr[2*Index1-1];
Insert('-', TmpStr1,3); Insert('-',TmpStr1,6);
Insert(' ',TmpStr1,9);
Insert(':',TmpStr1,12); Insert(':',TmpStr1,15);
TryStrToDateTime(TmpStr1, aSMSItem.SMSTime);
// aSMSItem.SMSTime := StrToDateTime(TmpStr1);
Position := Position + 14;
//第9步 处理PUD格式的用户数据
if aSMSItem.CodedType = esSevenBit then begin
// 162858100683D96037580C0683C56030180C264C01 第1个字节为16进制长度(即十进制22)
// 但后面的实际字节数为20,这时因为用7bit编码时,每8个字节压缩为7字节,而22表示
// 的是实际解码后的字节数
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
Index1 := Index1 - (Index1 div 8);
TmpStr1 := Copy(Msg, Position+2, 2*Index1);
SetLength(TmpStr, Index1);
HexToBin(PChar(TmpStr1),PChar(TmpStr),Index1);
aSMSItem.Msg := DecodeSevenBit(TmpStr);
end
else begin
// 044F60597D 第1个字节为16进制长度,该字节表示的实际的字节数
TmpStr := Copy(Msg, Position, 2);
Index1 := StrToInt('$'+TmpStr);
TmpStr := Copy(Msg, Position+2, 2*Index1);
if aSMSItem.CodedType = esUnicode then aSMSItem.Msg := DecodeChinese(TmpStr)
else aSMSItem.Msg := TmpStr;
end;
Result := True;
end;
// 分选短信
procedure TSMSComm.FilterSMS(Msg: string);
const
Separator = '+CMGL';
var
Index1, Index2, TotalLen: integer;
TmpStr: string;
aSMSItem: TSMSItem;
begin
TotalLen := Length(Msg);
Index1 := 1;
while Index1>0 do begin
Index1 := Pos(Separator, Msg);
if Index1>0 then begin
TmpStr := Copy(Msg, Index1+Length(Separator), TotalLen);
Index2 := Pos(Separator, TmpStr);
if Index2>0 then begin
TmpStr := Copy(Msg, Index1, Index2+Length(Separator)-1);
Msg := Copy(Msg, Index1+Index2+Length(Separator)-1, TotalLen);
end
else begin
TmpStr := Copy(Msg, Index1, TotalLen);
Msg := '';
end;
if ProcessSMSItemByCMGL(TmpStr, aSMSItem) then begin
if aSMSItem.SMSState = csRecUnRead then DoReceive(aSMSItem);
_GSM_AT_CMGD(aSMSItem.SerialNo);
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -