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.

782 lines
21 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
  1. /**
  2. * @file TinyGsmClientSequansMonarch.h
  3. * @author Michael Krumpus
  4. * @license LGPL-3.0
  5. * @copyright Copyright (c) 2019 Michael Krumpus
  6. * @date Jan 2019
  7. */
  8. #ifndef TinyGsmClientSequansMonarch_h
  9. #define TinyGsmClientSequansMonarch_h
  10. //#define TINY_GSM_DEBUG Serial
  11. #if !defined(TINY_GSM_RX_BUFFER)
  12. #define TINY_GSM_RX_BUFFER 64
  13. #endif
  14. #define TINY_GSM_MUX_COUNT 6
  15. #include <TinyGsmCommon.h>
  16. #define GSM_NL "\r\n"
  17. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  18. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  19. enum SimStatus {
  20. SIM_ERROR = 0,
  21. SIM_READY = 1,
  22. SIM_LOCKED = 2,
  23. };
  24. enum RegStatus {
  25. REG_UNREGISTERED = 0,
  26. REG_SEARCHING = 2,
  27. REG_DENIED = 3,
  28. REG_OK_HOME = 1,
  29. REG_OK_ROAMING = 5,
  30. REG_UNKNOWN = 4,
  31. };
  32. enum SocketStatus {
  33. SOCK_CLOSED = 0,
  34. SOCK_ACTIVE_DATA = 1,
  35. SOCK_SUSPENDED = 2,
  36. SOCK_SUSPENDED_PENDING_DATA = 3,
  37. SOCK_LISTENING = 4,
  38. SOCK_INCOMING = 5,
  39. SOCK_OPENING = 6,
  40. };
  41. class TinyGsmSequansMonarch
  42. {
  43. public:
  44. class GsmClient : public Client
  45. {
  46. friend class TinyGsmSequansMonarch;
  47. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  48. public:
  49. GsmClient() {}
  50. GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) {
  51. init(&modem, mux);
  52. }
  53. virtual ~GsmClient(){}
  54. bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
  55. this->at = modem;
  56. this->mux = mux;
  57. sock_available = 0;
  58. prev_check = 0;
  59. sock_connected = false;
  60. got_data = false;
  61. // adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
  62. // using modulus will force 6 back to 0
  63. at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
  64. return true;
  65. }
  66. public:
  67. virtual int connect(const char *host, uint16_t port, int timeout_s) {
  68. if (sock_connected) stop();
  69. TINY_GSM_YIELD();
  70. rx.clear();
  71. sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
  72. return sock_connected;
  73. }
  74. TINY_GSM_CLIENT_CONNECT_OVERLOADS()
  75. virtual void stop(uint32_t maxWaitMs) {
  76. TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
  77. at->sendAT(GF("+SQNSH="), mux);
  78. sock_connected = false;
  79. at->waitResponse();
  80. }
  81. virtual void stop() { stop(15000L); }
  82. TINY_GSM_CLIENT_WRITE()
  83. TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
  84. TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
  85. TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
  86. /*
  87. * Extended API
  88. */
  89. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  90. private:
  91. TinyGsmSequansMonarch* at;
  92. uint8_t mux;
  93. uint16_t sock_available;
  94. uint32_t prev_check;
  95. bool sock_connected;
  96. bool got_data;
  97. RxFifo rx;
  98. };
  99. class GsmClientSecure : public GsmClient
  100. {
  101. public:
  102. GsmClientSecure() {}
  103. GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1)
  104. : GsmClient(modem, mux)
  105. {}
  106. virtual ~GsmClientSecure(){}
  107. protected:
  108. bool strictSSL = false;
  109. public:
  110. virtual int connect(const char *host, uint16_t port, int timeout_s) {
  111. stop();
  112. TINY_GSM_YIELD();
  113. rx.clear();
  114. // configure security profile 1 with parameters:
  115. if (strictSSL) {
  116. // require minimum of TLS 1.2 (3)
  117. // only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
  118. // verify server certificate against imported CA certs 0 and enforce validity period (3)
  119. at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
  120. } else {
  121. // use TLS 1.0 or higher (1)
  122. // support wider variety of cipher suites
  123. // do not verify server certificate (0)
  124. at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\""));
  125. }
  126. if (at->waitResponse() != 1) {
  127. DBG("failed to configure security profile");
  128. return false;
  129. }
  130. sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
  131. return sock_connected;
  132. }
  133. void setStrictSSL(bool strict) {
  134. strictSSL = strict;
  135. }
  136. };
  137. public:
  138. TinyGsmSequansMonarch(Stream& stream)
  139. : stream(stream)
  140. {
  141. memset(sockets, 0, sizeof(sockets));
  142. }
  143. virtual ~TinyGsmSequansMonarch() {}
  144. /*
  145. * Basic functions
  146. */
  147. bool begin(const char* pin = NULL) {
  148. return init(pin);
  149. }
  150. bool init(const char* pin = NULL) {
  151. DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
  152. if (!testAT()) {
  153. return false;
  154. }
  155. sendAT(GF("E0")); // Echo Off
  156. if (waitResponse() != 1) {
  157. return false;
  158. }
  159. DBG(GF("### Modem:"), getModemName());
  160. int ret = getSimStatus();
  161. // if the sim isn't ready and a pin has been provided, try to unlock the sim
  162. if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
  163. simUnlock(pin);
  164. return (getSimStatus() == SIM_READY);
  165. }
  166. // if the sim is ready, or it's locked but no pin has been provided, return
  167. // true
  168. else {
  169. return (ret == SIM_READY || ret == SIM_LOCKED);
  170. }
  171. }
  172. String getModemName() {
  173. return "Sequans Monarch";
  174. }
  175. TINY_GSM_MODEM_SET_BAUD_IPR()
  176. TINY_GSM_MODEM_TEST_AT()
  177. void maintain() {
  178. for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) {
  179. GsmClient* sock = sockets[mux % TINY_GSM_MUX_COUNT];
  180. if (sock && sock->got_data) {
  181. sock->got_data = false;
  182. sock->sock_available = modemGetAvailable(mux);
  183. // modemGetConnected() always checks the state of ALL socks
  184. modemGetConnected();
  185. }
  186. }
  187. while (stream.available()) {
  188. waitResponse(15, NULL, NULL);
  189. }
  190. }
  191. bool factoryDefault() {
  192. sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
  193. waitResponse();
  194. sendAT(GF("+IPR=0")); // Auto-baud
  195. waitResponse();
  196. sendAT(GF("+IFC=0,0")); // No Flow Control
  197. waitResponse();
  198. sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
  199. waitResponse();
  200. sendAT(GF("+CSCLK=0")); // Disable Slow Clock
  201. waitResponse();
  202. sendAT(GF("&W")); // Write configuration
  203. return waitResponse() == 1;
  204. }
  205. TINY_GSM_MODEM_GET_INFO_ATI()
  206. bool hasSSL() {
  207. return true;
  208. }
  209. /*
  210. * Power functions
  211. */
  212. bool restart() {
  213. if (!testAT()) {
  214. return false;
  215. }
  216. sendAT(GF("+CFUN=0"));
  217. int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ;
  218. if (res != 1 && res != 3) {
  219. return false;
  220. }
  221. sendAT(GF("+CFUN=1,1"));
  222. res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)) ;
  223. if (res != 1 && res != 3) {
  224. return false;
  225. }
  226. delay(1000);
  227. return init();
  228. }
  229. bool poweroff() {
  230. sendAT(GF("+SQNSSHDN"));
  231. return waitResponse();
  232. }
  233. bool radioOff() {
  234. sendAT(GF("+CFUN=0"));
  235. if (waitResponse(10000L) != 1) {
  236. return false;
  237. }
  238. delay(3000);
  239. return true;
  240. }
  241. /*
  242. When power saving is enabled, UART0 interface is activated with sleep mode support.
  243. Module power state is controlled by RTS0 line. When no activity on UART, CTS line
  244. will be set to OFF state (driven high level) <timeout> milliseconds (100ms to 10s,
  245. default 5s) after the last sent character, then module will go to sleep mode as soon
  246. as DTE set RTS line to OFF state (driver high level).
  247. */
  248. bool sleepEnable(bool enable = true) {
  249. sendAT(GF("+SQNIPSCFG="), enable);
  250. return waitResponse() == 1;
  251. }
  252. /*
  253. * SIM card functions
  254. */
  255. TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
  256. String getSimCCID() {
  257. sendAT(GF("+SQNCCID"));
  258. if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) {
  259. return "";
  260. }
  261. String res = stream.readStringUntil('\n');
  262. waitResponse();
  263. res.trim();
  264. return res;
  265. }
  266. TINY_GSM_MODEM_GET_IMEI_GSN()
  267. SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
  268. for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
  269. sendAT(GF("+CPIN?"));
  270. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  271. delay(1000);
  272. continue;
  273. }
  274. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
  275. waitResponse();
  276. switch (status) {
  277. case 2:
  278. case 3: return SIM_LOCKED;
  279. case 1: return SIM_READY;
  280. default: return SIM_ERROR;
  281. }
  282. }
  283. return SIM_ERROR;
  284. }
  285. TINY_GSM_MODEM_GET_REGISTRATION_XREG(CEREG)
  286. TINY_GSM_MODEM_GET_OPERATOR_COPS()
  287. /*
  288. * Generic network functions
  289. */
  290. TINY_GSM_MODEM_GET_CSQ()
  291. bool isNetworkConnected() {
  292. RegStatus s = getRegistrationStatus();
  293. if (s == REG_OK_HOME || s == REG_OK_ROAMING) {
  294. // DBG(F("connected with status:"), s);
  295. return true;
  296. } else {
  297. return false;
  298. }
  299. }
  300. TINY_GSM_MODEM_WAIT_FOR_NETWORK()
  301. /*
  302. * GPRS functions
  303. */
  304. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
  305. gprsDisconnect();
  306. // Define the PDP context (This uses context #3!)
  307. sendAT(GF("+CGDCONT=3,\"IPV4V6\",\""), apn, '"');
  308. waitResponse();
  309. // Set authentication
  310. if (user && strlen(user) > 0) {
  311. sendAT(GF("+CGAUTH=3,1,\""), user, GF("\",\""), pwd, GF("\""));
  312. waitResponse();
  313. }
  314. // Activate the PDP context
  315. sendAT(GF("+CGACT=1,3"));
  316. waitResponse(60000L);
  317. // Attach to GPRS
  318. sendAT(GF("+CGATT=1"));
  319. if (waitResponse(60000L) != 1)
  320. return false;
  321. return true;
  322. }
  323. bool gprsDisconnect() {
  324. sendAT(GF("+CGATT=0"));
  325. if (waitResponse(60000L) != 1)
  326. return false;
  327. return true;
  328. }
  329. bool isGprsConnected() {
  330. sendAT(GF("+CGATT?"));
  331. if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
  332. return false;
  333. }
  334. int res = stream.readStringUntil('\n').toInt();
  335. waitResponse();
  336. if (res != 1)
  337. return false;
  338. return true;
  339. }
  340. /*
  341. * IP Address functions
  342. */
  343. String getLocalIP() {
  344. sendAT(GF("+CGPADDR=3"));
  345. if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) {
  346. return "";
  347. }
  348. String res = stream.readStringUntil('\"');
  349. waitResponse();
  350. return res;
  351. }
  352. IPAddress localIP() {
  353. return TinyGsmIpFromString(getLocalIP());
  354. }
  355. /*
  356. * Phone Call functions
  357. */
  358. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
  359. bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  360. bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  361. bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  362. String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  363. bool sendSMS(const String& number, const String& text) {
  364. sendAT(GF("+CMGF=1"));
  365. waitResponse();
  366. //Set GSM 7 bit default alphabet (3GPP TS 23.038)
  367. sendAT(GF("+CSCS=\"GSM\""));
  368. waitResponse();
  369. sendAT(GF("+CMGS=\""), number, GF("\""));
  370. if (waitResponse(GF(">")) != 1) {
  371. return false;
  372. }
  373. stream.print(text);
  374. stream.write((char)0x1A);
  375. stream.flush();
  376. return waitResponse(60000L) == 1;
  377. }
  378. bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  379. /*
  380. * Location functions
  381. */
  382. String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
  383. /*
  384. * Battery & temperature functions
  385. */
  386. uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
  387. int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
  388. uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
  389. bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
  390. float getTemperature() {
  391. sendAT(GF("+SMDTH"));
  392. if (waitResponse(10000L, GF("+SMDTH: ")) != 1) {
  393. return (float)-9999;
  394. }
  395. String res;
  396. if (waitResponse(1000L, res) != 1) {
  397. return (float)-9999;
  398. }
  399. if (res.indexOf("ERROR") >=0) {
  400. return (float)-9999;
  401. }
  402. return res.toFloat();
  403. }
  404. protected:
  405. bool modemConnect(const char* host, uint16_t port, uint8_t mux,
  406. bool ssl = false, int timeout_s = 75)
  407. {
  408. int rsp;
  409. unsigned long startMillis = millis();
  410. uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
  411. if (ssl) {
  412. // enable SSl and use security profile 1
  413. //AT+SQNSSCFG=<connId>,<enable>,<spId>
  414. sendAT(GF("+SQNSSCFG="), mux, GF(",1,1"));
  415. if (waitResponse() != 1) {
  416. DBG("### WARNING: failed to configure secure socket");
  417. return false;
  418. }
  419. }
  420. // Socket configuration
  421. //AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
  422. // <connId1> = Connection ID = mux
  423. // <cid1> = PDP context ID = 3 - this is number set up above in the GprsConnect function
  424. // <pktSz1> = Packet Size, used for online data mode only = 300 (default)
  425. // <maxTo1> = Max timeout in seconds = 90 (default)
  426. // <connTo1> = Connection timeout in hundreds of milliseconds = 600 (default)
  427. // <txTo1> = Data sending timeout in hundreds of milliseconds, used for online data mode only = 50 (default)
  428. sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50"));
  429. waitResponse(5000L);
  430. // Socket configuration extended
  431. //AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>, <listenAutoRsp1>, <sendDataMode1>
  432. // <connId1> = Connection ID = mux
  433. // <srMode1> = Send/Receive URC model = 1 - data amount mode
  434. // <recvDataMode1> = Receive data mode = 0 - data as text (1 would be as hex)
  435. // <keepalive1> = unused = 0
  436. // <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated
  437. // <sendDataMode1> = Send data mode = 0 - data as text (1 would be as hex)
  438. sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0"));
  439. waitResponse(5000L);
  440. // Socket dial
  441. //AT+SQNSD=<connId>,<txProt>,<rPort>,<IPaddr>[,<closureType>[,<lPort>[,<connMode>[,acceptAnyRemote]]]]
  442. // <connId> = Connection ID = mux
  443. // <txProt> = Transmission protocol = 0 - TCP (1 for UDP)
  444. // <rPort> = Remote host port to contact
  445. // <IPaddr> = Any valid IP address in the format “xxx.xxx.xxx.xxx” or any host name solved with a DNS query
  446. // <closureType> = Socket closure behaviour for TCP, has no effect for UDP = 0 - local port closes when remote does (default)
  447. // <lPort> = UDP connection local port, has no effect for TCP connections.
  448. // <connMode> = Connection mode = 1 - command mode connection
  449. // <acceptAnyRemote> = Applies to UDP only
  450. sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), ",0,0,1");
  451. rsp = waitResponse((timeout_ms - (millis() - startMillis)),
  452. GFP(GSM_OK),
  453. GFP(GSM_ERROR),
  454. GF("NO CARRIER" GSM_NL)
  455. );
  456. // creation of socket failed immediately.
  457. if (rsp != 1) return false;
  458. // wait until we get a good status
  459. bool connected = false;
  460. while (!connected && ((millis() - startMillis) < timeout_ms)) {
  461. connected = modemGetConnected(mux);
  462. delay(100); // socket may be in opening state
  463. }
  464. return connected;
  465. }
  466. int modemSend(const void* buff, size_t len, uint8_t mux) {
  467. if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) {
  468. DBG("### Sock closed, cannot send data!");
  469. return 0;
  470. }
  471. sendAT(GF("+SQNSSENDEXT="), mux, ',', len);
  472. waitResponse(10000L, GF(GSM_NL "> "));
  473. stream.write((uint8_t*)buff, len);
  474. stream.flush();
  475. if (waitResponse() != 1) {
  476. DBG("### no OK after send");
  477. return 0;
  478. }
  479. return len;
  480. // uint8_t nAttempts = 5;
  481. // bool gotPrompt = false;
  482. // while (nAttempts > 0 && !gotPrompt) {
  483. // sendAT(GF("+SQNSSEND="), mux);
  484. // if (waitResponse(5000, GF(GSM_NL "> ")) == 1) {
  485. // gotPrompt = true;
  486. // }
  487. // nAttempts--;
  488. // delay(50);
  489. // }
  490. // if (gotPrompt) {
  491. // stream.write((uint8_t*)buff, len);
  492. // stream.write((char)0x1A);
  493. // stream.flush();
  494. // if (waitResponse() != 1) {
  495. // DBG("### no OK after send");
  496. // return 0;
  497. // }
  498. // return len;
  499. // }
  500. // return 0;
  501. }
  502. size_t modemRead(size_t size, uint8_t mux) {
  503. sendAT(GF("+SQNSRECV="), mux, ',', size);
  504. if (waitResponse(GF("+SQNSRECV: ")) != 1) {
  505. return 0;
  506. }
  507. streamSkipUntil(','); // Skip mux
  508. size_t len = stream.readStringUntil('\n').toInt();
  509. for (size_t i=0; i<len; i++) {
  510. uint32_t startMillis = millis(); \
  511. while (!stream.available() && ((millis() - startMillis) < sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) { TINY_GSM_YIELD(); } \
  512. char c = stream.read(); \
  513. sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c);
  514. }
  515. DBG("### Read:", len, "from", mux);
  516. waitResponse();
  517. sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = modemGetAvailable(mux);
  518. return len;
  519. }
  520. size_t modemGetAvailable(uint8_t mux) {
  521. sendAT(GF("+SQNSI="), mux);
  522. size_t result = 0;
  523. if (waitResponse(GF("+SQNSI:")) == 1) {
  524. streamSkipUntil(','); // Skip mux
  525. streamSkipUntil(','); // Skip total sent
  526. streamSkipUntil(','); // Skip total received
  527. result = stream.readStringUntil(',').toInt(); // keep data not yet read
  528. waitResponse();
  529. }
  530. DBG("### Available:", result, "on", mux);
  531. return result;
  532. }
  533. bool modemGetConnected(uint8_t mux = 1) {
  534. // This single command always returns the connection status of all
  535. // six possible sockets.
  536. sendAT(GF("+SQNSS"));
  537. for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
  538. if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) {
  539. break;
  540. };
  541. uint8_t status = 0;
  542. // if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no
  543. // DBG("### Warning: misaligned mux numbers!");
  544. // }
  545. streamSkipUntil(','); // skip mux [use muxNo]
  546. status = stream.parseInt(); // Read the status
  547. // if mux is in use, will have comma then other info after the status
  548. // if not, there will be new line immediately after status
  549. // streamSkipUntil('\n'); // Skip port and IP info
  550. // SOCK_CLOSED = 0,
  551. // SOCK_ACTIVE_DATA = 1,
  552. // SOCK_SUSPENDED = 2,
  553. // SOCK_SUSPENDED_PENDING_DATA = 3,
  554. // SOCK_LISTENING = 4,
  555. // SOCK_INCOMING = 5,
  556. // SOCK_OPENING = 6,
  557. sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \
  558. ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING));
  559. }
  560. waitResponse(); // Should be an OK at the end
  561. return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected;
  562. }
  563. public:
  564. /*
  565. Utilities
  566. */
  567. TINY_GSM_MODEM_STREAM_UTILITIES()
  568. // TODO: Optimize this!
  569. uint8_t waitResponse(uint32_t timeout_ms, String& data,
  570. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  571. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  572. {
  573. /*String r1s(r1); r1s.trim();
  574. String r2s(r2); r2s.trim();
  575. String r3s(r3); r3s.trim();
  576. String r4s(r4); r4s.trim();
  577. String r5s(r5); r5s.trim();
  578. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  579. data.reserve(64);
  580. int index = 0;
  581. unsigned long startMillis = millis();
  582. do {
  583. TINY_GSM_YIELD();
  584. while (stream.available() > 0) {
  585. TINY_GSM_YIELD();
  586. int a = stream.read();
  587. if (a <= 0) continue; // Skip 0x00 bytes, just in case
  588. data += (char)a;
  589. if (r1 && data.endsWith(r1)) {
  590. index = 1;
  591. goto finish;
  592. } else if (r2 && data.endsWith(r2)) {
  593. index = 2;
  594. goto finish;
  595. } else if (r3 && data.endsWith(r3)) {
  596. index = 3;
  597. goto finish;
  598. } else if (r4 && data.endsWith(r4)) {
  599. index = 4;
  600. goto finish;
  601. } else if (r5 && data.endsWith(r5)) {
  602. index = 5;
  603. goto finish;
  604. } else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) {
  605. int mux = stream.readStringUntil(',').toInt();
  606. int len = stream.readStringUntil('\n').toInt();
  607. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) {
  608. sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
  609. sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
  610. }
  611. data = "";
  612. DBG("### URC Data Received:", len, "on", mux);
  613. } else if (data.endsWith(GF("SQNSH: "))) {
  614. int mux = stream.readStringUntil('\n').toInt();
  615. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) {
  616. sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
  617. }
  618. data = "";
  619. DBG("### URC Sock Closed: ", mux);
  620. }
  621. }
  622. } while (millis() - startMillis < timeout_ms);
  623. finish:
  624. if (!index) {
  625. data.trim();
  626. if (data.length()) {
  627. DBG("### Unhandled:", data);
  628. }
  629. data = "";
  630. }
  631. //data.replace(GSM_NL, "/");
  632. //DBG('<', index, '>', data);
  633. return index;
  634. }
  635. uint8_t waitResponse(uint32_t timeout_ms,
  636. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  637. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  638. {
  639. String data;
  640. return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
  641. }
  642. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  643. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  644. {
  645. return waitResponse(1000, r1, r2, r3, r4, r5);
  646. }
  647. public:
  648. Stream& stream;
  649. protected:
  650. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  651. };
  652. #endif