2011-03-14 132 views
0

我需要在pdu模式下发送短消息。任何人都可以给我一个GSM 7位编码/解码算法?寻找GSM 7bit编码/解码算法

+0

我很困惑有多少地方使用GSM这个词。我知道GSM不仅指无线电调制解调器标准,还用于软件中,作为音频编解码器标准的名称。这是一种用于SMS消息的GSM相关协议? – 2011-03-14 20:22:57

+0

也看到:在这里输入链接的描述] [1] [1]:http://stackoverflow.com/questions/11489025/when-i-encode-decode-sms-pdu-gsm-7 -bit-user-data-do-i-need-prepend-the-udh-fi – 2012-12-19 09:00:40

回答

5

看看这对你是否有用。代码来自我的一个非常古老的项目 - 可以按你的意愿使用。

unit SMSCodec; 

interface 

const 
    //:Default 7-bit alphabet. 
    CPDU7bit = #10#13' !"#$&''()*+,-./:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 

type 
    {:Encoder result. 
    @enum esEncoded Message encoded successfully. 
    @enum esTruncated Message encoded successfully, but truncated because it was too long. 
    @enum esError  Error. 
    } 
    TEncoderStatus = (esEncoded, esTruncated, esError); 

    {:Decoder result. 
    @enum dsDecoded Message decoded successfully. 
    @enum dsError  Error. 
    } 
    TDecoderStatus = (dsDecoded, dsError); 

    {:Message format. 
    @enum mf0340 ETS 300 901 (GSM 03.40) 
    @enum mf0705 GSM 07.05 
    } 
    TMessageFormat = (mf0340, mf0705); 

    {:Message Type 
    } 
    TMessageType = (mtSMSDeliver, mtSMSDeliverReport, mtSMSSubmitReport, 
    mtSMSSubmit, mtSMSStatusReport, mtSMSCommand, mtReserved); 

    {:TP-Status major information. 
    } 
    TTPStatusMajor = (tpsmDelivered, tpsmTemporaryError, tpsmPermanentError, 
    tpsmReserved); 

    {:TP-Status detailed information. 
    } 
    TTPStatusDetailed = (
    // tpsmDelivered 
    tpsdReceived,     // Short message received by the SME 
    tpsdForwardedNotConfirmed,  // Short message forwarded by the SC to the SME but the SC is unable to confirm delivery 
    tpsdReplaced,     // Short message replaced by the SC 
    // tpsmTemporaryError 
    tpsdCongestion,     // Congestion 
    tpsdSMEBusy,      // SME busy 
    tpsdNoResponseFromSME,   // No response from SME 
    tpsdServiceRejected,    // Service rejected 
    tpsdErrorInSME,     // Error in SME 
    // tpsmPermanentError 
    tpsdRemoteProcedureError,  // Remote procedure error 
    tpsdIncompatibleDestination,  // Incompatible destination 
    tpsdConnectionRejectedBySME,  // Connection rejected by SME 
    tpsdNotObtainable,    // Not obtainable 
    tpsdNoInternetworkingAvailable, // No interworking available 
    tpsdSMValitidyPerionExpired,  // SM Validity Period Expired 
    tpsdSMDeletedByOriginatingSME, // SM Deleted by originating SME 
    tpsdSMDeletedBySCAdministration, // SM Deleted by SC Administration 
    tpsdSMDoesNotExist,    // SM does not exist (The SM may have previously existed in the SC but the SC no longer has knowledge of it or the SM may never have previously existed in the SC) 
    // tpsmTemporaryError and tpsmPermanentError 
    tpsdQOSNotAvailable,    // Quality of service not available 
    // all major classes 
    tpsdReserved 
); 

    {:Decoded TP-Status, as specified in ETSI GSM 03.40 specification, 9.2.3.15 
    } 
    TTPStatus = record 
    tpsMajor  : TTPStatusMajor; 
    tpsWillContinue : boolean; 
    tpsDetailed  : TTPStatusDetailed; 
    tpsOriginal  : byte; 
    end; 

    {:Decoded message 
    } 
    TSMSDecodedMessage = record 
    sdcOriginalMessage : string; 
    sdcMessageType  : TMessageType; 
             // Set if sdcMessageType = 
    sdcSMSCenterNumber : string;  // * 
    sdcNumber   : string;  // mtSMSDeliver, mtSMSSubmit 
    sdcShortMessage : string;  // mtSMSDeliver, mtSMSSubmit 
    sdcValidityMinutes : integer;  // mtSMSSubmit 
    sdcRequestReport : boolean;  // mtSMSSubmit 
    sdcMessageReference: byte;   // mtSMSSubmit, mtSMSStatusReport 
    sdcRecipientAddress: string;  // mtSMSStatusReport 
    sdcSCTimeStamp  : TDateTime;  // mtSMSStatusReport 
    sdcDischargeTime : TDateTime;  // mtSMSStatusReport 
    sdcStatus   : TTPStatus;  // mtSMSStatusReport 
    sdcMessageFormat : TMessageFormat;// mtSMSDeliver, mtSMSStatusReport 
    sdcFFPadded  : boolean;  // mtSMSDeliver, mtSMSStatusReport 
    end; 

    {:SMS PDU coder/decoder. 
    } 
    TSMSCodec = class 
    private 
    tbl7bit: array [char] of byte; 
    tbl8bit: array [byte] of char; 
    procedure Create7bitLookupTable; 
    function Decode7bitText(var pdu: string; txtLen: byte; var decoded: boolean): string; 
    function DecodeDischargeTime(dtime: string): TDateTime; 
    function DecodeNumber(var pdu: string; countOctets: boolean; var decoded: boolean): string; 
    function DecodeTimeStamp(tstamp: string): TDateTime; 
    function DecodeTPStatus(status: string): TTPStatus; 
    function Encode7bitText(txt: string; maxLen: byte; var truncated: boolean): string; 
    function EncodeNumber(num: string; countOctets: boolean): string; 
    function EncodeTP_VP(validityMin: integer): string; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    function DecodeMessage(PDUMessage: string; 
     var DecodedMessage: TSMSDecodedMessage): TDecoderStatus; 
    function EncodeMessage(smsMessage: TSMSDecodedMessage; 
     var PDUMessage: string; var tpDataLen: integer): TEncoderStatus; 
    end; 

    function GetSMSDetailedErrorMessage(status: TTPStatusDetailed): string; 

