Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
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.

TinyGsmClientU201.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /**
  2. * file TinyGsmClientU201.h
  3. * author Volodymyr Shymanskyy
  4. * license LGPL-3.0
  5. * copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * date Nov 2016
  7. */
  8. #ifndef TinyGsmClientU201_h
  9. #define TinyGsmClientU201_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 5
  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. class TinyGsmU201
  33. {
  34. public:
  35. class GsmClient : public Client
  36. {
  37. friend class TinyGsmU201;
  38. typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
  39. public:
  40. GsmClient() {}
  41. GsmClient(TinyGsmU201& modem, uint8_t mux = 1)
  42. {
  43. init(&modem, mux);
  44. }
  45. bool init(TinyGsmU201* modem, uint8_t mux = 1)
  46. {
  47. this->at = modem;
  48. this->mux = mux;
  49. sock_available = 0;
  50. sock_connected = false;
  51. got_data = false;
  52. return true;
  53. }
  54. public:
  55. virtual int connect(const char *host, uint16_t port)
  56. {
  57. stop();
  58. TINY_GSM_YIELD();
  59. rx.clear();
  60. sock_connected = at->modemConnect(host, port, &mux);
  61. at->sockets[mux] = this;
  62. return sock_connected;
  63. }
  64. virtual int connect(IPAddress ip, uint16_t port)
  65. {
  66. String host;
  67. host.reserve(16);
  68. host += ip[0];
  69. host += ".";
  70. host += ip[1];
  71. host += ".";
  72. host += ip[2];
  73. host += ".";
  74. host += ip[3];
  75. return connect(host.c_str(), port);
  76. }
  77. virtual void stop()
  78. {
  79. TINY_GSM_YIELD();
  80. at->sendAT(GF("+USOCL="), mux);
  81. sock_connected = false;
  82. at->waitResponse();
  83. rx.clear();
  84. }
  85. virtual size_t write(const uint8_t *buf, size_t size)
  86. {
  87. TINY_GSM_YIELD();
  88. at->maintain();
  89. return at->modemSend(buf, size, mux);
  90. }
  91. virtual size_t write(uint8_t c)
  92. {
  93. return write(&c, 1);
  94. }
  95. virtual int available()
  96. {
  97. TINY_GSM_YIELD();
  98. if (!rx.size() && sock_connected) {
  99. at->maintain();
  100. }
  101. return rx.size() + sock_available;
  102. }
  103. virtual int read(uint8_t *buf, size_t size)
  104. {
  105. TINY_GSM_YIELD();
  106. at->maintain();
  107. size_t cnt = 0;
  108. while (cnt < size) {
  109. size_t chunk = TinyGsmMin(size-cnt, rx.size());
  110. if (chunk > 0) {
  111. rx.get(buf, chunk);
  112. buf += chunk;
  113. cnt += chunk;
  114. continue;
  115. }
  116. // TODO: Read directly into user buffer?
  117. at->maintain();
  118. if (sock_available > 0) {
  119. at->modemRead(rx.free(), mux);
  120. } else {
  121. break;
  122. }
  123. }
  124. return cnt;
  125. }
  126. virtual int read()
  127. {
  128. uint8_t c;
  129. if (read(&c, 1) == 1) {
  130. return c;
  131. }
  132. return -1;
  133. }
  134. virtual int peek()
  135. {
  136. return -1; //TODO
  137. }
  138. virtual void flush()
  139. {
  140. at->stream.flush();
  141. }
  142. virtual uint8_t connected()
  143. {
  144. if (available()) {
  145. return true;
  146. }
  147. return sock_connected;
  148. }
  149. virtual operator bool()
  150. {
  151. return connected();
  152. }
  153. /*
  154. * Extended API
  155. */
  156. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  157. private:
  158. TinyGsmU201* at;
  159. uint8_t mux;
  160. uint16_t sock_available;
  161. bool sock_connected;
  162. bool got_data;
  163. RxFifo rx;
  164. };
  165. class GsmClientSecure : public GsmClient
  166. {
  167. public:
  168. GsmClientSecure() {}
  169. GsmClientSecure(TinyGsmU201& modem, uint8_t mux = 1)
  170. : GsmClient(modem, mux)
  171. {}
  172. public:
  173. virtual int connect(const char *host, uint16_t port)
  174. {
  175. stop();
  176. TINY_GSM_YIELD();
  177. rx.clear();
  178. sock_connected = at->modemConnect(host, port, &mux, true);
  179. at->sockets[mux] = this;
  180. return sock_connected;
  181. }
  182. };
  183. public:
  184. #ifdef GSM_DEFAULT_STREAM
  185. explicit TinyGsmU201(Stream& stream = GSM_DEFAULT_STREAM)
  186. #else
  187. explicit TinyGsmU201(Stream& stream)
  188. #endif
  189. : stream(stream)
  190. {
  191. memset(sockets, 0, sizeof(sockets));
  192. }
  193. /*
  194. * Basic functions
  195. */
  196. bool begin(const char* pin = NULL)
  197. {
  198. return init(pin);
  199. }
  200. bool init(const char* pin = NULL)
  201. {
  202. if (!testAT()) {
  203. return false;
  204. }
  205. sendAT(GF("E0")); // Echo Off
  206. if (waitResponse() != 1) {
  207. return false;
  208. }
  209. int ret = getSimStatus();
  210. if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
  211. simUnlock(pin);
  212. }
  213. return (getSimStatus() == SIM_READY);
  214. }
  215. void setBaud(unsigned long baud)
  216. {
  217. sendAT(GF("+IPR="), baud);
  218. }
  219. bool testAT(unsigned long timeout = 10000L)
  220. {
  221. for (unsigned long start = millis(); millis() - start < timeout; ) {
  222. sendAT(GF(""));
  223. if (waitResponse(200) == 1) {
  224. delay(100);
  225. return true;
  226. }
  227. delay(100);
  228. }
  229. return false;
  230. }
  231. void maintain()
  232. {
  233. for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
  234. GsmClient* sock = sockets[mux];
  235. if (sock && sock->got_data) {
  236. sock->got_data = false;
  237. sock->sock_available = modemGetAvailable(mux);
  238. }
  239. }
  240. while (stream.available()) {
  241. waitResponse(10, NULL, NULL);
  242. }
  243. }
  244. bool factoryDefault()
  245. {
  246. sendAT(GF("+UFACTORY=0,1")); // Factory + Reset + Echo Off
  247. waitResponse();
  248. sendAT(GF("+CFUN=16")); // Auto-baud
  249. return waitResponse() == 1;
  250. }
  251. String getModemInfo() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  252. bool hasSSL()
  253. {
  254. return true;
  255. }
  256. /*
  257. * Power functions
  258. */
  259. bool restart()
  260. {
  261. if (!testAT()) {
  262. return false;
  263. }
  264. sendAT(GF("+CFUN=16"));
  265. if (waitResponse(10000L) != 1) {
  266. return false;
  267. }
  268. delay(3000);
  269. return init();
  270. }
  271. bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  272. /*
  273. * SIM card functions
  274. */
  275. bool simUnlock(const char *pin)
  276. {
  277. sendAT(GF("+CPIN=\""), pin, GF("\""));
  278. return waitResponse() == 1;
  279. }
  280. String getSimCCID()
  281. {
  282. sendAT(GF("+CCID"));
  283. if (waitResponse(GF(GSM_NL "+CCID:")) != 1) {
  284. return "";
  285. }
  286. String res = stream.readStringUntil('\n');
  287. waitResponse();
  288. res.trim();
  289. return res;
  290. }
  291. String getIMEI()
  292. {
  293. sendAT(GF("+CGSN"));
  294. if (waitResponse(GF(GSM_NL)) != 1) {
  295. return "";
  296. }
  297. String res = stream.readStringUntil('\n');
  298. waitResponse();
  299. res.trim();
  300. return res;
  301. }
  302. SimStatus getSimStatus(unsigned long timeout = 10000L)
  303. {
  304. for (unsigned long start = millis(); millis() - start < timeout; ) {
  305. sendAT(GF("+CPIN?"));
  306. if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
  307. delay(1000);
  308. continue;
  309. }
  310. int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
  311. waitResponse();
  312. switch (status) {
  313. case 2:
  314. case 3:
  315. return SIM_LOCKED;
  316. case 1:
  317. return SIM_READY;
  318. default:
  319. return SIM_ERROR;
  320. }
  321. }
  322. return SIM_ERROR;
  323. }
  324. RegStatus getRegistrationStatus()
  325. {
  326. sendAT(GF("+CGREG?"));
  327. if (waitResponse(GF(GSM_NL "+CGREG:")) != 1) {
  328. return REG_UNKNOWN;
  329. }
  330. streamSkipUntil(','); // Skip format (0)
  331. int status = stream.readStringUntil('\n').toInt();
  332. waitResponse();
  333. return (RegStatus)status;
  334. }
  335. String getOperator()
  336. {
  337. sendAT(GF("+COPS?"));
  338. if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
  339. return "";
  340. }
  341. streamSkipUntil('"'); // Skip mode and format
  342. String res = stream.readStringUntil('"');
  343. waitResponse();
  344. return res;
  345. }
  346. /*
  347. * Generic network functions
  348. */
  349. int getSignalQuality()
  350. {
  351. sendAT(GF("+CSQ"));
  352. if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
  353. return 99;
  354. }
  355. int res = stream.readStringUntil(',').toInt();
  356. waitResponse();
  357. return res;
  358. }
  359. bool isNetworkConnected()
  360. {
  361. RegStatus s = getRegistrationStatus();
  362. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  363. }
  364. bool waitForNetwork(unsigned long timeout = 60000L)
  365. {
  366. for (unsigned long start = millis(); millis() - start < timeout; ) {
  367. if (isNetworkConnected()) {
  368. return true;
  369. }
  370. delay(250);
  371. }
  372. return false;
  373. }
  374. /*
  375. * GPRS functions
  376. */
  377. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
  378. {
  379. gprsDisconnect();
  380. sendAT(GF("+CGATT=1"));
  381. waitResponse(5000L);
  382. sendAT(GF("+UPSD=0,1,\""), apn, '"');
  383. waitResponse();
  384. if (user && strlen(user) > 0) {
  385. sendAT(GF("+UPSD=0,2,\""), user, '"');
  386. waitResponse();
  387. }
  388. if (pwd && strlen(pwd) > 0) {
  389. sendAT(GF("+UPSD=0,3,\""), pwd, '"');
  390. waitResponse();
  391. }
  392. sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP
  393. waitResponse();
  394. sendAT(GF("+UPSDA=0,3"));
  395. waitResponse(6000L);
  396. // Open a GPRS context
  397. sendAT(GF("+UPSND=0,8"));
  398. if (waitResponse(GF(",8,1")) != 1) {
  399. return false;
  400. }
  401. return true;
  402. }
  403. bool gprsDisconnect()
  404. {
  405. sendAT(GF("+UPSDA=0,4"));
  406. if (waitResponse(60000L) != 1) {
  407. return false;
  408. }
  409. sendAT(GF("+CGATT=0"));
  410. if (waitResponse(60000L) != 1) {
  411. return false;
  412. }
  413. return true;
  414. }
  415. bool isGprsConnected()
  416. {
  417. sendAT(GF("+CGATT?"));
  418. if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
  419. return false;
  420. }
  421. int res = stream.readStringUntil('\n').toInt();
  422. waitResponse();
  423. if (res != 1) {
  424. return false;
  425. }
  426. sendAT(GF("+CIFSR"));
  427. if (waitResponse() != 1) {
  428. return false;
  429. }
  430. return true;
  431. }
  432. String getLocalIP()
  433. {
  434. sendAT(GF("+CIFSR;E0"));
  435. String res;
  436. if (waitResponse(10000L, res) != 1) {
  437. return "";
  438. }
  439. res.trim();
  440. return res;
  441. }
  442. IPAddress localIP()
  443. {
  444. return TinyGsmIpFromString(getLocalIP());
  445. }
  446. /*
  447. * Phone Call functions
  448. */
  449. bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  450. bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  451. bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  452. bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  453. /*
  454. * Messaging functions
  455. */
  456. String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  457. bool sendSMS(const String& number, const String& text) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  458. bool sendSMS_UTF16(const String& number, const void* text,
  459. size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  460. /*
  461. * Location functions
  462. */
  463. String getGsmLocation()
  464. {
  465. sendAT(GF("+ULOC=2,3,0,120,1"));
  466. if (waitResponse(GF(GSM_NL "+UULOC:")) != 1) {
  467. return "";
  468. }
  469. String res = stream.readStringUntil('\n');
  470. waitResponse();
  471. res.trim();
  472. return res;
  473. }
  474. /*
  475. * Battery functions
  476. */
  477. // Use: float vBatt = modem.getBattVoltage() / 1000.0;
  478. uint16_t getBattVoltage()
  479. {
  480. sendAT(GF("+CIND"));
  481. if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
  482. return 0;
  483. }
  484. uint16_t res = stream.readStringUntil(',').toInt();
  485. waitResponse();
  486. return res;
  487. }
  488. int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  489. protected:
  490. bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false)
  491. {
  492. sendAT(GF("+USOCR=6"));
  493. if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) {
  494. return false;
  495. }
  496. *mux = stream.readStringUntil('\n').toInt();
  497. waitResponse();
  498. if (ssl) {
  499. sendAT(GF("+USOSEC="), *mux, ",1");
  500. waitResponse();
  501. }
  502. sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
  503. int rsp = waitResponse(75000L);
  504. return (1 == rsp);
  505. }
  506. int modemSend(const void* buff, size_t len, uint8_t mux)
  507. {
  508. sendAT(GF("+USOWR="), mux, ',', len);
  509. if (waitResponse(GF("@")) != 1) {
  510. return -1;
  511. }
  512. // 50ms delay, see AT manual section 25.10.4
  513. delay(50);
  514. stream.write((uint8_t*)buff, len);
  515. stream.flush();
  516. if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
  517. return -1;
  518. }
  519. streamSkipUntil(','); // Skip mux
  520. return stream.readStringUntil('\n').toInt();
  521. }
  522. size_t modemRead(size_t size, uint8_t mux)
  523. {
  524. sendAT(GF("+USORD="), mux, ',', size);
  525. if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
  526. return 0;
  527. }
  528. streamSkipUntil(','); // Skip mux
  529. size_t len = stream.readStringUntil(',').toInt();
  530. streamSkipUntil('\"');
  531. for (size_t i=0; i<len; i++) {
  532. while (!stream.available()) {
  533. TINY_GSM_YIELD();
  534. }
  535. char c = stream.read();
  536. sockets[mux]->rx.put(c);
  537. }
  538. streamSkipUntil('\"');
  539. waitResponse();
  540. return len;
  541. }
  542. size_t modemGetAvailable(uint8_t mux)
  543. {
  544. sendAT(GF("+USORD="), mux, ',', 0);
  545. size_t result = 0;
  546. if (waitResponse(GF(GSM_NL "+USORD:")) == 1) {
  547. streamSkipUntil(','); // Skip mux
  548. result = stream.readStringUntil('\n').toInt();
  549. waitResponse();
  550. }
  551. if (!result) {
  552. sockets[mux]->sock_connected = modemGetConnected(mux);
  553. }
  554. return result;
  555. }
  556. bool modemGetConnected(uint8_t mux)
  557. {
  558. sendAT(GF("+USOCTL="), mux, ",10");
  559. if (waitResponse(GF(GSM_NL "+USOCTL:")) != 1) {
  560. return false;
  561. }
  562. streamSkipUntil(','); // Skip mux
  563. streamSkipUntil(','); // Skip type
  564. int result = stream.readStringUntil('\n').toInt();
  565. return result != 0;
  566. }
  567. public:
  568. /* Utilities */
  569. template<typename T>
  570. void streamWrite(T last)
  571. {
  572. stream.print(last);
  573. }
  574. template<typename T, typename... Args>
  575. void streamWrite(T head, Args... tail)
  576. {
  577. stream.print(head);
  578. streamWrite(tail...);
  579. }
  580. bool streamSkipUntil(char c) //TODO: timeout
  581. {
  582. while (true) {
  583. while (!stream.available()) {
  584. TINY_GSM_YIELD();
  585. }
  586. if (stream.read() == c) {
  587. return true;
  588. }
  589. }
  590. return false;
  591. }
  592. template<typename... Args>
  593. void sendAT(Args... cmd)
  594. {
  595. streamWrite("AT", cmd..., GSM_NL);
  596. stream.flush();
  597. TINY_GSM_YIELD();
  598. //DBG("### AT:", cmd...);
  599. }
  600. // TODO: Optimize this!
  601. uint8_t waitResponse(uint32_t timeout, String& data,
  602. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  603. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  604. {
  605. /*String r1s(r1); r1s.trim();
  606. String r2s(r2); r2s.trim();
  607. String r3s(r3); r3s.trim();
  608. String r4s(r4); r4s.trim();
  609. String r5s(r5); r5s.trim();
  610. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  611. data.reserve(64);
  612. int index = 0;
  613. unsigned long startMillis = millis();
  614. do {
  615. TINY_GSM_YIELD();
  616. while (stream.available() > 0) {
  617. int a = stream.read();
  618. if (a < 0) {
  619. continue;
  620. }
  621. data += (char)a;
  622. if (r1 && data.endsWith(r1)) {
  623. index = 1;
  624. goto finish;
  625. } else if (r2 && data.endsWith(r2)) {
  626. index = 2;
  627. goto finish;
  628. } else if (r3 && data.endsWith(r3)) {
  629. index = 3;
  630. goto finish;
  631. } else if (r4 && data.endsWith(r4)) {
  632. index = 4;
  633. goto finish;
  634. } else if (r5 && data.endsWith(r5)) {
  635. index = 5;
  636. goto finish;
  637. } else if (data.endsWith(GF(GSM_NL "+UUSORD:"))) {
  638. int mux = stream.readStringUntil(',').toInt();
  639. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  640. sockets[mux]->got_data = true;
  641. }
  642. data = "";
  643. } else if (data.endsWith(GF(GSM_NL "+UUSOCL:"))) {
  644. int mux = stream.readStringUntil('\n').toInt();
  645. if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
  646. sockets[mux]->sock_connected = false;
  647. }
  648. data = "";
  649. DBG("### Closed: ", mux);
  650. }
  651. }
  652. } while (millis() - startMillis < timeout);
  653. finish:
  654. if (!index) {
  655. data.trim();
  656. if (data.length()) {
  657. DBG("### Unhandled:", data);
  658. }
  659. data = "";
  660. }
  661. return index;
  662. }
  663. uint8_t waitResponse(uint32_t timeout,
  664. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  665. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  666. {
  667. String data;
  668. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  669. }
  670. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  671. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  672. {
  673. return waitResponse(1000, r1, r2, r3, r4, r5);
  674. }
  675. public:
  676. Stream& stream;
  677. protected:
  678. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  679. };
  680. #endif