⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smscomm.pas

📁 短信二次开发控件SMSComm
💻 PAS
📖 第 1 页 / 共 5 页
字号:
        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 + -