implementation 

uses 
    SysUtils, 
    GpIFF, 
    Gp17String; 

resourcestring 
    SSmsDetailedErrReserved       = '(reserved)'; 
    SSmsDetailedErrCongestion      = 'Congestion'; 
    SSmsDetailedErrConnectionRejectedBySME   = 'Connection rejected by SME'; 
    SSmsDetailedErrErrorInSME      = 'Error in SME'; 
    SSmsDetailedErrIncompatibleDestination   = 'Incompatible destination'; 
    SSmsDetailedErrMValidityPeriodExpired   = 'SM Validity Period Expired'; 
    SSmsDetailedErrNoInterworkingAvailable   = 'No interworking available'; 
    SSmsDetailedErrNoResponseFromSME     = 'No response from SME'; 
    SSmsDetailedErrNotObtainable      = 'Not obtainable'; 
    SSmsDetailedErrQualityOfServiceNotAvailable  = 'Quality of service not available'; 
    SSmsDetailedErrRemoteProcedureError    = 'Remote procedure error'; 
    SSmsDetailedErrServiceRejected     = 'Service rejected'; 
    SSmsDetailedErrShortMessageForwardedByTheSCtoThe = 'Short message forwarded by the SC to the SME but the SC is unable to confirm delivery'; 
    SSmsDetailedErrShortMessageReceivedByTheSME  = 'Short message received by the SME'; 
    SSmsDetailedErrShortMessageReplacedByTheSC  = 'Short message replaced by the SC'; 
    SSmsDetailedErrSMDeletedByOriginatingSME   = 'SM Deleted by originating SME'; 
    SSmsDetailedErrSMDeletedBySCAdministration  = 'SM Deleted by SC Administration'; 
    SSmsDetailedErrSMdoesNotExist     = 'SM does not exist (The SM may have previously existed in the SC but the SC no longer has knowledge of it or the SM may never have previously existed in the SC)'; 
    SSmsDetailedErrSMEbusy       = 'SME busy'; 
    SSmsDetailedErrSMValidityPeriodExpired   = 'SM validity period expired'; 

    function GetSMSDetailedErrorMessage(status: TTPStatusDetailed): string; 
    begin 
    case status of 
     tpsdReceived:     Result := SSmsDetailedErrShortMessageReceivedByTheSME; 
     tpsdForwardedNotConfirmed:  Result := SSmsDetailedErrShortMessageForwardedByTheSCtoThe; 
     tpsdReplaced:     Result := SSmsDetailedErrShortMessageReplacedByTheSC; 
     tpsdCongestion:     Result := SSmsDetailedErrCongestion; 
     tpsdSMEBusy:      Result := SSmsDetailedErrSMEbusy; 
     tpsdNoResponseFromSME:   Result := SSmsDetailedErrNoResponseFromSME; 
     tpsdServiceRejected:    Result := SSmsDetailedErrServiceRejected; 
     tpsdErrorInSME:     Result := SSmsDetailedErrErrorInSME; 
     tpsdRemoteProcedureError:  Result := SSmsDetailedErrRemoteProcedureError; 
     tpsdIncompatibleDestination:  Result := SSmsDetailedErrIncompatibleDestination; 
     tpsdConnectionRejectedBySME:  Result := SSmsDetailedErrConnectionRejectedBySME; 
     tpsdNotObtainable:    Result := SSmsDetailedErrNotObtainable; 
     tpsdNoInternetworkingAvailable: Result := SSmsDetailedErrNoInterworkingAvailable; 
     tpsdSMValitidyPerionExpired:  Result := SSmsDetailedErrSMValidityPeriodExpired; 
     tpsdSMDeletedByOriginatingSME: Result := SSmsDetailedErrSMDeletedByOriginatingSME; 
     tpsdSMDeletedBySCAdministration: Result := SSmsDetailedErrSMDeletedBySCAdministration; 
     tpsdSMDoesNotExist:    Result := SSmsDetailedErrSMdoesNotExist; 
     tpsdQOSNotAvailable:    Result := SSmsDetailedErrQualityOfServiceNotAvailable; 
     else        Result := SSmsDetailedErrReserved; 
    end; //case 
    end; 

