MySensors Library & Examples  2.3.2
TinyGsmClientSIM800.h
1 
9 #ifndef TinyGsmClientSIM800_h
10 #define TinyGsmClientSIM800_h
11 
12 //#define TINY_GSM_DEBUG Serial
13 //#define TINY_GSM_USE_HEX
14 
15 #if !defined(TINY_GSM_RX_BUFFER)
16 #define TINY_GSM_RX_BUFFER 64
17 #endif
18 
19 #define TINY_GSM_MUX_COUNT 5
20 
21 #include "TinyGsmCommon.h"
22 
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 
27 enum SimStatus {
28  SIM_ERROR = 0,
29  SIM_READY = 1,
30  SIM_LOCKED = 2,
31 };
32 
33 enum RegStatus {
34  REG_UNREGISTERED = 0,
35  REG_SEARCHING = 2,
36  REG_DENIED = 3,
37  REG_OK_HOME = 1,
38  REG_OK_ROAMING = 5,
39  REG_UNKNOWN = 4,
40 };
41 
42 
44 {
45 
46 public:
47 
48  class GsmClient : public Client
49  {
50  friend class TinyGsmSim800;
52 
53  public:
54  GsmClient() {}
55 
56  GsmClient(TinyGsmSim800& modem, uint8_t mux = 1)
57  {
58  init(&modem, mux);
59  }
60 
61  bool init(TinyGsmSim800* modem, uint8_t mux = 1)
62  {
63  this->at = modem;
64  this->mux = mux;
65  sock_available = 0;
66  prev_check = 0;
67  sock_connected = false;
68  got_data = false;
69 
70  at->sockets[mux] = this;
71 
72  return true;
73  }
74 
75  public:
76  virtual int connect(const char *host, uint16_t port)
77  {
78  stop();
79  TINY_GSM_YIELD();
80  rx.clear();
81  sock_connected = at->modemConnect(host, port, mux);
82  return sock_connected;
83  }
84 
85  virtual int connect(IPAddress ip, uint16_t port)
86  {
87  String host;
88  host.reserve(16);
89  host += ip[0];
90  host += ".";
91  host += ip[1];
92  host += ".";
93  host += ip[2];
94  host += ".";
95  host += ip[3];
96  return connect(host.c_str(), port);
97  }
98 
99  virtual void stop()
100  {
101  TINY_GSM_YIELD();
102  at->sendAT(GF("+CIPCLOSE="), mux);
103  sock_connected = false;
104  at->waitResponse();
105  rx.clear();
106  }
107 
108  virtual size_t write(const uint8_t *buf, size_t size)
109  {
110  TINY_GSM_YIELD();
111  at->maintain();
112  return at->modemSend(buf, size, mux);
113  }
114 
115  virtual size_t write(uint8_t c)
116  {
117  return write(&c, 1);
118  }
119 
120  virtual int available()
121  {
122  TINY_GSM_YIELD();
123  if (!rx.size() && sock_connected) {
124  // Workaround: sometimes SIM800 forgets to notify about data arrival.
125  // TODO: Currently we ping the module periodically,
126  // but maybe there's a better indicator that we need to poll
127  if (millis() - prev_check > 500) {
128  got_data = true;
129  prev_check = millis();
130  }
131  at->maintain();
132  }
133  return rx.size() + sock_available;
134  }
135 
136  virtual int read(uint8_t *buf, size_t size)
137  {
138  TINY_GSM_YIELD();
139  at->maintain();
140  size_t cnt = 0;
141  while (cnt < size && sock_connected) {
142  size_t chunk = TinyGsmMin(size-cnt, rx.size());
143  if (chunk > 0) {
144  rx.get(buf, chunk);
145  buf += chunk;
146  cnt += chunk;
147  continue;
148  }
149  // TODO: Read directly into user buffer?
150  at->maintain();
151  if (sock_available > 0) {
152  at->modemRead(rx.free(), mux);
153  } else {
154  break;
155  }
156  }
157  return cnt;
158  }
159 
160  virtual int read()
161  {
162  uint8_t c;
163  if (read(&c, 1) == 1) {
164  return c;
165  }
166  return -1;
167  }
168 
169  virtual int peek()
170  {
171  return -1; //TODO
172  }
173  virtual void flush()
174  {
175  at->stream.flush();
176  }
177 
178  virtual uint8_t connected()
179  {
180  if (available()) {
181  return true;
182  }
183  return sock_connected;
184  }
185  virtual operator bool()
186  {
187  return connected();
188  }
189 
190  /*
191  * Extended API
192  */
193 
194  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
195 
196  private:
197  TinyGsmSim800* at;
198  uint8_t mux;
199  uint16_t sock_available;
200  uint32_t prev_check;
201  bool sock_connected;
202  bool got_data;
203  RxFifo rx;
204  };
205 
206  class GsmClientSecure : public GsmClient
207  {
208  public:
209  GsmClientSecure() {}
210 
211  GsmClientSecure(TinyGsmSim800& modem, uint8_t mux = 1)
212  : GsmClient(modem, mux)
213  {}
214 
215  public:
216  virtual int connect(const char *host, uint16_t port)
217  {
218  stop();
219  TINY_GSM_YIELD();
220  rx.clear();
221  sock_connected = at->modemConnect(host, port, mux, true);
222  return sock_connected;
223  }
224  };
225 
226 public:
227 
228  explicit TinyGsmSim800(Stream& stream)
229  : stream(stream)
230  {
231  memset(sockets, 0, sizeof(sockets));
232  }
233 
234  /*
235  * Basic functions
236  */
237  bool begin()
238  {
239  return init();
240  }
241 
242  bool init()
243  {
244  if (!testAT()) {
245  return false;
246  }
247  sendAT(GF("&FZ")); // Factory + Reset
248  waitResponse();
249  sendAT(GF("E0")); // Echo Off
250  if (waitResponse() != 1) {
251  return false;
252  }
253  getSimStatus();
254  return true;
255  }
256 
257  void setBaud(unsigned long baud)
258  {
259  sendAT(GF("+IPR="), baud);
260  }
261 
262  bool testAT(unsigned long timeout = 10000L)
263  {
264  //streamWrite(GF("AAAAA" GSM_NL)); // TODO: extra A's to help detect the baud rate
265  for (unsigned long start = millis(); millis() - start < timeout; ) {
266  sendAT(GF(""));
267  if (waitResponse(200) == 1) {
268  delay(100);
269  return true;
270  }
271  delay(100);
272  }
273  return false;
274  }
275 
276  void maintain()
277  {
278  for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
279  GsmClient* sock = sockets[mux];
280  if (sock && sock->got_data) {
281  sock->got_data = false;
282  sock->sock_available = modemGetAvailable(mux);
283  }
284  }
285  while (stream.available()) {
286  waitResponse(10, NULL, NULL);
287  }
288  }
289 
290  bool factoryDefault()
291  {
292  sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
293  waitResponse();
294  sendAT(GF("+IPR=0")); // Auto-baud
295  waitResponse();
296  sendAT(GF("+IFC=0,0")); // No Flow Control
297  waitResponse();
298  sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
299  waitResponse();
300  sendAT(GF("+CSCLK=0")); // Disable Slow Clock
301  waitResponse();
302  sendAT(GF("&W")); // Write configuration
303  return waitResponse() == 1;
304  }
305 
306  String getModemInfo()
307  {
308  sendAT(GF("I"));
309  String res;
310  if (waitResponse(1000L, res) != 1) {
311  return "";
312  }
313  res.replace(GSM_NL "OK" GSM_NL, "");
314  res.replace(GSM_NL, " ");
315  res.trim();
316  return res;
317  }
318 
319  bool hasSSL()
320  {
321 #if defined(TINY_GSM_MODEM_SIM900)
322  return false;
323 #else
324  sendAT(GF("+CIPSSL=?"));
325  if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
326  return false;
327  }
328  return waitResponse() == 1;
329 #endif
330  }
331 
332  /*
333  * Power functions
334  */
335 
336  bool restart()
337  {
338  if (!testAT()) {
339  return false;
340  }
341  sendAT(GF("+CFUN=0"));
342  if (waitResponse(10000L) != 1) {
343  return false;
344  }
345  sendAT(GF("+CFUN=1,1"));
346  if (waitResponse(10000L) != 1) {
347  return false;
348  }
349  delay(3000);
350  return init();
351  }
352 
353  bool poweroff()
354  {
355  sendAT(GF("+CPOWD=1"));
356  return waitResponse(GF("NORMAL POWER DOWN")) == 1;
357  }
358 
359  bool radioOff()
360  {
361  sendAT(GF("+CFUN=0"));
362  if (waitResponse(10000L) != 1) {
363  return false;
364  }
365  delay(3000);
366  return true;
367  }
368 
369  /*
370  During sleep, the SIM800 module has its serial communication disabled. In order to reestablish communication
371  pull the DRT-pin of the SIM800 module LOW for at least 50ms. Then use this function to disable sleep mode.
372  The DTR-pin can then be released again.
373  */
374  bool sleepEnable(bool enable = true)
375  {
376  sendAT(GF("+CSCLK="), enable);
377  return waitResponse() == 1;
378  }
379 
380  /*
381  * SIM card functions
382  */
383 
384  bool simUnlock(const char *pin)
385  {
386  sendAT(GF("+CPIN=\""), pin, GF("\""));
387  return waitResponse() == 1;
388  }
389 
390  String getSimCCID()
391  {
392  sendAT(GF("+ICCID"));
393  if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
394  return "";
395  }
396  String res = stream.readStringUntil('\n');
397  waitResponse();
398  res.trim();
399  return res;
400  }
401 
402  String getIMEI()
403  {
404  sendAT(GF("+GSN"));
405  if (waitResponse(GF(GSM_NL)) != 1) {
406  return "";
407  }
408  String res = stream.readStringUntil('\n');
409  waitResponse();
410  res.trim();
411  return res;
412  }
413 
414  SimStatus getSimStatus(unsigned long timeout = 10000L)
415  {
416  for (unsigned long start = millis(); millis() - start < timeout; ) {
417  sendAT(GF("+CPIN?"));
418  if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
419  delay(1000);
420  continue;
421  }
422  int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
423  waitResponse();
424  switch (status) {
425  case 2:
426  case 3:
427  return SIM_LOCKED;
428  case 1:
429  return SIM_READY;
430  default:
431  return SIM_ERROR;
432  }
433  }
434  return SIM_ERROR;
435  }
436 
437  RegStatus getRegistrationStatus()
438  {
439  sendAT(GF("+CREG?"));
440  if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
441  return REG_UNKNOWN;
442  }
443  streamSkipUntil(','); // Skip format (0)
444  int status = stream.readStringUntil('\n').toInt();
445  waitResponse();
446  return (RegStatus)status;
447  }
448 
449  String getOperator()
450  {
451  sendAT(GF("+COPS?"));
452  if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
453  return "";
454  }
455  streamSkipUntil('"'); // Skip mode and format
456  String res = stream.readStringUntil('"');
457  waitResponse();
458  return res;
459  }
460 
461  /*
462  * Generic network functions
463  */
464 
465  int getSignalQuality()
466  {
467  sendAT(GF("+CSQ"));
468  if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
469  return 99;
470  }
471  int res = stream.readStringUntil(',').toInt();
472  waitResponse();
473  return res;
474  }
475 
476  bool isNetworkConnected()
477  {
478  RegStatus s = getRegistrationStatus();
479  return (s == REG_OK_HOME || s == REG_OK_ROAMING);
480  }
481 
482  bool waitForNetwork(unsigned long timeout = 60000L)
483  {
484  for (unsigned long start = millis(); millis() - start < timeout; ) {
485  if (isNetworkConnected()) {
486  return true;
487  }
488  delay(250);
489  }
490  return false;
491  }
492 
493  /*
494  * GPRS functions
495  */
496  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
497  {
498  gprsDisconnect();
499 
500  // Set the Bearer for the IP
501  sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS
502  waitResponse();
503 
504  sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN
505  waitResponse();
506 
507  if (user && strlen(user) > 0) {
508  sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name
509  waitResponse();
510  }
511  if (pwd && strlen(pwd) > 0) {
512  sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password
513  waitResponse();
514  }
515 
516  // Define the PDP context
517  sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
518  waitResponse();
519 
520  // Activate the PDP context
521  sendAT(GF("+CGACT=1,1"));
522  waitResponse(60000L);
523 
524  // Open the definied GPRS bearer context
525  sendAT(GF("+SAPBR=1,1"));
526  waitResponse(85000L);
527  // Query the GPRS bearer context status
528  sendAT(GF("+SAPBR=2,1"));
529  if (waitResponse(30000L) != 1) {
530  return false;
531  }
532 
533  // Attach to GPRS
534  sendAT(GF("+CGATT=1"));
535  if (waitResponse(60000L) != 1) {
536  return false;
537  }
538 
539  // TODO: wait AT+CGATT?
540 
541  // Set to multi-IP
542  sendAT(GF("+CIPMUX=1"));
543  if (waitResponse() != 1) {
544  return false;
545  }
546 
547  // Put in "quick send" mode (thus no extra "Send OK")
548  sendAT(GF("+CIPQSEND=1"));
549  if (waitResponse() != 1) {
550  return false;
551  }
552 
553  // Set to get data manually
554  sendAT(GF("+CIPRXGET=1"));
555  if (waitResponse() != 1) {
556  return false;
557  }
558 
559  // Start Task and Set APN, USER NAME, PASSWORD
560  sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
561  if (waitResponse(60000L) != 1) {
562  return false;
563  }
564 
565  // Bring Up Wireless Connection with GPRS or CSD
566  sendAT(GF("+CIICR"));
567  if (waitResponse(60000L) != 1) {
568  return false;
569  }
570 
571  // Get Local IP Address, only assigned after connection
572  sendAT(GF("+CIFSR;E0"));
573  if (waitResponse(10000L) != 1) {
574  return false;
575  }
576 
577  // Configure Domain Name Server (DNS)
578  sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\""));
579  if (waitResponse() != 1) {
580  return false;
581  }
582 
583  return true;
584  }
585 
586  bool gprsDisconnect()
587  {
588  // Shut the TCP/IP connection
589  sendAT(GF("+CIPSHUT"));
590  if (waitResponse(60000L) != 1) {
591  return false;
592  }
593 
594  sendAT(GF("+CGATT=0")); // Deactivate the bearer context
595  if (waitResponse(60000L) != 1) {
596  return false;
597  }
598 
599  return true;
600  }
601 
602  bool isGprsConnected()
603  {
604  sendAT(GF("+CGATT?"));
605  if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
606  return false;
607  }
608  int res = stream.readStringUntil('\n').toInt();
609  waitResponse();
610  if (res != 1) {
611  return false;
612  }
613 
614  sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1
615  if (waitResponse() != 1) {
616  return false;
617  }
618 
619  return true;
620  }
621 
622  String getLocalIP()
623  {
624  sendAT(GF("+CIFSR;E0"));
625  String res;
626  if (waitResponse(10000L, res) != 1) {
627  return "";
628  }
629  res.replace(GSM_NL "OK" GSM_NL, "");
630  res.replace(GSM_NL, "");
631  res.trim();
632  return res;
633  }
634 
635  IPAddress localIP()
636  {
637  return TinyGsmIpFromString(getLocalIP());
638  }
639 
640  /*
641  * Phone Call functions
642  */
643 
644  bool setGsmBusy(bool busy = true)
645  {
646  sendAT(GF("+GSMBUSY="), busy ? 1 : 0);
647  return waitResponse() == 1;
648  }
649 
650  bool callAnswer()
651  {
652  sendAT(GF("A"));
653  return waitResponse() == 1;
654  }
655 
656  // Returns true on pick-up, false on error/busy
657  bool callNumber(const String& number)
658  {
659  if (number == GF("last")) {
660  sendAT(GF("DL"));
661  } else {
662  sendAT(GF("D"), number, ";");
663  }
664  int status = waitResponse(60000L,
665  GFP(GSM_OK),
666  GF("BUSY" GSM_NL),
667  GF("NO ANSWER" GSM_NL),
668  GF("NO CARRIER" GSM_NL));
669  switch (status) {
670  case 1:
671  return true;
672  case 2:
673  case 3:
674  return false;
675  default:
676  return false;
677  }
678  }
679 
680  bool callHangup()
681  {
682  sendAT(GF("H"));
683  return waitResponse() == 1;
684  }
685 
686  // 0-9,*,#,A,B,C,D
687  bool dtmfSend(char cmd, int duration_ms = 100)
688  {
689  duration_ms = constrain(duration_ms, 100, 1000);
690 
691  sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second
692  waitResponse();
693 
694  sendAT(GF("+VTS="), cmd);
695  return waitResponse(10000L) == 1;
696  }
697 
698  /*
699  * Messaging functions
700  */
701 
702  String sendUSSD(const String& code)
703  {
704  sendAT(GF("+CMGF=1"));
705  waitResponse();
706  sendAT(GF("+CSCS=\"HEX\""));
707  waitResponse();
708  sendAT(GF("+CUSD=1,\""), code, GF("\""));
709  if (waitResponse() != 1) {
710  return "";
711  }
712  if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
713  return "";
714  }
715  stream.readStringUntil('"');
716  String hex = stream.readStringUntil('"');
717  stream.readStringUntil(',');
718  int dcs = stream.readStringUntil('\n').toInt();
719 
720  if (dcs == 15) {
721  return TinyGsmDecodeHex8bit(hex);
722  } else if (dcs == 72) {
723  return TinyGsmDecodeHex16bit(hex);
724  } else {
725  return hex;
726  }
727  }
728 
729  bool sendSMS(const String& number, const String& text)
730  {
731  sendAT(GF("+CMGF=1"));
732  waitResponse();
733  //Set GSM 7 bit default alphabet (3GPP TS 23.038)
734  sendAT(GF("+CSCS=\"GSM\""));
735  waitResponse();
736  sendAT(GF("+CMGS=\""), number, GF("\""));
737  if (waitResponse(GF(">")) != 1) {
738  return false;
739  }
740  stream.print(text);
741  stream.write((char)0x1A);
742  stream.flush();
743  return waitResponse(60000L) == 1;
744  }
745 
746  bool sendSMS_UTF16(const String& number, const void* text, size_t len)
747  {
748  sendAT(GF("+CMGF=1"));
749  waitResponse();
750  sendAT(GF("+CSCS=\"HEX\""));
751  waitResponse();
752  sendAT(GF("+CSMP=17,167,0,8"));
753  waitResponse();
754 
755  sendAT(GF("+CMGS=\""), number, GF("\""));
756  if (waitResponse(GF(">")) != 1) {
757  return false;
758  }
759 
760  uint16_t* t = (uint16_t*)text;
761  for (size_t i=0; i<len; i++) {
762  uint8_t c = t[i] >> 8;
763  if (c < 0x10) {
764  stream.print('0');
765  }
766  stream.print(c, HEX);
767  c = t[i] & 0xFF;
768  if (c < 0x10) {
769  stream.print('0');
770  }
771  stream.print(c, HEX);
772  }
773  stream.write((char)0x1A);
774  stream.flush();
775  return waitResponse(60000L) == 1;
776  }
777 
778 
779  /*
780  * Location functions
781  */
782 
783  String getGsmLocation()
784  {
785  sendAT(GF("+CIPGSMLOC=1,1"));
786  if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
787  return "";
788  }
789  String res = stream.readStringUntil('\n');
790  waitResponse();
791  res.trim();
792  return res;
793  }
794 
795  /*
796  * Battery functions
797  */
798  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
799  uint16_t getBattVoltage()
800  {
801  sendAT(GF("+CBC"));
802  if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
803  return 0;
804  }
805  streamSkipUntil(','); // Skip
806  streamSkipUntil(','); // Skip
807 
808  uint16_t res = stream.readStringUntil(',').toInt();
809  waitResponse();
810  return res;
811  }
812 
813  int getBattPercent()
814  {
815  sendAT(GF("+CBC"));
816  if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
817  return false;
818  }
819  stream.readStringUntil(',');
820  int res = stream.readStringUntil(',').toInt();
821  waitResponse();
822  return res;
823  }
824 
825 protected:
826 
827  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false)
828  {
829 #if !defined(TINY_GSM_MODEM_SIM900)
830  sendAT(GF("+CIPSSL="), ssl);
831  int rsp = waitResponse();
832  if (ssl && rsp != 1) {
833  return false;
834  }
835 #endif
836  sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
837  rsp = waitResponse(75000L,
838  GF("CONNECT OK" GSM_NL),
839  GF("CONNECT FAIL" GSM_NL),
840  GF("ALREADY CONNECT" GSM_NL),
841  GF("ERROR" GSM_NL),
842  GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails
843  );
844  return (1 == rsp);
845  }
846 
847  int modemSend(const void* buff, size_t len, uint8_t mux)
848  {
849  sendAT(GF("+CIPSEND="), mux, ',', len);
850  if (waitResponse(GF(">")) != 1) {
851  return 0;
852  }
853  stream.write((uint8_t*)buff, len);
854  stream.flush();
855  if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) {
856  return 0;
857  }
858  streamSkipUntil(','); // Skip mux
859  return stream.readStringUntil('\n').toInt();
860  }
861 
862  size_t modemRead(size_t size, uint8_t mux)
863  {
864 #ifdef TINY_GSM_USE_HEX
865  sendAT(GF("+CIPRXGET=3,"), mux, ',', size);
866  if (waitResponse(GF("+CIPRXGET:")) != 1) {
867  return 0;
868  }
869 #else
870  sendAT(GF("+CIPRXGET=2,"), mux, ',', size);
871  if (waitResponse(GF("+CIPRXGET:")) != 1) {
872  return 0;
873  }
874 #endif
875  streamSkipUntil(','); // Skip mode 2/3
876  streamSkipUntil(','); // Skip mux
877  size_t len = stream.readStringUntil(',').toInt();
878  sockets[mux]->sock_available = stream.readStringUntil('\n').toInt();
879 
880  for (size_t i=0; i<len; i++) {
881 #ifdef TINY_GSM_USE_HEX
882  while (stream.available() < 2) {
883  TINY_GSM_YIELD();
884  }
885  char buf[4] = { 0, };
886  buf[0] = stream.read();
887  buf[1] = stream.read();
888  char c = strtol(buf, NULL, 16);
889 #else
890  while (!stream.available()) {
891  TINY_GSM_YIELD();
892  }
893  char c = stream.read();
894 #endif
895  sockets[mux]->rx.put(c);
896  }
897  waitResponse();
898  return len;
899  }
900 
901  size_t modemGetAvailable(uint8_t mux)
902  {
903  sendAT(GF("+CIPRXGET=4,"), mux);
904  size_t result = 0;
905  if (waitResponse(GF("+CIPRXGET:")) == 1) {
906  streamSkipUntil(','); // Skip mode 4
907  streamSkipUntil(','); // Skip mux
908  result = stream.readStringUntil('\n').toInt();
909  waitResponse();
910  }
911  if (!result) {
912  sockets[mux]->sock_connected = modemGetConnected(mux);
913  }
914  return result;
915  }
916 
917  bool modemGetConnected(uint8_t mux)
918  {
919  sendAT(GF("+CIPSTATUS="), mux);
920  int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""),
921  GF(",\"INITIAL\""));
922  waitResponse();
923  return 1 == res;
924  }
925 
926 public:
927 
928  /* Utilities */
929 
930  template<typename T>
931  void streamWrite(T last)
932  {
933  stream.print(last);
934  }
935 
936  template<typename T, typename... Args>
937  void streamWrite(T head, Args... tail)
938  {
939  stream.print(head);
940  streamWrite(tail...);
941  }
942 
943  bool streamSkipUntil(char c) //TODO: timeout
944  {
945  while (true) {
946  while (!stream.available()) {
947  TINY_GSM_YIELD();
948  }
949  if (stream.read() == c) {
950  return true;
951  }
952  }
953  return false;
954  }
955 
956  template<typename... Args>
957  void sendAT(Args... cmd)
958  {
959  streamWrite("AT", cmd..., GSM_NL);
960  stream.flush();
961  TINY_GSM_YIELD();
962  //DBG("### AT:", cmd...);
963  }
964 
965  // TODO: Optimize this!
966  uint8_t waitResponse(uint32_t timeout, String& data,
967  GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
968  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
969  {
970  /*String r1s(r1); r1s.trim();
971  String r2s(r2); r2s.trim();
972  String r3s(r3); r3s.trim();
973  String r4s(r4); r4s.trim();
974  String r5s(r5); r5s.trim();
975  DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
976  data.reserve(64);
977  int index = 0;
978  unsigned long startMillis = millis();
979  do {
980  TINY_GSM_YIELD();
981  while (stream.available() > 0) {
982  int a = stream.read();
983  if (a <= 0) {
984  continue; // Skip 0x00 bytes, just in case
985  }
986  data += (char)a;
987  if (r1 && data.endsWith(r1)) {
988  index = 1;
989  goto finish;
990  } else if (r2 && data.endsWith(r2)) {
991  index = 2;
992  goto finish;
993  } else if (r3 && data.endsWith(r3)) {
994  index = 3;
995  goto finish;
996  } else if (r4 && data.endsWith(r4)) {
997  index = 4;
998  goto finish;
999  } else if (r5 && data.endsWith(r5)) {
1000  index = 5;
1001  goto finish;
1002  } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
1003  String mode = stream.readStringUntil(',');
1004  if (mode.toInt() == 1) {
1005  int mux = stream.readStringUntil('\n').toInt();
1006  if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
1007  sockets[mux]->got_data = true;
1008  }
1009  data = "";
1010  } else {
1011  data += mode;
1012  }
1013  } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
1014  int nl = data.lastIndexOf(GSM_NL, data.length()-8);
1015  int coma = data.indexOf(',', nl+2);
1016  int mux = data.substring(nl+2, coma).toInt();
1017  if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
1018  sockets[mux]->sock_connected = false;
1019  }
1020  data = "";
1021  DBG("### Closed: ", mux);
1022  }
1023  }
1024  } while (millis() - startMillis < timeout);
1025 finish:
1026  if (!index) {
1027  data.trim();
1028  if (data.length()) {
1029  DBG("### Unhandled:", data);
1030  }
1031  data = "";
1032  }
1033  return index;
1034  }
1035 
1036  uint8_t waitResponse(uint32_t timeout,
1037  GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
1038  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
1039  {
1040  String data;
1041  return waitResponse(timeout, data, r1, r2, r3, r4, r5);
1042  }
1043 
1044  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
1045  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
1046  {
1047  return waitResponse(1000, r1, r2, r3, r4, r5);
1048  }
1049 
1050 public:
1051  Stream& stream;
1052 
1053 protected:
1054  GsmClient* sockets[TINY_GSM_MUX_COUNT];
1055 };
1056 
1057 #endif
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:653
TinyGsmSim800
Definition: TinyGsmClientSIM800.h:43
last
uint8_t last
8 bit - Id of last node this message passed
Definition: MyMessage.h:334
TinyGsmSim800::GsmClient
Definition: TinyGsmClientSIM800.h:48
TinyGsmFifo< uint8_t, TINY_GSM_RX_BUFFER >
TinyGsmSim800::GsmClientSecure
Definition: TinyGsmClientSIM800.h:206
IPAddress
A class to make it easier to handle and pass around IP addresses.
Definition: IPAddress.h:32