libPDU.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #include "libPDU.h"
  2. #include "Arduino.h"
  3. #include "WProgram.h"
  4. char lookup_ascii8to7[]= {
  5. NPC7, /* 0 null [NUL] */
  6. NPC7, /* 1 start of heading [SOH] */
  7. NPC7, /* 2 start of text [STX] */
  8. NPC7, /* 3 end of text [ETX] */
  9. NPC7, /* 4 end of transmission [EOT] */
  10. NPC7, /* 5 enquiry [ENQ] */
  11. NPC7, /* 6 acknowledge [ACK] */
  12. NPC7, /* 7 bell [BEL] */
  13. NPC7, /* 8 backspace [BS] */
  14. NPC7, /* 9 horizontal tab [HT] */
  15. 10, /* 10 line feed [LF] */
  16. NPC7, /* 11 vertical tab [VT] */
  17. 10+256, /* 12 form feed [FF] */
  18. 13, /* 13 carriage return [CR] */
  19. NPC7, /* 14 shift out [SO] */
  20. NPC7, /* 15 shift in [SI] */
  21. NPC7, /* 16 data link escape [DLE] */
  22. NPC7, /* 17 device control 1 [DC1] */
  23. NPC7, /* 18 device control 2 [DC2] */
  24. NPC7, /* 19 device control 3 [DC3] */
  25. NPC7, /* 20 device control 4 [DC4] */
  26. NPC7, /* 21 negative acknowledge [NAK] */
  27. NPC7, /* 22 synchronous idle [SYN] */
  28. NPC7, /* 23 end of trans. block [ETB] */
  29. NPC7, /* 24 cancel [CAN] */
  30. NPC7, /* 25 end of medium [EM] */
  31. NPC7, /* 26 substitute [SUB] */
  32. NPC7, /* 27 escape [ESC] */
  33. NPC7, /* 28 file separator [FS] */
  34. NPC7, /* 29 group separator [GS] */
  35. NPC7, /* 30 record separator [RS] */
  36. NPC7, /* 31 unit separator [US] */
  37. 32, /* 32 space */
  38. 33, /* 33 ! exclamation mark */
  39. 34, /* 34 " double quotation mark */
  40. 35, /* 35 # number sign */
  41. 2, /* 36 $ dollar sign */
  42. 37, /* 37 % percent sign */
  43. 38, /* 38 & ampersand */
  44. 39, /* 39 ' apostrophe */
  45. 40, /* 40 ( left parenthesis */
  46. 41, /* 41 ) right parenthesis */
  47. 42, /* 42 * asterisk */
  48. 43, /* 43 + plus sign */
  49. 44, /* 44 , comma */
  50. 45, /* 45 - hyphen */
  51. 46, /* 46 . period */
  52. 47, /* 47 / slash, */
  53. 48, /* 48 0 digit 0 */
  54. 49, /* 49 1 digit 1 */
  55. 50, /* 50 2 digit 2 */
  56. 51, /* 51 3 digit 3 */
  57. 52, /* 52 4 digit 4 */
  58. 53, /* 53 5 digit 5 */
  59. 54, /* 54 6 digit 6 */
  60. 55, /* 55 7 digit 7 */
  61. 56, /* 56 8 digit 8 */
  62. 57, /* 57 9 digit 9 */
  63. 58, /* 58 : colon */
  64. 59, /* 59 ; semicolon */
  65. 60, /* 60 < less-than sign */
  66. 61, /* 61 = equal sign */
  67. 62, /* 62 > greater-than sign */
  68. 63, /* 63 ? question mark */
  69. 0, /* 64 @ commercial at sign */
  70. 65, /* 65 A uppercase A */
  71. 66, /* 66 B uppercase B */
  72. 67, /* 67 C uppercase C */
  73. 68, /* 68 D uppercase D */
  74. 69, /* 69 E uppercase E */
  75. 70, /* 70 F uppercase F */
  76. 71, /* 71 G uppercase G */
  77. 72, /* 72 H uppercase H */
  78. 73, /* 73 I uppercase I */
  79. 74, /* 74 J uppercase J */
  80. 75, /* 75 K uppercase K */
  81. 76, /* 76 L uppercase L */
  82. 77, /* 77 M uppercase M */
  83. 78, /* 78 N uppercase N */
  84. 79, /* 79 O uppercase O */
  85. 80, /* 80 P uppercase P */
  86. 81, /* 81 Q uppercase Q */
  87. 82, /* 82 R uppercase R */
  88. 83, /* 83 S uppercase S */
  89. 84, /* 84 T uppercase T */
  90. 85, /* 85 U uppercase U */
  91. 86, /* 86 V uppercase V */
  92. 87, /* 87 W uppercase W */
  93. 88, /* 88 X uppercase X */
  94. 89, /* 89 Y uppercase Y */
  95. 90, /* 90 Z uppercase Z */
  96. 60+256, /* 91 [ left square bracket */
  97. 47+256, /* 92 \ backslash */
  98. 62+256, /* 93 ] right square bracket */
  99. 20+256, /* 94 ^ circumflex accent */
  100. 17, /* 95 _ underscore */
  101. -39, /* 96 ` back apostrophe */
  102. 97, /* 97 a lowercase a */
  103. 98, /* 98 b lowercase b */
  104. 99, /* 99 c lowercase c */
  105. 100, /* 100 d lowercase d */
  106. 101, /* 101 e lowercase e */
  107. 102, /* 102 f lowercase f */
  108. 103, /* 103 g lowercase g */
  109. 104, /* 104 h lowercase h */
  110. 105, /* 105 i lowercase i */
  111. 106, /* 106 j lowercase j */
  112. 107, /* 107 k lowercase k */
  113. 108, /* 108 l lowercase l */
  114. 109, /* 109 m lowercase m */
  115. 110, /* 110 n lowercase n */
  116. 111, /* 111 o lowercase o */
  117. 112, /* 112 p lowercase p */
  118. 113, /* 113 q lowercase q */
  119. 114, /* 114 r lowercase r */
  120. 115, /* 115 s lowercase s */
  121. 116, /* 116 t lowercase t */
  122. 117, /* 117 u lowercase u */
  123. 118, /* 118 v lowercase v */
  124. 119, /* 119 w lowercase w */
  125. 120, /* 120 x lowercase x */
  126. 121, /* 121 y lowercase y */
  127. 122, /* 122 z lowercase z */
  128. 40+256, /* 123 { left brace */
  129. 64+256, /* 124 | vertical bar */
  130. 41+256, /* 125 } right brace */
  131. 61+256, /* 126 ~ tilde accent */
  132. NPC7, /* 127 delete [DEL] */
  133. NPC7, /* 128 */
  134. NPC7, /* 129 */
  135. -39, /* 130 low left rising single quote */
  136. -102, /* 131 lowercase italic f */
  137. -34, /* 132 low left rising double quote */
  138. NPC7, /* 133 low horizontal ellipsis */
  139. NPC7, /* 134 dagger mark */
  140. NPC7, /* 135 double dagger mark */
  141. NPC7, /* 136 letter modifying circumflex */
  142. NPC7, /* 137 per thousand (mille) sign */
  143. -83, /* 138 uppercase S caron or hacek */
  144. -39, /* 139 left single angle quote mark */
  145. -214, /* 140 uppercase OE ligature */
  146. NPC7, /* 141 */
  147. NPC7, /* 142 */
  148. NPC7, /* 143 */
  149. NPC7, /* 144 */
  150. -39, /* 145 left single quotation mark */
  151. -39, /* 146 right single quote mark */
  152. -34, /* 147 left double quotation mark */
  153. -34, /* 148 right double quote mark */
  154. -42, /* 149 round filled bullet */
  155. -45, /* 150 en dash */
  156. -45, /* 151 em dash */
  157. -39, /* 152 small spacing tilde accent */
  158. NPC7, /* 153 trademark sign */
  159. -115, /* 154 lowercase s caron or hacek */
  160. -39, /* 155 right single angle quote mark */
  161. -111, /* 156 lowercase oe ligature */
  162. NPC7, /* 157 */
  163. NPC7, /* 158 */
  164. -89, /* 159 uppercase Y dieresis or umlaut */
  165. -32, /* 160 ? non-breaking space */
  166. 64, /* 161 ? inverted exclamation mark */
  167. -99, /* 162 ? cent sign */
  168. 1, /* 163 ? pound sterling sign */
  169. 36, /* 164 ? general currency sign */
  170. 3, /* 165 ? yen sign */
  171. -33, /* 166 ? broken vertical bar */
  172. 95, /* 167 ? section sign */
  173. -34, /* 168 ? spacing dieresis or umlaut */
  174. NPC7, /* 169 ? copyright sign */
  175. NPC7, /* 170 ? feminine ordinal indicator */
  176. -60, /* 171 ? left (double) angle quote */
  177. NPC7, /* 172 ? logical not sign */
  178. -45, /* 173 ? soft hyphen */
  179. NPC7, /* 174 ? registered trademark sign */
  180. NPC7, /* 175 ? spacing macron (long) accent */
  181. NPC7, /* 176 ? degree sign */
  182. NPC7, /* 177 ? plus-or-minus sign */
  183. -50, /* 178 ? superscript 2 */
  184. -51, /* 179 ? superscript 3 */
  185. -39, /* 180 ? spacing acute accent */
  186. -117, /* 181 ? micro sign */
  187. NPC7, /* 182 ? paragraph sign, pilcrow sign */
  188. NPC7, /* 183 ? middle dot, centered dot */
  189. NPC7, /* 184 ? spacing cedilla */
  190. -49, /* 185 ? superscript 1 */
  191. NPC7, /* 186 ? masculine ordinal indicator */
  192. -62, /* 187 ? right (double) angle quote (guillemet) */
  193. NPC7, /* 188 ? fraction 1/4 */
  194. NPC7, /* 189 ? fraction 1/2 */
  195. NPC7, /* 190 ? fraction 3/4 */
  196. 96, /* 191 ? inverted question mark */
  197. -65, /* 192 ? uppercase A grave */
  198. -65, /* 193 ? uppercase A acute */
  199. -65, /* 194 ? uppercase A circumflex */
  200. -65, /* 195 ? uppercase A tilde */
  201. 91, /* 196 ? uppercase A dieresis or umlaut */
  202. 14, /* 197 ? uppercase A ring */
  203. 28, /* 198 ? uppercase AE ligature */
  204. 9, /* 199 ? uppercase C cedilla */
  205. -31, /* 200 ? uppercase E grave */
  206. 31, /* 201 ? uppercase E acute */
  207. -31, /* 202 ? uppercase E circumflex */
  208. -31, /* 203 ? uppercase E dieresis or umlaut */
  209. -73, /* 204 ? uppercase I grave */
  210. -73, /* 205 ? uppercase I acute */
  211. -73, /* 206 ? uppercase I circumflex */
  212. -73, /* 207 ? uppercase I dieresis or umlaut */
  213. -68, /* 208 ? uppercase ETH */
  214. 93, /* 209 ? uppercase N tilde */
  215. -79, /* 210 ? uppercase O grave */
  216. -79, /* 211 ? uppercase O acute */
  217. -79, /* 212 ? uppercase O circumflex */
  218. -79, /* 213 ? uppercase O tilde */
  219. 92, /* 214 ? uppercase O dieresis or umlaut */
  220. -42, /* 215 ? multiplication sign */
  221. 11, /* 216 ? uppercase O slash */
  222. -85, /* 217 ? uppercase U grave */
  223. -85, /* 218 ? uppercase U acute */
  224. -85, /* 219 ? uppercase U circumflex */
  225. 94, /* 220 ? uppercase U dieresis or umlaut */
  226. -89, /* 221 ? uppercase Y acute */
  227. NPC7, /* 222 ? uppercase THORN */
  228. 30, /* 223 ? lowercase sharp s, sz ligature */
  229. 127, /* 224 ? lowercase a grave */
  230. -97, /* 225 ? lowercase a acute */
  231. -97, /* 226 ? lowercase a circumflex */
  232. -97, /* 227 ? lowercase a tilde */
  233. 123, /* 228 ? lowercase a dieresis or umlaut */
  234. 15, /* 229 ? lowercase a ring */
  235. 29, /* 230 ? lowercase ae ligature */
  236. -9, /* 231 ? lowercase c cedilla */
  237. 4, /* 232 ? lowercase e grave */
  238. 5, /* 233 ? lowercase e acute */
  239. -101, /* 234 ? lowercase e circumflex */
  240. -101, /* 235 ? lowercase e dieresis or umlaut */
  241. 7, /* 236 ? lowercase i grave */
  242. 7, /* 237 ? lowercase i acute */
  243. -105, /* 238 ? lowercase i circumflex */
  244. -105, /* 239 ? lowercase i dieresis or umlaut */
  245. NPC7, /* 240 ? lowercase eth */
  246. 125, /* 241 ? lowercase n tilde */
  247. 8, /* 242 ? lowercase o grave */
  248. -111, /* 243 ? lowercase o acute */
  249. -111, /* 244 ? lowercase o circumflex */
  250. -111, /* 245 ? lowercase o tilde */
  251. 124, /* 246 ? lowercase o dieresis or umlaut */
  252. -47, /* 247 ? division sign */
  253. 12, /* 248 ? lowercase o slash */
  254. 6, /* 249 ? lowercase u grave */
  255. -117, /* 250 ? lowercase u acute */
  256. -117, /* 251 ? lowercase u circumflex */
  257. 126, /* 252 ? lowercase u dieresis or umlaut */
  258. -121, /* 253 ? lowercase y acute */
  259. NPC7, /* 254 ? lowercase thorn */
  260. -121 /* 255 ? lowercase y dieresis or umlaut */
  261. };
  262. String PDU::decode(String pdu_text) {
  263. uint8_t len = strtol(pdu_text.substring(0, 2).c_str(), NULL, 16); //the fist byte contains the number of chars
  264. return pdu_decode(pdu_text.substring(2), len);
  265. }
  266. String PDU::decode(String pdu_text, uint8_t len) {
  267. char plain_bytes[256];
  268. byte high_mask = 128; // byte:10000000;
  269. byte low_mask;
  270. byte shift = 0;
  271. byte this_byte;
  272. byte high_byte_new = 0;
  273. byte high_byte_old = 0;
  274. byte low_byte = 0;
  275. int y = 0;
  276. int i = 0;
  277. for (y = 0; y < len ; y++) {
  278. this_byte = strtol(pdu_text.substring(i * 2, (i * 2) + 2).c_str(), NULL, 16);
  279. low_mask = high_mask ^ 0xFF; //invert
  280. high_byte_new = this_byte & high_mask; // 10000000 = 11000111 & 10000000
  281. low_byte = this_byte & low_mask; // 01000111 = 11000111 & 01111111
  282. plain_bytes[y] = low_byte << shift; // 10001110
  283. high_byte_old = high_byte_old >> (8 - shift); // 00000001
  284. plain_bytes[y] = plain_bytes[y] + high_byte_old; // 10001111
  285. if (shift == 6) {
  286. y++;
  287. plain_bytes[y] = high_byte_new >> 1;
  288. }
  289. high_mask = high_mask >> 1; // 10000000 > 01000000
  290. high_mask = high_mask + 128; // 01000000 > 11000000
  291. if (high_mask == 255)high_mask = 128; // 11111111 > 10000000
  292. low_mask = high_mask ^ 0xFF; // invert
  293. high_byte_old = high_byte_new;
  294. shift++;
  295. if (shift == 7) {
  296. shift = 0;
  297. }
  298. i++;
  299. }
  300. plain_bytes[y] = 0;
  301. char *plain_text = new char[y];
  302. strcpy(plain_text, plain_bytes);
  303. return plain_text;
  304. }
  305. String PDU::semiOctetToString (String semiOctet) {
  306. unsigned int i;
  307. String OctetString;
  308. for (i = 0; i < ( semiOctet.length() / 2 ); i++) {
  309. OctetString += semiOctet.substring(i*2 + 1,i*2 + 1+1);
  310. OctetString += semiOctet.substring(i*2, i*2+1);
  311. }
  312. return OctetString;
  313. }
  314. String PDU::stringToSemiOctet (String StringData) {
  315. if ( StringData.length() % 2 != 0 ) {
  316. StringData += "F";
  317. }
  318. return semiOctetToString(StringData);
  319. }
  320. int PDU::hexStringToInt (String hexString) {
  321. unsigned int i;
  322. int charvalue;
  323. int returnvalue = 0;
  324. for (i = 0; i < hexString.length(); i++) {
  325. if ( hexString[i] >= 'a' && hexString[i] <= 'f' ) {
  326. charvalue = (int) hexString[i] - 87;
  327. }
  328. if ( hexString[i] >= 'A' && hexString[i] <= 'F' ) {
  329. charvalue = (int) hexString[i] - 55;
  330. }
  331. if ( hexString[i] >= '0' && hexString[i] <= '9' ) {
  332. charvalue = (int) hexString[i] - 48;
  333. }
  334. returnvalue += charvalue * ( pow(16, (int)(hexString.length() - (i + 1)) ));
  335. }
  336. return returnvalue;
  337. }
  338. String PDU::intToHexString (int integer) {
  339. String hexString = "";
  340. //Conversion from intToHex
  341. char buf[3];
  342. sprintf(buf,"%X",integer);
  343. hexString = (String)buf;
  344. //Prepend a 0 when not even
  345. if ( hexString.length() % 2 != 0 ){
  346. hexString = "0" + hexString;
  347. }
  348. return hexString;
  349. }
  350. int PDU::binStringToInt (String binString) {
  351. unsigned int pos;
  352. int integerReturn = 0;
  353. int base = 2;
  354. for (pos = 0; pos < binString.length(); pos++) {
  355. if ( binString.substring(pos, pos+1) == "1" ) {
  356. integerReturn += pow(base, (binString.length() - (pos + 1)) );
  357. }
  358. }
  359. return integerReturn;
  360. }
  361. String PDU::intToBinString (int integer) {
  362. String stringReturn;
  363. if (integer <= 0) {
  364. return "0";
  365. }
  366. while ( integer > 0 ) {
  367. if ( integer % 2 == 1 ) {
  368. stringReturn = "1" + stringReturn;
  369. --integer;
  370. } else {
  371. stringReturn = "0" + stringReturn;
  372. }
  373. integer = integer / 2;
  374. }
  375. //Changed 8 to 7 because the characters are in septets
  376. while ( stringReturn.length() % 7 != 0 ) {
  377. stringReturn = "0" + stringReturn;
  378. }
  379. return stringReturn;
  380. }
  381. int PDU::pow(int n, int i)
  382. {
  383. if (i == 0)
  384. return 1;
  385. else if (i == 1)
  386. return n;
  387. else {
  388. int partial = pow(n, i / 2);
  389. if (i % 2 == 0)
  390. return partial * partial;
  391. else
  392. return partial * partial * n;
  393. }
  394. }
  395. int PDU::setText( String smstext ) {
  396. if ( smstext.length() > 160 ) {
  397. return 0;
  398. }
  399. this->tp_text = smstext;
  400. return 1;
  401. }
  402. int PDU::setSender( String number ) {
  403. this->sender_type_of_address = 146;
  404. if ( number.substring(0,1) == "+" ) {
  405. this->sender_type_of_address = 145;
  406. this->sender_number = number.substring(1, number.length());
  407. } else {
  408. this->sender_number = number;
  409. }
  410. this->sender_length = this->sender_number.length();
  411. if ( this->sender_number.length() % 2 == 1 ) {
  412. this->sender_number + "F";
  413. }
  414. return 1;
  415. }
  416. String PDU::userTextTo7(void) {
  417. unsigned int pos;
  418. String current, octetFirst, octetSecond, currentOctet;
  419. String output;
  420. for (pos = 0; pos < this->tp_text.length(); pos++) {
  421. current = intToBinString(lookup_ascii8to7[ this->tp_text[pos] ]);
  422. if ( ( pos != 0 ) && ( pos % 8 != 0 ) ) {
  423. octetFirst = current.substring(7 - ( pos % 8 ), current.length() );
  424. currentOctet = octetFirst + octetSecond;
  425. output += intToHexString(binStringToInt(currentOctet));
  426. octetSecond = current.substring(0, 7 - (pos % 8));
  427. }
  428. else {
  429. octetSecond = current.substring(0, 7 - (pos % 8));
  430. }
  431. if ( ( pos + 1 == this->tp_text.length() ) && ( octetSecond != "" ) ) {
  432. output += intToHexString(binStringToInt(octetSecond));
  433. }
  434. }
  435. return output;
  436. }
  437. String PDU::encode() {
  438. String pduString;
  439. pduString = "00"; // SMSC_LENGHT
  440. pduString += "1100"; // FIRST OCTET ( message submit & tp reference)
  441. pduString += intToHexString(this->sender_length); // SENDER_LENGHT
  442. pduString += intToHexString(this->sender_type_of_address); // SENDER_TYPE
  443. pduString += stringToSemiOctet(this->sender_number); // SENDER_NUMBER
  444. pduString += "0000"; // TP-PID TP-DCS ( 7-bit default encoding )
  445. pduString += "AA"; // VALIDITY ( 4 days )
  446. pduString += intToHexString(this->tp_text.length());
  447. pduString += userTextTo7();
  448. return pduString;
  449. }