{ TSMSCodec } 

{: TSMSCodec constructor. Prepares lookup table for character conversion. 
} 
constructor TSMSCodec.Create; 
begin 
    inherited; 
    Create7bitLookupTable; 
end; 

{:Creates lookup table to convert from 8-bit to 7-bit character codes. 
} 
procedure TSMSCodec.Create7bitLookupTable; 
var 
    b : byte; 
    i : integer; 
    ch: char; 
const 
    eqlASCII : string = CPDU7bit; 
begin 
    // TODO 1 -oPrimoz Gabrijelcic: Incomplete: all Greek characters and umlauts are missing 
    for ch := Low(tbl7bit) to High(tbl7bit) do 
    tbl7bit[ch] := $20; // space 
    for i := 1 to Length(eqlASCII) do 
    tbl7bit[eqlASCII[i]] := Ord(eqlASCII[i]); 
    tbl7bit['@'] := $00; 
    tbl7bit['$'] := $02; 

    for b := Low(tbl8bit) to High(tbl8bit) do 
    tbl8bit[b] := ' '; 
    for ch := Low(tbl7bit) to High(tbl7bit) do 
    if tbl7bit[ch] <> $20 then 
     tbl8bit[tbl7bit[ch]] := ch; 
end; 

{:Decodes 7-bit "packed" form (coded in hexadecimal - as received in PDU SMS) 
    into 8-bit text. 
    @param pdu  Hexadecimal representation of packed form. 
    @param txtLen Length of unpacked string. 
    @param decoded True if decoded successfully. 
    @returns Unpacked string. 
} 
function TSMSCodec.Decode7bitText(var pdu: string; txtLen: byte; 
    var decoded: boolean): string; 
