📄 sms_pudunit.pas
字号:
// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
procChar := Byte(pSrc[i]);
tmpChar := (procChar shl (8 - nChar)) or nLeft;
fmtstr(s, '%2.2X', [tmpChar]);
pDst := pDst + s;
// 将该字节剩下的左边部分,作为残余数据保存起来
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -