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.

868 lines
20 KiB

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