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.

747 lines
18 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
6 years ago
6 years ago
5 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. #if !defined(TINY_GSM_RX_BUFFER)
  13. #define TINY_GSM_RX_BUFFER 64
  14. #endif
  15. #define TINY_GSM_MUX_COUNT 6
  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 TinyGsmM95
  34. {
  35. public:
  36. class GsmClient : public Client
  37. {
  38. friend class TinyGsmM95;
  39. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  40. public:
  41. GsmClient() {}
  42. GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
  43. init(&modem, mux);
  44. }
  45. virtual ~GsmClient(){}
  46. bool init(TinyGsmM95* modem, uint8_t mux = 1) {
  47. this->at = modem;
  48. this->mux = mux;
  49. sock_available = 0;
  50. sock_connected = false;
  51. got_data = false;
  52. at->sockets[mux] = this;
  53. return true;
  54. }
  55. public:
  56. virtual int connect(const char *host, uint16_t port, int timeout_s) {
  57. stop();
  58. TINY_GSM_YIELD();
  59. rx.clear();
  60. sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
  61. return sock_connected;
  62. }
  63. TINY_GSM_CLIENT_CONNECT_OVERLOADS()
  64. virtual void stop(uint32_t maxWaitMs) {
  65. TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
  66. at->sendAT(GF("+QICLOSE="), mux);
  67. sock_connected = false;
  68. at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
  69. }
  70. virtual void stop() { stop(75000L); }
  71. TINY_GSM_CLIENT_WRITE()
  72. TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
  73. TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
  74. TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
  75. /*
  76. * Extended API
  77. */
  78. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  79. private:
  80. TinyGsmM95* at;
  81. uint8_t mux;
  82. uint16_t sock_available;
  83. bool sock_connected;
  84. bool got_data;
  85. RxFifo rx;
  86. };
  87. // class GsmClientSecure : public GsmClient
  88. // {
  89. // public:
  90. // GsmClientSecure() {}
  91. //
  92. // GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
  93. // : GsmClient(modem, mux)
  94. // {}
  95. //
  96. // virtual ~GsmClientSecure() {}
  97. //
  98. // public:
  99. // virtual int connect(const char *host, uint16_t port, int timeout_s) {
  100. // stop();
  101. // TINY_GSM_YIELD();
  102. // rx.clear();
  103. // sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
  104. // return sock_connected;
  105. // }
  106. // };
  107. public:
  108. TinyGsmM95(Stream& stream)
  109. : stream(stream)
  110. {
  111. memset(sockets, 0, sizeof(sockets));
  112. }
  113. virtual ~TinyGsmM95() {}
  114. /*
  115. * Basic functions
  116. */
  117. bool begin(const char* pin = NULL) {
  118. return init(pin);
  119. }
  120. bool init(const char* pin = NULL) {
  121. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  122. if (!testAT()) {
  123. return false;
  124. }
  125. sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
  126. if (waitResponse() != 1) {
  127. return false;
  128. }
  129. #ifdef TINY_GSM_DEBUG
  130. sendAT(GF("+CMEE=2"));
  131. waitResponse();
  132. #endif
  133. DBG(GF("### Modem:"), getModemName());
  134. getSimStatus();
  135. return true;
  136. }
  137. String getModemName() {
  138. return "Quectel M95";
  139. }
  140. TINY_GSM_MODEM_SET_BAUD_IPR()
  141. TINY_GSM_MODEM_TEST_AT()
  142. TINY_GSM_MODEM_MAINTAIN_LISTEN()
  143. bool factoryDefault() {
  144. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  145. waitResponse();
  146. sendAT(GF("+IPR=0")); // Auto-baud
  147. waitResponse();
  148. sendAT(GF("&W")); // Write configuration
  149. return waitResponse() == 1;
  150. }
  151. TINY_GSM_MODEM_GET_INFO_ATI()
  152. bool hasSSL() {
  153. return false; // TODO: For now
  154. }
  155. bool hasWifi() {
  156. return false;
  157. }
  158. bool hasGPRS() {
  159. return true;
  160. }
  161. /*
  162. * Power functions
  163. */
  164. bool restart() {
  165. if (!testAT()) {
  166. return false;
  167. }
  168. sendAT(GF("+CFUN=0"));
  169. if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) {
  170. return false;
  171. }
  172. sendAT(GF("+CFUN=1"));
  173. if (waitResponse(10000L, GF("Call Ready"), GF("OK"), GF("FAIL")) == 3) {
  174. return false;
  175. }
  176. return init();
  177. }
  178. bool poweroff() {
  179. sendAT(GF("+QPOWD=1"));
  180. return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
  181. }
  182. bool radioOff() {
  183. sendAT(GF("+CFUN=0"));
  184. if (waitResponse(10000L) != 1) {
  185. return false;
  186. }
  187. delay(3000);
  188. return true;
  189. }
  190. bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  191. /*
  192. * SIM card functions
  193. */
  194. TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
  195. String getSimCCID() {
  196. sendAT(GF("+QCCID"));
  197. if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
  198. return "";
  199. }
  200. String res = stream.readStringUntil('\n');
  201. waitResponse();
  202. res.trim();
  203. return res;
  204. }
  205. TINY_GSM_MODEM_GET_IMEI_GSN()
  206. SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
  207. for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
  208. sendAT(GF("+CPIN?"));
  209. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  210. delay(1000);
  211. continue;
  212. }
  213. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
  214. waitResponse();
  215. switch (status) {
  216. case 2:
  217. case 3: return SIM_LOCKED;
  218. case 1: return SIM_READY;
  219. default: return SIM_ERROR;
  220. }
  221. }
  222. return SIM_ERROR;
  223. }
  224. TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
  225. TINY_GSM_MODEM_GET_OPERATOR_COPS()
  226. /*
  227. * Generic network functions
  228. */
  229. TINY_GSM_MODEM_GET_CSQ()
  230. bool isNetworkConnected() {
  231. RegStatus s = getRegistrationStatus();
  232. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  233. }
  234. void setHostFormat( bool useDottedQuad ) {
  235. if ( useDottedQuad ) {
  236. sendAT(GF("+QIDNSIP=0"));
  237. } else {
  238. sendAT(GF("+QIDNSIP=1"));
  239. }
  240. waitResponse();
  241. }
  242. TINY_GSM_MODEM_WAIT_FOR_NETWORK()
  243. /*
  244. * GPRS functions
  245. */
  246. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
  247. gprsDisconnect();
  248. // select foreground context 0 = VIRTUAL_UART_1
  249. sendAT(GF("+QIFGCNT=0"));
  250. if (waitResponse() != 1) {
  251. return false;
  252. }
  253. //Select GPRS (=1) as the Bearer
  254. sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  255. if (waitResponse() != 1) {
  256. return false;
  257. }
  258. //Start TCPIP Task and Set APN, User Name and Password
  259. sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" );
  260. if (waitResponse() != 1) {
  261. return false;
  262. }
  263. //Activate GPRS/CSD Context
  264. sendAT(GF("+QIACT"));
  265. if (waitResponse(10000) != 1) {
  266. return false;
  267. }
  268. //Enable multiple TCP/IP connections
  269. sendAT(GF("+QIMUX=1"));
  270. if (waitResponse() != 1) {
  271. return false;
  272. }
  273. //Request an IP header for received data ("IPD(data length):")
  274. sendAT(GF("+QIHEAD=1"));
  275. if (waitResponse() != 1) {
  276. return false;
  277. }
  278. //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
  279. sendAT(GF("+QINDI=1"));
  280. if (waitResponse() != 1) {
  281. return false;
  282. }
  283. return true;
  284. }
  285. bool gprsDisconnect() {
  286. sendAT(GF("+QIDEACT"));
  287. return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
  288. }
  289. TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
  290. /*
  291. * IP Address functions
  292. */
  293. String getLocalIP() {
  294. sendAT(GF("+QILOCIP"));
  295. stream.readStringUntil('\n');
  296. String res = stream.readStringUntil('\n');
  297. res.trim();
  298. return res;
  299. }
  300. IPAddress localIP() {
  301. return TinyGsmIpFromString(getLocalIP());
  302. }
  303. /*
  304. * Messaging functions
  305. */
  306. String sendUSSD(const String& code) {
  307. sendAT(GF("+CMGF=1"));
  308. waitResponse();
  309. sendAT(GF("+CSCS=\"HEX\""));
  310. waitResponse();
  311. sendAT(GF("+CUSD=1,\""), code, GF("\""));
  312. if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
  313. return "";
  314. }
  315. stream.readStringUntil('"');
  316. String hex = stream.readStringUntil('"');
  317. stream.readStringUntil(',');
  318. int dcs = stream.readStringUntil('\n').toInt();
  319. if (waitResponse() != 1) {
  320. return "";
  321. }
  322. if (dcs == 15) {
  323. return TinyGsmDecodeHex8bit(hex);
  324. } else if (dcs == 72) {
  325. return TinyGsmDecodeHex16bit(hex);
  326. } else {
  327. return hex;
  328. }
  329. }
  330. bool sendSMS(const String& number, const String& text) {
  331. sendAT(GF("+CMGF=1"));
  332. waitResponse();
  333. //Set GSM 7 bit default alphabet (3GPP TS 23.038)
  334. sendAT(GF("+CSCS=\"GSM\""));
  335. waitResponse();
  336. sendAT(GF("+CMGS=\""), number, GF("\""));
  337. if (waitResponse(GF(">")) != 1) {
  338. return false;
  339. }
  340. stream.print(text);
  341. stream.write((char)0x1A);
  342. stream.flush();
  343. return waitResponse(60000L) == 1;
  344. }
  345. bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
  346. sendAT(GF("+CMGF=1"));
  347. waitResponse();
  348. sendAT(GF("+CSCS=\"HEX\""));
  349. waitResponse();
  350. sendAT(GF("+CSMP=17,167,0,8"));
  351. waitResponse();
  352. sendAT(GF("+CMGS=\""), number, GF("\""));
  353. if (waitResponse(GF(">")) != 1) {
  354. return false;
  355. }
  356. uint16_t* t = (uint16_t*)text;
  357. for (size_t i=0; i<len; i++) {
  358. uint8_t c = t[i] >> 8;
  359. if (c < 0x10) { stream.print('0'); }
  360. stream.print(c, HEX);
  361. c = t[i] & 0xFF;
  362. if (c < 0x10) { stream.print('0'); }
  363. stream.print(c, HEX);
  364. }
  365. stream.write((char)0x1A);
  366. stream.flush();
  367. return waitResponse(60000L) == 1;
  368. }
  369. /** Delete all SMS */
  370. bool deleteAllSMS() {
  371. sendAT(GF("+QMGDA=6"));
  372. if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
  373. return true;
  374. }
  375. return false;
  376. }
  377. /*
  378. * Phone Call functions
  379. */
  380. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  381. bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
  382. bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
  383. bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
  384. /*
  385. * Location functions
  386. */
  387. String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
  388. /*
  389. * Battery & temperature functions
  390. */
  391. // Use: float vBatt = modem.getBattVoltage() / 1000.0;
  392. uint16_t getBattVoltage() {
  393. sendAT(GF("+CBC"));
  394. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  395. return 0;
  396. }
  397. streamSkipUntil(','); // Skip battery charge status
  398. streamSkipUntil(','); // Skip battery charge level
  399. // return voltage in mV
  400. uint16_t res = stream.readStringUntil(',').toInt();
  401. // Wait for final OK
  402. waitResponse();
  403. return res;
  404. }
  405. int8_t getBattPercent() {
  406. sendAT(GF("+CBC"));
  407. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  408. return false;
  409. }
  410. streamSkipUntil(','); // Skip battery charge status
  411. // Read battery charge level
  412. int res = stream.readStringUntil(',').toInt();
  413. // Wait for final OK
  414. waitResponse();
  415. return res;
  416. }
  417. uint8_t getBattChargeState() {
  418. sendAT(GF("+CBC?"));
  419. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  420. return false;
  421. }
  422. // Read battery charge status
  423. int res = stream.readStringUntil(',').toInt();
  424. // Wait for final OK
  425. waitResponse();
  426. return res;
  427. }
  428. bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
  429. sendAT(GF("+CBC?"));
  430. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
  431. return false;
  432. }
  433. chargeState = stream.readStringUntil(',').toInt();
  434. percent = stream.readStringUntil(',').toInt();
  435. milliVolts = stream.readStringUntil('\n').toInt();
  436. // Wait for final OK
  437. waitResponse();
  438. return true;
  439. }
  440. float getTemperature() {
  441. sendAT(GF("+QTEMP"));
  442. if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) {
  443. return (float)-9999;
  444. }
  445. streamSkipUntil(','); // Skip mode
  446. // Read charge of thermistor
  447. // milliVolts = stream.readStringUntil(',').toInt();
  448. streamSkipUntil(','); // Skip thermistor charge
  449. float temp = stream.readStringUntil('\n').toFloat();
  450. // Wait for final OK
  451. waitResponse();
  452. return temp;
  453. }
  454. /*
  455. * Client related functions
  456. */
  457. protected:
  458. bool modemConnect(const char* host, uint16_t port, uint8_t mux,
  459. bool ssl = false, int timeout_s = 75)
  460. {
  461. uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
  462. sendAT(GF("+QIOPEN="), mux, GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  463. int rsp = waitResponse(timeout_ms,
  464. GF("CONNECT OK" GSM_NL),
  465. GF("CONNECT FAIL" GSM_NL),
  466. GF("ALREADY CONNECT" GSM_NL));
  467. return (1 == rsp);
  468. }
  469. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  470. sendAT(GF("+QISEND="), mux, ',', len);
  471. if (waitResponse(GF(">")) != 1) {
  472. return 0;
  473. }
  474. stream.write((uint8_t*)buff, len);
  475. stream.flush();
  476. if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
  477. return 0;
  478. }
  479. bool allAcknowledged = false;
  480. // bool failed = false;
  481. while ( !allAcknowledged ) {
  482. sendAT( GF("+QISACK"));
  483. if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
  484. return -1;
  485. } else {
  486. streamSkipUntil(','); /** Skip total */
  487. streamSkipUntil(','); /** Skip acknowledged data size */
  488. if ( stream.readStringUntil('\n').toInt() == 0 ) {
  489. allAcknowledged = true;
  490. }
  491. }
  492. }
  493. waitResponse(5000L);
  494. // streamSkipUntil(','); // Skip mux
  495. // return stream.readStringUntil('\n').toInt();
  496. return len; // TODO
  497. }
  498. size_t modemRead(size_t size, uint8_t mux) {
  499. // TODO: Does this work????
  500. // AT+QIRD=<id>,<sc>,<sid>,<len>
  501. // id = GPRS context number - 0, set in GPRS connect
  502. // sc = roll in connection - 1, client of connection
  503. // sid = index of connection - mux
  504. // len = maximum length of data to send
  505. sendAT(GF("+QIRD=0,1,"), mux, ',', size);
  506. // sendAT(GF("+QIRD="), mux, ',', size);
  507. if (waitResponse(GF("+QIRD:")) != 1) {
  508. return 0;
  509. }
  510. streamSkipUntil(':'); // skip IP address
  511. streamSkipUntil(','); // skip port
  512. streamSkipUntil(','); // skip connection type (TCP/UDP)
  513. size_t len = stream.readStringUntil('\n').toInt(); // read length
  514. for (size_t i=0; i<len; i++) {
  515. TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
  516. sockets[mux]->sock_available--;
  517. // ^^ One less character available after moving from modem's FIFO to our FIFO
  518. }
  519. waitResponse(); // ends with an OK
  520. DBG("### READ:", len, "from", mux);
  521. return len;
  522. }
  523. bool modemGetConnected(uint8_t mux) {
  524. sendAT(GF("+QISTATE=1,"), mux);
  525. //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
  526. if (waitResponse(GF("+QISTATE:")))
  527. return false;
  528. streamSkipUntil(','); // Skip mux
  529. streamSkipUntil(','); // Skip socket type
  530. streamSkipUntil(','); // Skip remote ip
  531. streamSkipUntil(','); // Skip remote port
  532. streamSkipUntil(','); // Skip local port
  533. int res = stream.readStringUntil(',').toInt(); // socket state
  534. waitResponse();
  535. // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
  536. return 2 == res;
  537. }
  538. public:
  539. /*
  540. Utilities
  541. */
  542. TINY_GSM_MODEM_STREAM_UTILITIES()
  543. // TODO: Optimize this!
  544. uint8_t waitResponse(uint32_t timeout_ms, String& data,
  545. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  546. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  547. {
  548. /*String r1s(r1); r1s.trim();
  549. String r2s(r2); r2s.trim();
  550. String r3s(r3); r3s.trim();
  551. String r4s(r4); r4s.trim();
  552. String r5s(r5); r5s.trim();
  553. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  554. data.reserve(64);
  555. int index = 0;
  556. unsigned long startMillis = millis();
  557. do {
  558. TINY_GSM_YIELD();
  559. while (stream.available() > 0) {
  560. TINY_GSM_YIELD();
  561. int a = stream.read();
  562. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  563. data += (char)a;
  564. if (r1 && data.endsWith(r1)) {
  565. index = 1;
  566. goto finish;
  567. } else if (r2 && data.endsWith(r2)) {
  568. index = 2;
  569. goto finish;
  570. } else if (r3 && data.endsWith(r3)) {
  571. index = 3;
  572. goto finish;
  573. } else if (r4 && data.endsWith(r4)) {
  574. index = 4;
  575. goto finish;
  576. } else if (r5 && data.endsWith(r5)) {
  577. index = 5;
  578. goto finish;
  579. } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) { // TODO: QIRD? or QIRDI?
  580. streamSkipUntil(','); // Skip the context
  581. streamSkipUntil(','); // Skip the role
  582. int mux = stream.readStringUntil('\n').toInt();
  583. DBG("### Got Data:", mux);
  584. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  585. sockets[mux]->got_data = true;
  586. }
  587. } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
  588. int nl = data.lastIndexOf(GSM_NL, data.length()-8);
  589. int coma = data.indexOf(',', nl+2);
  590. int mux = data.substring(nl+2, coma).toInt();
  591. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  592. sockets[mux]->sock_connected = false;
  593. }
  594. data = "";
  595. DBG("### Closed: ", mux);
  596. }
  597. }
  598. } while (millis() - startMillis < timeout_ms);
  599. finish:
  600. if (!index) {
  601. data.trim();
  602. if (data.length()) {
  603. DBG("### Unhandled:", data);
  604. }
  605. data = "";
  606. }
  607. //data.replace(GSM_NL, "/");
  608. //DBG('<', index, '>', data);
  609. return index;
  610. }
  611. uint8_t waitResponse(uint32_t timeout_ms,
  612. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  613. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  614. {
  615. String data;
  616. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  617. }
  618. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  619. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  620. {
  621. return waitResponse(1000, r1, r2, r3, r4, r5);
  622. }
  623. public:
  624. Stream& stream;
  625. protected:
  626. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  627. };
  628. #endif