Skip to content

Instantly share code, notes, and snippets.

@lsongdev
Created November 6, 2016 12:11
Show Gist options
  • Save lsongdev/3b9755bea0654ed0c2d14773b4300c86 to your computer and use it in GitHub Desktop.
Save lsongdev/3b9755bea0654ed0c2d14773b4300c86 to your computer and use it in GitHub Desktop.
/*
PduEncoder.cpp - Message PDU format encoder library
Author : Ludovic Laurent.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
The latest version of this library can always be found at
http://users.skynet.be/moustic/PduEncoder.zip
if questions ask to Moustic on Arduino Forum.
*/
#include "WProgram.h"
#include "PduEncoder.h"
/****************************************************************************
This lookup table converts from ISO-8859-1 8-bit ASCII to the
7 bit "default alphabet" as defined in ETSI GSM 03.38
ISO-characters that don't have any correspondning character in the
7-bit alphabet is replaced with the NPC7-character. If there's
a close match between the ISO-char and a 7-bit character (for example
the letter i with a circumflex and the plain i-character) a substitution
is done. These "close-matches" are marked in the lookup table by
having its value negated.
There are some character (for example the curly brace "}") that must
be converted into a 2 byte 7-bit sequence. These characters are
marked in the table by having 256 added to its value.
****************************************************************************/
char lookup_ascii8to7[]= {
NPC7, /* 0 null [NUL] */
NPC7, /* 1 start of heading [SOH] */
NPC7, /* 2 start of text [STX] */
NPC7, /* 3 end of text [ETX] */
NPC7, /* 4 end of transmission [EOT] */
NPC7, /* 5 enquiry [ENQ] */
NPC7, /* 6 acknowledge [ACK] */
NPC7, /* 7 bell [BEL] */
NPC7, /* 8 backspace [BS] */
NPC7, /* 9 horizontal tab [HT] */
10, /* 10 line feed [LF] */
NPC7, /* 11 vertical tab [VT] */
10+256, /* 12 form feed [FF] */
13, /* 13 carriage return [CR] */
NPC7, /* 14 shift out [SO] */
NPC7, /* 15 shift in [SI] */
NPC7, /* 16 data link escape [DLE] */
NPC7, /* 17 device control 1 [DC1] */
NPC7, /* 18 device control 2 [DC2] */
NPC7, /* 19 device control 3 [DC3] */
NPC7, /* 20 device control 4 [DC4] */
NPC7, /* 21 negative acknowledge [NAK] */
NPC7, /* 22 synchronous idle [SYN] */
NPC7, /* 23 end of trans. block [ETB] */
NPC7, /* 24 cancel [CAN] */
NPC7, /* 25 end of medium [EM] */
NPC7, /* 26 substitute [SUB] */
NPC7, /* 27 escape [ESC] */
NPC7, /* 28 file separator [FS] */
NPC7, /* 29 group separator [GS] */
NPC7, /* 30 record separator [RS] */
NPC7, /* 31 unit separator [US] */
32, /* 32 space */
33, /* 33 ! exclamation mark */
34, /* 34 " double quotation mark */
35, /* 35 # number sign */
2, /* 36 $ dollar sign */
37, /* 37 % percent sign */
38, /* 38 & ampersand */
39, /* 39 ' apostrophe */
40, /* 40 ( left parenthesis */
41, /* 41 ) right parenthesis */
42, /* 42 * asterisk */
43, /* 43 + plus sign */
44, /* 44 , comma */
45, /* 45 - hyphen */
46, /* 46 . period */
47, /* 47 / slash, */
48, /* 48 0 digit 0 */
49, /* 49 1 digit 1 */
50, /* 50 2 digit 2 */
51, /* 51 3 digit 3 */
52, /* 52 4 digit 4 */
53, /* 53 5 digit 5 */
54, /* 54 6 digit 6 */
55, /* 55 7 digit 7 */
56, /* 56 8 digit 8 */
57, /* 57 9 digit 9 */
58, /* 58 : colon */
59, /* 59 ; semicolon */
60, /* 60 < less-than sign */
61, /* 61 = equal sign */
62, /* 62 > greater-than sign */
63, /* 63 ? question mark */
0, /* 64 @ commercial at sign */
65, /* 65 A uppercase A */
66, /* 66 B uppercase B */
67, /* 67 C uppercase C */
68, /* 68 D uppercase D */
69, /* 69 E uppercase E */
70, /* 70 F uppercase F */
71, /* 71 G uppercase G */
72, /* 72 H uppercase H */
73, /* 73 I uppercase I */
74, /* 74 J uppercase J */
75, /* 75 K uppercase K */
76, /* 76 L uppercase L */
77, /* 77 M uppercase M */
78, /* 78 N uppercase N */
79, /* 79 O uppercase O */
80, /* 80 P uppercase P */
81, /* 81 Q uppercase Q */
82, /* 82 R uppercase R */
83, /* 83 S uppercase S */
84, /* 84 T uppercase T */
85, /* 85 U uppercase U */
86, /* 86 V uppercase V */
87, /* 87 W uppercase W */
88, /* 88 X uppercase X */
89, /* 89 Y uppercase Y */
90, /* 90 Z uppercase Z */
60+256, /* 91 [ left square bracket */
47+256, /* 92 \ backslash */
62+256, /* 93 ] right square bracket */
20+256, /* 94 ^ circumflex accent */
17, /* 95 _ underscore */
-39, /* 96 ` back apostrophe */
97, /* 97 a lowercase a */
98, /* 98 b lowercase b */
99, /* 99 c lowercase c */
100, /* 100 d lowercase d */
101, /* 101 e lowercase e */
102, /* 102 f lowercase f */
103, /* 103 g lowercase g */
104, /* 104 h lowercase h */
105, /* 105 i lowercase i */
106, /* 106 j lowercase j */
107, /* 107 k lowercase k */
108, /* 108 l lowercase l */
109, /* 109 m lowercase m */
110, /* 110 n lowercase n */
111, /* 111 o lowercase o */
112, /* 112 p lowercase p */
113, /* 113 q lowercase q */
114, /* 114 r lowercase r */
115, /* 115 s lowercase s */
116, /* 116 t lowercase t */
117, /* 117 u lowercase u */
118, /* 118 v lowercase v */
119, /* 119 w lowercase w */
120, /* 120 x lowercase x */
121, /* 121 y lowercase y */
122, /* 122 z lowercase z */
40+256, /* 123 { left brace */
64+256, /* 124 | vertical bar */
41+256, /* 125 } right brace */
61+256, /* 126 ~ tilde accent */
NPC7, /* 127 delete [DEL] */
NPC7, /* 128 */
NPC7, /* 129 */
-39, /* 130 low left rising single quote */
-102, /* 131 lowercase italic f */
-34, /* 132 low left rising double quote */
NPC7, /* 133 low horizontal ellipsis */
NPC7, /* 134 dagger mark */
NPC7, /* 135 double dagger mark */
NPC7, /* 136 letter modifying circumflex */
NPC7, /* 137 per thousand (mille) sign */
-83, /* 138 uppercase S caron or hacek */
-39, /* 139 left single angle quote mark */
-214, /* 140 uppercase OE ligature */
NPC7, /* 141 */
NPC7, /* 142 */
NPC7, /* 143 */
NPC7, /* 144 */
-39, /* 145 left single quotation mark */
-39, /* 146 right single quote mark */
-34, /* 147 left double quotation mark */
-34, /* 148 right double quote mark */
-42, /* 149 round filled bullet */
-45, /* 150 en dash */
-45, /* 151 em dash */
-39, /* 152 small spacing tilde accent */
NPC7, /* 153 trademark sign */
-115, /* 154 lowercase s caron or hacek */
-39, /* 155 right single angle quote mark */
-111, /* 156 lowercase oe ligature */
NPC7, /* 157 */
NPC7, /* 158 */
-89, /* 159 uppercase Y dieresis or umlaut */
-32, /* 160 ? non-breaking space */
64, /* 161 ? inverted exclamation mark */
-99, /* 162 ? cent sign */
1, /* 163 ? pound sterling sign */
36, /* 164 ? general currency sign */
3, /* 165 ? yen sign */
-33, /* 166 ? broken vertical bar */
95, /* 167 ? section sign */
-34, /* 168 ? spacing dieresis or umlaut */
NPC7, /* 169 ? copyright sign */
NPC7, /* 170 ? feminine ordinal indicator */
-60, /* 171 ? left (double) angle quote */
NPC7, /* 172 ? logical not sign */
-45, /* 173 ? soft hyphen */
NPC7, /* 174 ? registered trademark sign */
NPC7, /* 175 ? spacing macron (long) accent */
NPC7, /* 176 ? degree sign */
NPC7, /* 177 ? plus-or-minus sign */
-50, /* 178 ? superscript 2 */
-51, /* 179 ? superscript 3 */
-39, /* 180 ? spacing acute accent */
-117, /* 181 ? micro sign */
NPC7, /* 182 ? paragraph sign, pilcrow sign */
NPC7, /* 183 ? middle dot, centered dot */
NPC7, /* 184 ? spacing cedilla */
-49, /* 185 ? superscript 1 */
NPC7, /* 186 ? masculine ordinal indicator */
-62, /* 187 ? right (double) angle quote (guillemet) */
NPC7, /* 188 ? fraction 1/4 */
NPC7, /* 189 ? fraction 1/2 */
NPC7, /* 190 ? fraction 3/4 */
96, /* 191 ? inverted question mark */
-65, /* 192 ? uppercase A grave */
-65, /* 193 ? uppercase A acute */
-65, /* 194 ? uppercase A circumflex */
-65, /* 195 ? uppercase A tilde */
91, /* 196 ? uppercase A dieresis or umlaut */
14, /* 197 ? uppercase A ring */
28, /* 198 ? uppercase AE ligature */
9, /* 199 ? uppercase C cedilla */
-31, /* 200 ? uppercase E grave */
31, /* 201 ? uppercase E acute */
-31, /* 202 ? uppercase E circumflex */
-31, /* 203 ? uppercase E dieresis or umlaut */
-73, /* 204 ? uppercase I grave */
-73, /* 205 ? uppercase I acute */
-73, /* 206 ? uppercase I circumflex */
-73, /* 207 ? uppercase I dieresis or umlaut */
-68, /* 208 ? uppercase ETH */
93, /* 209 ? uppercase N tilde */
-79, /* 210 ? uppercase O grave */
-79, /* 211 ? uppercase O acute */
-79, /* 212 ? uppercase O circumflex */
-79, /* 213 ? uppercase O tilde */
92, /* 214 ? uppercase O dieresis or umlaut */
-42, /* 215 ? multiplication sign */
11, /* 216 ? uppercase O slash */
-85, /* 217 ? uppercase U grave */
-85, /* 218 ? uppercase U acute */
-85, /* 219 ? uppercase U circumflex */
94, /* 220 ? uppercase U dieresis or umlaut */
-89, /* 221 ? uppercase Y acute */
NPC7, /* 222 ? uppercase THORN */
30, /* 223 ? lowercase sharp s, sz ligature */
127, /* 224 ? lowercase a grave */
-97, /* 225 ? lowercase a acute */
-97, /* 226 ? lowercase a circumflex */
-97, /* 227 ? lowercase a tilde */
123, /* 228 ? lowercase a dieresis or umlaut */
15, /* 229 ? lowercase a ring */
29, /* 230 ? lowercase ae ligature */
-9, /* 231 ? lowercase c cedilla */
4, /* 232 ? lowercase e grave */
5, /* 233 ? lowercase e acute */
-101, /* 234 ? lowercase e circumflex */
-101, /* 235 ? lowercase e dieresis or umlaut */
7, /* 236 ? lowercase i grave */
7, /* 237 ? lowercase i acute */
-105, /* 238 ? lowercase i circumflex */
-105, /* 239 ? lowercase i dieresis or umlaut */
NPC7, /* 240 ? lowercase eth */
125, /* 241 ? lowercase n tilde */
8, /* 242 ? lowercase o grave */
-111, /* 243 ? lowercase o acute */
-111, /* 244 ? lowercase o circumflex */
-111, /* 245 ? lowercase o tilde */
124, /* 246 ? lowercase o dieresis or umlaut */
-47, /* 247 ? division sign */
12, /* 248 ? lowercase o slash */
6, /* 249 ? lowercase u grave */
-117, /* 250 ? lowercase u acute */
-117, /* 251 ? lowercase u circumflex */
126, /* 252 ? lowercase u dieresis or umlaut */
-121, /* 253 ? lowercase y acute */
NPC7, /* 254 ? lowercase thorn */
-121 /* 255 ? lowercase y dieresis or umlaut */
};
String PduEncoder::semiOctetToString (String semiOctet) {
unsigned int i;
String OctetString;
for (i = 0; i < ( semiOctet.length() / 2 ); i++) {
OctetString += semiOctet.substring(i*2 + 1,i*2 + 1+1);
OctetString += semiOctet.substring(i*2, i*2+1);
}
return OctetString;
}
String PduEncoder::stringToSemiOctet (String StringData) {
if ( StringData.length() % 2 != 0 ) {
StringData += "F";
}
return semiOctetToString(StringData);
}
int PduEncoder::hexStringToInt (String hexString) {
unsigned int i;
int charvalue;
int returnvalue = 0;
for (i = 0; i < hexString.length(); i++) {
if ( hexString[i] >= 'a' && hexString[i] <= 'f' ) {
charvalue = (int) hexString[i] - 87;
}
if ( hexString[i] >= 'A' && hexString[i] <= 'F' ) {
charvalue = (int) hexString[i] - 55;
}
if ( hexString[i] >= '0' && hexString[i] <= '9' ) {
charvalue = (int) hexString[i] - 48;
}
returnvalue += charvalue * ( pow(16, (int)(hexString.length() - (i + 1)) ));
}
return returnvalue;
}
String PduEncoder::intToHexString (int integer) {
String hexString = "";
//Conversion from intToHex
char buf[3];
sprintf(buf,"%X",integer);
hexString = (String)buf;
//Prepend a 0 when not even
if ( hexString.length() % 2 != 0 ){
hexString = "0" + hexString;
}
return hexString;
}
int PduEncoder::binStringToInt (String binString) {
unsigned int pos;
int integerReturn = 0;
int base = 2;
for (pos = 0; pos < binString.length(); pos++) {
if ( binString.substring(pos, pos+1) == "1" ) {
integerReturn += pow(base, (binString.length() - (pos + 1)) );
}
}
return integerReturn;
}
String PduEncoder::intToBinString (int integer) {
String stringReturn;
if (integer <= 0) {
return "0";
}
while ( integer > 0 ) {
if ( integer % 2 == 1 ) {
stringReturn = "1" + stringReturn;
--integer;
} else {
stringReturn = "0" + stringReturn;
}
integer = integer / 2;
}
//Changed 8 to 7 because the characters are in septets
while ( stringReturn.length() % 7 != 0 ) {
stringReturn = "0" + stringReturn;
}
return stringReturn;
}
int PduEncoder::pow(int n, int i)
{
if (i == 0)
return 1;
else if (i == 1)
return n;
else {
int partial = pow(n, i / 2);
if (i % 2 == 0)
return partial * partial;
else
return partial * partial * n;
}
}
int PduEncoder::setText( String smstext ) {
if ( smstext.length() > 160 ) {
return 0;
}
this->tp_text = smstext;
return 1;
}
int PduEncoder::setSender( String number ) {
this->sender_type_of_address = 146;
if ( number.substring(0,1) == "+" ) {
this->sender_type_of_address = 145;
this->sender_number = number.substring(1, number.length());
} else {
this->sender_number = number;
}
this->sender_length = this->sender_number.length();
if ( this->sender_number.length() % 2 == 1 ) {
this->sender_number + "F";
}
return 1;
}
String PduEncoder::userTextTo7(void) {
unsigned int pos;
String current, octetFirst, octetSecond, currentOctet;
String output;
for (pos = 0; pos < this->tp_text.length(); pos++) {
current = intToBinString(lookup_ascii8to7[ this->tp_text[pos] ]);
if ( ( pos != 0 ) && ( pos % 8 != 0 ) ) {
octetFirst = current.substring(7 - ( pos % 8 ), current.length() );
currentOctet = octetFirst + octetSecond;
output += intToHexString(binStringToInt(currentOctet));
octetSecond = current.substring(0, 7 - (pos % 8));
}
else {
octetSecond = current.substring(0, 7 - (pos % 8));
}
if ( ( pos + 1 == this->tp_text.length() ) && ( octetSecond != "" ) ) {
output += intToHexString(binStringToInt(octetSecond));
}
}
return output;
}
String PduEncoder::encode() {
String pduString;
pduString = "00"; // SMSC_LENGHT
pduString += "1100"; // FIRST OCTET ( message submit & tp reference)
pduString += intToHexString(this->sender_length); // SENDER_LENGHT
pduString += intToHexString(this->sender_type_of_address); // SENDER_TYPE
pduString += stringToSemiOctet(this->sender_number); // SENDER_NUMBER
pduString += "0000"; // TP-PID TP-DCS ( 7-bit default encoding )
pduString += "AA"; // VALIDITY ( 4 days )
pduString += intToHexString(this->tp_text.length());
pduString += userTextTo7();
return pduString;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment