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.

836 lines
19 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /**
  2. * @file TinyGsmClientM95.h
  3. * @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com>
  6. * @date Nov 2016
  7. */
  8. #ifndef TinyGsmClientM95_h
  9. #define TinyGsmClientM95_h
  10. //#pragma message("TinyGSM: TinyGsmClientM95")
  11. //#define TINY_GSM_DEBUG Serial
  12. //#define TINY_GSM_USE_HEX
  13. #define TINY_GSM_MUX_COUNT 6
  14. #include <TinyGsmCommon.h>
  15. #define GSM_NL "\r\n"
  16. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  17. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  18. enum SimStatus {
  19. SIM_ERROR = 0,
  20. SIM_READY = 1,
  21. SIM_LOCKED = 2,
  22. };
  23. enum RegStatus {
  24. REG_UNREGISTERED = 0,
  25. REG_SEARCHING = 2,
  26. REG_DENIED = 3,
  27. REG_OK_HOME = 1,
  28. REG_OK_ROAMING = 5,
  29. REG_UNKNOWN = 4,
  30. };
  31. class TinyGsmM95 : public TinyGsmModem
  32. {
  33. public:
  34. class GsmClient : public Client
  35. {
  36. friend class TinyGsmM95;
  37. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  38. public:
  39. GsmClient() {}
  40. GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
  41. init(&modem, mux);
  42. }
  43. bool init(TinyGsmM95* modem, uint8_t mux = 1) {
  44. this->at = modem;
  45. this->mux = mux;
  46. sock_available = 0;
  47. sock_connected = false;
  48. got_data = false;
  49. at->sockets[mux] = this;
  50. return true;
  51. }
  52. public:
  53. virtual int connect(const char *host, uint16_t port) {
  54. stop();
  55. TINY_GSM_YIELD();
  56. rx.clear();
  57. sock_connected = at->modemConnect(host, port, mux);
  58. return sock_connected;
  59. }
  60. virtual int connect(IPAddress ip, uint16_t port) {
  61. String host; host.reserve(16);
  62. host += ip[0];
  63. host += ".";
  64. host += ip[1];
  65. host += ".";
  66. host += ip[2];
  67. host += ".";
  68. host += ip[3];
  69. return connect(host.c_str(), port);
  70. }
  71. virtual void stop() {
  72. TINY_GSM_YIELD();
  73. at->sendAT(GF("+QICLOSE="), mux);
  74. sock_connected = false;
  75. at->waitResponse(60000L, GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
  76. rx.clear();
  77. }
  78. virtual size_t write(const uint8_t *buf, size_t size) {
  79. TINY_GSM_YIELD();
  80. at->maintain();
  81. return at->modemSend(buf, size, mux);
  82. }
  83. virtual size_t write(uint8_t c) {
  84. return write(&c, 1);
  85. }
  86. virtual size_t write(const char *str) {
  87. if (str == NULL) return 0;
  88. return write((const uint8_t *)str, strlen(str));
  89. }
  90. virtual int available() {
  91. TINY_GSM_YIELD();
  92. if (!rx.size()) {
  93. at->maintain();
  94. }
  95. return rx.size() + sock_available;
  96. }
  97. virtual int read(uint8_t *buf, size_t size) {
  98. TINY_GSM_YIELD();
  99. at->maintain();
  100. size_t cnt = 0;
  101. while (cnt < size) {
  102. size_t chunk = TinyGsmMin(size-cnt, rx.size());
  103. if (chunk > 0) {
  104. rx.get(buf, chunk);
  105. buf += chunk;
  106. cnt += chunk;
  107. continue;
  108. }
  109. // TODO: Read directly into user buffer?
  110. at->maintain();
  111. if (sock_available > 0) {
  112. sock_available -= at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux);
  113. } else {
  114. break;
  115. }
  116. }
  117. return cnt;
  118. }
  119. virtual int read() {
  120. uint8_t c;
  121. if (read(&c, 1) == 1) {
  122. return c;
  123. }
  124. return -1;
  125. }
  126. virtual int peek() { return -1; } //TODO
  127. virtual void flush() { at->stream.flush(); }
  128. virtual uint8_t connected() {
  129. if (available()) {
  130. return true;
  131. }
  132. return sock_connected;
  133. }
  134. virtual operator bool() { return connected(); }
  135. /*
  136. * Extended API
  137. */
  138. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  139. private:
  140. TinyGsmM95* at;
  141. uint8_t mux;
  142. uint16_t sock_available;
  143. bool sock_connected;
  144. bool got_data;
  145. RxFifo rx;
  146. };
  147. // class GsmClientSecure : public GsmClient
  148. // {
  149. // public:
  150. // GsmClientSecure() {}
  151. //
  152. // GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
  153. // : GsmClient(modem, mux)
  154. // {}
  155. //
  156. // public:
  157. // virtual int connect(const char *host, uint16_t port) {
  158. // stop();
  159. // TINY_GSM_YIELD();
  160. // rx.clear();
  161. // sock_connected = at->modemConnect(host, port, mux, true);
  162. // return sock_connected;
  163. // }
  164. // };
  165. public:
  166. TinyGsmM95(Stream& stream)
  167. : TinyGsmModem(stream), stream(stream)
  168. {
  169. memset(sockets, 0, sizeof(sockets));
  170. }
  171. /*
  172. * Basic functions
  173. */
  174. bool init(const char* pin = NULL) {
  175. if (!testAT()) {
  176. return false;
  177. }
  178. sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
  179. if (waitResponse() != 1) {
  180. return false;
  181. }
  182. #ifdef TINY_GSM_DEBUG
  183. sendAT(GF("+CMEE=2"));
  184. waitResponse();
  185. #endif
  186. DBG(GF("### Modem:"), getModemName());
  187. getSimStatus();
  188. return true;
  189. }
  190. String getModemName() {
  191. return "Quectel M95";
  192. }
  193. void setBaud(unsigned long baud) {
  194. sendAT(GF("+IPR="), baud);
  195. }
  196. bool testAT(unsigned long timeout = 10000L) {
  197. for (unsigned long start = millis(); millis() - start < timeout; ) {
  198. sendAT(GF(""));
  199. if (waitResponse(200) == 1) return true;
  200. delay(100);
  201. }
  202. return false;
  203. }
  204. void maintain() {
  205. for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
  206. GsmClient* sock = sockets[mux];
  207. if (sock && sock->got_data) {
  208. sock->got_data = false;
  209. sock->sock_available = modemGetAvailable(mux);
  210. }
  211. }
  212. while (stream.available()) {
  213. waitResponse(10, NULL, NULL);
  214. }
  215. }
  216. bool factoryDefault() {
  217. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  218. waitResponse();
  219. sendAT(GF("+IPR=0")); // Auto-baud
  220. waitResponse();
  221. sendAT(GF("&W")); // Write configuration
  222. return waitResponse() == 1;
  223. }
  224. String getModemInfo() {
  225. sendAT(GF("I"));
  226. String res;
  227. if (waitResponse(1000L, res) != 1) {
  228. return "";
  229. }
  230. res.replace(GSM_NL "OK" GSM_NL, "");
  231. res.replace(GSM_NL, " ");
  232. res.trim();
  233. return res;
  234. }
  235. bool hasSSL() {
  236. return false; // TODO: For now
  237. }
  238. bool hasWifi() {
  239. return false;
  240. }
  241. bool hasGPRS() {
  242. return true;
  243. }
  244. /*
  245. * Power functions
  246. */
  247. bool restart() {
  248. if (!testAT()) {
  249. return false;
  250. }
  251. sendAT(GF("+CFUN=0"));
  252. if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) {
  253. return false;
  254. }
  255. sendAT(GF("+CFUN=1"));
  256. if (waitResponse(10000L, GF("Call Ready"), GF("OK"), GF("FAIL")) == 3) {
  257. return false;
  258. }
  259. return init();
  260. }
  261. bool poweroff() {
  262. sendAT(GF("+QPOWD=1"));
  263. return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
  264. }
  265. bool radioOff() {
  266. sendAT(GF("+CFUN=0"));
  267. if (waitResponse(10000L) != 1) {
  268. return false;
  269. }
  270. delay(3000);
  271. return true;
  272. }
  273. bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  274. /*
  275. * SIM card functions
  276. */
  277. bool simUnlock(const char *pin) {
  278. sendAT(GF("+CPIN=\""), pin, GF("\""));
  279. return waitResponse() == 1;
  280. }
  281. String getSimCCID() {
  282. sendAT(GF("+ICCID"));
  283. if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
  284. return "";
  285. }
  286. String res = stream.readStringUntil('\n');
  287. waitResponse();
  288. res.trim();
  289. return res;
  290. }
  291. String getIMEI() {
  292. sendAT(GF("+GSN"));
  293. if (waitResponse(GF(GSM_NL)) != 1) {
  294. return "";
  295. }
  296. String res = stream.readStringUntil('\n');
  297. waitResponse();
  298. res.trim();
  299. return res;
  300. }
  301. SimStatus getSimStatus(unsigned long timeout = 10000L) {
  302. for (unsigned long start = millis(); millis() - start < timeout; ) {
  303. sendAT(GF("+CPIN?"));
  304. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  305. delay(1000);
  306. continue;
  307. }
  308. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
  309. waitResponse();
  310. switch (status) {
  311. case 2:
  312. case 3: return SIM_LOCKED;
  313. case 1: return SIM_READY;
  314. default: return SIM_ERROR;
  315. }
  316. }
  317. return SIM_ERROR;
  318. }
  319. RegStatus getRegistrationStatus() {
  320. sendAT(GF("+CREG?"));
  321. if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
  322. return REG_UNKNOWN;
  323. }
  324. streamSkipUntil(','); // Skip format (0)
  325. int status = stream.readStringUntil('\n').toInt();
  326. waitResponse();
  327. return (RegStatus)status;
  328. }
  329. String getOperator() {
  330. sendAT(GF("+COPS?"));
  331. if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
  332. return "";
  333. }
  334. streamSkipUntil('"'); // Skip mode and format
  335. String res = stream.readStringUntil('"');
  336. waitResponse();
  337. return res;
  338. }
  339. /*
  340. * Generic network functions
  341. */
  342. int16_t getSignalQuality() {
  343. sendAT(GF("+CSQ"));
  344. if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
  345. return 99;
  346. }
  347. int res = stream.readStringUntil(',').toInt();
  348. waitResponse();
  349. return res;
  350. }
  351. bool isNetworkConnected() {
  352. RegStatus s = getRegistrationStatus();
  353. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  354. }
  355. void setHostFormat( bool useDottedQuad ) {
  356. if ( useDottedQuad ) {
  357. sendAT(GF("+QIDNSIP=0"));
  358. } else {
  359. sendAT(GF("+QIDNSIP=1"));
  360. }
  361. waitResponse();
  362. }
  363. /*
  364. * GPRS functions
  365. */
  366. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
  367. gprsDisconnect();
  368. // select foreground context 0 = VIRTUAL_UART_1
  369. sendAT(GF("+QIFGCNT=0"));
  370. if (waitResponse() != 1) {
  371. return false;
  372. }
  373. //Select GPRS (=1) as the Bearer
  374. sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  375. if (waitResponse() != 1) {
  376. return false;
  377. }
  378. //Start TCPIP Task and Set APN, User Name and Password
  379. sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" );
  380. if (waitResponse() != 1) {
  381. return false;
  382. }
  383. //Activate GPRS/CSD Context
  384. sendAT(GF("+QIACT"));
  385. if (waitResponse(10000) != 1) {
  386. return false;
  387. }
  388. //Enable multiple TCP/IP connections
  389. sendAT(GF("+QIMUX=1"));
  390. if (waitResponse() != 1) {
  391. return false;
  392. }
  393. //Request an IP header for received data ("IPD(data length):")
  394. sendAT(GF("+QIHEAD=1"));
  395. if (waitResponse() != 1) {
  396. return false;
  397. }
  398. //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
  399. sendAT(GF("+QINDI=1"));
  400. if (waitResponse() != 1) {
  401. return false;
  402. }
  403. return true;
  404. }
  405. bool gprsDisconnect() {
  406. sendAT(GF("+QIDEACT"));
  407. return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
  408. }
  409. bool isGprsConnected() {
  410. sendAT(GF("+CGATT?"));
  411. if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
  412. return false;
  413. }
  414. int res = stream.readStringUntil('\n').toInt();
  415. waitResponse();
  416. if (res != 1)
  417. return false;
  418. return localIP() != 0;
  419. }
  420. /*
  421. * IP Address functions
  422. */
  423. String getLocalIP() {
  424. sendAT(GF("+QILOCIP"));
  425. stream.readStringUntil('\n');
  426. String res = stream.readStringUntil('\n');
  427. res.trim();
  428. return res;
  429. }
  430. /*
  431. * Messaging functions
  432. */
  433. String sendUSSD(const String& code) {
  434. sendAT(GF("+CMGF=1"));
  435. waitResponse();
  436. sendAT(GF("+CSCS=\"HEX\""));
  437. waitResponse();
  438. sendAT(GF("+CUSD=1,\""), code, GF("\""));
  439. if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
  440. return "";
  441. }
  442. stream.readStringUntil('"');
  443. String hex = stream.readStringUntil('"');
  444. stream.readStringUntil(',');
  445. int dcs = stream.readStringUntil('\n').toInt();
  446. if (waitResponse() != 1) {
  447. return "";
  448. }
  449. if (dcs == 15) {
  450. return TinyGsmDecodeHex8bit(hex);
  451. } else if (dcs == 72) {
  452. return TinyGsmDecodeHex16bit(hex);
  453. } else {
  454. return hex;
  455. }
  456. }
  457. bool sendSMS(const String& number, const String& text) {
  458. sendAT(GF("+CMGF=1"));
  459. waitResponse();
  460. //Set GSM 7 bit default alphabet (3GPP TS 23.038)
  461. sendAT(GF("+CSCS=\"GSM\""));
  462. waitResponse();
  463. sendAT(GF("+CMGS=\""), number, GF("\""));
  464. if (waitResponse(GF(">")) != 1) {
  465. return false;
  466. }
  467. stream.print(text);
  468. stream.write((char)0x1A);
  469. stream.flush();
  470. return waitResponse(60000L) == 1;
  471. }
  472. bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
  473. sendAT(GF("+CMGF=1"));
  474. waitResponse();
  475. sendAT(GF("+CSCS=\"HEX\""));
  476. waitResponse();
  477. sendAT(GF("+CSMP=17,167,0,8"));
  478. waitResponse();
  479. sendAT(GF("+CMGS=\""), number, GF("\""));
  480. if (waitResponse(GF(">")) != 1) {
  481. return false;
  482. }
  483. uint16_t* t = (uint16_t*)text;
  484. for (size_t i=0; i<len; i++) {
  485. uint8_t c = t[i] >> 8;
  486. if (c < 0x10) { stream.print('0'); }
  487. stream.print(c, HEX);
  488. c = t[i] & 0xFF;
  489. if (c < 0x10) { stream.print('0'); }
  490. stream.print(c, HEX);
  491. }
  492. stream.write((char)0x1A);
  493. stream.flush();
  494. return waitResponse(60000L) == 1;
  495. }
  496. /** Delete all SMS */
  497. bool deleteAllSMS() {
  498. sendAT(GF("+QMGDA=6"));
  499. if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
  500. return true;
  501. }
  502. return false;
  503. }
  504. /*
  505. * Phone Call functions
  506. */
  507. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  508. bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
  509. bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
  510. bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
  511. /*
  512. * Location functions
  513. */
  514. String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
  515. /*
  516. * Battery functions
  517. */
  518. // Use: float vBatt = modem.getBattVoltage() / 1000.0;
  519. uint16_t getBattVoltage() {
  520. sendAT(GF("+CBC"));
  521. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  522. return 0;
  523. }
  524. streamSkipUntil(','); // Skip
  525. streamSkipUntil(','); // Skip
  526. uint16_t res = stream.readStringUntil(',').toInt();
  527. waitResponse();
  528. return res;
  529. }
  530. int8_t getBattPercent() {
  531. sendAT(GF("+CBC"));
  532. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  533. return false;
  534. }
  535. stream.readStringUntil(',');
  536. int res = stream.readStringUntil(',').toInt();
  537. waitResponse();
  538. return res;
  539. }
  540. /*
  541. * Client related functions
  542. */
  543. protected:
  544. bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
  545. sendAT(GF("+QIOPEN="), mux, GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  546. int rsp = waitResponse(75000L,
  547. GF("CONNECT OK" GSM_NL),
  548. GF("CONNECT FAIL" GSM_NL),
  549. GF("ALREADY CONNECT" GSM_NL));
  550. return (1 == rsp);
  551. }
  552. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  553. sendAT(GF("+QISEND="), mux, ',', len);
  554. if (waitResponse(GF(">")) != 1) {
  555. return 0;
  556. }
  557. stream.write((uint8_t*)buff, len);
  558. stream.flush();
  559. if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
  560. return 0;
  561. }
  562. bool allAcknowledged = false;
  563. // bool failed = false;
  564. while ( !allAcknowledged ) {
  565. sendAT( GF("+QISACK"));
  566. if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
  567. return -1;
  568. } else {
  569. streamSkipUntil(','); /** Skip total */
  570. streamSkipUntil(','); /** Skip acknowledged data size */
  571. if ( stream.readStringUntil('\n').toInt() == 0 ) {
  572. allAcknowledged = true;
  573. }
  574. }
  575. }
  576. waitResponse(5000L);
  577. // streamSkipUntil(','); // Skip mux
  578. // return stream.readStringUntil('\n').toInt();
  579. return 1;
  580. }
  581. size_t modemRead(size_t size, uint8_t mux) {
  582. sendAT(GF("+QIRD="), mux, ',', size);
  583. if (waitResponse(GF("+QIRD:")) != 1) {
  584. return 0;
  585. }
  586. size_t len = stream.readStringUntil('\n').toInt();
  587. for (size_t i=0; i<len; i++) {
  588. while (!stream.available()) { TINY_GSM_YIELD(); }
  589. char c = stream.read();
  590. sockets[mux]->rx.put(c);
  591. }
  592. waitResponse();
  593. DBG("### READ:", mux, ",", len);
  594. return len;
  595. }
  596. size_t modemGetAvailable(uint8_t mux) {
  597. sendAT(GF("+QIRD="), mux, GF(",0"));
  598. size_t result = 0;
  599. if (waitResponse(GF("+QIRD:")) == 1) {
  600. streamSkipUntil(','); // Skip total received
  601. streamSkipUntil(','); // Skip have read
  602. result = stream.readStringUntil('\n').toInt();
  603. DBG("### STILL:", mux, "has", result);
  604. waitResponse();
  605. }
  606. if (!result) {
  607. sockets[mux]->sock_connected = modemGetConnected(mux);
  608. }
  609. return result;
  610. }
  611. bool modemGetConnected(uint8_t mux) {
  612. sendAT(GF("+QISTATE=1,"), mux);
  613. //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
  614. if (waitResponse(GF("+QISTATE:")))
  615. return false;
  616. streamSkipUntil(','); // Skip mux
  617. streamSkipUntil(','); // Skip socket type
  618. streamSkipUntil(','); // Skip remote ip
  619. streamSkipUntil(','); // Skip remote port
  620. streamSkipUntil(','); // Skip local port
  621. int res = stream.readStringUntil(',').toInt(); // socket state
  622. waitResponse();
  623. // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
  624. return 2 == res;
  625. }
  626. public:
  627. /*
  628. Utilities
  629. */
  630. template<typename... Args>
  631. void sendAT(Args... cmd) {
  632. streamWrite("AT", cmd..., GSM_NL);
  633. stream.flush();
  634. TINY_GSM_YIELD();
  635. //DBG("### AT:", cmd...);
  636. }
  637. // TODO: Optimize this!
  638. uint8_t waitResponse(uint32_t timeout, String& data,
  639. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  640. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  641. {
  642. /*String r1s(r1); r1s.trim();
  643. String r2s(r2); r2s.trim();
  644. String r3s(r3); r3s.trim();
  645. String r4s(r4); r4s.trim();
  646. String r5s(r5); r5s.trim();
  647. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  648. data.reserve(64);
  649. int index = 0;
  650. unsigned long startMillis = millis();
  651. do {
  652. TINY_GSM_YIELD();
  653. while (stream.available() > 0) {
  654. int a = stream.read();
  655. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  656. data += (char)a;
  657. if (r1 && data.endsWith(r1)) {
  658. index = 1;
  659. goto finish;
  660. } else if (r2 && data.endsWith(r2)) {
  661. index = 2;
  662. goto finish;
  663. } else if (r3 && data.endsWith(r3)) {
  664. index = 3;
  665. goto finish;
  666. } else if (r4 && data.endsWith(r4)) {
  667. index = 4;
  668. goto finish;
  669. } else if (r5 && data.endsWith(r5)) {
  670. index = 5;
  671. goto finish;
  672. } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) {
  673. streamSkipUntil(','); // Skip the context
  674. streamSkipUntil(','); // Skip the role
  675. int mux = stream.readStringUntil('\n').toInt();
  676. DBG("### Got Data:", mux);
  677. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  678. sockets[mux]->got_data = true;
  679. }
  680. } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
  681. int nl = data.lastIndexOf(GSM_NL, data.length()-8);
  682. int coma = data.indexOf(',', nl+2);
  683. int mux = data.substring(nl+2, coma).toInt();
  684. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  685. sockets[mux]->sock_connected = false;
  686. }
  687. data = "";
  688. DBG("### Closed: ", mux);
  689. }
  690. }
  691. } while (millis() - startMillis < timeout);
  692. finish:
  693. if (!index) {
  694. data.trim();
  695. if (data.length()) {
  696. DBG("### Unhandled:", data);
  697. }
  698. data = "";
  699. }
  700. //DBG('<', index, '>');
  701. return index;
  702. }
  703. uint8_t waitResponse(uint32_t timeout,
  704. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  705. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  706. {
  707. String data;
  708. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  709. }
  710. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  711. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  712. {
  713. return waitResponse(1000, r1, r2, r3, r4, r5);
  714. }
  715. public:
  716. Stream& stream;
  717. protected:
  718. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  719. };
  720. #endif