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