MySensors Library & Examples  2.3.2
TinyGsmClientXBee.h
1 
9 #ifndef TinyGsmClientXBee_h
10 #define TinyGsmClientXBee_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 1 // Multi-plexing isn't supported using command mode
19 
20 #include "TinyGsmCommon.h"
21 
22 #define GSM_NL "\r"
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 XBeeType {
33  S6B = 0,
34  LTEC1 = 1,
35 };
36 
37 enum RegStatus {
38  REG_UNREGISTERED = 0,
39  REG_SEARCHING = 2,
40  REG_DENIED = 3,
41  REG_OK_HOME = 1,
42  REG_OK_ROAMING = 5,
43  REG_UNKNOWN = 4,
44 };
45 
46 
47 class TinyGsm
48 {
49 
50 public:
51 
52  class GsmClient : public Client
53  {
54  friend class TinyGsm;
55 
56  public:
57  GsmClient() {}
58 
59  GsmClient(TinyGsm& modem, uint8_t mux = 0)
60  {
61  init(&modem, mux);
62  }
63 
64  bool init(TinyGsm* modem, uint8_t mux = 0)
65  {
66  this->at = modem;
67  this->mux = mux;
68  sock_connected = 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  at->streamClear(); // Empty anything remaining in the buffer;
79  at->commandMode();
80  sock_connected = at->modemConnect(host, port, mux, false);
81  at->writeChanges();
82  at->exitCommand();
83  return sock_connected;
84  }
85 
86  virtual int connect(IPAddress ip, uint16_t port)
87  {
88  at->streamClear(); // Empty anything remaining in the buffer;
89  at->commandMode();
90  sock_connected = at->modemConnect(ip, port, mux, false);
91  at->writeChanges();
92  at->exitCommand();
93  return sock_connected;
94  }
95 
96  // This is a hack to shut the socket by setting the timeout to zero and
97  // then sending an empty line to the server.
98  virtual void stop()
99  {
100  at->streamClear(); // Empty anything remaining in the buffer;
101  at->commandMode();
102  at->sendAT(GF("TM0")); // Set socket timeout to 0;
103  at->waitResponse();
104  at->writeChanges();
105  at->exitCommand();
106  at->modemSend("", 1, mux);
107  at->commandMode();
108  at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds;
109  at->waitResponse();
110  at->writeChanges();
111  at->exitCommand();
112  at->streamClear(); // Empty anything remaining in the buffer;
113  sock_connected = false;
114  }
115 
116  virtual size_t write(const uint8_t *buf, size_t size)
117  {
118  TINY_GSM_YIELD();
119  //at->maintain();
120  return at->modemSend(buf, size, mux);
121  }
122 
123  virtual size_t write(uint8_t c)
124  {
125  return write(&c, 1);
126  }
127 
128  virtual int available()
129  {
130  TINY_GSM_YIELD();
131  return at->stream.available();
132  }
133 
134  virtual int read(uint8_t *buf, size_t size)
135  {
136  TINY_GSM_YIELD();
137  return at->stream.readBytes(buf, size);
138  }
139 
140  virtual int read()
141  {
142  TINY_GSM_YIELD();
143  return at->stream.read();
144  }
145 
146  virtual int peek()
147  {
148  return at->stream.peek();
149  }
150  virtual void flush()
151  {
152  at->stream.flush();
153  }
154 
155  virtual uint8_t connected()
156  {
157  if (available()) {
158  return true;
159  }
160  return sock_connected;
161  }
162  virtual operator bool()
163  {
164  return connected();
165  }
166 
167  /*
168  * Extended API
169  */
170 
171  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
172 
173  private:
174  TinyGsm* at;
175  uint8_t mux;
176  bool sock_connected;
177  };
178 
179  class GsmClientSecure : public GsmClient
180  {
181  public:
182  GsmClientSecure() {}
183 
184  GsmClientSecure(TinyGsm& modem, uint8_t mux = 1)
185  : GsmClient(modem, mux)
186  {}
187 
188  public:
189  virtual int connect(const char *host, uint16_t port)
190  {
191  at->streamClear(); // Empty anything remaining in the buffer;
192  at->commandMode();
193  sock_connected = at->modemConnect(host, port, mux, true);
194  at->writeChanges();
195  at->exitCommand();
196  return sock_connected;
197  }
198 
199  virtual int connect(IPAddress ip, uint16_t port)
200  {
201  at->streamClear(); // Empty anything remaining in the buffer;
202  at->commandMode();
203  sock_connected = at->modemConnect(ip, port, mux, true);
204  at->writeChanges();
205  at->exitCommand();
206  return sock_connected;
207  }
208  };
209 
210 public:
211 
212  explicit TinyGsm(Stream& stream)
213  : stream(stream)
214  {
215  memset(sockets, 0, sizeof(sockets));
216  }
217 
218  /*
219  * Basic functions
220  */
221  bool begin()
222  {
223  return init();
224  }
225 
226  bool init()
227  {
228  guardTime = 1100;
229  commandMode();
230  sendAT(GF("AP0")); // Put in transparent mode
231  waitResponse();
232  sendAT(GF("GT64")); // shorten the guard time to 100ms
233  waitResponse();
234  writeChanges();
235  sendAT(GF("HS")); // Get the "Hardware Series"; 0x601 for S6B (Wifi)
236  // wait for the response
237  unsigned long startMillis = millis();
238  while (!stream.available() && millis() - startMillis < 1000) {};
239  String res = streamReadUntil('\r'); // Does not send an OK, just the result
240  exitCommand();
241  if (res == "601") {
242  beeType = S6B;
243  } else {
244  beeType = LTEC1;
245  }
246  guardTime = 125;
247  return true;
248  }
249 
250  bool testAT(unsigned long timeout = 10000L)
251  {
252  for (unsigned long start = millis(); millis() - start < timeout; ) {
253  if (commandMode()) {
254  sendAT();
255  if (waitResponse(200) == 1) {
256  return true;
257  }
258  exitCommand();
259  }
260  delay(100);
261  }
262  return false;
263  }
264 
265  void maintain() {}
266 
267  bool factoryDefault()
268  {
269  commandMode();
270  sendAT(GF("RE"));
271  bool ret_val = waitResponse() == 1;
272  writeChanges();
273  exitCommand();
274  return ret_val;
275  }
276 
277  bool hasSSL()
278  {
279  if (beeType == S6B) {
280  return false;
281  } else {
282  return true;
283  }
284  }
285 
286  /*
287  * Power functions
288  */
289 
290  bool restart()
291  {
292  commandMode();
293  sendAT(GF("FR"));
294  if (waitResponse() != 1) {
295  return false;
296  }
297  delay (2000); // Actually resets about 2 seconds later
298  for (unsigned long start = millis(); millis() - start < 60000L; ) {
299  if (commandMode()) {
300  exitCommand();
301  return true;
302  }
303  }
304  exitCommand();
305  return false;;
306  }
307 
308  void setupPinSleep()
309  {
310  commandMode();
311  sendAT(GF("SM"),1);
312  waitResponse();
313  if (beeType == S6B) {
314  sendAT(GF("SO"),200);
315  waitResponse();
316  }
317  writeChanges();
318  exitCommand();
319  }
320 
321  /*
322  * SIM card functions
323  */
324 
325  bool simUnlock(const char *pin) // Not supported
326  {
327  return false;
328  }
329 
330  String getSimCCID()
331  {
332  commandMode();
333  sendAT(GF("S#"));
334  // wait for the response
335  unsigned long startMillis = millis();
336  while (!stream.available() && millis() - startMillis < 1000) {};
337  String res = streamReadUntil('\r'); // Does not send an OK, just the result
338  exitCommand();
339  return res;
340  }
341 
342  String getIMEI()
343  {
344  commandMode();
345  sendAT(GF("IM"));
346  // wait for the response
347  unsigned long startMillis = millis();
348  while (!stream.available() && millis() - startMillis < 1000) {};
349  String res = streamReadUntil('\r'); // Does not send an OK, just the result
350  exitCommand();
351  return res;
352  }
353 
354  SimStatus getSimStatus(unsigned long timeout = 10000L)
355  {
356  return SIM_READY; // unsupported
357  }
358 
359  RegStatus getRegistrationStatus()
360  {
361  commandMode();
362  sendAT(GF("AI"));
363  // wait for the response
364  unsigned long startMillis = millis();
365  while (!stream.available() && millis() - startMillis < 1000) {};
366  String res = streamReadUntil('\r'); // Does not send an OK, just the result
367  exitCommand();
368 
369  if(res == GF("0")) {
370  return REG_OK_HOME;
371  }
372 
373  else if(res == GF("13") || res == GF("2A")) {
374  return REG_UNREGISTERED;
375  }
376 
377  else if(res == GF("FF") || res == GF("22") || res == GF("23") ||
378  res == GF("40") || res == GF("41") || res == GF("42")) {
379  return REG_SEARCHING;
380  }
381 
382  else if(res == GF("24") || res == GF("25") || res == GF("27")) {
383  return REG_DENIED;
384  }
385 
386  else {
387  return REG_UNKNOWN;
388  }
389  }
390 
391  String getOperator()
392  {
393  commandMode();
394  sendAT(GF("MN"));
395  // wait for the response
396  unsigned long startMillis = millis();
397  while (!stream.available() && millis() - startMillis < 1000) {};
398  String res = streamReadUntil('\r'); // Does not send an OK, just the result
399  exitCommand();
400  return res;
401  }
402 
403  /*
404  * Generic network functions
405  */
406 
407  int getSignalQuality()
408  {
409  commandMode();
410  if (beeType == S6B) {
411  sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity
412  } else {
413  sendAT(GF("DB")); // ask for the cell strength in dBm
414  }
415  // wait for the response
416  unsigned long startMillis = millis();
417  while (!stream.available() && millis() - startMillis < 1000) {};
418  char buf[2] = {0}; // Set up buffer for response
419  buf[0] = streamRead();
420  buf[1] = streamRead();
421  // DBG(buf[0], buf[1], "\n");
422  exitCommand();
423  int intr = strtol(buf, 0, 16);
424  if (beeType == S6B) {
425  return -93 + intr; // the maximum sensitivity is -93dBm
426  } else {
427  return -1*intr; // need to convert to negative number
428  }
429  }
430 
431  bool isNetworkConnected()
432  {
433  RegStatus s = getRegistrationStatus();
434  return (s == REG_OK_HOME || s == REG_OK_ROAMING);
435  }
436 
437  bool waitForNetwork(unsigned long timeout = 60000L)
438  {
439  for (unsigned long start = millis(); millis() - start < timeout; ) {
440  if (isNetworkConnected()) {
441  return true;
442  }
443  delay(250);
444  }
445  return false;
446  }
447 
448  /*
449  * WiFi functions
450  */
451  bool networkConnect(const char* ssid, const char* pwd)
452  {
453 
454  commandMode();
455 
456  sendAT(GF("EE"), 2); // Set security to WPA2
457  waitResponse();
458 
459  sendAT(GF("ID"), ssid);
460  if (waitResponse() != 1) {
461  goto fail;
462  }
463 
464  sendAT(GF("PK"), pwd);
465  if (waitResponse() != 1) {
466  goto fail;
467  }
468 
469  writeChanges();
470  exitCommand();
471 
472  return true;
473 
474 fail:
475  exitCommand();
476  return false;
477  }
478 
479  bool networkDisconnect()
480  {
481  return false; // Doesn't support disconnecting
482  }
483 
484  String getLocalIP()
485  {
486  commandMode();
487  sendAT(GF("MY"));
488  String IPaddr;
489  IPaddr.reserve(16);
490  // wait for the response
491  unsigned long startMillis = millis();
492  while (stream.available() < 8 && millis() - startMillis < 30000) {};
493  IPaddr = streamReadUntil('\r'); // read result
494  return IPaddr;
495  }
496 
497  IPAddress localIP()
498  {
499  return TinyGsmIpFromString(getLocalIP());
500  }
501 
502  /*
503  * GPRS functions
504  */
505  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
506  {
507  commandMode();
508  sendAT(GF("AN"), apn); // Set the APN
509  waitResponse();
510  writeChanges();
511  exitCommand();
512  return true;
513  }
514 
515  bool gprsDisconnect() // TODO
516  {
517  return false;
518  }
519 
520  /*
521  * Messaging functions
522  */
523 
524  String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
525 
526  bool sendSMS(const String& number, const String& text)
527  {
528  commandMode();
529  sendAT(GF("IP"), 2); // Put in text messaging mode
530  waitResponse();
531  sendAT(GF("PH"), number); // Set the phone number
532  waitResponse();
533  sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return)
534  waitResponse();
535  writeChanges();
536  exitCommand();
537  stream.print(text);
538  stream.write((char)0x0D); // close off with the carriage return
539  return true;
540  }
541 
542 
543 private:
544 
545  int modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false)
546  {
547  sendAT(GF("LA"), host);
548  String strIP;
549  strIP.reserve(16);
550  // wait for the response
551  unsigned long startMillis = millis();
552  while (stream.available() < 8 && millis() - startMillis < 30000) {};
553  strIP = streamReadUntil('\r'); // read result
554  IPAddress ip = TinyGsmIpFromString(strIP);
555  return modemConnect(ip, port, mux, ssl);
556  }
557 
558  int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false)
559  {
560  String host;
561  host.reserve(16);
562  host += ip[0];
563  host += ".";
564  host += ip[1];
565  host += ".";
566  host += ip[2];
567  host += ".";
568  host += ip[3];
569  if (ssl) {
570  sendAT(GF("IP"), 4); // Put in TCP mode
571  waitResponse();
572  } else {
573  sendAT(GF("IP"), 1); // Put in TCP mode
574  waitResponse();
575  }
576  sendAT(GF("DL"), host); // Set the "Destination Address Low"
577  waitResponse();
578  sendAT(GF("DE"), String(port, HEX)); // Set the destination port
579  int rsp = waitResponse();
580  return rsp;
581  }
582 
583  int modemSend(const void* buff, size_t len, uint8_t mux = 0)
584  {
585  stream.write((uint8_t*)buff, len);
586  stream.flush();
587  return len;
588  }
589 
590  bool modemGetConnected(uint8_t mux = 0)
591  {
592  commandMode();
593  sendAT(GF("AI"));
594  int res = waitResponse(GF("0"));
595  exitCommand();
596  return 1 == res;
597  }
598 
599 public:
600 
601  /* Utilities */
602 
603  template<typename T>
604  void streamWrite(T last)
605  {
606  stream.print(last);
607  }
608 
609  template<typename T, typename... Args>
610  void streamWrite(T head, Args... tail)
611  {
612  stream.print(head);
613  streamWrite(tail...);
614  }
615 
616  int streamRead()
617  {
618  return stream.read();
619  }
620 
621  String streamReadUntil(char c)
622  {
623  TINY_GSM_YIELD();
624  String return_string = stream.readStringUntil(c);
625  return_string.trim();
626  // DBG(return_string, c);
627  return return_string;
628  }
629 
630  void streamClear(void)
631  {
632  while (stream.available()) {
633  streamRead();
634  }
635  }
636 
637  bool commandMode(void)
638  {
639  delay(guardTime); // cannot send anything for 1 second before entering command mode
640  streamWrite(GF("+++")); // enter command mode
641  // DBG("\r\n+++\r\n");
642  return 1 == waitResponse(guardTime*2);
643  }
644 
645  void writeChanges(void)
646  {
647  sendAT(GF("WR")); // Write changes to flash
648  waitResponse();
649  sendAT(GF("AC")); // Apply changes
650  waitResponse();
651  }
652 
653  void exitCommand(void)
654  {
655  sendAT(GF("CN")); // Exit command mode
656  waitResponse();
657  }
658 
659  template<typename... Args>
660  void sendAT(Args... cmd)
661  {
662  streamWrite("AT", cmd..., GSM_NL);
663  stream.flush();
664  TINY_GSM_YIELD();
665  //DBG("### AT:", cmd...);
666  }
667 
668  // TODO: Optimize this!
669  uint8_t waitResponse(uint32_t timeout, String& data,
670  GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
671  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
672  {
673  /*String r1s(r1); r1s.trim();
674  String r2s(r2); r2s.trim();
675  String r3s(r3); r3s.trim();
676  String r4s(r4); r4s.trim();
677  String r5s(r5); r5s.trim();
678  DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
679  data.reserve(64);
680  int index = 0;
681  unsigned long startMillis = millis();
682  do {
683  TINY_GSM_YIELD();
684  while (stream.available() > 0) {
685  int a = streamRead();
686  if (a <= 0) {
687  continue; // Skip 0x00 bytes, just in case
688  }
689  data += (char)a;
690  if (r1 && data.endsWith(r1)) {
691  index = 1;
692  goto finish;
693  } else if (r2 && data.endsWith(r2)) {
694  index = 2;
695  goto finish;
696  } else if (r3 && data.endsWith(r3)) {
697  index = 3;
698  goto finish;
699  } else if (r4 && data.endsWith(r4)) {
700  index = 4;
701  goto finish;
702  } else if (r5 && data.endsWith(r5)) {
703  index = 5;
704  goto finish;
705  }
706  }
707  } while (millis() - startMillis < timeout);
708 finish:
709  if (!index) {
710  data.trim();
711  data.replace(GSM_NL GSM_NL, GSM_NL);
712  data.replace(GSM_NL, "\r\n" " ");
713  if (data.length()) {
714  DBG("### Unhandled:", data, "\r\n");
715  } else {
716  DBG("### NO RESPONSE!\r\n");
717  }
718  } else {
719  data.trim();
720  data.replace(GSM_NL GSM_NL, GSM_NL);
721  data.replace(GSM_NL, "\r\n ");
722  if (data.length()) {
723  // DBG("<<< ", data);
724  }
725  }
726  return index;
727  }
728 
729  uint8_t waitResponse(uint32_t timeout,
730  GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
731  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
732  {
733  String data;
734  return waitResponse(timeout, data, r1, r2, r3, r4, r5);
735  }
736 
737  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
738  GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
739  {
740  return waitResponse(1000, r1, r2, r3, r4, r5);
741  }
742 
743 public:
744  Stream& stream;
745 
746 protected:
747  int guardTime;
748  XBeeType beeType;
749  GsmClient* sockets[TINY_GSM_MUX_COUNT];
750 };
751 
752 #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
IPAddress
A class to make it easier to handle and pass around IP addresses.
Definition: IPAddress.h:32