var 
    by : byte; 
    currBy: byte; 
    i  : integer; 
    left : byte; 
    mask : byte; 
    nextBy: byte; 
begin 
    decoded := false; 
    Result := ''; 
    left := 7; 
    mask := $7F; 
    nextBy := 0; 
    for i := 1 to txtLen do begin 
    if mask = 0 then begin 
     Result := Result + tbl8bit[nextBy]; 
     left := 7; 
     mask := $7F; 
     nextBy := 0; 
    end 
    else begin 
     if pdu = '' then Exit; 
     by := StrToInt('$'+Copy(pdu,1,2)); Delete(pdu,1,2); 
     currBy := ((by AND mask) SHL (7-left)) OR nextBy; 
     nextBy := (by AND (NOT mask)) shr left; 
     Result := Result + tbl8bit[currBy]; 
     mask := mask SHR 1; 
     left := left-1; 
    end; 
    end; //for 
    decoded := true; 
end; 

{:Decodes 7-byte discharge time. 
    @param dtime Discharge time in hexadecimal form (0340530S.PDF, 9.2.3.13). 
    @returns Decoded discharge time. 
    @since 2000-09-05 (1.02) 
} 
function TSMSCodec.DecodeDischargeTime(dtime: string): TDateTime; 
begin 
    Result := DecodeTimestamp(dtime); 
end; 

{:Decodes PDU message. Most flags are ignored. 
    @param PDUMessage  Encoded message, represented in hexadecimal form (as received from GSM 07.05 device). 
    @param DecodedMessage (out) Decoded message. 
    @returns Error status. 
} 
function TSMSCodec.DecodeMessage(PDUMessage: string; 
    var DecodedMessage: TSMSDecodedMessage): TDecoderStatus; 

    // Mobitel (293 41) sometimes pads PDU with FF bytes up to maximum length - 
    // this function detects this condition. It is called with unparsed part of 
    // PDU as parameter. This parameter should be empty or at least contain only 
    // 'F' characters. 
    function AllFF(s: string): boolean; 
    var 
    iCh: integer; 
    begin 
    Result := false; 
    for iCh := 1 to Length(s) do 
     if s[iCh] <> 'F' then 
     Exit; 
    Result := true; 
    end; 

var 
    decoded : boolean; 
    origPDU : string; 
    PDUtype : byte; 
    UDL  : byte; 
    workaround: boolean; 
