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