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.

766 lines
22 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
4 years ago
8 years ago
8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
  1. /**
  2. * @file TinyGsmClientSIM800.h
  3. * @author Volodymyr Shymanskyy
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * @date Nov 2016
  7. */
  8. #ifndef SRC_TINYGSMCLIENTSIM800_H_
  9. #define SRC_TINYGSMCLIENTSIM800_H_
  10. // #pragma message("TinyGSM: TinyGsmClientSIM800")
  11. // #define TINY_GSM_DEBUG Serial
  12. // #define TINY_GSM_USE_HEX
  13. #define TINY_GSM_MUX_COUNT 5
  14. #define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
  15. #include "TinyGsmBattery.tpp"
  16. #include "TinyGsmCalling.tpp"
  17. #include "TinyGsmGPRS.tpp"
  18. #include "TinyGsmGSMLocation.tpp"
  19. #include "TinyGsmModem.tpp"
  20. #include "TinyGsmSMS.tpp"
  21. #include "TinyGsmSSL.tpp"
  22. #include "TinyGsmTCP.tpp"
  23. #include "TinyGsmTime.tpp"
  24. #define GSM_NL "\r\n"
  25. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  26. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  27. #if defined TINY_GSM_DEBUG
  28. static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
  29. static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
  30. #endif
  31. enum RegStatus {
  32. REG_NO_RESULT = -1,
  33. REG_UNREGISTERED = 0,
  34. REG_SEARCHING = 2,
  35. REG_DENIED = 3,
  36. REG_OK_HOME = 1,
  37. REG_OK_ROAMING = 5,
  38. REG_UNKNOWN = 4,
  39. };
  40. class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
  41. public TinyGsmGPRS<TinyGsmSim800>,
  42. public TinyGsmTCP<TinyGsmSim800, TINY_GSM_MUX_COUNT>,
  43. public TinyGsmSSL<TinyGsmSim800>,
  44. public TinyGsmCalling<TinyGsmSim800>,
  45. public TinyGsmSMS<TinyGsmSim800>,
  46. public TinyGsmGSMLocation<TinyGsmSim800>,
  47. public TinyGsmTime<TinyGsmSim800>,
  48. public TinyGsmBattery<TinyGsmSim800> {
  49. friend class TinyGsmModem<TinyGsmSim800>;
  50. friend class TinyGsmGPRS<TinyGsmSim800>;
  51. friend class TinyGsmTCP<TinyGsmSim800, TINY_GSM_MUX_COUNT>;
  52. friend class TinyGsmSSL<TinyGsmSim800>;
  53. friend class TinyGsmCalling<TinyGsmSim800>;
  54. friend class TinyGsmSMS<TinyGsmSim800>;
  55. friend class TinyGsmGSMLocation<TinyGsmSim800>;
  56. friend class TinyGsmTime<TinyGsmSim800>;
  57. friend class TinyGsmBattery<TinyGsmSim800>;
  58. /*
  59. * Inner Client
  60. */
  61. public:
  62. class GsmClientSim800 : public GsmClient {
  63. friend class TinyGsmSim800;
  64. public:
  65. GsmClientSim800() {}
  66. explicit GsmClientSim800(TinyGsmSim800& modem, uint8_t mux = 0) {
  67. init(&modem, mux);
  68. }
  69. bool init(TinyGsmSim800* modem, uint8_t mux = 0) {
  70. this->at = modem;
  71. sock_available = 0;
  72. prev_check = 0;
  73. sock_connected = false;
  74. got_data = false;
  75. if (mux < TINY_GSM_MUX_COUNT) {
  76. this->mux = mux;
  77. } else {
  78. this->mux = (mux % TINY_GSM_MUX_COUNT);
  79. }
  80. at->sockets[this->mux] = this;
  81. return true;
  82. }
  83. public:
  84. virtual int connect(const char* host, uint16_t port, int timeout_s) {
  85. stop();
  86. TINY_GSM_YIELD();
  87. rx.clear();
  88. sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
  89. return sock_connected;
  90. }
  91. TINY_GSM_CLIENT_CONNECT_OVERRIDES
  92. void stop(uint32_t maxWaitMs) {
  93. dumpModemBuffer(maxWaitMs);
  94. at->sendAT(GF("+CIPCLOSE="), mux, GF(",1")); // Quick close
  95. sock_connected = false;
  96. at->waitResponse();
  97. }
  98. void stop() override {
  99. stop(15000L);
  100. }
  101. /*
  102. * Extended API
  103. */
  104. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  105. };
  106. /*
  107. * Inner Secure Client
  108. */
  109. public:
  110. class GsmClientSecureSim800 : public GsmClientSim800 {
  111. public:
  112. GsmClientSecureSim800() {}
  113. explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 0)
  114. : GsmClientSim800(modem, mux) {}
  115. public:
  116. int connect(const char* host, uint16_t port, int timeout_s) override {
  117. stop();
  118. TINY_GSM_YIELD();
  119. rx.clear();
  120. sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
  121. return sock_connected;
  122. }
  123. TINY_GSM_CLIENT_CONNECT_OVERRIDES
  124. };
  125. /*
  126. * Constructor
  127. */
  128. public:
  129. explicit TinyGsmSim800(Stream& stream) : stream(stream) {
  130. memset(sockets, 0, sizeof(sockets));
  131. }
  132. /*
  133. * Basic functions
  134. */
  135. protected:
  136. bool initImpl(const char* pin = NULL) {
  137. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  138. DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM800"));
  139. if (!testAT()) { return false; }
  140. // sendAT(GF("&FZ")); // Factory + Reset
  141. // waitResponse();
  142. sendAT(GF("E0")); // Echo Off
  143. if (waitResponse() != 1) { return false; }
  144. #ifdef TINY_GSM_DEBUG
  145. sendAT(GF("+CMEE=2")); // turn on verbose error codes
  146. #else
  147. sendAT(GF("+CMEE=0")); // turn off error codes
  148. #endif
  149. waitResponse();
  150. DBG(GF("### Modem:"), getModemName());
  151. // Enable Local Time Stamp for getting network time
  152. sendAT(GF("+CLTS=1"));
  153. if (waitResponse(10000L) != 1) { return false; }
  154. // Enable battery checks
  155. sendAT(GF("+CBATCHK=1"));
  156. waitResponse();
  157. SimStatus ret = getSimStatus();
  158. // if the sim isn't ready and a pin has been provided, try to unlock the sim
  159. if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
  160. simUnlock(pin);
  161. return (getSimStatus() == SIM_READY);
  162. } else {
  163. // if the sim is ready, or it's locked but no pin has been provided,
  164. // return true
  165. return (ret == SIM_READY || ret == SIM_LOCKED);
  166. }
  167. }
  168. String getModemNameImpl() {
  169. String name = "";
  170. #if defined(TINY_GSM_MODEM_SIM800)
  171. name = "SIMCom SIM800";
  172. #elif defined(TINY_GSM_MODEM_SIM808)
  173. name = "SIMCom SIM808";
  174. #elif defined(TINY_GSM_MODEM_SIM868)
  175. name = "SIMCom SIM868";
  176. #elif defined(TINY_GSM_MODEM_SIM900)
  177. name = "SIMCom SIM900";
  178. #endif
  179. sendAT(GF("+GMM"));
  180. String res2;
  181. if (waitResponse(1000L, res2) != 1) { return name; }
  182. res2.replace(GSM_NL "OK" GSM_NL, "");
  183. res2.replace("_", " ");
  184. res2.trim();
  185. name = res2;
  186. DBG("### Modem:", name);
  187. return name;
  188. }
  189. bool factoryDefaultImpl() {
  190. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  191. waitResponse();
  192. sendAT(GF("+IPR=0")); // Auto-baud
  193. waitResponse();
  194. sendAT(GF("+IFC=0,0")); // No Flow Control
  195. waitResponse();
  196. sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
  197. waitResponse();
  198. sendAT(GF("+CSCLK=0")); // Disable Slow Clock
  199. waitResponse();
  200. sendAT(GF("&W")); // Write configuration
  201. return waitResponse() == 1;
  202. }
  203. /*
  204. bool thisHasSSL() {
  205. #if defined(TINY_GSM_MODEM_SIM900)
  206. return false;
  207. #else
  208. sendAT(GF("+CIPSSL=?"));
  209. if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { return false; }
  210. return waitResponse() == 1;
  211. #endif
  212. }
  213. */
  214. /*
  215. * Power functions
  216. */
  217. protected:
  218. bool restartImpl() {
  219. if (!testAT()) { return false; }
  220. sendAT(GF("&W"));
  221. waitResponse();
  222. if (!setPhoneFunctionality(0)) { return false; }
  223. if (!setPhoneFunctionality(1, true)) { return false; }
  224. delay(3000);
  225. return init();
  226. }
  227. bool powerOffImpl() {
  228. sendAT(GF("+CPOWD=1"));
  229. return waitResponse(10000L, GF("NORMAL POWER DOWN")) == 1;
  230. }
  231. // During sleep, the SIM800 module has its serial communication disabled. In
  232. // order to reestablish communication pull the DRT-pin of the SIM800 module
  233. // LOW for at least 50ms. Then use this function to disable sleep mode. The
  234. // DTR-pin can then be released again.
  235. bool sleepEnableImpl(bool enable = true) {
  236. sendAT(GF("+CSCLK="), enable);
  237. return waitResponse() == 1;
  238. }
  239. // <fun> 0 Minimum functionality
  240. // <fun> 1 Full functionality (Default)
  241. // <fun> 4 Disable phone both transmit and receive RF circuits.
  242. // <rst> Reset the MT before setting it to <fun> power level.
  243. bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
  244. sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
  245. return waitResponse(10000L) == 1;
  246. }
  247. /*
  248. * Generic network functions
  249. */
  250. public:
  251. RegStatus getRegistrationStatus() {
  252. return (RegStatus)getRegistrationStatusXREG("CREG");
  253. }
  254. protected:
  255. bool isNetworkConnectedImpl() {
  256. RegStatus s = getRegistrationStatus();
  257. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  258. }
  259. String getLocalIPImpl() {
  260. sendAT(GF("+CIFSR;E0"));
  261. String res;
  262. if (waitResponse(10000L, res) != 1) { return ""; }
  263. res.replace(GSM_NL "OK" GSM_NL, "");
  264. res.replace(GSM_NL, "");
  265. res.trim();
  266. return res;
  267. }
  268. /*
  269. * GPRS functions
  270. */
  271. protected:
  272. bool gprsConnectImpl(const char* apn, const char* user = NULL,
  273. const char* pwd = NULL) {
  274. gprsDisconnect();
  275. // Set the Bearer for the IP
  276. sendAT(GF(
  277. "+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
  278. waitResponse();
  279. sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
  280. waitResponse();
  281. if (user && strlen(user) > 0) {
  282. sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
  283. waitResponse();
  284. }
  285. if (pwd && strlen(pwd) > 0) {
  286. sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
  287. waitResponse();
  288. }
  289. // Define the PDP context
  290. sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
  291. waitResponse();
  292. // Activate the PDP context
  293. sendAT(GF("+CGACT=1,1"));
  294. waitResponse(60000L);
  295. // Open the definied GPRS bearer context
  296. sendAT(GF("+SAPBR=1,1"));
  297. waitResponse(85000L);
  298. // Query the GPRS bearer context status
  299. sendAT(GF("+SAPBR=2,1"));
  300. if (waitResponse(30000L) != 1) { return false; }
  301. // Attach to GPRS
  302. sendAT(GF("+CGATT=1"));
  303. if (waitResponse(60000L) != 1) { return false; }
  304. // TODO(?): wait AT+CGATT?
  305. // Set to multi-IP
  306. sendAT(GF("+CIPMUX=1"));
  307. if (waitResponse() != 1) { return false; }
  308. // Put in "quick send" mode (thus no extra "Send OK")
  309. sendAT(GF("+CIPQSEND=1"));
  310. if (waitResponse() != 1) { return false; }
  311. // Set to get data manually
  312. sendAT(GF("+CIPRXGET=1"));
  313. if (waitResponse() != 1) { return false; }
  314. // Start Task and Set APN, USER NAME, PASSWORD
  315. sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
  316. if (waitResponse(60000L) != 1) { return false; }
  317. // Bring Up Wireless Connection with GPRS or CSD
  318. sendAT(GF("+CIICR"));
  319. if (waitResponse(60000L) != 1) { return false; }
  320. // Get Local IP Address, only assigned after connection
  321. sendAT(GF("+CIFSR;E0"));
  322. if (waitResponse(10000L) != 1) { return false; }
  323. // Configure Domain Name Server (DNS)
  324. sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
  325. if (waitResponse() != 1) { return false; }
  326. return true;
  327. }
  328. bool gprsDisconnectImpl() {
  329. // Shut the TCP/IP connection
  330. // CIPSHUT will close *all* open connections
  331. sendAT(GF("+CIPSHUT"));
  332. if (waitResponse(60000L) != 1) { return false; }
  333. sendAT(GF("+CGATT=0")); // Detach from GPRS
  334. if (waitResponse(60000L) != 1) { return false; }
  335. return true;
  336. }
  337. /*
  338. * SIM card functions
  339. */
  340. protected:
  341. // May not return the "+CCID" before the number
  342. String getSimCCIDImpl() {
  343. sendAT(GF("+CCID"));
  344. if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
  345. String res = stream.readStringUntil('\n');
  346. waitResponse();
  347. // Trim out the CCID header in case it is there
  348. res.replace("CCID:", "");
  349. res.trim();
  350. return res;
  351. }
  352. /*
  353. * Phone Call functions
  354. */
  355. public:
  356. bool setGsmBusy(bool busy = true) {
  357. sendAT(GF("+GSMBUSY="), busy ? 1 : 0);
  358. return waitResponse() == 1;
  359. }
  360. /*
  361. * Messaging functions
  362. */
  363. protected:
  364. // Follows all messaging functions per template
  365. /*
  366. * GSM Location functions
  367. */
  368. protected:
  369. // Depending on the exacty model and firmware revision, should return a
  370. // GSM-based location from CLBS as per the template
  371. // TODO(?): Check number of digits in year (2 or 4)
  372. /*
  373. * GPS/GNSS/GLONASS location functions
  374. */
  375. protected:
  376. // No functions of this type supported
  377. /*
  378. * Time functions
  379. */
  380. protected:
  381. // Can follow the standard CCLK function in the template
  382. /*
  383. * Battery functions
  384. */
  385. protected:
  386. // Follows all battery functions per template
  387. /*
  388. * NTP server functions
  389. */
  390. public:
  391. boolean isValidNumber(String str) {
  392. if (!(str.charAt(0) == '+' || str.charAt(0) == '-' ||
  393. isDigit(str.charAt(0))))
  394. return false;
  395. for (byte i = 1; i < str.length(); i++) {
  396. if (!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) { return false; }
  397. }
  398. return true;
  399. }
  400. String ShowNTPError(byte error) {
  401. switch (error) {
  402. case 1: return "Network time synchronization is successful";
  403. case 61: return "Network error";
  404. case 62: return "DNS resolution error";
  405. case 63: return "Connection error";
  406. case 64: return "Service response error";
  407. case 65: return "Service response timeout";
  408. default: return "Unknown error: " + String(error);
  409. }
  410. }
  411. byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
  412. // Set GPRS bearer profile to associate with NTP sync
  413. sendAT(GF("+CNTPCID=1"));
  414. if (waitResponse(10000L) != 1) { return -1; }
  415. // Set NTP server and timezone
  416. sendAT(GF("+CNTP="), server, ',', String(TimeZone));
  417. if (waitResponse(10000L) != 1) { return -1; }
  418. // Request network synchronization
  419. sendAT(GF("+CNTP"));
  420. if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) {
  421. String result = stream.readStringUntil('\n');
  422. result.trim();
  423. if (isValidNumber(result)) { return result.toInt(); }
  424. } else {
  425. return -1;
  426. }
  427. return -1;
  428. }
  429. /*
  430. * Client related functions
  431. */
  432. protected:
  433. bool modemConnect(const char* host, uint16_t port, uint8_t mux,
  434. bool ssl = false, int timeout_s = 75) {
  435. int8_t rsp;
  436. uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
  437. #if !defined(TINY_GSM_MODEM_SIM900)
  438. sendAT(GF("+CIPSSL="), ssl);
  439. rsp = waitResponse();
  440. if (ssl && rsp != 1) { return false; }
  441. #ifdef TINY_GSM_SSL_CLIENT_AUTHENTICATION
  442. // set SSL options
  443. // +SSLOPT=<opt>,<enable>
  444. // <opt>
  445. // 0 (default) ignore invalid certificate
  446. // 1 client authentication
  447. // <enable>
  448. // 0 (default) close
  449. // 1 open
  450. sendAT(GF("+CIPSSL=1,1"));
  451. if (waitResponse() != 1) return false;
  452. #endif
  453. #endif
  454. sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host,
  455. GF("\","), port);
  456. rsp = waitResponse(
  457. timeout_ms, GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL),
  458. GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL),
  459. GF("CLOSE OK" GSM_NL)); // Happens when HTTPS handshake fails
  460. return (1 == rsp);
  461. }
  462. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  463. sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
  464. if (waitResponse(GF(">")) != 1) { return 0; }
  465. stream.write(reinterpret_cast<const uint8_t*>(buff), len);
  466. stream.flush();
  467. if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; }
  468. streamSkipUntil(','); // Skip mux
  469. return streamGetIntBefore('\n');
  470. }
  471. size_t modemRead(size_t size, uint8_t mux) {
  472. if (!sockets[mux]) return 0;
  473. #ifdef TINY_GSM_USE_HEX
  474. sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
  475. if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
  476. #else
  477. sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
  478. if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
  479. #endif
  480. streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX
  481. streamSkipUntil(','); // Skip mux
  482. int16_t len_requested = streamGetIntBefore(',');
  483. // ^^ Requested number of data bytes (1-1460 bytes)to be read
  484. int16_t len_confirmed = streamGetIntBefore('\n');
  485. // ^^ Confirmed number of data bytes to be read, which may be less than
  486. // requested. 0 indicates that no data can be read.
  487. // SRGD NOTE: Contrary to above (which is copied from AT command manual)
  488. // this is actually be the number of bytes that will be remaining in the
  489. // buffer after the read.
  490. for (int i = 0; i < len_requested; i++) {
  491. uint32_t startMillis = millis();
  492. #ifdef TINY_GSM_USE_HEX
  493. while (stream.available() < 2 &&
  494. (millis() - startMillis < sockets[mux]->_timeout)) {
  495. TINY_GSM_YIELD();
  496. }
  497. char buf[4] = {
  498. 0,
  499. };
  500. buf[0] = stream.read();
  501. buf[1] = stream.read();
  502. char c = strtol(buf, NULL, 16);
  503. #else
  504. while (!stream.available() &&
  505. (millis() - startMillis < sockets[mux]->_timeout)) {
  506. TINY_GSM_YIELD();
  507. }
  508. char c = stream.read();
  509. #endif
  510. sockets[mux]->rx.put(c);
  511. }
  512. // DBG("### READ:", len_requested, "from", mux);
  513. // sockets[mux]->sock_available = modemGetAvailable(mux);
  514. sockets[mux]->sock_available = len_confirmed;
  515. waitResponse();
  516. return len_requested;
  517. }
  518. size_t modemGetAvailable(uint8_t mux) {
  519. if (!sockets[mux]) return 0;
  520. sendAT(GF("+CIPRXGET=4,"), mux);
  521. size_t result = 0;
  522. if (waitResponse(GF("+CIPRXGET:")) == 1) {
  523. streamSkipUntil(','); // Skip mode 4
  524. streamSkipUntil(','); // Skip mux
  525. result = streamGetIntBefore('\n');
  526. waitResponse();
  527. }
  528. // DBG("### Available:", result, "on", mux);
  529. if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
  530. return result;
  531. }
  532. bool modemGetConnected(uint8_t mux) {
  533. sendAT(GF("+CIPSTATUS="), mux);
  534. waitResponse(GF("+CIPSTATUS"));
  535. int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
  536. GF(",\"CLOSING\""), GF(",\"REMOTE CLOSING\""),
  537. GF(",\"INITIAL\""));
  538. waitResponse();
  539. return 1 == res;
  540. }
  541. /*
  542. * Utilities
  543. */
  544. public:
  545. // TODO(vshymanskyy): Optimize this!
  546. int8_t waitResponse(uint32_t timeout_ms, String& data,
  547. GsmConstStr r1 = GFP(GSM_OK),
  548. GsmConstStr r2 = GFP(GSM_ERROR),
  549. #if defined TINY_GSM_DEBUG
  550. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  551. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  552. #else
  553. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  554. #endif
  555. GsmConstStr r5 = NULL) {
  556. /*String r1s(r1); r1s.trim();
  557. String r2s(r2); r2s.trim();
  558. String r3s(r3); r3s.trim();
  559. String r4s(r4); r4s.trim();
  560. String r5s(r5); r5s.trim();
  561. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  562. data.reserve(64);
  563. uint8_t index = 0;
  564. uint32_t startMillis = millis();
  565. do {
  566. TINY_GSM_YIELD();
  567. while (stream.available() > 0) {
  568. TINY_GSM_YIELD();
  569. int8_t a = stream.read();
  570. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  571. data += static_cast<char>(a);
  572. if (r1 && data.endsWith(r1)) {
  573. index = 1;
  574. goto finish;
  575. } else if (r2 && data.endsWith(r2)) {
  576. index = 2;
  577. goto finish;
  578. } else if (r3 && data.endsWith(r3)) {
  579. #if defined TINY_GSM_DEBUG
  580. if (r3 == GFP(GSM_CME_ERROR)) {
  581. streamSkipUntil('\n'); // Read out the error
  582. }
  583. #endif
  584. index = 3;
  585. goto finish;
  586. } else if (r4 && data.endsWith(r4)) {
  587. index = 4;
  588. goto finish;
  589. } else if (r5 && data.endsWith(r5)) {
  590. index = 5;
  591. goto finish;
  592. } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
  593. int8_t mode = streamGetIntBefore(',');
  594. if (mode == 1) {
  595. int8_t mux = streamGetIntBefore('\n');
  596. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  597. sockets[mux]->got_data = true;
  598. }
  599. data = "";
  600. // DBG("### Got Data:", mux);
  601. } else {
  602. data += mode;
  603. }
  604. } else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
  605. int8_t mux = streamGetIntBefore(',');
  606. int16_t len = streamGetIntBefore('\n');
  607. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  608. sockets[mux]->got_data = true;
  609. if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
  610. }
  611. data = "";
  612. // DBG("### Got Data:", len, "on", mux);
  613. } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
  614. int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
  615. int8_t coma = data.indexOf(',', nl + 2);
  616. int8_t mux = data.substring(nl + 2, coma).toInt();
  617. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  618. sockets[mux]->sock_connected = false;
  619. }
  620. data = "";
  621. DBG("### Closed: ", mux);
  622. } else if (data.endsWith(GF("*PSNWID:"))) {
  623. streamSkipUntil('\n'); // Refresh network name by network
  624. data = "";
  625. DBG("### Network name updated.");
  626. } else if (data.endsWith(GF("*PSUTTZ:"))) {
  627. streamSkipUntil('\n'); // Refresh time and time zone by network
  628. data = "";
  629. DBG("### Network time and time zone updated.");
  630. } else if (data.endsWith(GF("+CTZV:"))) {
  631. streamSkipUntil('\n'); // Refresh network time zone by network
  632. data = "";
  633. DBG("### Network time zone updated.");
  634. } else if (data.endsWith(GF("DST:"))) {
  635. streamSkipUntil(
  636. '\n'); // Refresh Network Daylight Saving Time by network
  637. data = "";
  638. DBG("### Daylight savings time state updated.");
  639. }
  640. }
  641. } while (millis() - startMillis < timeout_ms);
  642. finish:
  643. if (!index) {
  644. data.trim();
  645. if (data.length()) { DBG("### Unhandled:", data); }
  646. data = "";
  647. }
  648. // data.replace(GSM_NL, "/");
  649. // DBG('<', index, '>', data);
  650. return index;
  651. }
  652. int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
  653. GsmConstStr r2 = GFP(GSM_ERROR),
  654. #if defined TINY_GSM_DEBUG
  655. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  656. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  657. #else
  658. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  659. #endif
  660. GsmConstStr r5 = NULL) {
  661. String data;
  662. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  663. }
  664. int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
  665. GsmConstStr r2 = GFP(GSM_ERROR),
  666. #if defined TINY_GSM_DEBUG
  667. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  668. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  669. #else
  670. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  671. #endif
  672. GsmConstStr r5 = NULL) {
  673. return waitResponse(1000, r1, r2, r3, r4, r5);
  674. }
  675. public:
  676. Stream& stream;
  677. protected:
  678. GsmClientSim800* sockets[TINY_GSM_MUX_COUNT];
  679. const char* gsmNL = GSM_NL;
  680. };
  681. #endif // SRC_TINYGSMCLIENTSIM800_H_