// DCS  : byte; 
// PID  : byte; 
// SCTC : int64; 
begin 
    DecodedMessage.sdcMessageType := mtReserved; // not decoded 
    DecodedMessage.sdcOriginalMessage := PDUMessage; 
    DecodedMessage.sdcFFPadded := false; 
    Result := dsError; 
    origPDU := PDUMessage; 
    try 
    DecodedMessage.sdcMessageFormat := mf0340; 
    for workaround := false to true do begin 
     PDUMessage := origPDU; 
     if workaround then begin 
     // Try to detect whether message is in 03.40 format (without SMS Center 
     // Number) or in 07.05 format (with SMS Center Number). 
     DecodedMessage.sdcSMSCenterNumber := DecodeNumber(PDUMessage,true,decoded); 
     if not decoded then 
      Exit; 
     DecodedMessage.sdcMessageFormat := mf0705; 
     end; 
     PDUtype := StrToInt('$'+Copy(PDUMessage,1,2)); Delete(PDUMessage,1,2); 
     case PDUtype AND $03 of 
     0: DecodedMessage.sdcMessageType := mtSMSDeliver; 
     1: DecodedMessage.sdcMessageType := mtSMSSubmitReport; 
     2: DecodedMessage.sdcMessageType := mtSMSStatusReport; 
     3: DecodedMessage.sdcMessageType := mtReserved; 
     end; //case 
     if (not workaround) and (DecodedMessage.sdcMessageType = mtReserved) then 
     continue; // ??? maybe we are decoding PDU from not-completely-compliant telephone ??? 
     case DecodedMessage.sdcMessageType of 
     mtSMSDeliver: 
      begin 
      DecodedMessage.sdcNumber := DecodeNumber(PDUMessage,false,decoded); 
      if not decoded then 
       Exit; 
      {PID := StrToInt('$'+Copy(PDUMessage,1,2));} Delete(PDUMessage,1,2); 
      {DCS := StrToInt('$'+Copy(PDUMessage,1,2));} Delete(PDUMessage,1,2); 
      {SCTC := StrToInt64('$'+Copy(PDUMessage,1,14));} Delete(PDUMessage,1,14); 
      UDL := StrToInt('$'+Copy(PDUMessage,1,2)); Delete(PDUMessage,1,2); 
      DecodedMessage.sdcShortMessage := Decode7bitText(PDUMessage,UDL,decoded); 
      if not decoded then 
       if not workaround then 
       continue // ??? maybe we are decoding PDU from not-completely-compliant telephone ??? 
       else 
       Exit; 
      end; //mtSMSDeliver 
     mtSMSSubmitReport: 
      begin 
      // don't know how to decode, yet 
      if workaround then // if first way round, assume that we only tried the wrong approach 
       PDUMessage := ''; 
      end; //mtSMSSubmitReport 
     mtSMSStatusReport: 
      begin // 0340530S.PDF, 9.2.2.3 SMS-STATUS-REPORT type 
      DecodedMessage.sdcMessageReference := StrToInt('$'+Copy(PDUMessage,1,2)); Delete(PDUMessage,1,2); 
      DecodedMessage.sdcRecipientAddress := DecodeNumber(PDUMessage,false,decoded); 
      if not decoded then 
       Exit; 
      DecodedMessage.sdcSCTimeStamp := DecodeTimeStamp(Copy(PDUMessage,1,14)); Delete(PDUMessage,1,14); 
      DecodedMessage.sdcDischargeTime := DecodeDischargeTime(Copy(PDUMessage,1,14)); Delete(PDUMessage,1,14); 
      DecodedMessage.sdcStatus := DecodeTPStatus(Copy(PDUMessage,1,2)); Delete(PDUMessage,1,2); 
      end; //mtSMSStatusReport 
     mtReserved: 
      begin 
      // don't know how to decode - obviously 
      PDUMessage := ''; 
      end; //mtReserved 
     end; //case 
     if PDUMessage = '' then begin 
     Result := dsDecoded; 
     break; 
     end; 
     if AllFF(PDUMessage) then begin 
     DecodedMessage.sdcFFPadded := true; 
     Result := dsDecoded; 
     break; 
     end; 
    end; //for workaround 
    except 
    on EConvertError do ; 
    end; 
end; 

{:Decodes number by GSM standards. Understands two formats - prefixed with 
    number of bytes (if countOctets is set) or number of digits in original number. 
    @param pdu   (in, out) PDU string. Number will be cut from it. 
    @param countOctets If true, number is written with number of resulting bytes prepended. 
    @param decoded  (out) Set to true if number was decoded successfully. 
    @returns Decoded number. 
} 
function TSMSCodec.DecodeNumber(var pdu: string; 
    countOctets: boolean; var decoded: boolean): string; 
var 
    iOct : integer; 
    n1  : integer; 
    n2  : integer; 
    numLen : byte; 
    numType: byte; 
begin 
    Result := ''; 
    decoded := false; 
    if pdu <> '' then begin 
    try 
     numLen := StrToInt('$'+Copy(pdu,1,2)); Delete(pdu,1,2); 
     numType := StrToInt('$'+Copy(pdu,1,2)); Delete(pdu,1,2); 
     if (numType AND $90) = $90 then 
     Result := '+'; 
     if not countOctets then 
     numLen := (numLen+1) div 2 + 1; 
     for iOct := 1 to numLen-1 do begin 
     n1 := StrToInt('$'+Copy(pdu,1,1)); Delete(pdu,1,1); 
     n2 := StrToInt('$'+Copy(pdu,1,1)); Delete(pdu,1,1); 
     Result := Result + IntToStr(n2); 
     if n1 <> $F then 
      Result := Result + IntToStr(n1); 
     end; //for 
     decoded := true; 
    except 
     on EConvertError do Result := ''; 
     on ERangeError do Result := ''; 
    end; 
    end; 
