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.

TinyGsmClientA6.h 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. /**
  2. * file TinyGsmClientA6.h
  3. * author Volodymyr Shymanskyy
  4. * license LGPL-3.0
  5. * copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * date Nov 2016
  7. */
  8. #ifndef TinyGsmClientA6_h
  9. #define TinyGsmClientA6_h
  10. //#define TINY_GSM_DEBUG Serial
  11. #if !defined(TINY_GSM_RX_BUFFER)
  12. #define TINY_GSM_RX_BUFFER 256
  13. #endif
  14. #define TINY_GSM_MUX_COUNT 8
  15. #include "TinyGsmCommon.h"
  16. #define GSM_NL "\r\n"
  17. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  18. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  19. enum SimStatus {
  20. SIM_ERROR = 0,
  21. SIM_READY = 1,
  22. SIM_LOCKED = 2,
  23. };
  24. enum RegStatus {
  25. REG_UNREGISTERED = 0,
  26. REG_SEARCHING = 2,
  27. REG_DENIED = 3,
  28. REG_OK_HOME = 1,
  29. REG_OK_ROAMING = 5,
  30. REG_UNKNOWN = 4,
  31. };
  32. class TinyGsm
  33. {
  34. public:
  35. class GsmClient : public Client
  36. {
  37. friend class TinyGsm;
  38. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  39. public:
  40. GsmClient() {}
  41. GsmClient(TinyGsm& modem)
  42. {
  43. init(&modem);
  44. }
  45. bool init(TinyGsm* modem)
  46. {
  47. this->at = modem;
  48. this->mux = -1;
  49. sock_connected = false;
  50. return true;
  51. }
  52. public:
  53. virtual int connect(const char *host, uint16_t port)
  54. {
  55. stop();
  56. TINY_GSM_YIELD();
  57. rx.clear();
  58. uint8_t newMux = -1;
  59. sock_connected = at->modemConnect(host, port, &newMux);
  60. if (sock_connected) {
  61. mux = newMux;
  62. at->sockets[mux] = this;
  63. }
  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. at->maintain();
  102. }
  103. return rx.size();
  104. }
  105. virtual int read(uint8_t *buf, size_t size)
  106. {
  107. TINY_GSM_YIELD();
  108. size_t cnt = 0;
  109. while (cnt < size) {
  110. size_t chunk = TinyGsmMin(size-cnt, rx.size());
  111. if (chunk > 0) {
  112. rx.get(buf, chunk);
  113. buf += chunk;
  114. cnt += chunk;
  115. continue;
  116. }
  117. // TODO: Read directly into user buffer?
  118. if (!rx.size() && sock_connected) {
  119. at->maintain();
  120. //break;
  121. }
  122. }
  123. return cnt;
  124. }
  125. virtual int read()
  126. {
  127. uint8_t c;
  128. if (read(&c, 1) == 1) {
  129. return c;
  130. }
  131. return -1;
  132. }
  133. virtual int peek()
  134. {
  135. return -1; //TODO
  136. }
  137. virtual void flush()
  138. {
  139. at->stream.flush();
  140. }
  141. virtual uint8_t connected()
  142. {
  143. if (available()) {
  144. return true;
  145. }
  146. return sock_connected;
  147. }
  148. virtual operator bool()
  149. {
  150. return connected();
  151. }
  152. /*
  153. * Extended API
  154. */
  155. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  156. private:
  157. TinyGsm* at;
  158. uint8_t mux;
  159. bool sock_connected;
  160. RxFifo rx;
  161. };
  162. public:
  163. explicit TinyGsm(Stream& stream)
  164. : stream(stream)
  165. {
  166. memset(sockets, 0, sizeof(sockets));
  167. }
  168. /*
  169. * Basic functions
  170. */
  171. bool begin()
  172. {
  173. return init();
  174. }
  175. bool init()
  176. {
  177. if (!testAT()) {
  178. return false;
  179. }
  180. sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
  181. if (waitResponse() != 1) {
  182. return false;
  183. }
  184. sendAT(GF("+CMEE=0"));
  185. waitResponse();
  186. sendAT(GF("+CMER=3,0,0,2"));
  187. waitResponse();
  188. getSimStatus();
  189. return true;
  190. }
  191. void setBaud(unsigned long baud)
  192. {
  193. sendAT(GF("+IPR="), baud);
  194. }
  195. bool testAT(unsigned long timeout = 10000L)
  196. {
  197. for (unsigned long start = millis(); millis() - start < timeout; ) {
  198. sendAT(GF(""));
  199. if (waitResponse(200) == 1) {
  200. delay(100);
  201. return true;
  202. }
  203. delay(100);
  204. }
  205. return false;
  206. }
  207. void maintain()
  208. {
  209. waitResponse(10, NULL, NULL);
  210. }
  211. bool factoryDefault()
  212. {
  213. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  214. waitResponse();
  215. sendAT(GF("&W")); // Write configuration
  216. return waitResponse() == 1;
  217. }
  218. String getModemInfo()
  219. {
  220. sendAT(GF("I"));
  221. String res;
  222. if (waitResponse(1000L, res) != 1) {
  223. return "";
  224. }
  225. res.replace(GSM_NL "OK" GSM_NL, "");
  226. res.replace(GSM_NL, " ");
  227. res.trim();
  228. return res;
  229. }
  230. bool hasSSL()
  231. {
  232. return false;
  233. }
  234. /*
  235. * Power functions
  236. */
  237. bool restart()
  238. {
  239. if (!testAT()) {
  240. return false;
  241. }
  242. sendAT(GF("+RST=1"));
  243. delay(3000);
  244. return init();
  245. }
  246. bool poweroff()
  247. {
  248. sendAT(GF("+CPOF"));
  249. return waitResponse() == 1;
  250. }
  251. bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  252. bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  253. /*
  254. * SIM card functions
  255. */
  256. bool simUnlock(const char *pin)
  257. {
  258. sendAT(GF("+CPIN=\""), pin, GF("\""));
  259. return waitResponse() == 1;
  260. }
  261. String getSimCCID()
  262. {
  263. sendAT(GF("+CCID"));
  264. if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
  265. return "";
  266. }
  267. String res = stream.readStringUntil('\n');
  268. waitResponse();
  269. res.trim();
  270. return res;
  271. }
  272. String getIMEI()
  273. {
  274. sendAT(GF("+GSN"));
  275. if (waitResponse(GF(GSM_NL)) != 1) {
  276. return "";
  277. }
  278. String res = stream.readStringUntil('\n');
  279. waitResponse();
  280. res.trim();
  281. return res;
  282. }
  283. SimStatus getSimStatus(unsigned long timeout = 10000L)
  284. {
  285. for (unsigned long start = millis(); millis() - start < timeout; ) {
  286. sendAT(GF("+CPIN?"));
  287. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  288. delay(1000);
  289. continue;
  290. }
  291. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
  292. waitResponse();
  293. switch (status) {
  294. case 2:
  295. case 3:
  296. return SIM_LOCKED;
  297. case 1:
  298. return SIM_READY;
  299. default:
  300. return SIM_ERROR;
  301. }
  302. }
  303. return SIM_ERROR;
  304. }
  305. RegStatus getRegistrationStatus()
  306. {
  307. sendAT(GF("+CREG?"));
  308. if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
  309. return REG_UNKNOWN;
  310. }
  311. streamSkipUntil(','); // Skip format (0)
  312. int status = stream.readStringUntil('\n').toInt();
  313. waitResponse();
  314. return (RegStatus)status;
  315. }
  316. String getOperator()
  317. {
  318. sendAT(GF("+COPS=3,0")); // Set format
  319. waitResponse();
  320. sendAT(GF("+COPS?"));
  321. if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
  322. return "";
  323. }
  324. streamSkipUntil('"'); // Skip mode and format
  325. String res = stream.readStringUntil('"');
  326. waitResponse();
  327. return res;
  328. }
  329. /*
  330. * Generic network functions
  331. */
  332. int getSignalQuality()
  333. {
  334. sendAT(GF("+CSQ"));
  335. if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
  336. return 99;
  337. }
  338. int res = stream.readStringUntil(',').toInt();
  339. waitResponse();
  340. return res;
  341. }
  342. bool isNetworkConnected()
  343. {
  344. RegStatus s = getRegistrationStatus();
  345. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  346. }
  347. bool waitForNetwork(unsigned long timeout = 60000L)
  348. {
  349. for (unsigned long start = millis(); millis() - start < timeout; ) {
  350. if (isNetworkConnected()) {
  351. return true;
  352. }
  353. delay(250);
  354. }
  355. return false;
  356. }
  357. /*
  358. * GPRS functions
  359. */
  360. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
  361. {
  362. gprsDisconnect();
  363. sendAT(GF("+CGATT=1"));
  364. if (waitResponse(60000L) != 1) {
  365. return false;
  366. }
  367. // TODO: wait AT+CGATT?
  368. sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
  369. waitResponse();
  370. if (!user) {
  371. user = "";
  372. }
  373. if (!pwd) {
  374. pwd = "";
  375. }
  376. sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  377. if (waitResponse(60000L) != 1) {
  378. return false;
  379. }
  380. sendAT(GF("+CGACT=1,1"));
  381. waitResponse(60000L);
  382. sendAT(GF("+CIPMUX=1"));
  383. if (waitResponse() != 1) {
  384. return false;
  385. }
  386. return true;
  387. }
  388. bool gprsDisconnect()
  389. {
  390. // Shut the TCP/IP connection
  391. sendAT(GF("+CIPSHUT"));
  392. if (waitResponse(60000L) != 1) {
  393. return false;
  394. }
  395. for (int i = 0; i<3; i++) {
  396. sendAT(GF("+CGATT=0"));
  397. if (waitResponse(5000L) == 1) {
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. bool isGprsConnected()
  404. {
  405. sendAT(GF("+CGATT?"));
  406. if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
  407. return false;
  408. }
  409. int res = stream.readStringUntil('\n').toInt();
  410. waitResponse();
  411. return (res == 1);
  412. }
  413. String getLocalIP()
  414. {
  415. sendAT(GF("+CIFSR"));
  416. String res;
  417. if (waitResponse(10000L, res) != 1) {
  418. return "";
  419. }
  420. res.replace(GSM_NL "OK" GSM_NL, "");
  421. res.replace(GSM_NL, "");
  422. res.trim();
  423. return res;
  424. }
  425. IPAddress localIP()
  426. {
  427. return TinyGsmIpFromString(getLocalIP());
  428. }
  429. /*
  430. * Phone Call functions
  431. */
  432. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  433. bool callAnswer()
  434. {
  435. sendAT(GF("A"));
  436. return waitResponse() == 1;
  437. }
  438. // Returns true on pick-up, false on error/busy
  439. bool callNumber(const String& number)
  440. {
  441. if (number == GF("last")) {
  442. sendAT(GF("DLST"));
  443. } else {
  444. sendAT(GF("D\""), number, "\";");
  445. }
  446. if (waitResponse(5000L) != 1) {
  447. return false;
  448. }
  449. if (waitResponse(60000L,
  450. GF(GSM_NL "+CIEV: \"CALL\",1"),
  451. GF(GSM_NL "+CIEV: \"CALL\",0"),
  452. GFP(GSM_ERROR)) != 1) {
  453. return false;
  454. }
  455. int rsp = waitResponse(60000L,
  456. GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
  457. GF(GSM_NL "+CIEV: \"CALL\",0"));
  458. int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL));
  459. return rsp == 1 && rsp2 == 0;
  460. }
  461. bool callHangup()
  462. {
  463. sendAT(GF("H"));
  464. return waitResponse() == 1;
  465. }
  466. // 0-9,*,#,A,B,C,D
  467. bool dtmfSend(char cmd, unsigned duration_ms = 100)
  468. {
  469. duration_ms = constrain(duration_ms, 100, 1000);
  470. // The duration parameter is not working, so we simulate it using delay..
  471. // TODO: Maybe there's another way...
  472. //sendAT(GF("+VTD="), duration_ms / 100);
  473. //waitResponse();
  474. sendAT(GF("+VTS="), cmd);
  475. if (waitResponse(10000L) == 1) {
  476. delay(duration_ms);
  477. return true;
  478. }
  479. return false;
  480. }
  481. /*
  482. * Audio functions
  483. */
  484. bool audioSetHeadphones()
  485. {
  486. sendAT(GF("+SNFS=0"));
  487. return waitResponse() == 1;
  488. }
  489. bool audioSetSpeaker()
  490. {
  491. sendAT(GF("+SNFS=1"));
  492. return waitResponse() == 1;
  493. }
  494. bool audioMuteMic(bool mute)
  495. {
  496. sendAT(GF("+CMUT="), mute);
  497. return waitResponse() == 1;
  498. }
  499. /*
  500. * Messaging functions
  501. */
  502. String sendUSSD(const String& code)
  503. {
  504. sendAT(GF("+CMGF=1"));
  505. waitResponse();
  506. sendAT(GF("+CSCS=\"HEX\""));
  507. waitResponse();
  508. sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
  509. if (waitResponse(10000L) != 1) {
  510. return "";
  511. }
  512. if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
  513. return "";
  514. }
  515. stream.readStringUntil('"');
  516. String hex = stream.readStringUntil('"');
  517. stream.readStringUntil(',');
  518. int dcs = stream.readStringUntil('\n').toInt();
  519. if (dcs == 15) {
  520. return TinyGsmDecodeHex7bit(hex);
  521. } else if (dcs == 72) {
  522. return TinyGsmDecodeHex16bit(hex);
  523. } else {
  524. return hex;
  525. }
  526. }
  527. bool sendSMS(const String& number, const String& text)
  528. {
  529. sendAT(GF("+CMGF=1"));
  530. waitResponse();
  531. sendAT(GF("+CMGS=\""), number, GF("\""));
  532. if (waitResponse(GF(">")) != 1) {
  533. return false;
  534. }
  535. stream.print(text);
  536. stream.write((char)0x1A);
  537. stream.flush();
  538. return waitResponse(60000L) == 1;
  539. }
  540. /*
  541. * Location functions
  542. */
  543. String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
  544. /*
  545. * Battery functions
  546. */
  547. uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
  548. int getBattPercent()
  549. {
  550. sendAT(GF("+CBC?"));
  551. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  552. return false;
  553. }
  554. stream.readStringUntil(',');
  555. int res = stream.readStringUntil('\n').toInt();
  556. waitResponse();
  557. return res;
  558. }
  559. protected:
  560. bool modemConnect(const char* host, uint16_t port, uint8_t* mux)
  561. {
  562. sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  563. if (waitResponse(75000L, GF(GSM_NL "+CIPNUM:")) != 1) {
  564. return false;
  565. }
  566. int newMux = stream.readStringUntil('\n').toInt();
  567. int rsp = waitResponse(75000L,
  568. GF("CONNECT OK" GSM_NL),
  569. GF("CONNECT FAIL" GSM_NL),
  570. GF("ALREADY CONNECT" GSM_NL));
  571. if (waitResponse() != 1) {
  572. return false;
  573. }
  574. *mux = newMux;
  575. return (1 == rsp);
  576. }
  577. int modemSend(const void* buff, size_t len, uint8_t mux)
  578. {
  579. sendAT(GF("+CIPSEND="), mux, ',', len);
  580. if (waitResponse(2000L, GF(GSM_NL ">")) != 1) {
  581. return 0;
  582. }
  583. stream.write((uint8_t*)buff, len);
  584. stream.flush();
  585. if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) {
  586. return 0;
  587. }
  588. return len;
  589. }
  590. bool modemGetConnected(uint8_t mux)
  591. {
  592. sendAT(GF("+CIPSTATUS")); //TODO mux?
  593. int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
  594. GF(",\"INITIAL\""));
  595. waitResponse();
  596. return 1 == res;
  597. }
  598. public:
  599. /* Utilities */
  600. template<typename T>
  601. void streamWrite(T last)
  602. {
  603. stream.print(last);
  604. }
  605. template<typename T, typename... Args>
  606. void streamWrite(T head, Args... tail)
  607. {
  608. stream.print(head);
  609. streamWrite(tail...);
  610. }
  611. bool streamSkipUntil(char c) //TODO: timeout
  612. {
  613. while (true) {
  614. while (!stream.available()) {
  615. TINY_GSM_YIELD();
  616. }
  617. if (stream.read() == c) {
  618. return true;
  619. }
  620. }
  621. return false;
  622. }
  623. template<typename... Args>
  624. void sendAT(Args... cmd)
  625. {
  626. streamWrite("AT", cmd..., GSM_NL);
  627. stream.flush();
  628. TINY_GSM_YIELD();
  629. //DBG("### AT:", cmd...);
  630. }
  631. // TODO: Optimize this!
  632. uint8_t waitResponse(uint32_t timeout, String& data,
  633. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  634. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  635. {
  636. /*String r1s(r1); r1s.trim();
  637. String r2s(r2); r2s.trim();
  638. String r3s(r3); r3s.trim();
  639. String r4s(r4); r4s.trim();
  640. String r5s(r5); r5s.trim();
  641. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  642. data.reserve(64);
  643. int index = 0;
  644. unsigned long startMillis = millis();
  645. do {
  646. TINY_GSM_YIELD();
  647. while (stream.available() > 0) {
  648. int a = stream.read();
  649. if (a <= 0) {
  650. continue; // Skip 0x00 bytes, just in case
  651. }
  652. data += (char)a;
  653. if (r1 && data.endsWith(r1)) {
  654. index = 1;
  655. goto finish;
  656. } else if (r2 && data.endsWith(r2)) {
  657. index = 2;
  658. goto finish;
  659. } else if (r3 && data.endsWith(r3)) {
  660. index = 3;
  661. goto finish;
  662. } else if (r4 && data.endsWith(r4)) {
  663. index = 4;
  664. goto finish;
  665. } else if (r5 && data.endsWith(r5)) {
  666. index = 5;
  667. goto finish;
  668. } else if (data.endsWith(GF("+CIPRCV:"))) {
  669. int mux = stream.readStringUntil(',').toInt();
  670. int len = stream.readStringUntil(',').toInt();
  671. int len_orig = len;
  672. if (len > sockets[mux]->rx.free()) {
  673. DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
  674. } else {
  675. DBG("### Got: ", len, "->", sockets[mux]->rx.free());
  676. }
  677. while (len--) {
  678. while (!stream.available()) {
  679. TINY_GSM_YIELD();
  680. }
  681. sockets[mux]->rx.put(stream.read());
  682. }
  683. if (len_orig > sockets[mux]->available()) { // TODO
  684. DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
  685. }
  686. data = "";
  687. } else if (data.endsWith(GF("+TCPCLOSED:"))) {
  688. int mux = stream.readStringUntil('\n').toInt();
  689. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
  690. sockets[mux]->sock_connected = false;
  691. }
  692. data = "";
  693. DBG("### Closed: ", mux);
  694. }
  695. }
  696. } while (millis() - startMillis < timeout);
  697. finish:
  698. if (!index) {
  699. data.trim();
  700. if (data.length()) {
  701. DBG("### Unhandled:", data);
  702. }
  703. data = "";
  704. }
  705. return index;
  706. }
  707. uint8_t waitResponse(uint32_t timeout,
  708. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  709. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  710. {
  711. String data;
  712. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  713. }
  714. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  715. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  716. {
  717. return waitResponse(1000, r1, r2, r3, r4, r5);
  718. }
  719. public:
  720. Stream& stream;
  721. protected:
  722. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  723. };
  724. #endif