Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TinyGsmClientSIM800.h 21KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. /**
  2. * file TinyGsmClientSIM800.h
  3. * author Volodymyr Shymanskyy
  4. * license LGPL-3.0
  5. * copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * date Nov 2016
  7. */
  8. #ifndef TinyGsmClientSIM800_h
  9. #define TinyGsmClientSIM800_h
  10. //#define TINY_GSM_DEBUG Serial
  11. //#define TINY_GSM_USE_HEX
  12. #if !defined(TINY_GSM_RX_BUFFER)
  13. #define TINY_GSM_RX_BUFFER 64
  14. #endif
  15. #define TINY_GSM_MUX_COUNT 5
  16. #include "TinyGsmCommon.h"
  17. #define GSM_NL "\r\n"
  18. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  19. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  20. enum SimStatus {
  21. SIM_ERROR = 0,
  22. SIM_READY = 1,
  23. SIM_LOCKED = 2,
  24. };
  25. enum RegStatus {
  26. REG_UNREGISTERED = 0,
  27. REG_SEARCHING = 2,
  28. REG_DENIED = 3,
  29. REG_OK_HOME = 1,
  30. REG_OK_ROAMING = 5,
  31. REG_UNKNOWN = 4,
  32. };
  33. class TinyGsmSim800
  34. {
  35. public:
  36. class GsmClient : public Client
  37. {
  38. friend class TinyGsmSim800;
  39. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  40. public:
  41. GsmClient() {}
  42. GsmClient(TinyGsmSim800& modem, uint8_t mux = 1)
  43. {
  44. init(&modem, mux);
  45. }
  46. bool init(TinyGsmSim800* modem, uint8_t mux = 1)
  47. {
  48. this->at = modem;
  49. this->mux = mux;
  50. sock_available = 0;
  51. prev_check = 0;
  52. sock_connected = false;
  53. got_data = false;
  54. at->sockets[mux] = this;
  55. return true;
  56. }
  57. public:
  58. virtual int connect(const char *host, uint16_t port)
  59. {
  60. stop();
  61. TINY_GSM_YIELD();
  62. rx.clear();
  63. sock_connected = at->modemConnect(host, port, mux);
  64. return sock_connected;
  65. }
  66. virtual int connect(IPAddress ip, uint16_t port)
  67. {
  68. String host;
  69. host.reserve(16);
  70. host += ip[0];
  71. host += ".";
  72. host += ip[1];
  73. host += ".";
  74. host += ip[2];
  75. host += ".";
  76. host += ip[3];
  77. return connect(host.c_str(), port);
  78. }
  79. virtual void stop()
  80. {
  81. TINY_GSM_YIELD();
  82. at->sendAT(GF("+CIPCLOSE="), mux);
  83. sock_connected = false;
  84. at->waitResponse();
  85. rx.clear();
  86. }
  87. virtual size_t write(const uint8_t *buf, size_t size)
  88. {
  89. TINY_GSM_YIELD();
  90. at->maintain();
  91. return at->modemSend(buf, size, mux);
  92. }
  93. virtual size_t write(uint8_t c)
  94. {
  95. return write(&c, 1);
  96. }
  97. virtual int available()
  98. {
  99. TINY_GSM_YIELD();
  100. if (!rx.size() && sock_connected) {
  101. // Workaround: sometimes SIM800 forgets to notify about data arrival.
  102. // TODO: Currently we ping the module periodically,
  103. // but maybe there's a better indicator that we need to poll
  104. if (millis() - prev_check > 500) {
  105. got_data = true;
  106. prev_check = millis();
  107. }
  108. at->maintain();
  109. }
  110. return rx.size() + sock_available;
  111. }
  112. virtual int read(uint8_t *buf, size_t size)
  113. {
  114. TINY_GSM_YIELD();
  115. at->maintain();
  116. size_t cnt = 0;
  117. while (cnt < size && sock_connected) {
  118. size_t chunk = TinyGsmMin(size-cnt, rx.size());
  119. if (chunk > 0) {
  120. rx.get(buf, chunk);
  121. buf += chunk;
  122. cnt += chunk;
  123. continue;
  124. }
  125. // TODO: Read directly into user buffer?
  126. at->maintain();
  127. if (sock_available > 0) {
  128. at->modemRead(rx.free(), mux);
  129. } else {
  130. break;
  131. }
  132. }
  133. return cnt;
  134. }
  135. virtual int read()
  136. {
  137. uint8_t c;
  138. if (read(&c, 1) == 1) {
  139. return c;
  140. }
  141. return -1;
  142. }
  143. virtual int peek()
  144. {
  145. return -1; //TODO
  146. }
  147. virtual void flush()
  148. {
  149. at->stream.flush();
  150. }
  151. virtual uint8_t connected()
  152. {
  153. if (available()) {
  154. return true;
  155. }
  156. return sock_connected;
  157. }
  158. virtual operator bool()
  159. {
  160. return connected();
  161. }
  162. /*
  163. * Extended API
  164. */
  165. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  166. private:
  167. TinyGsmSim800* at;
  168. uint8_t mux;
  169. uint16_t sock_available;
  170. uint32_t prev_check;
  171. bool sock_connected;
  172. bool got_data;
  173. RxFifo rx;
  174. };
  175. class GsmClientSecure : public GsmClient
  176. {
  177. public:
  178. GsmClientSecure() {}
  179. GsmClientSecure(TinyGsmSim800& modem, uint8_t mux = 1)
  180. : GsmClient(modem, mux)
  181. {}
  182. public:
  183. virtual int connect(const char *host, uint16_t port)
  184. {
  185. stop();
  186. TINY_GSM_YIELD();
  187. rx.clear();
  188. sock_connected = at->modemConnect(host, port, mux, true);
  189. return sock_connected;
  190. }
  191. };
  192. public:
  193. explicit TinyGsmSim800(Stream& stream)
  194. : stream(stream)
  195. {
  196. memset(sockets, 0, sizeof(sockets));
  197. }
  198. /*
  199. * Basic functions
  200. */
  201. bool begin()
  202. {
  203. return init();
  204. }
  205. bool init()
  206. {
  207. if (!testAT()) {
  208. return false;
  209. }
  210. sendAT(GF("&FZ")); // Factory + Reset
  211. waitResponse();
  212. sendAT(GF("E0")); // Echo Off
  213. if (waitResponse() != 1) {
  214. return false;
  215. }
  216. getSimStatus();
  217. return true;
  218. }
  219. void setBaud(unsigned long baud)
  220. {
  221. sendAT(GF("+IPR="), baud);
  222. }
  223. bool testAT(unsigned long timeout = 10000L)
  224. {
  225. //streamWrite(GF("AAAAA" GSM_NL)); // TODO: extra A's to help detect the baud rate
  226. for (unsigned long start = millis(); millis() - start < timeout; ) {
  227. sendAT(GF(""));
  228. if (waitResponse(200) == 1) {
  229. delay(100);
  230. return true;
  231. }
  232. delay(100);
  233. }
  234. return false;
  235. }
  236. void maintain()
  237. {
  238. for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
  239. GsmClient* sock = sockets[mux];
  240. if (sock && sock->got_data) {
  241. sock->got_data = false;
  242. sock->sock_available = modemGetAvailable(mux);
  243. }
  244. }
  245. while (stream.available()) {
  246. waitResponse(10, NULL, NULL);
  247. }
  248. }
  249. bool factoryDefault()
  250. {
  251. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  252. waitResponse();
  253. sendAT(GF("+IPR=0")); // Auto-baud
  254. waitResponse();
  255. sendAT(GF("+IFC=0,0")); // No Flow Control
  256. waitResponse();
  257. sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
  258. waitResponse();
  259. sendAT(GF("+CSCLK=0")); // Disable Slow Clock
  260. waitResponse();
  261. sendAT(GF("&W")); // Write configuration
  262. return waitResponse() == 1;
  263. }
  264. String getModemInfo()
  265. {
  266. sendAT(GF("I"));
  267. String res;
  268. if (waitResponse(1000L, res) != 1) {
  269. return "";
  270. }
  271. res.replace(GSM_NL "OK" GSM_NL, "");
  272. res.replace(GSM_NL, " ");
  273. res.trim();
  274. return res;
  275. }
  276. bool hasSSL()
  277. {
  278. #if defined(TINY_GSM_MODEM_SIM900)
  279. return false;
  280. #else
  281. sendAT(GF("+CIPSSL=?"));
  282. if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
  283. return false;
  284. }
  285. return waitResponse() == 1;
  286. #endif
  287. }
  288. /*
  289. * Power functions
  290. */
  291. bool restart()
  292. {
  293. if (!testAT()) {
  294. return false;
  295. }
  296. sendAT(GF("+CFUN=0"));
  297. if (waitResponse(10000L) != 1) {
  298. return false;
  299. }
  300. sendAT(GF("+CFUN=1,1"));
  301. if (waitResponse(10000L) != 1) {
  302. return false;
  303. }
  304. delay(3000);
  305. return init();
  306. }
  307. bool poweroff()
  308. {
  309. sendAT(GF("+CPOWD=1"));
  310. return waitResponse(GF("NORMAL POWER DOWN")) == 1;
  311. }
  312. bool radioOff()
  313. {
  314. sendAT(GF("+CFUN=0"));
  315. if (waitResponse(10000L) != 1) {
  316. return false;
  317. }
  318. delay(3000);
  319. return true;
  320. }
  321. /*
  322. During sleep, the SIM800 module has its serial communication disabled. In order to reestablish communication
  323. pull the DRT-pin of the SIM800 module LOW for at least 50ms. Then use this function to disable sleep mode.
  324. The DTR-pin can then be released again.
  325. */
  326. bool sleepEnable(bool enable = true)
  327. {
  328. sendAT(GF("+CSCLK="), enable);
  329. return waitResponse() == 1;
  330. }
  331. /*
  332. * SIM card functions
  333. */
  334. bool simUnlock(const char *pin)
  335. {
  336. sendAT(GF("+CPIN=\""), pin, GF("\""));
  337. return waitResponse() == 1;
  338. }
  339. String getSimCCID()
  340. {
  341. sendAT(GF("+ICCID"));
  342. if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
  343. return "";
  344. }
  345. String res = stream.readStringUntil('\n');
  346. waitResponse();
  347. res.trim();
  348. return res;
  349. }
  350. String getIMEI()
  351. {
  352. sendAT(GF("+GSN"));
  353. if (waitResponse(GF(GSM_NL)) != 1) {
  354. return "";
  355. }
  356. String res = stream.readStringUntil('\n');
  357. waitResponse();
  358. res.trim();
  359. return res;
  360. }
  361. SimStatus getSimStatus(unsigned long timeout = 10000L)
  362. {
  363. for (unsigned long start = millis(); millis() - start < timeout; ) {
  364. sendAT(GF("+CPIN?"));
  365. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  366. delay(1000);
  367. continue;
  368. }
  369. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
  370. waitResponse();
  371. switch (status) {
  372. case 2:
  373. case 3:
  374. return SIM_LOCKED;
  375. case 1:
  376. return SIM_READY;
  377. default:
  378. return SIM_ERROR;
  379. }
  380. }
  381. return SIM_ERROR;
  382. }
  383. RegStatus getRegistrationStatus()
  384. {
  385. sendAT(GF("+CREG?"));
  386. if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
  387. return REG_UNKNOWN;
  388. }
  389. streamSkipUntil(','); // Skip format (0)
  390. int status = stream.readStringUntil('\n').toInt();
  391. waitResponse();
  392. return (RegStatus)status;
  393. }
  394. String getOperator()
  395. {
  396. sendAT(GF("+COPS?"));
  397. if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
  398. return "";
  399. }
  400. streamSkipUntil('"'); // Skip mode and format
  401. String res = stream.readStringUntil('"');
  402. waitResponse();
  403. return res;
  404. }
  405. /*
  406. * Generic network functions
  407. */
  408. int getSignalQuality()
  409. {
  410. sendAT(GF("+CSQ"));
  411. if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
  412. return 99;
  413. }
  414. int res = stream.readStringUntil(',').toInt();
  415. waitResponse();
  416. return res;
  417. }
  418. bool isNetworkConnected()
  419. {
  420. RegStatus s = getRegistrationStatus();
  421. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  422. }
  423. bool waitForNetwork(unsigned long timeout = 60000L)
  424. {
  425. for (unsigned long start = millis(); millis() - start < timeout; ) {
  426. if (isNetworkConnected()) {
  427. return true;
  428. }
  429. delay(250);
  430. }
  431. return false;
  432. }
  433. /*
  434. * GPRS functions
  435. */
  436. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
  437. {
  438. gprsDisconnect();
  439. // Set the Bearer for the IP
  440. sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
  441. waitResponse();
  442. sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
  443. waitResponse();
  444. if (user && strlen(user) > 0) {
  445. sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
  446. waitResponse();
  447. }
  448. if (pwd && strlen(pwd) > 0) {
  449. sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
  450. waitResponse();
  451. }
  452. // Define the PDP context
  453. sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
  454. waitResponse();
  455. // Activate the PDP context
  456. sendAT(GF("+CGACT=1,1"));
  457. waitResponse(60000L);
  458. // Open the definied GPRS bearer context
  459. sendAT(GF("+SAPBR=1,1"));
  460. waitResponse(85000L);
  461. // Query the GPRS bearer context status
  462. sendAT(GF("+SAPBR=2,1"));
  463. if (waitResponse(30000L) != 1) {
  464. return false;
  465. }
  466. // Attach to GPRS
  467. sendAT(GF("+CGATT=1"));
  468. if (waitResponse(60000L) != 1) {
  469. return false;
  470. }
  471. // TODO: wait AT+CGATT?
  472. // Set to multi-IP
  473. sendAT(GF("+CIPMUX=1"));
  474. if (waitResponse() != 1) {
  475. return false;
  476. }
  477. // Put in "quick send" mode (thus no extra "Send OK")
  478. sendAT(GF("+CIPQSEND=1"));
  479. if (waitResponse() != 1) {
  480. return false;
  481. }
  482. // Set to get data manually
  483. sendAT(GF("+CIPRXGET=1"));
  484. if (waitResponse() != 1) {
  485. return false;
  486. }
  487. // Start Task and Set APN, USER NAME, PASSWORD
  488. sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  489. if (waitResponse(60000L) != 1) {
  490. return false;
  491. }
  492. // Bring Up Wireless Connection with GPRS or CSD
  493. sendAT(GF("+CIICR"));
  494. if (waitResponse(60000L) != 1) {
  495. return false;
  496. }
  497. // Get Local IP Address, only assigned after connection
  498. sendAT(GF("+CIFSR;E0"));
  499. if (waitResponse(10000L) != 1) {
  500. return false;
  501. }
  502. // Configure Domain Name Server (DNS)
  503. sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
  504. if (waitResponse() != 1) {
  505. return false;
  506. }
  507. return true;
  508. }
  509. bool gprsDisconnect()
  510. {
  511. // Shut the TCP/IP connection
  512. sendAT(GF("+CIPSHUT"));
  513. if (waitResponse(60000L) != 1) {
  514. return false;
  515. }
  516. sendAT(GF("+CGATT=0")); // Deactivate the bearer context
  517. if (waitResponse(60000L) != 1) {
  518. return false;
  519. }
  520. return true;
  521. }
  522. bool isGprsConnected()
  523. {
  524. sendAT(GF("+CGATT?"));
  525. if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
  526. return false;
  527. }
  528. int res = stream.readStringUntil('\n').toInt();
  529. waitResponse();
  530. if (res != 1) {
  531. return false;
  532. }
  533. sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1
  534. if (waitResponse() != 1) {
  535. return false;
  536. }
  537. return true;
  538. }
  539. String getLocalIP()
  540. {
  541. sendAT(GF("+CIFSR;E0"));
  542. String res;
  543. if (waitResponse(10000L, res) != 1) {
  544. return "";
  545. }
  546. res.replace(GSM_NL "OK" GSM_NL, "");
  547. res.replace(GSM_NL, "");
  548. res.trim();
  549. return res;
  550. }
  551. IPAddress localIP()
  552. {
  553. return TinyGsmIpFromString(getLocalIP());
  554. }
  555. /*
  556. * Phone Call functions
  557. */
  558. bool setGsmBusy(bool busy = true)
  559. {
  560. sendAT(GF("+GSMBUSY="), busy ? 1 : 0);
  561. return waitResponse() == 1;
  562. }
  563. bool callAnswer()
  564. {
  565. sendAT(GF("A"));
  566. return waitResponse() == 1;
  567. }
  568. // Returns true on pick-up, false on error/busy
  569. bool callNumber(const String& number)
  570. {
  571. if (number == GF("last")) {
  572. sendAT(GF("DL"));
  573. } else {
  574. sendAT(GF("D"), number, ";");
  575. }
  576. int status = waitResponse(60000L,
  577. GFP(GSM_OK),
  578. GF("BUSY" GSM_NL),
  579. GF("NO ANSWER" GSM_NL),
  580. GF("NO CARRIER" GSM_NL));
  581. switch (status) {
  582. case 1:
  583. return true;
  584. case 2:
  585. case 3:
  586. return false;
  587. default:
  588. return false;
  589. }
  590. }
  591. bool callHangup()
  592. {
  593. sendAT(GF("H"));
  594. return waitResponse() == 1;
  595. }
  596. // 0-9,*,#,A,B,C,D
  597. bool dtmfSend(char cmd, int duration_ms = 100)
  598. {
  599. duration_ms = constrain(duration_ms, 100, 1000);
  600. sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second
  601. waitResponse();
  602. sendAT(GF("+VTS="), cmd);
  603. return waitResponse(10000L) == 1;
  604. }
  605. /*
  606. * Messaging functions
  607. */
  608. String sendUSSD(const String& code)
  609. {
  610. sendAT(GF("+CMGF=1"));
  611. waitResponse();
  612. sendAT(GF("+CSCS=\"HEX\""));
  613. waitResponse();
  614. sendAT(GF("+CUSD=1,\""), code, GF("\""));
  615. if (waitResponse() != 1) {
  616. return "";
  617. }
  618. if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
  619. return "";
  620. }
  621. stream.readStringUntil('"');
  622. String hex = stream.readStringUntil('"');
  623. stream.readStringUntil(',');
  624. int dcs = stream.readStringUntil('\n').toInt();
  625. if (dcs == 15) {
  626. return TinyGsmDecodeHex8bit(hex);
  627. } else if (dcs == 72) {
  628. return TinyGsmDecodeHex16bit(hex);
  629. } else {
  630. return hex;
  631. }
  632. }
  633. bool sendSMS(const String& number, const String& text)
  634. {
  635. sendAT(GF("+CMGF=1"));
  636. waitResponse();
  637. //Set GSM 7 bit default alphabet (3GPP TS 23.038)
  638. sendAT(GF("+CSCS=\"GSM\""));
  639. waitResponse();
  640. sendAT(GF("+CMGS=\""), number, GF("\""));
  641. if (waitResponse(GF(">")) != 1) {
  642. return false;
  643. }
  644. stream.print(text);
  645. stream.write((char)0x1A);
  646. stream.flush();
  647. return waitResponse(60000L) == 1;
  648. }
  649. bool sendSMS_UTF16(const String& number, const void* text, size_t len)
  650. {
  651. sendAT(GF("+CMGF=1"));
  652. waitResponse();
  653. sendAT(GF("+CSCS=\"HEX\""));
  654. waitResponse();
  655. sendAT(GF("+CSMP=17,167,0,8"));
  656. waitResponse();
  657. sendAT(GF("+CMGS=\""), number, GF("\""));
  658. if (waitResponse(GF(">")) != 1) {
  659. return false;
  660. }
  661. uint16_t* t = (uint16_t*)text;
  662. for (size_t i=0; i<len; i++) {
  663. uint8_t c = t[i] >> 8;
  664. if (c < 0x10) {
  665. stream.print('0');
  666. }
  667. stream.print(c, HEX);
  668. c = t[i] & 0xFF;
  669. if (c < 0x10) {
  670. stream.print('0');
  671. }
  672. stream.print(c, HEX);
  673. }
  674. stream.write((char)0x1A);
  675. stream.flush();
  676. return waitResponse(60000L) == 1;
  677. }
  678. /*
  679. * Location functions
  680. */
  681. String getGsmLocation()
  682. {
  683. sendAT(GF("+CIPGSMLOC=1,1"));
  684. if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
  685. return "";
  686. }
  687. String res = stream.readStringUntil('\n');
  688. waitResponse();
  689. res.trim();
  690. return res;
  691. }
  692. /*
  693. * Battery functions
  694. */
  695. // Use: float vBatt = modem.getBattVoltage() / 1000.0;
  696. uint16_t getBattVoltage()
  697. {
  698. sendAT(GF("+CBC"));
  699. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  700. return 0;
  701. }
  702. streamSkipUntil(','); // Skip
  703. streamSkipUntil(','); // Skip
  704. uint16_t res = stream.readStringUntil(',').toInt();
  705. waitResponse();
  706. return res;
  707. }
  708. int getBattPercent()
  709. {
  710. sendAT(GF("+CBC"));
  711. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  712. return false;
  713. }
  714. stream.readStringUntil(',');
  715. int res = stream.readStringUntil(',').toInt();
  716. waitResponse();
  717. return res;
  718. }
  719. protected:
  720. bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false)
  721. {
  722. #if !defined(TINY_GSM_MODEM_SIM900)
  723. sendAT(GF("+CIPSSL="), ssl);
  724. int rsp = waitResponse();
  725. if (ssl && rsp != 1) {
  726. return false;
  727. }
  728. #endif
  729. sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  730. rsp = waitResponse(75000L,
  731. GF("CONNECT OK" GSM_NL),
  732. GF("CONNECT FAIL" GSM_NL),
  733. GF("ALREADY CONNECT" GSM_NL),
  734. GF("ERROR" GSM_NL),
  735. GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails
  736. );
  737. return (1 == rsp);
  738. }
  739. int modemSend(const void* buff, size_t len, uint8_t mux)
  740. {
  741. sendAT(GF("+CIPSEND="), mux, ',', len);
  742. if (waitResponse(GF(">")) != 1) {
  743. return 0;
  744. }
  745. stream.write((uint8_t*)buff, len);
  746. stream.flush();
  747. if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) {
  748. return 0;
  749. }
  750. streamSkipUntil(','); // Skip mux
  751. return stream.readStringUntil('\n').toInt();
  752. }
  753. size_t modemRead(size_t size, uint8_t mux)
  754. {
  755. #ifdef TINY_GSM_USE_HEX
  756. sendAT(GF("+CIPRXGET=3,"), mux, ',', size);
  757. if (waitResponse(GF("+CIPRXGET:")) != 1) {
  758. return 0;
  759. }
  760. #else
  761. sendAT(GF("+CIPRXGET=2,"), mux, ',', size);
  762. if (waitResponse(GF("+CIPRXGET:")) != 1) {
  763. return 0;
  764. }
  765. #endif
  766. streamSkipUntil(','); // Skip mode 2/3
  767. streamSkipUntil(','); // Skip mux
  768. size_t len = stream.readStringUntil(',').toInt();
  769. sockets[mux]->sock_available = stream.readStringUntil('\n').toInt();
  770. for (size_t i=0; i<len; i++) {
  771. #ifdef TINY_GSM_USE_HEX
  772. while (stream.available() < 2) {
  773. TINY_GSM_YIELD();
  774. }
  775. char buf[4] = { 0, };
  776. buf[0] = stream.read();
  777. buf[1] = stream.read();
  778. char c = strtol(buf, NULL, 16);
  779. #else
  780. while (!stream.available()) {
  781. TINY_GSM_YIELD();
  782. }
  783. char c = stream.read();
  784. #endif
  785. sockets[mux]->rx.put(c);
  786. }
  787. waitResponse();
  788. return len;
  789. }
  790. size_t modemGetAvailable(uint8_t mux)
  791. {
  792. sendAT(GF("+CIPRXGET=4,"), mux);
  793. size_t result = 0;
  794. if (waitResponse(GF("+CIPRXGET:")) == 1) {
  795. streamSkipUntil(','); // Skip mode 4
  796. streamSkipUntil(','); // Skip mux
  797. result = stream.readStringUntil('\n').toInt();
  798. waitResponse();
  799. }
  800. if (!result) {
  801. sockets[mux]->sock_connected = modemGetConnected(mux);
  802. }
  803. return result;
  804. }
  805. bool modemGetConnected(uint8_t mux)
  806. {
  807. sendAT(GF("+CIPSTATUS="), mux);
  808. int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
  809. GF(",\"INITIAL\""));
  810. waitResponse();
  811. return 1 == res;
  812. }
  813. public:
  814. /* Utilities */
  815. template<typename T>
  816. void streamWrite(T last)
  817. {
  818. stream.print(last);
  819. }
  820. template<typename T, typename... Args>
  821. void streamWrite(T head, Args... tail)
  822. {
  823. stream.print(head);
  824. streamWrite(tail...);
  825. }
  826. bool streamSkipUntil(char c) //TODO: timeout
  827. {
  828. while (true) {
  829. while (!stream.available()) {
  830. TINY_GSM_YIELD();
  831. }
  832. if (stream.read() == c) {
  833. return true;
  834. }
  835. }
  836. return false;
  837. }
  838. template<typename... Args>
  839. void sendAT(Args... cmd)
  840. {
  841. streamWrite("AT", cmd..., GSM_NL);
  842. stream.flush();
  843. TINY_GSM_YIELD();
  844. //DBG("### AT:", cmd...);
  845. }
  846. // TODO: Optimize this!
  847. uint8_t waitResponse(uint32_t timeout, String& data,
  848. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  849. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  850. {
  851. /*String r1s(r1); r1s.trim();
  852. String r2s(r2); r2s.trim();
  853. String r3s(r3); r3s.trim();
  854. String r4s(r4); r4s.trim();
  855. String r5s(r5); r5s.trim();
  856. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  857. data.reserve(64);
  858. int index = 0;
  859. unsigned long startMillis = millis();
  860. do {
  861. TINY_GSM_YIELD();
  862. while (stream.available() > 0) {
  863. int a = stream.read();
  864. if (a <= 0) {
  865. continue; // Skip 0x00 bytes, just in case
  866. }
  867. data += (char)a;
  868. if (r1 && data.endsWith(r1)) {
  869. index = 1;
  870. goto finish;
  871. } else if (r2 && data.endsWith(r2)) {
  872. index = 2;
  873. goto finish;
  874. } else if (r3 && data.endsWith(r3)) {
  875. index = 3;
  876. goto finish;
  877. } else if (r4 && data.endsWith(r4)) {
  878. index = 4;
  879. goto finish;
  880. } else if (r5 && data.endsWith(r5)) {
  881. index = 5;
  882. goto finish;
  883. } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
  884. String mode = stream.readStringUntil(',');
  885. if (mode.toInt() == 1) {
  886. int mux = stream.readStringUntil('\n').toInt();
  887. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  888. sockets[mux]->got_data = true;
  889. }
  890. data = "";
  891. } else {
  892. data += mode;
  893. }
  894. } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
  895. int nl = data.lastIndexOf(GSM_NL, data.length()-8);
  896. int coma = data.indexOf(',', nl+2);
  897. int mux = data.substring(nl+2, coma).toInt();
  898. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  899. sockets[mux]->sock_connected = false;
  900. }
  901. data = "";
  902. DBG("### Closed: ", mux);
  903. }
  904. }
  905. } while (millis() - startMillis < timeout);
  906. finish:
  907. if (!index) {
  908. data.trim();
  909. if (data.length()) {
  910. DBG("### Unhandled:", data);
  911. }
  912. data = "";
  913. }
  914. return index;
  915. }
  916. uint8_t waitResponse(uint32_t timeout,
  917. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  918. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  919. {
  920. String data;
  921. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  922. }
  923. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  924. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  925. {
  926. return waitResponse(1000, r1, r2, r3, r4, r5);
  927. }
  928. public:
  929. Stream& stream;
  930. protected:
  931. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  932. };
  933. #endif