end; 

{:Decodes 7-byte timestamp. 
    @param tstamp Timestamp in hexadecimal form (0340530S.PDF, 9.2.3.11). 
    @returns Decoded timestamp. 
    @since 2000-09-05 (1.02) 
} 
function TSMSCodec.DecodeTimeStamp(tstamp: string): TDateTime; 
var 
    day : integer; 
    gmt : integer; 
    gmtSign: integer; 
    hour : integer; 
    minute : integer; 
    month : integer; 
    second : integer; 
    year : integer; 
begin 
    year := StrToInt(tstamp[ 2]+tstamp[ 1]); 
    month := StrToInt(tstamp[ 4]+tstamp[ 3]); 
    day  := StrToInt(tstamp[ 6]+tstamp[ 5]); 
    hour := StrToInt(tstamp[ 8]+tstamp[ 7]); 
    minute := StrToInt(tstamp[10]+tstamp[ 9]); 
    second := StrToInt(tstamp[12]+tstamp[11]); 
    gmtSign := IFF(StrToInt(tstamp[14]) AND 8 = 0, 1, -1); 
    gmt  := (StrToInt(tstamp[13]) + 10*(StrToInt(tstamp[14]) AND (NOT 8))) * gmtSign; 
    if year > 80 then 
    year := 1900 + year 
    else 
    year := 2000 + year; 
    try 
    Result := EncodeDate(year,month,day) + EncodeTime(hour, minute, second, 0) - gmt; 
    except 
    on EConvertError do 
     Result := 0; 
    end; 
end; 

{:Decodes TP-Status. 
    @param status TP-Status (0340530S.PDF, 9.2.3.15). 
    @returns Decoded status 
    @since 2000-09-05 (1.02) 
} 
function TSMSCodec.DecodeTPStatus(status: string): TTPStatus; 
begin 
    Result.tpsOriginal := StrToInt('$'+status); 
    if Result.tpsOriginal <= 2 then 
    Result.tpsMajor := tpsmDelivered 
    else if (Result.tpsOriginal AND $60) = $20 then begin 
    Result.tpsMajor := tpsmTemporaryError; 
    Result.tpsWillContinue := true; 
    end 
    else if (Result.tpsOriginal AND $60) = $40 then begin 
    Result.tpsMajor := tpsmPermanentError; 
    Result.tpsWillContinue := false; 
    end 
    else if (Result.tpsOriginal AND $60) = $40 then begin 
    Result.tpsMajor := tpsmTemporaryError; 
    Result.tpsWillContinue := false; 
    end 
    else 
    Result.tpsMajor := tpsmReserved; 
    case Result.tpsMajor of 
    tpsmDelivered: 
     begin 
     case Result.tpsOriginal of 
      0: Result.tpsDetailed := tpsdReceived; 
      1: Result.tpsDetailed := tpsdForwardedNotConfirmed; 
      2: Result.tpsDetailed := tpsdReplaced; 
      else Result.tpsDetailed := tpsdReserved; 
     end; //case 
     end; // tmspDelivered 
    tpsmTemporaryError: 
     begin 
     case Result.tpsOriginal AND (NOT $40) of 
      32: Result.tpsDetailed := tpsdCongestion; 
      33: Result.tpsDetailed := tpsdSMEBusy; 
      34: Result.tpsDetailed := tpsdNoResponseFromSME; 
      35: Result.tpsDetailed := tpsdServiceRejected; 
      36: Result.tpsDetailed := tpsdQOSNotAvailable; 
      37: Result.tpsDetailed := tpsdErrorInSME; 
      else Result.tpsDetailed := tpsdReserved; 
     end; //case 
     end; // tpsmTemporaryError 
    tpsmPermanentError: 
     begin 
     case Result.tpsOriginal of 
      64: Result.tpsDetailed := tpsdRemoteProcedureError; 
      65: Result.tpsDetailed := tpsdIncompatibleDestination; 
      66: Result.tpsDetailed := tpsdConnectionRejectedBySME; 
      67: Result.tpsDetailed := tpsdNotObtainable; 
      68: Result.tpsDetailed := tpsdQOSNotAvailable; 
      69: Result.tpsDetailed := tpsdNoInternetworkingAvailable; 
      70: Result.tpsDetailed := tpsdSMValitidyPerionExpired; 
      71: Result.tpsDetailed := tpsdSMDeletedByOriginatingSME; 
      72: Result.tpsDetailed := tpsdSMDeletedBySCAdministration; 
      73: Result.tpsDetailed := tpsdSMDoesNotExist; 
      else Result.tpsDetailed := tpsdReserved; 
     end; //case 
     end; // tpsmPermanentError 
    tpsmReserved: 
     begin 
     Result.tpsDetailed := tpsdReserved; 
     end; // tpsmReserved 
    end; //case 
end; 

{: TSMSCodec destructor. No special cleanup required. 
} 
destructor TSMSCodec.Destroy; 
begin 
    inherited; 
end; 

{:Encodes 8-bit text into 7-bit "packed" form. 160 8-bit characters can be 
    packed into 140 bytes (consisting of 160 7-bit characters). Packed string is 
    converted into hexadecimal form as required by GSM standards. If input string 
    is longer that maxLen parameter, truncated flag is set and string is truncated. 
    @param txt  Original 8-bit character string. 
    @param maxLen Maximum length of original string. 
    @param truncated (out) Set if original string is longer than maxLen. 
    @returns Packed string in hexadecimal form. 
} 
function TSMSCodec.Encode7bitText(txt: string; maxLen: byte; var truncated: boolean): string; 
var 
    buffer : byte; 
    ch  : byte; 
    i  : integer; 
    leftover: byte; 
begin 
    truncated := (Length(txt) > maxLen); 
    if truncated then 
    txt := First(txt,maxLen); 
    Result := ''; 
    buffer := 0; 
    leftover := 0; 
    for i := 1 to Length(txt) do begin 
    ch := tbl7bit[txt[i]]; 
    if leftover = 0 then begin 
     buffer := ch; 
     leftover := 1; 
    end 
    else begin 
     buffer := buffer OR byte(ch SHL (8-leftover)); 
     Result := Result + HexStr(buffer,1); 
     if leftover < 7 then begin 
     buffer := ch SHR leftover; 
     Inc(leftover); 
     end 
     else begin 
     buffer := 0; 
     leftover := 0; 
     end; 
    end; 
    end; //for 
    if leftover > 0 then 
    Result := Result + HexStr(buffer,1); 
end; 

{:Prepares PDU message. If original message is longer than 160 characters, it 
    will be truncated. Most of the parameters are currently hardcoded. 
    @param decodedMessage Message record. 
    @param PDUMessage  (out) Encoded message, represented in hexadecimal form (suitable for sending to GSM 07.05 device). 
    @param tpDataLen  (out) Number of bytes in TP layer data unit. 
    @returns Error status. 
} 
function TSMSCodec.EncodeMessage(smsMessage: TSMSDecodedMessage; 
    var PDUMessage: string; var tpDataLen: integer): TEncoderStatus; 
var 
    DCS : byte; 
    MR  : byte; 
    PDUtype: byte; 
    PID : byte; 
    TP_VP : string; 
    TP_VPF : integer; 
    tpLayer: string; 
    trunc : boolean; 
    UD  : string; 
    UDL : byte; 
