📄 txmobile.~pas
字号:
// 作 者 : 王建东
// 创建时间 : 2003-9-26
// 备 注 : TMobile类用于接入西门子手机
unit TXMobile;
interface
uses
SyncObjs,Windows,SysUtils,Outputunit,Dialogs;
const
ReceiveBufLength = 200 ;
ReadBufLength = 4000 ; // 读出缓冲大小
type
TReceiveMsg = Record //接收短信记录类型
dtReceiveTime : TDatetime;
strSourceMobile : String ;
strContent : String ;
nIndex : Integer ;
end;
TReceiveBuf = Array [0.. ReceiveBufLength -1 ] of TReceiveMsg ;
TReadBuf = Array [0..ReadBufLength -1] of Char; // 读的缓冲区数组类型
TMobile = Class
constructor Create ;
public
function OpenComm( strComName : string ) : Boolean ; // 打开端口
procedure CloseComm ; // 关闭端口
function SetDCB( DCB1 : TDCB ) : Boolean;
function GetDCB : TDCB ;
procedure SetSCA( _SCA : String ) ;
function SendMsg(strTargetMobile : String ; strContent : string ) : Boolean ;
function ReceiveMessage( var ReceiveBuf : TReceiveBuf ) : Integer ; // 返回接收的个数
function TestAtCommand( AtCommand : String ) : String;
function ReadBuf : Ansistring;
protected
// 与串口通信有关的变量
DCB : TDCB ; // 串口通信参数设置
CommTimeOut : TCOMMTIMEOUTS ; // 读写时延设置
WriteEndEvent,ReadEndEvent : TEvent; // WriteEndEvent 写完事件,ReadEndEvent 读完事件
CommHandle : THandle ;
bConnected : Boolean;
//以下为短信相关资料
strSMAddress : String ; // 短信中心地址
strTypeOfSCA : String ; // 短信中心地址类型
strTypeOfOA : String ; // 被叫号码的类型
function GetMsg(var MsgBuf : TReadBuf ): TReceiveMsg ; // 从pdu短信报文取出短信
function ConvertPhoneNum(strNum:string):string ; // 反转手机号码
function MakePDU(DestNumber,Content,SCAddress:String; // 产生PDU报文
Result_String:pchar ; var LenOfSCA : DWORD ):Bool ;
function SMSEncode(s:WideString;Result_Code:pchar):Bool ;
function ConvertDeliverAddress(strAddress : string ) : String;
end;
implementation
uses
IniFiles;
constructor TMobile.Create ;
var
IniFile : TIniFile ;
begin
// 读入硬件通信参数
IniFile := TIniFile.Create(GetCurrentDir + '\Mobile.ini');
self.DCB.BaudRate := IniFile.ReadInteger('Siemens','DCB_BaudRate',9600);
self.DCB.ByteSize := IniFile.ReadInteger('Siemens','DCB_ByteSize',8);
self.DCB.Parity := IniFile.ReadInteger('Siemens','DCB_Parity',0);
self.DCB.StopBits := IniFile.ReadInteger('Siemens','DCB_StopBits',0);
self.CommTimeOut.ReadIntervalTimeout := 0;
self.CommTimeOut.ReadTotalTimeoutMultiplier := 0 ;
self.CommTimeOut.ReadTotalTimeoutConstant := IniFile.ReadInteger('Siemens','ReadTimeoutConstant',3000);
self.CommTimeOut.WriteTotalTimeoutMultiplier:= 0 ;
self.CommTimeOut.WriteTotalTimeoutConstant := IniFile.ReadInteger('Siemens','WriteTimeoutContant',3000);
WriteEndEvent := TEvent.Create(nil,True,False,'WriteEnd');
ReadEndEvent := TEvent.Create(nil,True,False,'ReadEnd');
// 读入PDU报文相关信息
self.strSMAddress := Trim(IniFile.ReadString('SendModule1','SCA','8613800759500'));
self.strTypeOfSCA := Trim(IniFile.ReadString('SendModule1','TypeOfSCA','91'));
self.strTypeOfOA := Trim(self.strTypeOfSCA);
self.bConnected := FALSE;
end;
function TMobile.OpenComm( strComName : string ) : Boolean ;
var
DCB1 : TDCB;
fRetVal : Boolean;
begin
CommHandle := CreateFile(PChar(strComName),
GENERIC_READ or GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0);
if CommHandle = INVALID_HANDLE_VALUE then
begin
Result := FALSE; // ('GPS串口连接失败');
exit;
end;
SetCommTimeouts(CommHandle, CommTimeOut);
GetCommState(CommHandle,DCB1);
DCB1.BaudRate := DCB.BaudRate ; // 播特率
DCB1.ByteSize := DCB.ByteSize ; // 数据位
DCB1.Parity := NoParity ; // 奇偶校验
DCB1.StopBits := DCB.StopBits ; // 停止位
DCB := DCB1;
fRetVal := SetCommState(CommHandle, DCB);
if (fRetVal) then
bConnected := TRUE
else
begin
Result := False;
bConnected := FALSE;
CloseHandle(CommHandle);
Exit;
end;
Result := True;
end;
procedure TMobile.CloseComm ;
begin
try
CloseHandle(self.CommHandle);
bConnected := False;
except
on EExternalException do WriteDbg('TMobile.CloseComm -- 关闭失败 ');
end;
end;
function TMobile.SendMsg(strTargetMobile : String ;
strContent : string ) : Boolean ;
var
Buf : TReadBuf ;
PDUCode : AnsiString;
nLen,nWriteRet,nReadRet,nCodeLen,nLenOfSCA : DWord;
str1,strRet : string;
Overlapped: TOverlapped ;
bRet : Boolean;
begin
WriteDbg('TMobile.SendMsg -- In ');
FillChar(Buf,ReadBufLength,0);
if MakePDU(strTargetMobile,strContent,strSMAddress,Buf,nLenOfSCA ) = True then
begin
PDUCode := strpas(buf);
nCodeLen := (Length(PDUCode) div 2)- nLenOfSCA -1 ; // 长度要除去短信中心号码长度
end
else
begin
Result := False;
Exit;
end;
// 写入AT+CMGS 命令
WriteDbg('SendMsg : 写入AT+CMGS 命令 ' );
str1 := 'AT+CMGS=' + IntToStr(nCodeLen)+ #13;
nLen := Length(str1);
FillChar(Buf,ReadBufLength,0);
StrPCopy(Buf,str1);
Overlapped.hEvent := WriteEndEvent.Handle;
WriteEndEvent.ResetEvent ;
WriteFile(CommHandle,Buf,nLen,nWriteRet,@Overlapped);
bRet := GetOverlappedResult(CommHandle,Overlapped,nWriteRet,True);
if ( nLen <> nWriteRet ) then // 写入长度不对
begin
WriteDbg('SendMsg : 写入长度不对 ... ');
Result := FALSE;
Exit;
end;
if ( bRet = False ) then // 调用GetOverlappedResult 失败
begin
WriteDbg('SendMsg : 调用GetOverlappedResult 失败');
Result := FALSE ;
Exit;
end;
WriteEndEvent.ResetEvent ;
// 读出写入命令结果
WriteDbg('SendMsg : 读出写入命令结果 ' );
Overlapped.hEvent := self.ReadEndEvent.Handle;
ReadEndEvent.ResetEvent;
FillChar(Buf,ReadBufLength,0);
ReadFile(CommHandle,Buf,1000,nReadRet,@Overlapped);
bRet := GetOverlappedResult(CommHandle,Overlapped,nReadRet,True);
if ( bRet = False ) then
begin
WriteDbg('TMobile.SendMsg -- 调用GetOverlappedResult 失败');
Result := FALSE;
Exit;
end;
ReadEndEvent.ResetEvent ;
WriteDbg('读出写入命令结果 = ' + strpas(Buf)) ;
// 写入PDU编码
WriteDbg('SendMsg : 写入PDU编码 -- ' + PDUCode );
str1 := PDUCode + #26;
nLen := Length(str1);
FillChar(Buf,ReadBufLength,0);
StrPCopy(Buf,str1);
Overlapped.hEvent := WriteEndEvent.Handle;
WriteEndEvent.ResetEvent ;
WriteFile(CommHandle,Buf,nLen,nWriteRet,@Overlapped);
bRet := GetOverlappedResult(CommHandle,Overlapped,nWriteRet,True);
if ( bRet = False ) then
begin
Result := FALSE;
Exit;
end;
FillChar(Buf,ReadBufLength-1,0);
WriteEndEvent.ResetEvent ;
// 读出写入PDU编码结果
WriteDbg('TMobile.SendMsg -- 读出写入PDU编码结果 ' );
Overlapped.hEvent := self.ReadEndEvent.Handle;
ReadEndEvent.ResetEvent;
FillChar(Buf,ReadBufLength,0);
ReadFile(CommHandle,Buf,1000,nReadRet,@Overlapped);
bRet := GetOverlappedResult(CommHandle,Overlapped,nReadRet,True);
if ( bRet = False ) then
begin
Result := FALSE; // GetOverlappedResult 调用失败 !');
Exit;
end;
ReadEndEvent.ResetEvent ;
WriteDbg('TMobile.SendMsg -- 读出写入PDU编码结果 Content:' + StrPas(Buf) +
',Length :' + IntToStr(nReadRet) );
// 读出发送结果
ReadEndEvent.ResetEvent;
FillChar(Buf,ReadBufLength,0);
ReadFile(CommHandle,Buf,1000,nReadRet,@Overlapped);
bRet := GetOverlappedResult(CommHandle,Overlapped,nReadRet,True);
if ( bRet = False ) then
begin
Result := FALSE; // GetOverlappedResult 调用失败 !');
Exit;
end;
ReadEndEvent.ResetEvent ;
WriteDbg('TMobile.SendMsg -- 读出发送结果 Content:' + StrPas(Buf) +',Length :' + IntToStr(nReadRet) );
strRet := Copy(buf,3,5) ;
if ( strRet = '+CMGS') then
begin
Result := True ;
WriteDbg('TMobile.SendMsg -- Succeed to Send ||'+ strRet);
end
else
begin
Result := FALSE;
WriteDbg('TMobile.SendMsg -- Fail to Send ||'+strRet);
end;
WriteDbg('TMobile.SendMsg -- Out ');
end;
function TMobile.GetMsg(var MsgBuf : TReadBuf ): TReceiveMsg ;
var
i,j,z,k,nOctetNum,nSCALen,nFirstOctetPos,nAddressFieldLen,
nDataLen,nPIDPos,nIndexEnd : Integer ;
nDCS,PreByte,CurByte: Byte ; // 编码方式
strLen,strAddressFieldLen,strDCS,strDataLen,strData,
str1,strIndex: string ;
DataBuf : Array [0..3000] of char ;
wc : WideChar ;
dw,nAddrTail : DWord ;
begin
// showmessage(strpas(msgbuf));
i:= 0 ;
while ( i<= 100 ) do // 求短信的索引号
if MsgBuf[i] = ',' then
break
else
Inc(i,1);
nIndexEnd := i -1 ;
if nIndexEnd >= 7 then
begin
strIndex := '';
for i:= 7 to nIndexEnd do
strIndex := strIndex + MsgBuf[i];
Result.nIndex := StrToInt(strIndex);
end
else
begin
Result.nIndex := -1 ;
end;
i:= 0;
while ( i<= 3000 ) do
if MsgBuf[i] = #13 then
Break
else
Inc(i,1);
Inc(i,1);
strLen := MsgBuf[i+1] +MsgBuf[i+2];
nSCALen := StrToInt('$'+strLen);
nFirstOctetPos := i + 2 + nSCALen * 2 + 1 ; // 文件头位置
strAddressFieldLen := MsgBuf[nFirstOctetPos + 2] + MsgBuf[nFirstOctetPos+3];
nAddressFieldLen := StrToInt('$'+strAddressFieldLen);
if nAddressFieldLen > 2 then
begin
Result.strSourceMobile := '';
if ( nAddressFieldLen mod 2 = 0 ) then
nAddrTail := 0
else
nAddrTail := 1 ;
for j:= nFirstOctetPos + 6 to nFirstOctetPos + 6 +nAddressFieldLen -1 + nAddrTail do
Result.strSourceMobile := Result.strSourceMobile + MsgBuf[j];
Result.strSourceMobile := ConvertDeliverAddress(Result.strSourceMobile);
end
else
Result.strSourceMobile := '5555';
if ( nAddressFieldLen mod 2 ) = 1 then
begin
strDCS := MsgBuf[nFirstOctetPos + 6 + nAddressFieldLen + 3 ]+
MsgBuf[nFirstOctetPos + 6 + nAddressFieldLen + 4 ];
nPIDPos := nFirstOctetPos + 6 + nAddressFieldLen +1 ;
end
else
begin
strDCS := MsgBuf[nFirstOctetPos + 6 + nAddressFieldLen + 2 ]+
MsgBuf[nFirstOctetPos + 6 + nAddressFieldLen + 3 ] ;
nPIDPos := nFirstOctetPos + 6 + nAddressFieldLen ;
end;
strDataLen := MsgBuf[nPIDPos + 18] + MsgBuf[nPIDPos + 19] ;
nDataLen := StrToInt('$'+strDataLen);
nDCS := StrToInt('$'+strDCS);
if ( nDCS and 12 ) = 8 then // 用于判断编码方式
begin
// unicode 编码 ( 16 bit)
FillChar(DataBuf,3001,0);
for j := 0 to nDataLen * 2 -1 do
DataBuf[j] := MsgBuf[j + nPIDPos + 20 ];
strData := '';
for J := 0 to nDataLen div 2 - 1 do
begin
str1:= DataBuf[j * 4 ]+DataBuf[j* 4 +1]+DataBuf[j* 4 +2]+
DataBuf[j* 4 +3];
dw := StrToInt('$'+str1);
wc := WideChar(dw);
strData := strData+ wc;
end;
end
else
if ( nDCS and 12 = 4 ) then // 8位编码规则
begin
FillChar(DataBuf,3001,0);
nOctetNum := nDataLen ;
for j:= 0 to nOctetNum - 1 do
DataBuf[j] := Chr( StrToInt('$' + MsgBuf[j*2+nPIDPos + 20] + MsgBuf[j*2 + nPIDPos + 20 + 1] ));
strData := '';
for j:=0 to nOctetNum -1 do
strData := strData + DataBuf[j] ;
end
else
if ( nDCS and 12 = 0 ) then // 7 位编码规则
begin
FillChar(DataBuf,3001,0);
if (( nDataLen * 7 ) mod 8 ) = 0 then
nOctetNum := nDataLen * 7 div 8
else
nOctetNum := nDataLen * 7 div 8 + 1 ;
For j:= 0 to nOctetNum -1 do // 取出用户数据
DataBuf[j] :=Chr(StrToInt('$'+MsgBuf[j*2+nPIDPos+20]+
MsgBuf[j*2+nPIDPos+20+1] ));
strData := '';
for j:= 0 to nOctetNum -1 do
begin
k := (j + 1) mod 7 ;
if ( k = 1 ) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -