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.

748 lines
18 KiB

6 years ago
7 years ago
5 years ago
5 years ago
6 years ago
6 years ago
7 years ago
6 years ago
5 years ago
  1. /**
  2. * @file TinyGsmClientUBLOX.h
  3. * @author Volodymyr Shymanskyy
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * @date Nov 2016
  7. */
  8. #ifndef TinyGsmClientUBLOX_h
  9. #define TinyGsmClientUBLOX_h
  10. //#pragma message("TinyGSM: TinyGsmClientUBLOX")
  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 7
  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. static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
  21. enum SimStatus {
  22. SIM_ERROR = 0,
  23. SIM_READY = 1,
  24. SIM_LOCKED = 2,
  25. };
  26. enum RegStatus {
  27. REG_UNREGISTERED = 0,
  28. REG_SEARCHING = 2,
  29. REG_DENIED = 3,
  30. REG_OK_HOME = 1,
  31. REG_OK_ROAMING = 5,
  32. REG_UNKNOWN = 4,
  33. };
  34. class TinyGsmUBLOX
  35. {
  36. public:
  37. class GsmClient : public Client
  38. {
  39. friend class TinyGsmUBLOX;
  40. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  41. public:
  42. GsmClient() {}
  43. GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) {
  44. init(&modem, mux);
  45. }
  46. bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) {
  47. this->at = modem;
  48. this->mux = mux;
  49. sock_available = 0;
  50. prev_check = 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, int timeout_s) {
  58. stop();
  59. TINY_GSM_YIELD();
  60. rx.clear();
  61. uint8_t oldMux = mux;
  62. sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
  63. if (mux != oldMux) {
  64. DBG("WARNING: Mux number changed from", oldMux, "to", mux);
  65. at->sockets[oldMux] = NULL;
  66. }
  67. at->sockets[mux] = this;
  68. at->maintain();
  69. return sock_connected;
  70. }
  71. TINY_GSM_CLIENT_CONNECT_OVERLOADS()
  72. virtual void stop() {
  73. TINY_GSM_YIELD();
  74. // Read and dump anything remaining in the modem's internal buffer.
  75. // The socket will appear open in response to connected() even after it
  76. // closes until all data is read from the buffer.
  77. // Doing it this way allows the external mcu to find and get all of the data
  78. // that it wants from the socket even if it was closed externally.
  79. rx.clear();
  80. at->maintain();
  81. while (sock_available > 0) {
  82. at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux);
  83. rx.clear();
  84. at->maintain();
  85. }
  86. at->modemDisconnect(mux);
  87. }
  88. TINY_GSM_CLIENT_WRITE() ;
  89. TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() ;
  90. TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() ;
  91. TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
  92. /*
  93. * Extended API
  94. */
  95. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  96. private:
  97. TinyGsmUBLOX* at;
  98. uint8_t mux;
  99. uint16_t sock_available;
  100. uint32_t prev_check;
  101. bool sock_connected;
  102. bool got_data;
  103. RxFifo rx;
  104. };
  105. class GsmClientSecure : public GsmClient
  106. {
  107. public:
  108. GsmClientSecure() {}
  109. GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1)
  110. : GsmClient(modem, mux)
  111. {}
  112. public:
  113. virtual int connect(const char *host, uint16_t port, int timeout_s) {
  114. stop();
  115. TINY_GSM_YIELD();
  116. rx.clear();
  117. uint8_t oldMux = mux;
  118. sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
  119. if (mux != oldMux) {
  120. DBG("WARNING: Mux number changed from", oldMux, "to", mux);
  121. at->sockets[oldMux] = NULL;
  122. }
  123. at->sockets[mux] = this;
  124. at->maintain();
  125. return sock_connected;
  126. }
  127. };
  128. public:
  129. TinyGsmUBLOX(Stream& stream)
  130. : stream(stream)
  131. {
  132. memset(sockets, 0, sizeof(sockets));
  133. }
  134. /*
  135. * Basic functions
  136. */
  137. bool begin(const char* pin = NULL) {
  138. return init(pin);
  139. }
  140. bool init(const char* pin = NULL) {
  141. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  142. if (!testAT()) {
  143. return false;
  144. }
  145. sendAT(GF("E0")); // Echo Off
  146. if (waitResponse() != 1) {
  147. return false;
  148. }
  149. #ifdef TINY_GSM_DEBUG
  150. sendAT(GF("+CMEE=2")); // turn on verbose error codes
  151. #else
  152. sendAT(GF("+CMEE=0")); // turn off error codes
  153. #endif
  154. waitResponse();
  155. getModemName();
  156. int ret = getSimStatus();
  157. // if the sim isn't ready and a pin has been provided, try to unlock the sim
  158. if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
  159. simUnlock(pin);
  160. return (getSimStatus() == SIM_READY);
  161. }
  162. // if the sim is ready, or it's locked but no pin has been provided, return true
  163. else {
  164. return (ret == SIM_READY || ret == SIM_LOCKED);
  165. }
  166. }
  167. String getModemName() {
  168. sendAT(GF("+CGMI"));
  169. String res1;
  170. if (waitResponse(1000L, res1) != 1) {
  171. return "u-blox Cellular Modem";
  172. }
  173. res1.replace(GSM_NL "OK" GSM_NL, "");
  174. res1.trim();
  175. sendAT(GF("+GMM"));
  176. String res2;
  177. if (waitResponse(1000L, res2) != 1) {
  178. return "u-blox Cellular Modem";
  179. }
  180. res2.replace(GSM_NL "OK" GSM_NL, "");
  181. res2.trim();
  182. String name = res1 + String(' ') + res2;
  183. DBG("### Modem:", name);
  184. if (name.startsWith("u-blox SARA-R4") || name.startsWith("u-blox SARA-N4")) {
  185. DBG("### WARNING: You are using the wrong TinyGSM modem!");
  186. }
  187. else if (name.startsWith("u-blox SARA-N2")) {
  188. DBG("### SARA N2 NB-IoT modems not supported!");
  189. }
  190. return name;
  191. }
  192. TINY_GSM_MODEM_SET_BAUD_IPR()
  193. TINY_GSM_MODEM_TEST_AT()
  194. TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
  195. bool factoryDefault() {
  196. sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM
  197. waitResponse();
  198. sendAT(GF("+CFUN=16")); // Reset
  199. return waitResponse() == 1;
  200. }
  201. TINY_GSM_MODEM_GET_INFO_ATI()
  202. bool hasSSL() {
  203. return true;
  204. }
  205. bool hasWifi() {
  206. return false;
  207. }
  208. bool hasGPRS() {
  209. return true;
  210. }
  211. /*
  212. * Power functions
  213. */
  214. bool restart() {
  215. if (!testAT()) {
  216. return false;
  217. }
  218. sendAT(GF("+CFUN=16"));
  219. if (waitResponse(10000L) != 1) {
  220. return false;
  221. }
  222. delay(3000); // TODO: Verify delay timing here
  223. return init();
  224. }
  225. bool poweroff() {
  226. sendAT(GF("+CPWROFF"));
  227. return waitResponse(40000L) == 1;
  228. }
  229. bool radioOff() {
  230. sendAT(GF("+CFUN=0"));
  231. if (waitResponse(10000L) != 1) {
  232. return false;
  233. }
  234. delay(3000);
  235. return true;
  236. }
  237. bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  238. /*
  239. * SIM card functions
  240. */
  241. TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
  242. TINY_GSM_MODEM_GET_SIMCCID_CCID()
  243. String getIMEI() {
  244. sendAT(GF("+CGSN"));
  245. if (waitResponse(GF(GSM_NL)) != 1) {
  246. return "";
  247. }
  248. String res = stream.readStringUntil('\n');
  249. waitResponse();
  250. res.trim();
  251. return res;
  252. }
  253. SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
  254. for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
  255. sendAT(GF("+CPIN?"));
  256. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  257. delay(1000);
  258. continue;
  259. }
  260. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
  261. waitResponse();
  262. switch (status) {
  263. case 2:
  264. case 3: return SIM_LOCKED;
  265. case 1: return SIM_READY;
  266. default: return SIM_ERROR;
  267. }
  268. }
  269. return SIM_ERROR;
  270. }
  271. TINY_GSM_MODEM_GET_REGISTRATION_XREG(CGREG)
  272. TINY_GSM_MODEM_GET_OPERATOR_COPS()
  273. /*
  274. * Generic network functions
  275. */
  276. TINY_GSM_MODEM_GET_CSQ()
  277. bool isNetworkConnected() {
  278. RegStatus s = getRegistrationStatus();
  279. if (s == REG_OK_HOME || s == REG_OK_ROAMING)
  280. return true;
  281. else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
  282. return isGprsConnected();
  283. else return false;
  284. }
  285. TINY_GSM_MODEM_WAIT_FOR_NETWORK()
  286. /*
  287. * GPRS functions
  288. */
  289. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
  290. gprsDisconnect();
  291. sendAT(GF("+CGATT=1")); // attach to GPRS
  292. if (waitResponse(360000L) != 1) {
  293. return false;
  294. }
  295. // Setting up the PSD profile/PDP context with the UPSD commands sets up an
  296. // "internal" PDP context, i.e. a data connection using the internal IP
  297. // stack and related AT commands for sockets.
  298. sendAT(GF("+UPSD=0,1,\""), apn, '"'); // Set APN for PSD profile 0
  299. waitResponse();
  300. if (user && strlen(user) > 0) {
  301. sendAT(GF("+UPSD=0,2,\""), user, '"'); // Set user for PSD profile 0
  302. waitResponse();
  303. }
  304. if (pwd && strlen(pwd) > 0) {
  305. sendAT(GF("+UPSD=0,3,\""), pwd, '"'); // Set password for PSD profile 0
  306. waitResponse();
  307. }
  308. sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP on PSD profile 0
  309. waitResponse();
  310. sendAT(GF("+UPSDA=0,3")); // Activate the PDP context associated with profile 0
  311. if (waitResponse(360000L) != 1) {
  312. return false;
  313. }
  314. sendAT(GF("+UPSND=0,8")); // Activate PSD profile 0
  315. if (waitResponse(GF(",8,1")) != 1) {
  316. return false;
  317. }
  318. waitResponse();
  319. return true;
  320. }
  321. bool gprsDisconnect() {
  322. sendAT(GF("+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
  323. if (waitResponse(360000L) != 1) {
  324. return false;
  325. }
  326. sendAT(GF("+CGATT=0")); // detach from GPRS
  327. if (waitResponse(360000L) != 1) {
  328. return false;
  329. }
  330. return true;
  331. }
  332. TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
  333. /*
  334. * IP Address functions
  335. */
  336. String getLocalIP() {
  337. sendAT(GF("+UPSND=0,0"));
  338. if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
  339. return "";
  340. }
  341. streamSkipUntil(','); // Skip PSD profile
  342. streamSkipUntil('\"'); // Skip request type
  343. String res = stream.readStringUntil('\"');
  344. if (waitResponse() != 1) {
  345. return "";
  346. }
  347. return res;
  348. }
  349. IPAddress localIP() {
  350. return TinyGsmIpFromString(getLocalIP());
  351. }
  352. /*
  353. * Phone Call functions
  354. */
  355. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  356. bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  357. bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  358. bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  359. /*
  360. * Messaging functions
  361. */
  362. String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  363. bool sendSMS(const String& number, const String& text) {
  364. sendAT(GF("+CSCS=\"GSM\"")); // Set GSM default alphabet
  365. waitResponse();
  366. sendAT(GF("+CMGF=1")); // Set preferred message format to text mode
  367. waitResponse();
  368. sendAT(GF("+CMGS=\""), number, GF("\"")); // set the phone number
  369. if (waitResponse(GF(">")) != 1) {
  370. return false;
  371. }
  372. stream.print(text); // Actually send the message
  373. stream.write((char)0x1A);
  374. stream.flush();
  375. return waitResponse(60000L) == 1;
  376. }
  377. bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  378. /*
  379. * Location functions
  380. */
  381. String getGsmLocation() {
  382. sendAT(GF("+ULOC=2,3,0,120,1"));
  383. if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) {
  384. return "";
  385. }
  386. String res = stream.readStringUntil('\n');
  387. waitResponse();
  388. res.trim();
  389. return res;
  390. }
  391. /*
  392. * Battery & temperature functions
  393. */
  394. uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
  395. int8_t getBattPercent() {
  396. sendAT(GF("+CIND?"));
  397. if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
  398. return 0;
  399. }
  400. int res = stream.readStringUntil(',').toInt();
  401. waitResponse();
  402. return res;
  403. }
  404. uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
  405. bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
  406. percent = getBattPercent();
  407. return true;
  408. }
  409. // This would only available for a small number of modules in this group (TOBY-L)
  410. float getTemperature() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  411. /*
  412. * Client related functions
  413. */
  414. protected:
  415. bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
  416. bool ssl = false, int timeout_s = 120)
  417. {
  418. uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
  419. sendAT(GF("+USOCR=6")); // create a socket
  420. if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { // reply is +USOCR: ## of socket created
  421. return false;
  422. }
  423. *mux = stream.readStringUntil('\n').toInt();
  424. waitResponse();
  425. if (ssl) {
  426. sendAT(GF("+USOSEC="), *mux, ",1");
  427. waitResponse();
  428. }
  429. // Enable NODELAY
  430. sendAT(GF("+USOSO="), *mux, GF(",6,1,1"));
  431. waitResponse();
  432. // Enable KEEPALIVE, 30 sec
  433. //sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
  434. //waitResponse();
  435. // connect on the allocated socket
  436. // TODO: Use faster "asynchronous" connection?
  437. // We would have to wait for the +UUSOCO URC to verify connection
  438. sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
  439. int rsp = waitResponse(timeout_ms);
  440. return (1 == rsp);
  441. }
  442. bool modemDisconnect(uint8_t mux) {
  443. TINY_GSM_YIELD();
  444. if (!modemGetConnected(mux)) {
  445. sockets[mux]->sock_connected = false;
  446. return true;
  447. }
  448. bool success;
  449. sendAT(GF("+USOCL="), mux);
  450. success = 1 == waitResponse(); // should return within 1s
  451. if (success) {
  452. sockets[mux]->sock_connected = false;
  453. }
  454. return success;
  455. }
  456. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  457. sendAT(GF("+USOWR="), mux, ',', len);
  458. if (waitResponse(GF("@")) != 1) {
  459. return 0;
  460. }
  461. // 50ms delay, see AT manual section 25.10.4
  462. delay(50);
  463. stream.write((uint8_t*)buff, len);
  464. stream.flush();
  465. if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
  466. return 0;
  467. }
  468. streamSkipUntil(','); // Skip mux
  469. int sent = stream.readStringUntil('\n').toInt();
  470. waitResponse(); // sends back OK after the confirmation of number sent
  471. return sent;
  472. }
  473. size_t modemRead(size_t size, uint8_t mux) {
  474. sendAT(GF("+USORD="), mux, ',', size);
  475. if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
  476. return 0;
  477. }
  478. streamSkipUntil(','); // Skip mux
  479. size_t len = stream.readStringUntil(',').toInt();
  480. sockets[mux]->sock_available = len;
  481. streamSkipUntil('\"');
  482. for (size_t i=0; i<len; i++) {
  483. TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
  484. }
  485. streamSkipUntil('\"');
  486. waitResponse();
  487. DBG("### READ:", len, "from", mux);
  488. return len;
  489. }
  490. size_t modemGetAvailable(uint8_t mux) {
  491. // NOTE: Querying a closed socket gives an error "operation not allowed"
  492. sendAT(GF("+USORD="), mux, ",0");
  493. size_t result = 0;
  494. uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
  495. // Will give error "operation not allowed" when attempting to read a socket
  496. // that you have already told to close
  497. if (res == 1) {
  498. streamSkipUntil(','); // Skip mux
  499. result = stream.readStringUntil('\n').toInt();
  500. // if (result) DBG("### DATA AVAILABLE:", result, "on", mux);
  501. waitResponse();
  502. }
  503. if (!result && res != 2 && res != 3) { // Don't check modemGetConnected after an error
  504. sockets[mux]->sock_connected = modemGetConnected(mux);
  505. }
  506. return result;
  507. }
  508. bool modemGetConnected(uint8_t mux) {
  509. // NOTE: Querying a closed socket gives an error "operation not allowed"
  510. sendAT(GF("+USOCTL="), mux, ",10");
  511. uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
  512. if (res != 1)
  513. return false;
  514. streamSkipUntil(','); // Skip mux
  515. streamSkipUntil(','); // Skip type
  516. int result = stream.readStringUntil('\n').toInt();
  517. // 0: the socket is in INACTIVE status (it corresponds to CLOSED status
  518. // defined in RFC793 "TCP Protocol Specification" [112])
  519. // 1: the socket is in LISTEN status
  520. // 2: the socket is in SYN_SENT status
  521. // 3: the socket is in SYN_RCVD status
  522. // 4: the socket is in ESTABILISHED status
  523. // 5: the socket is in FIN_WAIT_1 status
  524. // 6: the socket is in FIN_WAIT_2 status
  525. // 7: the sokcet is in CLOSE_WAIT status
  526. // 8: the socket is in CLOSING status
  527. // 9: the socket is in LAST_ACK status
  528. // 10: the socket is in TIME_WAIT status
  529. waitResponse();
  530. return (result != 0);
  531. }
  532. public:
  533. /*
  534. Utilities
  535. */
  536. TINY_GSM_MODEM_STREAM_UTILITIES()
  537. // TODO: Optimize this!
  538. uint8_t waitResponse(uint32_t timeout_ms, String& data,
  539. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  540. GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  541. {
  542. /*String r1s(r1); r1s.trim();
  543. String r2s(r2); r2s.trim();
  544. String r3s(r3); r3s.trim();
  545. String r4s(r4); r4s.trim();
  546. String r5s(r5); r5s.trim();
  547. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  548. data.reserve(64);
  549. int index = 0;
  550. unsigned long startMillis = millis();
  551. do {
  552. TINY_GSM_YIELD();
  553. while (stream.available() > 0) {
  554. int a = stream.read();
  555. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  556. data += (char)a;
  557. if (r1 && data.endsWith(r1)) {
  558. index = 1;
  559. goto finish;
  560. } else if (r2 && data.endsWith(r2)) {
  561. index = 2;
  562. goto finish;
  563. } else if (r3 && data.endsWith(r3)) {
  564. index = 3;
  565. goto finish;
  566. } else if (r4 && data.endsWith(r4)) {
  567. index = 4;
  568. goto finish;
  569. } else if (r5 && data.endsWith(r5)) {
  570. index = 5;
  571. goto finish;
  572. } else if (data.endsWith(GF(GSM_NL "+UUSORD:"))) {
  573. int mux = stream.readStringUntil(',').toInt();
  574. int len = stream.readStringUntil('\n').toInt();
  575. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  576. sockets[mux]->got_data = true;
  577. sockets[mux]->sock_available = len;
  578. }
  579. data = "";
  580. DBG("### URC Data Received:", len, "on", mux);
  581. } else if (data.endsWith(GF(GSM_NL "+UUSOCL:"))) {
  582. int mux = stream.readStringUntil('\n').toInt();
  583. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  584. sockets[mux]->sock_connected = false;
  585. }
  586. data = "";
  587. DBG("### URC Sock Closed: ", mux);
  588. }
  589. }
  590. } while (millis() - startMillis < timeout_ms);
  591. finish:
  592. if (!index) {
  593. data.trim();
  594. if (data.length()) {
  595. DBG("### Unhandled:", data);
  596. }
  597. data = "";
  598. }
  599. //DBG('<', index, '>');
  600. return index;
  601. }
  602. uint8_t waitResponse(uint32_t timeout_ms,
  603. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  604. GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  605. {
  606. String data;
  607. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  608. }
  609. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  610. GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  611. {
  612. return waitResponse(1000, r1, r2, r3, r4, r5);
  613. }
  614. public:
  615. Stream& stream;
  616. protected:
  617. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  618. };
  619. #endif