📄 sms_pudunit.pas
字号:
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft := Byte(pSrc[i]) shr nChar;
// 修改目标串的指针和计数值 pDst++;
// nDst++;
end;
// 修改源串的指针和计数值
Inc(i);
Inc(nSrc);
end;
// 返回目标串
Result := pDst;
end;
// 7-bit解码
// pSrc: 源编码串指针
// nSrcLength: 源编码串长度
// 返回: 目标字符串
function gsmDecode7bit(pSrc:string; nSrcLength:Integer):string;
var
nSrc:Integer; // 源字符串的计数值
nByte:Integer; // 当前正在处理的组内字节的序号,范围是0-6
nLeft:Byte; // 上一字节残余的数据
tmpChar:Byte;
pDst:string;
begin
// 计数值初始化
nSrc := 1;
// 组内字节序号和残余数据初始化
nByte := 0;
nLeft := 0;
pdst := '';
// 将源数据每7个字节分为一组,解压缩成8个字节
// 循环该处理过程,直至源数据被处理完
// 如果分组不到7字节,也能正确处理
while (nSrc < nSrcLength) do
begin
tmpChar := byte(StrToInt('$' + pSrc[nsrc] + pSrc[nsrc + 1]));
// 将源字节右边部分与残余数据相加,去掉最高位,得到一个目标解码字节
pDst := pDst + Char(((tmpchar shl nByte) or nLeft) and $7F);
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft := tmpChar shr (7 - nByte);
// 修改字节计数值
Inc(nByte);
// 到了一组的最后一个字节
if (nByte = 7) then
begin
// 额外得到一个目标解码字节
pdst := pDst + Char(nLeft);
// 组内字节序号和残余数据初始化
nByte := 0;
nLeft := 0;
end;
// 修改源串的指针和计数值
nSrc := nSrc + 2;
end;
// 返回目标串长度
result := pdst;
end;
constructor TSMSPDUproc.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FCurrSMSIndex:=0;
FTP_DCS := tdUCS2;
FTP_DA := '';
FSMSC := '';
SetLength(Ftp_udbyte, 140);
FTP_UDStr := '';
FBaudRate := 4800;
SMScomm := TComm.Create(Self);
SMScomm.OnReceiveData := SMSReceiveData;
FActive := False;
CurrState := NORMAL;
OTTimer := TTimer.Create(Self);
OTTimer.Interval := 100;
OTTimer.OnTimer := OTTimerTimer;
end;
procedure TSMSPDUproc.DecodePUD(s: string);
var
smsclen,PhoneIDLen,InfoLen:integer;
tmp:string;
cpos:Integer;
mSMSC,mPhoneID,mInfo:string;
mGTime:TDateTime;
mType:TTP_DCS;
begin
mSMSC:='';
mPhoneID:='';
mInfo:='';
mType:=tdUCS2;
//08 地址信息的长度 个八位字节(包括91)
cpos:=1;
//消息中心长度
smsclen:=StrToInt('$'+MidStr(s,cpos,2));
//91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
//68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
if smsclen=0 then
cpos:=cpos+2
else
begin
cpos:=cpos+4; //略去91;
tmp:=MidStr(s,cpos,smsclen*2-2);
mSMSC:=ResumeOrder(tmp);
cpos:=cpos+smsclen*2-2;
end;
//84 基本参数(TP-MTI/MMS/RP) 接收,无更多消息,有回复地址
cpos:=cpos+2;
//0D 回复地址数字个数 共13个十进制数(不包括91和‘F’)
PhoneIDLen:=StrToInt('$'+MidStr(s,cpos,2));
if (PhoneIDLen mod 2)>0 then Inc(PhoneIDLen);
cpos:=cpos+2;
//91 回复地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
//68 31 58 81 27 64 F8 回复地址(TP-RA) 8613851872468,补‘F’凑成偶数个
if PhoneIDLen=0 then
cpos:=cpos+2
else
begin
cpos:=cpos+2;
tmp:=MidStr(s,cpos,PhoneIDLen);
mPhoneID:=ResumeOrder(tmp);
cpos:=cpos+PhoneIDLen;
end;
//00 协议标识(TP-PID) 是普通GSM类型,点到点方式
cpos:=cpos+2;
//08 用户信息编码方式(TP-DCS) UCS2编码
case StrToInt(MidStr(s,cpos,2)) of
0:
mType:= td7_Bit;
8:
mtype:=tdUCS2;
15:
mType:=td8_Bit;
end;
cpos:=cpos+2;
//30 30 21 80 63 54 80 时间戳(TP-SCTS) 2003-3-12 08:36:45 +8时区
tmp:=MidStr(s,cpos,14);
tmp:=ChangeLeftAndRight(tmp);
mGTime:=StrToDate(MidStr(tmp,1,2)+'-'+MidStr(tmp,3,2)+'-'+MidStr(tmp,5,2));
mGTime:=mGTime+ StrToTime(MidStr(tmp,7,2)+':'+MidStr(tmp,9,2)+':'+MidStr(tmp,11,2));
cpos:=cpos+14;
//06 用户信息长度(TP-UDL) 实际长度6个字节
InfoLen:=StrToInt('$'+MidStr(s,cpos,2));
cpos:=cpos+2;
//4F 60 59 7D 00 21 用户信息(TP-UD) “你好!”
if InfoLen>0 then
begin
tmp:=MidStr(s,cpos,InfoLen*2);
case mType of
td7_Bit:
mInfo:=gsmDecode7bit(tmp,InfoLen*2);
td8_Bit:
;
tdUCS2:
mInfo:=UniCodeToGB5(tmp);
end;
end;
if Assigned(fonReceiveSMS ) then
FOnReceiveSMS(Self,mSMSC,mPhoneID,mInfo,mGTime);
end;
destructor TSMSPDUproc.Destroy;
begin
SMScomm.Free;
inherited;
end;
/// <summary>
/// 取处理过后的PUD字符串
/// </summary>
/// <returns> PUD字符串 </returns>
function TSMSPDUproc.getPUDStr:string;
var
mPudStr:string;
tmp, s:string;
tmp2:PChar;
len:integer;
begin
len := Length(FSMSC);
//08 SMSC地址信息的长度 共8个八位字节(包括91)
//91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
//68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
if len > 0 then
begin
tmp := '91' + ChangeLeftAndRight(FSMSC);
len := Length(tmp) div 2;
end;
fmtstr(s, '%2.2D', [len]);
mPudStr := s + tmp;
//11 基本参数(TP-MTI/VFP) 发送,TP-VP用相对格式
//00 消息基准值(TP-MR) 0
mPudStr := mPudStr + '1100';
//0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
FmtStr(s, '%2.2X', [Length(FTP_DA)]);
//91 目标地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
//68 31 58 81 27 64 F8 目标地址(TP-DA) 8613851872468,补‘F’凑成偶数个
mPudStr := mPudStr + s + '91' + ChangeLeftAndRight(FTP_DA);
//00 协议标识(TP-PID) 是普通GSM类型,点到点方式
mPudStr := mPudStr + '00';
//00 用户信息编码方式(TP-DCS) 7-bit编码
//00 有效期(TP-VP) 5分钟
//06 用户信息长度(TP-UDL) 实际长度6个字节
//C8 32 9B FD 0E 01 用户信息(TP-UD) “Hello!”
case FTP_DCS of
td7_Bit:
begin
if Length(AnsiString(FTP_UDStr))>160 then
begin
GetMem(tmp2,160);
StrLCopy(tmp2,PAnsiChar(FTP_UDStr),160);
FTP_UDStr:=tmp2;
FreeMem(tmp2);
end;
mPudStr := mPudStr + '0000'; //tp-dcs + tp-vp
fmtstr(s, '%2.2X', [Length(FTP_UDStr)]);
mpudstr := mpudstr + s; //tp-udl
mpudstr := mpudstr + gsmEncode7bit(Ftp_udstr, Length(FTP_UDStr)); //tp-ud
end;
td8_Bit:
begin
mPudStr := mPudStr + '1500'; //tp-dcs + tp-vp
end;
tdUCS2:
begin
if Length(widestring(FTP_UDStr))>70 then
begin
GetMem(tmp2,140);
StrLCopy(tmp2,PAnsiChar(FTP_UDStr),140);
FTP_UDStr:=tmp2;
FreeMem(tmp2);
end;
mPudStr := mPudStr + '0800';
tmp := GB5ToUniCode(FTP_UDStr);
FmtStr(s, '%2.2X', [Length(tmp) div 2]);
mPudStr := mPudStr + s; //tp-udl
mPudStr := mPudStr + tmp;
end;
else
begin
mPudStr := mPudStr + '0800';
tmp := GB5ToUniCode(FTP_UDStr);
FmtStr(s, '%2.2X', [Length(tmp) div 2]);
mPudStr := mPudStr + s; //tp-udl
mPudStr := mPudStr + tmp;
end;
end;
if len > 0 then
FmtStr(FCMGSLen, '%3.3D', [Length(mPudStr) div 2 - len - 1])
else
FmtStr(FCMGSLen, '%3.3D', [Length(mPudStr) div 2 - 1]);
FPUDStr:=mPudStr;
Result := mPudStr;
end;
//初始化模块,发送ATE测试模块连接是否正常
procedure TSMSPDUproc.OTTimerTimer(Sender:TObject);
begin
Inc(tver);
if tver > 50 then //等待回码超时的处理
begin
tver := 0;
case CurrState of
NORMAL:
;
ATE:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('ate' + #$D);
end
else //超过3次报错
begin;
ReSendCount := 0;
OnError(Self,'ATE发送错误');
end;
end;
ATCMGF:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('at+cmgf=0' + #$D);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(Self,'AT+CMGF发送错误');
end;
end;
ATCNMI:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('at+cnmi=2,1,0,0,0' + #$D);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(Self,'AT+CNMI发送错误')
end;
end;
ATCMGS_1:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('at+cmgs='+ FCMGSLen +#$D);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(Self,'AT+CMGS_1发送错误');
end;
end;
ATCMGS_2:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm(FPUDStr+#$1A);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(self,'AT+CMGS_2发送错误');
end;
end;
ATCMGR:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('at+cmgr='+inttostr(FCurrSMSIndex)+#$D);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(self,'AT+CMGR发送错误');
end;
end;
ATCMGD:
begin
if ReSendCount < 2 then //重发次数少于3次
begin
sendStrToComm('at+cmgd='+inttostr(FCurrSMSIndex)+#$D);
end
else //超过3次报错
begin
ReSendCount := 0;
OnError(self,'AT+CMGD发送错误');
end;
end;
end;
OnError(Self,'通讯超时');
tver:=0;
OTTimer.Enabled:=False;
end;
end;
procedure TSMSPDUproc.resetSMS;
begin
CurrState := ATE;
ReSendCount := 0;
sendStrToComm('ate' + #$D);
end;
procedure TSMSPDUproc.SendSM;
begin
ReSendCount:=0;
getPUDStr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -