#include "libPDU.h" #include "Arduino.h" #include "WProgram.h" 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 PDU::decode(String pdu_text) { uint8_t len = strtol(pdu_text.substring(0, 2).c_str(), NULL, 16); //the fist byte contains the number of chars return pdu_decode(pdu_text.substring(2), len); } String PDU::decode(String pdu_text, uint8_t len) { char plain_bytes[256]; byte high_mask = 128; // byte:10000000; byte low_mask; byte shift = 0; byte this_byte; byte high_byte_new = 0; byte high_byte_old = 0; byte low_byte = 0; int y = 0; int i = 0; for (y = 0; y < len ; y++) { this_byte = strtol(pdu_text.substring(i * 2, (i * 2) + 2).c_str(), NULL, 16); low_mask = high_mask ^ 0xFF; //invert high_byte_new = this_byte & high_mask; // 10000000 = 11000111 & 10000000 low_byte = this_byte & low_mask; // 01000111 = 11000111 & 01111111 plain_bytes[y] = low_byte << shift; // 10001110 high_byte_old = high_byte_old >> (8 - shift); // 00000001 plain_bytes[y] = plain_bytes[y] + high_byte_old; // 10001111 if (shift == 6) { y++; plain_bytes[y] = high_byte_new >> 1; } high_mask = high_mask >> 1; // 10000000 > 01000000 high_mask = high_mask + 128; // 01000000 > 11000000 if (high_mask == 255)high_mask = 128; // 11111111 > 10000000 low_mask = high_mask ^ 0xFF; // invert high_byte_old = high_byte_new; shift++; if (shift == 7) { shift = 0; } i++; } plain_bytes[y] = 0; char *plain_text = new char[y]; strcpy(plain_text, plain_bytes); return plain_text; } String PDU::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 PDU::stringToSemiOctet (String StringData) { if ( StringData.length() % 2 != 0 ) { StringData += "F"; } return semiOctetToString(StringData); } int PDU::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 PDU::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 PDU::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 PDU::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 PDU::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 PDU::setText( String smstext ) { if ( smstext.length() > 160 ) { return 0; } this->tp_text = smstext; return 1; } int PDU::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 PDU::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 PDU::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; }