I need to Send Short message in pdu mode. Anybody can give me a GSM 7bit encode/decode algorithm?
See if this is of any use to you. Code taken from one of my very old projects - may be used as you wish.
unit SMSCodec;
interface
const
//:Default 7-bit alphabet.
CPDU7bit = #10#13' !"#$&''()*+,-./0123456789:;<=>?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.