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.

741 lines
22 KiB

4 years ago
4 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
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
  1. /**
  2. * @file TinyGsmClientSIM5360.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_TINYGSMCLIENTSIM5360_H_
  9. #define SRC_TINYGSMCLIENTSIM5360_H_
  10. // #define TINY_GSM_DEBUG Serial
  11. // #define TINY_GSM_USE_HEX
  12. #define TINY_GSM_MUX_COUNT 10
  13. #define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
  14. #include "TinyGsmBattery.tpp"
  15. #include "TinyGsmGPRS.tpp"
  16. #include "TinyGsmGSMLocation.tpp"
  17. #include "TinyGsmModem.tpp"
  18. #include "TinyGsmSMS.tpp"
  19. #include "TinyGsmTCP.tpp"
  20. #include "TinyGsmTemperature.tpp"
  21. #include "TinyGsmTime.tpp"
  22. #include "TinyGsmNTP.tpp"
  23. #define GSM_NL "\r\n"
  24. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  25. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  26. #if defined TINY_GSM_DEBUG
  27. static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
  28. static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
  29. #endif
  30. enum RegStatus {
  31. REG_NO_RESULT = -1,
  32. REG_UNREGISTERED = 0,
  33. REG_SEARCHING = 2,
  34. REG_DENIED = 3,
  35. REG_OK_HOME = 1,
  36. REG_OK_ROAMING = 5,
  37. REG_UNKNOWN = 4,
  38. };
  39. class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
  40. public TinyGsmGPRS<TinyGsmSim5360>,
  41. public TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>,
  42. public TinyGsmSMS<TinyGsmSim5360>,
  43. public TinyGsmTime<TinyGsmSim5360>,
  44. public TinyGsmNTP<TinyGsmSim5360>,
  45. public TinyGsmGSMLocation<TinyGsmSim5360>,
  46. public TinyGsmBattery<TinyGsmSim5360>,
  47. public TinyGsmTemperature<TinyGsmSim5360> {
  48. friend class TinyGsmModem<TinyGsmSim5360>;
  49. friend class TinyGsmGPRS<TinyGsmSim5360>;
  50. friend class TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>;
  51. friend class TinyGsmSMS<TinyGsmSim5360>;
  52. friend class TinyGsmTime<TinyGsmSim5360>;
  53. friend class TinyGsmNTP<TinyGsmSim5360>;
  54. friend class TinyGsmGSMLocation<TinyGsmSim5360>;
  55. friend class TinyGsmBattery<TinyGsmSim5360>;
  56. friend class TinyGsmTemperature<TinyGsmSim5360>;
  57. /*
  58. * Inner Client
  59. */
  60. public:
  61. class GsmClientSim5360 : public GsmClient {
  62. friend class TinyGsmSim5360;
  63. public:
  64. GsmClientSim5360() {}
  65. explicit GsmClientSim5360(TinyGsmSim5360& modem, uint8_t mux = 0) {
  66. init(&modem, mux);
  67. }
  68. bool init(TinyGsmSim5360* modem, uint8_t mux = 0) {
  69. this->at = modem;
  70. sock_available = 0;
  71. prev_check = 0;
  72. sock_connected = false;
  73. got_data = false;
  74. if (mux < TINY_GSM_MUX_COUNT) {
  75. this->mux = mux;
  76. } else {
  77. this->mux = (mux % TINY_GSM_MUX_COUNT);
  78. }
  79. at->sockets[this->mux] = this;
  80. return true;
  81. }
  82. public:
  83. virtual int connect(const char* host, uint16_t port, int timeout_s) {
  84. stop();
  85. TINY_GSM_YIELD();
  86. rx.clear();
  87. sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
  88. return sock_connected;
  89. }
  90. TINY_GSM_CLIENT_CONNECT_OVERRIDES
  91. void stop(uint32_t maxWaitMs) {
  92. dumpModemBuffer(maxWaitMs);
  93. at->sendAT(GF("+CIPCLOSE="), mux);
  94. sock_connected = false;
  95. at->waitResponse();
  96. }
  97. void stop() override {
  98. stop(15000L);
  99. }
  100. /*
  101. * Extended API
  102. */
  103. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  104. };
  105. /*
  106. * Inner Secure Client
  107. */
  108. // TODO(?): Add SSL support
  109. /*
  110. class GsmClientSecureSim5360 : public GsmClientSim5360 {
  111. public:
  112. GsmClientSecureSim5360() {}
  113. explicit GsmClientSecureSim5360(TinyGsmSim5360& modem, uint8_t mux = 0)
  114. : GsmClientSim5360(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. /*
  127. * Constructor
  128. */
  129. public:
  130. explicit TinyGsmSim5360(Stream& stream) : stream(stream) {
  131. memset(sockets, 0, sizeof(sockets));
  132. }
  133. /*
  134. * Basic functions
  135. */
  136. protected:
  137. bool initImpl(const char* pin = NULL) {
  138. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  139. DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM5360"));
  140. if (!testAT()) { return false; }
  141. sendAT(GF("E0")); // Echo Off
  142. if (waitResponse() != 1) { return false; }
  143. #ifdef TINY_GSM_DEBUG
  144. sendAT(GF("+CMEE=2")); // turn on verbose error codes
  145. #else
  146. sendAT(GF("+CMEE=0")); // turn off error codes
  147. #endif
  148. waitResponse();
  149. DBG(GF("### Modem:"), getModemName());
  150. // Disable time and time zone URC's
  151. sendAT(GF("+CTZR=0"));
  152. if (waitResponse(10000L) != 1) { return false; }
  153. // Enable automatic time zome update
  154. sendAT(GF("+CTZU=1"));
  155. if (waitResponse(10000L) != 1) { return false; }
  156. SimStatus 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. } else {
  162. // if the sim is ready, or it's locked but no pin has been provided,
  163. // return true
  164. return (ret == SIM_READY || ret == SIM_LOCKED);
  165. }
  166. }
  167. String getModemNameImpl() {
  168. String name = "SIMCom SIM5360";
  169. sendAT(GF("+CGMM"));
  170. String res2;
  171. if (waitResponse(1000L, res2) != 1) { return name; }
  172. res2.replace(GSM_NL "OK" GSM_NL, "");
  173. res2.replace("_", " ");
  174. res2.trim();
  175. name = res2;
  176. DBG("### Modem:", name);
  177. return name;
  178. }
  179. bool factoryDefaultImpl() { // these commands aren't supported
  180. return false;
  181. }
  182. /*
  183. * Power functions
  184. */
  185. protected:
  186. bool restartImpl(const char* pin = NULL) {
  187. if (!testAT()) { return false; }
  188. sendAT(GF("+REBOOT"));
  189. // Should return an 'OK' after reboot command is sent
  190. if (waitResponse(10000L) != 1) { return false; }
  191. // After booting, modem sends out messages as each of its
  192. // internal modules loads. The final message is "PB DONE".
  193. if (waitResponse(40000L, GF(GSM_NL "PB DONE")) != 1) { return false; }
  194. return init(pin);
  195. }
  196. bool powerOffImpl() {
  197. sendAT(GF("+CPOF"));
  198. return waitResponse() == 1;
  199. }
  200. bool radioOffImpl() {
  201. if (!setPhoneFunctionality(4)) { return false; }
  202. delay(3000);
  203. return true;
  204. }
  205. bool sleepEnableImpl(bool enable = true) {
  206. sendAT(GF("+CSCLK="), enable);
  207. return waitResponse() == 1;
  208. }
  209. bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
  210. sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
  211. return waitResponse(10000L) == 1;
  212. }
  213. /*
  214. * Generic network functions
  215. */
  216. public:
  217. RegStatus getRegistrationStatus() {
  218. return (RegStatus)getRegistrationStatusXREG("CGREG");
  219. }
  220. protected:
  221. bool isNetworkConnectedImpl() {
  222. RegStatus s = getRegistrationStatus();
  223. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  224. }
  225. public:
  226. String getNetworkModes() {
  227. sendAT(GF("+CNMP=?"));
  228. if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
  229. String res = stream.readStringUntil('\n');
  230. waitResponse();
  231. return res;
  232. }
  233. int16_t getNetworkMode() {
  234. sendAT(GF("+CNMP?"));
  235. if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
  236. int16_t mode = streamGetIntBefore('\n');
  237. waitResponse();
  238. return mode;
  239. }
  240. bool setNetworkMode(uint8_t mode) {
  241. sendAT(GF("+CNMP="), mode);
  242. return waitResponse() == 1;
  243. }
  244. String getLocalIPImpl() {
  245. sendAT(GF("+IPADDR")); // Inquire Socket PDP address
  246. // sendAT(GF("+CGPADDR=1")); // Show PDP address
  247. String res;
  248. if (waitResponse(10000L, res) != 1) { return ""; }
  249. res.replace(GSM_NL "OK" GSM_NL, "");
  250. res.replace(GSM_NL, "");
  251. res.trim();
  252. return res;
  253. }
  254. /*
  255. * GPRS functions
  256. */
  257. protected:
  258. bool gprsConnectImpl(const char* apn, const char* user = NULL,
  259. const char* pwd = NULL) {
  260. gprsDisconnect(); // Make sure we're not connected first
  261. // Define the PDP context
  262. // The CGDCONT commands set up the "external" PDP context
  263. // Set the external authentication
  264. if (user && strlen(user) > 0) {
  265. sendAT(GF("+CGAUTH=1,0,\""), user, GF("\",\""), pwd, '"');
  266. waitResponse();
  267. }
  268. // Define external PDP context 1
  269. sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"', ",\"0.0.0.0\",0,0");
  270. waitResponse();
  271. // The CGSOCKCONT commands define the "embedded" PDP context for TCP/IP
  272. // Define the socket PDP context
  273. sendAT(GF("+CGSOCKCONT=1,\"IP\",\""), apn, '"');
  274. waitResponse();
  275. // Set the embedded authentication
  276. if (user && strlen(user) > 0) {
  277. sendAT(GF("+CSOCKAUTH=1,1,\""), user, "\",\"", pwd, '"');
  278. waitResponse();
  279. }
  280. // Set active PDP context's profile number
  281. // This ties the embedded TCP/IP application to the external PDP context
  282. sendAT(GF("+CSOCKSETPN=1"));
  283. waitResponse();
  284. // Configure TCP parameters
  285. // Select TCP/IP application mode (command mode)
  286. sendAT(GF("+CIPMODE=0"));
  287. waitResponse();
  288. // Set Sending Mode - send without waiting for peer TCP ACK
  289. sendAT(GF("+CIPSENDMODE=0"));
  290. waitResponse();
  291. // Configure socket parameters
  292. // AT+CIPCCFG= <NmRetry>, <DelayTm>, <Ack>, <errMode>, <HeaderType>,
  293. // <AsyncMode>, <TimeoutVal>
  294. // NmRetry = number of retransmission to be made for an IP packet
  295. // = 10 (default)
  296. // DelayTm = number of milliseconds to delay before outputting received data
  297. // = 0 (default)
  298. // Ack = sets whether reporting a string "Send ok" = 0 (don't report)
  299. // errMode = mode of reporting error result code = 0 (numberic values)
  300. // HeaderType = which data header of receiving data in multi-client mode
  301. // = 1 (+RECEIVE,<link num>,<data length>)
  302. // AsyncMode = sets mode of executing commands
  303. // = 0 (synchronous command executing)
  304. // TimeoutVal = minimum retransmission timeout in milliseconds = 75000
  305. sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000"));
  306. if (waitResponse() != 1) { return false; }
  307. // Configure timeouts for opening and closing sockets
  308. // AT+CIPTIMEOUT=<netopen_timeout>, <cipopen_timeout>, <cipsend_timeout>
  309. sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000);
  310. waitResponse();
  311. // Start the socket service
  312. // This activates and attaches to the external PDP context that is tied
  313. // to the embedded context for TCP/IP (ie AT+CGACT=1,1 and AT+CGATT=1)
  314. // Response may be an immediate "OK" followed later by "+NETOPEN: 0".
  315. // We to ignore any immediate response and wait for the
  316. // URC to show it's really connected.
  317. sendAT(GF("+NETOPEN"));
  318. if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; }
  319. return true;
  320. }
  321. bool gprsDisconnectImpl() {
  322. // Close any open sockets
  323. for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
  324. GsmClientSim5360* sock = sockets[mux];
  325. if (sock) { sock->stop(); }
  326. }
  327. // Stop the socket service
  328. // Note: all sockets should be closed first - on 3G/4G models the sockets
  329. // must be closed manually
  330. sendAT(GF("+NETCLOSE"));
  331. if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; }
  332. return true;
  333. }
  334. bool isGprsConnectedImpl() {
  335. sendAT(GF("+NETOPEN?"));
  336. // May return +NETOPEN: 1, 0. We just confirm that the first number is 1
  337. if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; }
  338. waitResponse();
  339. sendAT(GF("+IPADDR")); // Inquire Socket PDP address
  340. // sendAT(GF("+CGPADDR=1")); // Show PDP address
  341. if (waitResponse() != 1) { return false; }
  342. return true;
  343. }
  344. /*
  345. * SIM card functions
  346. */
  347. protected:
  348. // Gets the CCID of a sim card via AT+CCID
  349. String getSimCCIDImpl() {
  350. sendAT(GF("+CICCID"));
  351. if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; }
  352. String res = stream.readStringUntil('\n');
  353. waitResponse();
  354. res.trim();
  355. return res;
  356. }
  357. /*
  358. * Messaging functions
  359. */
  360. protected:
  361. // Follows all messaging functions per template
  362. /*
  363. * GSM Location functions
  364. */
  365. protected:
  366. // SIM5360 and SIM7100 can return a GSM-based location from CLBS as per the
  367. // template; SIM5320 doesn't not appear to be able to
  368. /*
  369. * Time functions
  370. */
  371. protected:
  372. // Can follow the standard CCLK function in the template
  373. /*
  374. * NTP server functions
  375. */
  376. // Can sync with server using CNTP as per template
  377. /*
  378. * Battery functions
  379. */
  380. protected:
  381. // SRGD Note: Returns voltage in VOLTS instead of millivolts
  382. uint16_t getBattVoltageImpl() {
  383. sendAT(GF("+CBC"));
  384. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }
  385. streamSkipUntil(','); // Skip battery charge status
  386. streamSkipUntil(','); // Skip battery charge level
  387. // get voltage in VOLTS
  388. float voltage = streamGetFloatBefore('\n');
  389. // Wait for final OK
  390. waitResponse();
  391. // Return millivolts
  392. uint16_t res = voltage * 1000;
  393. return res;
  394. }
  395. // SRGD Note: Returns voltage in VOLTS instead of millivolts
  396. bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
  397. uint16_t& milliVolts) {
  398. sendAT(GF("+CBC"));
  399. if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
  400. chargeState = streamGetIntBefore(',');
  401. percent = streamGetIntBefore(',');
  402. // get voltage in VOLTS
  403. float voltage = streamGetFloatBefore('\n');
  404. milliVolts = voltage * 1000;
  405. // Wait for final OK
  406. waitResponse();
  407. return true;
  408. }
  409. /*
  410. * Temperature functions
  411. */
  412. protected:
  413. // get temperature in degree celsius
  414. float getTemperatureImpl() {
  415. // Enable Temparature Reading
  416. sendAT(GF("+CMTE=1"));
  417. if (waitResponse() != 1) { return 0; }
  418. // Get Temparature Value
  419. sendAT(GF("+CMTE?"));
  420. if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { return false; }
  421. float res = streamGetFloatBefore('\n');
  422. // Wait for final OK
  423. waitResponse();
  424. return res;
  425. }
  426. /*
  427. * Client related functions
  428. */
  429. protected:
  430. bool modemConnect(const char* host, uint16_t port, uint8_t mux,
  431. bool ssl = false, int timeout_s = 15) {
  432. if (ssl) { DBG("SSL not yet supported on this module!"); }
  433. // Make sure we'll be getting data manually on this connection
  434. sendAT(GF("+CIPRXGET=1"));
  435. if (waitResponse() != 1) { return false; }
  436. // Establish a connection in multi-socket mode
  437. uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
  438. sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","),
  439. port);
  440. // The reply is +CIPOPEN: ## of socket created
  441. if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; }
  442. return true;
  443. }
  444. int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
  445. sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
  446. if (waitResponse(GF(">")) != 1) { return 0; }
  447. stream.write(reinterpret_cast<const uint8_t*>(buff), len);
  448. stream.flush();
  449. if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; }
  450. streamSkipUntil(','); // Skip mux
  451. streamSkipUntil(','); // Skip requested bytes to send
  452. // TODO(?): make sure requested and confirmed bytes match
  453. return streamGetIntBefore('\n');
  454. }
  455. size_t modemRead(size_t size, uint8_t mux) {
  456. if (!sockets[mux]) return 0;
  457. #ifdef TINY_GSM_USE_HEX
  458. sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
  459. if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
  460. #else
  461. sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
  462. if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
  463. #endif
  464. streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX
  465. streamSkipUntil(','); // Skip mux/cid (connecion id)
  466. int16_t len_requested = streamGetIntBefore(',');
  467. // ^^ Requested number of data bytes (1-1460 bytes)to be read
  468. int16_t len_confirmed = streamGetIntBefore('\n');
  469. // ^^ The data length which not read in the buffer
  470. for (int i = 0; i < len_requested; i++) {
  471. uint32_t startMillis = millis();
  472. #ifdef TINY_GSM_USE_HEX
  473. while (stream.available() < 2 &&
  474. (millis() - startMillis < sockets[mux]->_timeout)) {
  475. TINY_GSM_YIELD();
  476. }
  477. char buf[4] = {
  478. 0,
  479. };
  480. buf[0] = stream.read();
  481. buf[1] = stream.read();
  482. char c = strtol(buf, NULL, 16);
  483. #else
  484. while (!stream.available() &&
  485. (millis() - startMillis < sockets[mux]->_timeout)) {
  486. TINY_GSM_YIELD();
  487. }
  488. char c = stream.read();
  489. #endif
  490. sockets[mux]->rx.put(c);
  491. }
  492. // DBG("### READ:", len_requested, "from", mux);
  493. // sockets[mux]->sock_available = modemGetAvailable(mux);
  494. sockets[mux]->sock_available = len_confirmed;
  495. waitResponse();
  496. return len_requested;
  497. }
  498. size_t modemGetAvailable(uint8_t mux) {
  499. if (!sockets[mux]) return 0;
  500. sendAT(GF("+CIPRXGET=4,"), mux);
  501. size_t result = 0;
  502. if (waitResponse(GF("+CIPRXGET:")) == 1) {
  503. streamSkipUntil(','); // Skip mode 4
  504. streamSkipUntil(','); // Skip mux
  505. result = streamGetIntBefore('\n');
  506. waitResponse();
  507. }
  508. // DBG("### Available:", result, "on", mux);
  509. if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
  510. return result;
  511. }
  512. bool modemGetConnected(uint8_t mux) {
  513. // Read the status of all sockets at once
  514. sendAT(GF("+CIPCLOSE?"));
  515. if (waitResponse(GF("+CIPCLOSE:")) != 1) { return false; }
  516. for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
  517. // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state>
  518. bool muxState = stream.parseInt();
  519. if (sockets[muxNo]) { sockets[muxNo]->sock_connected = muxState; }
  520. }
  521. waitResponse(); // Should be an OK at the end
  522. if (!sockets[mux]) return false;
  523. return sockets[mux]->sock_connected;
  524. }
  525. /*
  526. * Utilities
  527. */
  528. public:
  529. // TODO(vshymanskyy): Optimize this!
  530. int8_t waitResponse(uint32_t timeout_ms, String& data,
  531. GsmConstStr r1 = GFP(GSM_OK),
  532. GsmConstStr r2 = GFP(GSM_ERROR),
  533. #if defined TINY_GSM_DEBUG
  534. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  535. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  536. #else
  537. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  538. #endif
  539. GsmConstStr r5 = NULL) {
  540. /*String r1s(r1); r1s.trim();
  541. String r2s(r2); r2s.trim();
  542. String r3s(r3); r3s.trim();
  543. String r4s(r4); r4s.trim();
  544. String r5s(r5); r5s.trim();
  545. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  546. data.reserve(64);
  547. uint8_t index = 0;
  548. uint32_t startMillis = millis();
  549. do {
  550. TINY_GSM_YIELD();
  551. while (stream.available() > 0) {
  552. TINY_GSM_YIELD();
  553. int8_t a = stream.read();
  554. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  555. data += static_cast<char>(a);
  556. if (r1 && data.endsWith(r1)) {
  557. index = 1;
  558. goto finish;
  559. } else if (r2 && data.endsWith(r2)) {
  560. index = 2;
  561. goto finish;
  562. } else if (r3 && data.endsWith(r3)) {
  563. #if defined TINY_GSM_DEBUG
  564. if (r3 == GFP(GSM_CME_ERROR)) {
  565. streamSkipUntil('\n'); // Read out the error
  566. }
  567. #endif
  568. index = 3;
  569. goto finish;
  570. } else if (r4 && data.endsWith(r4)) {
  571. index = 4;
  572. goto finish;
  573. } else if (r5 && data.endsWith(r5)) {
  574. index = 5;
  575. goto finish;
  576. } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
  577. int8_t mode = streamGetIntBefore(',');
  578. if (mode == 1) {
  579. int8_t mux = streamGetIntBefore('\n');
  580. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  581. sockets[mux]->got_data = true;
  582. }
  583. data = "";
  584. // DBG("### Got Data:", mux);
  585. } else {
  586. data += mode;
  587. }
  588. } else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
  589. int8_t mux = streamGetIntBefore(',');
  590. int16_t len = streamGetIntBefore('\n');
  591. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  592. sockets[mux]->got_data = true;
  593. if (len >= 0 && len <= 1024) { sockets[mux]->sock_available = len; }
  594. }
  595. data = "";
  596. // DBG("### Got Data:", len, "on", mux);
  597. } else if (data.endsWith(GF("+IPCLOSE:"))) {
  598. int8_t mux = streamGetIntBefore(',');
  599. streamSkipUntil('\n'); // Skip the reason code
  600. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  601. sockets[mux]->sock_connected = false;
  602. }
  603. data = "";
  604. DBG("### Closed: ", mux);
  605. } else if (data.endsWith(GF("+CIPEVENT:"))) {
  606. // Need to close all open sockets and release the network library.
  607. // User will then need to reconnect.
  608. DBG("### Network error!");
  609. if (!isGprsConnected()) { gprsDisconnect(); }
  610. data = "";
  611. }
  612. }
  613. } while (millis() - startMillis < timeout_ms);
  614. finish:
  615. if (!index) {
  616. data.trim();
  617. if (data.length()) { DBG("### Unhandled:", data); }
  618. data = "";
  619. }
  620. // data.replace(GSM_NL, "/");
  621. // DBG('<', index, '>', data);
  622. return index;
  623. }
  624. int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
  625. GsmConstStr r2 = GFP(GSM_ERROR),
  626. #if defined TINY_GSM_DEBUG
  627. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  628. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  629. #else
  630. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  631. #endif
  632. GsmConstStr r5 = NULL) {
  633. String data;
  634. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  635. }
  636. int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
  637. GsmConstStr r2 = GFP(GSM_ERROR),
  638. #if defined TINY_GSM_DEBUG
  639. GsmConstStr r3 = GFP(GSM_CME_ERROR),
  640. GsmConstStr r4 = GFP(GSM_CMS_ERROR),
  641. #else
  642. GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
  643. #endif
  644. GsmConstStr r5 = NULL) {
  645. return waitResponse(1000, r1, r2, r3, r4, r5);
  646. }
  647. public:
  648. Stream& stream;
  649. protected:
  650. GsmClientSim5360* sockets[TINY_GSM_MUX_COUNT];
  651. const char* gsmNL = GSM_NL;
  652. };
  653. #endif // SRC_TINYGSMCLIENTSIM5360_H_