begin 
    // Some parameters are hardcoded 
    if smsMessage.sdcValidityMinutes = 0 then begin 
    TP_VPF := 0; // TP-VP field not present 
    TP_VP := ''; 
    end 
    else begin 
    TP_VPF := 2; // TP-VP field present and integer represented (relative) 
    TP_VP := EncodeTP_VP(smsMessage.sdcValidityMinutes); 
    end; 
    PDUtype := $01 OR (TP_VPF SHL 3) OR ((Ord(smsMessage.sdcRequestReport) AND 1) SHL 5); 

    MR  := smsMessage.sdcMessageReference; 
    PID  := $00; 
    DCS  := $00; 
    UD  := Encode7bitText(smsMessage.sdcShortMessage,160,trunc); 
    UDL  := Length(smsMessage.sdcShortMessage); 
    tpLayer := 
    HexStr(PDUtype,1)     + 
    HexStr(MR,1)      + 
    EncodeNumber(smsMessage.sdcNumber,false) + 
    HexStr(PID,1)      + 
    HexStr(DCS,1)      + 
    TP_VP        + 
    HexStr(UDL,1)      + 
    UD; 
    PDUMessage := 
    EncodeNumber(smsMessage.sdcSMSCenterNumber,true) + 
    tpLayer; 
    tpDataLen := Length(tpLayer) div 2; 
    if trunc then 
    Result := esTruncated 
    else 
    Result := esEncoded; 
end; 

{:Encodes number by GSM standards. Prefixes it with either number of bytes 
    (if countOctets is set) or number of digits in original number. 
    @param num   Telephone number if international (starts with + or 00) or local form. 
    @param countOctets If true, number of resulting bytes will be prepended, if false, number of digits in num. 
    @returns Encoded number. 
} 
function TSMSCodec.EncodeNumber(num: string; countOctets: boolean): string; 
var 
    numLen : byte; 
    numType: byte; 
begin 
    num := Replace(ReplaceAllSet(num,[#0..#255]-['0'..'9','+'],' '),' ',''); 
    if num <> '' then begin 
    if num[1] = '+' then begin 
     Delete(num,1,1); 
     numType := $91; 
    end 
    else if First(num,2) = '00' then begin 
     Delete(num,1,2); 
     numType := $91; 
    end 
    else numType := $81; 
    if countOctets then 
     numLen := ((Length(num)+1) div 2) + 1 
    else 
     numLen := Length(num); 
    if Odd(Length(num)) then num := num + 'F'; 
    Result := HexStr(numLen,1) + HexStr(numType,1); 
    while num <> '' do begin 
     Result := Result + num[2] + num[1]; 
     Delete(num,1,2); 
    end; //while 
    end 
    else Result := '00'; 
end; 

{:Encodes relative validity into TP_VP parameter. GSM 03.40, 9.2.3.12. 
    @param validityMin Validity period in minutes. 
    @returns Encoded TP_VP. 
    @since 2000-09-06 (1.02) 
} 
function TSMSCodec.EncodeTP_VP(validityMin: integer): string; 
var 
    value: byte; 
begin 
// 5 minute intervals : 5 minutes    to 12 hours (720 minutes) 
// 30 minute intervals: 12.5 hours (750 minutes) to 24 hours (1440 minutes) 
// 1 hour intervals : 2 days (2880 minutes) to 30 days (43200 minutes) 
// 1 week intervals : 5 weeks (50400 minutes) to 63 weeks (635040 minutes) 

    if validityMin <= 720 then begin 
    if validityMin < 5 then 
     validityMin := 5; 
    value := ((validityMin-1) div 5); 
    end 
    else if validityMin <= 1440 then 
    value := (((validityMin-1) - 720) div 30) + 144 
    else if validityMin <= 43200 then 
    value := ((validityMin-1) div 1440) + 167 
    else begin 
    if validityMin > 635040 then 
     validityMin := 635040; 
    value := ((validityMin-1) div 10080) + 193; 
    end; 
    Result := HexStr(value,1); 
end; 

end. 
+0

gabr,非常感谢!你能给我的Gp17String下载网址? – Leo 2011-03-14 15:52:15

+0

http://17slon.com/krama/Gp17String.pas – gabr 2011-03-14 16:36:36

+0

gabr,我发现TSMSCodec.Decode7bitText函数可能有一个缺陷:8位解压文本:“12345 $ 6”,用7位编码是:“31D98C5613D800” ,我打电话给Decode7bitText,它返回一个错误的值:“12345 $ 6 @” – Leo 2011-03-15 01:32:46

0

在TurboPower的AsyncPro中查看SMS组件。