Creating a super-class for modems
This commit is contained in:
		@@ -13,7 +13,7 @@
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_SSL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7)
 | 
			
		||||
#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7) || defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -38,6 +38,12 @@
 | 
			
		||||
  typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
 | 
			
		||||
  typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_M95)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPRS
 | 
			
		||||
  #include <TinyGsmClientM95.h>
 | 
			
		||||
  typedef TinyGsmM95 TinyGsm;
 | 
			
		||||
  typedef TinyGsmM95::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_BG96)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPRS
 | 
			
		||||
  #include <TinyGsmClientBG96.h>
 | 
			
		||||
@@ -56,6 +62,11 @@
 | 
			
		||||
  typedef TinyGsmM590 TinyGsm;
 | 
			
		||||
  typedef TinyGsmM590::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
  #include <TinyGsmClientMC60.h>
 | 
			
		||||
  typedef TinyGsmMC60 TinyGsm;
 | 
			
		||||
  typedef TinyGsmMC60::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_ESP8266)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_WIFI
 | 
			
		||||
  #include <TinyGsmClientESP8266.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmA6
 | 
			
		||||
class TinyGsmA6 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -178,7 +178,7 @@ private:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmA6(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -186,11 +186,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -208,6 +205,15 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_A6)
 | 
			
		||||
      return "AI-Thinker A6";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_A7)
 | 
			
		||||
      return "AI-Thinker A7";
 | 
			
		||||
    #endif
 | 
			
		||||
    return "AI-Thinker A6";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -251,6 +257,14 @@ public:
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -367,22 +381,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -441,6 +439,10 @@ public:
 | 
			
		||||
    return (res == 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIFSR"));
 | 
			
		||||
    String res;
 | 
			
		||||
@@ -453,10 +455,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -606,6 +604,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t* mux) {
 | 
			
		||||
@@ -650,30 +652,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmBG96
 | 
			
		||||
class TinyGsmBG96 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -115,7 +115,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size()) {
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
@@ -125,7 +125,7 @@ public:
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size) {
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
@@ -179,30 +179,30 @@ private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GsmClientSecure : public GsmClient
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  GsmClientSecure() {}
 | 
			
		||||
 | 
			
		||||
  GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
 | 
			
		||||
    : GsmClient(modem, mux)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmBG96(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -210,11 +210,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -226,6 +223,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Quectel BG96";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -280,6 +281,14 @@ public:
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -401,44 +410,30 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    //Configure the TCPIP Context
 | 
			
		||||
    sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT=1"));
 | 
			
		||||
    if (waitResponse(150000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Attach to Packet Domain service - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -463,12 +458,13 @@ public:
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CGPADDR=1"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CGPADDR:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(',');
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
@@ -476,10 +472,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -535,6 +527,8 @@ public:
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
@@ -567,14 +561,42 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
  uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    int rsp;
 | 
			
		||||
    // <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE",
 | 
			
		||||
    // "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer)
 | 
			
		||||
    sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
 | 
			
		||||
    rsp = waitResponse();
 | 
			
		||||
 | 
			
		||||
@@ -660,30 +682,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmESP8266
 | 
			
		||||
class TinyGsmESP8266 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -191,10 +191,11 @@ public:
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmESP8266(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -202,11 +203,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -225,6 +223,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "ESP8266";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -266,6 +268,14 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -362,6 +372,10 @@ public:
 | 
			
		||||
    return retVal;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIPSTA_CUR??"));
 | 
			
		||||
    int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
 | 
			
		||||
@@ -373,33 +387,9 @@ public:
 | 
			
		||||
    return res2;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool gprsDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
@@ -438,30 +428,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmM590
 | 
			
		||||
class TinyGsmM590 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -175,7 +175,7 @@ private:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmM590(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -183,11 +183,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -204,6 +201,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Neoway M590";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -255,6 +256,14 @@ public:
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -375,22 +384,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -447,6 +440,10 @@ public:
 | 
			
		||||
    return res == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+XIIC?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
 | 
			
		||||
@@ -459,10 +456,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -538,6 +531,10 @@ public:
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux) {
 | 
			
		||||
@@ -595,30 +592,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										843
									
								
								src/TinyGsmClientM95.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										843
									
								
								src/TinyGsmClientM95.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,843 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientM95.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com>
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TinyGsmClientM95_h
 | 
			
		||||
#define TinyGsmClientM95_h
 | 
			
		||||
 | 
			
		||||
//#define TINY_GSM_DEBUG Serial
 | 
			
		||||
//#define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#if !defined(TINY_GSM_RX_BUFFER)
 | 
			
		||||
  #define TINY_GSM_RX_BUFFER 64
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 6
 | 
			
		||||
 | 
			
		||||
#include <TinyGsmCommon.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
 | 
			
		||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
 | 
			
		||||
 | 
			
		||||
enum SimStatus {
 | 
			
		||||
  SIM_ERROR = 0,
 | 
			
		||||
  SIM_READY = 1,
 | 
			
		||||
  SIM_LOCKED = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmM95 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
class GsmClient : public Client
 | 
			
		||||
{
 | 
			
		||||
  friend class TinyGsmM95;
 | 
			
		||||
  typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  GsmClient() {}
 | 
			
		||||
 | 
			
		||||
  GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
 | 
			
		||||
    init(&modem, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(TinyGsmM95* modem, uint8_t mux = 1) {
 | 
			
		||||
    this->at = modem;
 | 
			
		||||
    this->mux = mux;
 | 
			
		||||
    sock_available = 0;
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    got_data = false;
 | 
			
		||||
 | 
			
		||||
    at->sockets[mux] = this;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int connect(IPAddress ip, uint16_t port) {
 | 
			
		||||
    String host; host.reserve(16);
 | 
			
		||||
    host += ip[0];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[1];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[2];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[3];
 | 
			
		||||
    return connect(host.c_str(), port);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual void stop() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->sendAT(GF("+QICLOSE="), mux);
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    at->waitResponse(60000L, GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
 | 
			
		||||
    rx.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    return at->modemSend(buf, size, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(uint8_t c) {
 | 
			
		||||
    return write(&c, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const char *str) {
 | 
			
		||||
    if (str == NULL) return 0;
 | 
			
		||||
    return write((const uint8_t *)str, strlen(str));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read(uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
        buf += chunk;
 | 
			
		||||
        cnt += chunk;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      // TODO: Read directly into user buffer?
 | 
			
		||||
      at->maintain();
 | 
			
		||||
      if (sock_available > 0) {
 | 
			
		||||
        at->modemRead(rx.free(), mux);
 | 
			
		||||
      } else {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return cnt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read() {
 | 
			
		||||
    uint8_t c;
 | 
			
		||||
    if (read(&c, 1) == 1) {
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int peek() { return -1; } //TODO
 | 
			
		||||
  virtual void flush() { at->stream.flush(); }
 | 
			
		||||
 | 
			
		||||
  virtual uint8_t connected() {
 | 
			
		||||
    if (available()) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
  virtual operator bool() { return connected(); }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Extended API
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  TinyGsmM95*   at;
 | 
			
		||||
  uint8_t       mux;
 | 
			
		||||
  uint16_t      sock_available;
 | 
			
		||||
  bool          sock_connected;
 | 
			
		||||
  bool          got_data;
 | 
			
		||||
  RxFifo        rx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmM95(Stream& stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("&FZE0"));  // Factory + Reset + Echo Off
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef TINY_GSM_DEBUG
 | 
			
		||||
    sendAT(GF("+CMEE=2"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    getSimStatus();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Quectel M95";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool testAT(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF(""));
 | 
			
		||||
      if (waitResponse(200) == 1) {
 | 
			
		||||
        delay(100);
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(100);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void maintain() {
 | 
			
		||||
    for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
 | 
			
		||||
      GsmClient* sock = sockets[mux];
 | 
			
		||||
      if (sock && sock->got_data) {
 | 
			
		||||
        sock->got_data = false;
 | 
			
		||||
        sock->sock_available = modemGetAvailable(mux);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    while (stream.available()) {
 | 
			
		||||
      waitResponse(10, NULL, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefault() {
 | 
			
		||||
    sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+IPR=0"));   // Auto-baud
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("&W"));       // Write configuration
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemInfo() {
 | 
			
		||||
    sendAT(GF("I"));
 | 
			
		||||
    String res;
 | 
			
		||||
    if (waitResponse(1000L, res) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    res.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res.replace(GSM_NL, " ");
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasSSL() {
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool restart() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=1"));
 | 
			
		||||
    if (waitResponse(10000L, GF("Call Ready"), GF("OK"), GF("FAIL")) == 3) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool poweroff() {
 | 
			
		||||
    sendAT(GF("+QPOWD"));
 | 
			
		||||
    return waitResponse(GF("POWERED DOWN")) == 1; // TODO
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool radioOff() {
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool simUnlock(const char *pin) {
 | 
			
		||||
    sendAT(GF("+CPIN=\""), pin, GF("\""));
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getSimCCID() {
 | 
			
		||||
    sendAT(GF("+ICCID"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getIMEI() {
 | 
			
		||||
    sendAT(GF("+GSN"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL)) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SimStatus getSimStatus(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF("+CPIN?"));
 | 
			
		||||
      if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
 | 
			
		||||
        delay(1000);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      switch (status) {
 | 
			
		||||
        case 2:
 | 
			
		||||
        case 3:  return SIM_LOCKED;
 | 
			
		||||
        case 1:  return SIM_READY;
 | 
			
		||||
        default: return SIM_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return SIM_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    sendAT(GF("+CREG?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
 | 
			
		||||
      return REG_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip format (0)
 | 
			
		||||
    int status = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return (RegStatus)status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getOperator() {
 | 
			
		||||
    sendAT(GF("+COPS?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil('"'); // Skip mode and format
 | 
			
		||||
    String res = stream.readStringUntil('"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int getSignalQuality() {
 | 
			
		||||
    sendAT(GF("+CSQ"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
 | 
			
		||||
      return 99;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isNetworkConnected() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setHostFormat( bool useDottedQuad ) {
 | 
			
		||||
    if ( useDottedQuad ) {
 | 
			
		||||
      sendAT(GF("+QIDNSIP=0"));
 | 
			
		||||
    } else {
 | 
			
		||||
      sendAT(GF("+QIDNSIP=1"));
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // select foreground context 0 = VIRTUAL_UART_1
 | 
			
		||||
    sendAT(GF("+QIFGCNT=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Select GPRS (=1) as the Bearer
 | 
			
		||||
    sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Start TCPIP Task and Set APN, User Name and Password
 | 
			
		||||
    sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" );
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT"));
 | 
			
		||||
    if (waitResponse(10000) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Enable multiple TCP/IP connections
 | 
			
		||||
    sendAT(GF("+QIMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Request an IP header for received data ("IPD(data length):")
 | 
			
		||||
    sendAT(GF("+QIHEAD=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
 | 
			
		||||
    sendAT(GF("+QINDI=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnect() {
 | 
			
		||||
    sendAT(GF("+QIDEACT"));
 | 
			
		||||
    return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isGprsConnected() {
 | 
			
		||||
    sendAT(GF("+CGATT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    if (res != 1)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String sendUSSD(const String& code) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CUSD=1,\""), code, GF("\""));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil('"');
 | 
			
		||||
    String hex = stream.readStringUntil('"');
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int dcs = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dcs == 15) {
 | 
			
		||||
      return TinyGsmDecodeHex8bit(hex);
 | 
			
		||||
    } else if (dcs == 72) {
 | 
			
		||||
      return TinyGsmDecodeHex16bit(hex);
 | 
			
		||||
    } else {
 | 
			
		||||
      return hex;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS(const String& number, const String& text) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    //Set GSM 7 bit default alphabet (3GPP TS 23.038)
 | 
			
		||||
    sendAT(GF("+CSCS=\"GSM\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.print(text);
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t* t = (uint16_t*)text;
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      uint8_t c = t[i] >> 8;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
      c = t[i] & 0xFF;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Delete all SMS */
 | 
			
		||||
  bool deleteAllSMS() {
 | 
			
		||||
    sendAT(GF("+QMGDA=6"));
 | 
			
		||||
    if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    sendAT(GF("+QIOPEN="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
 | 
			
		||||
    int rsp = waitResponse(75000L,
 | 
			
		||||
                           GF("CONNECT OK" GSM_NL),
 | 
			
		||||
                           GF("CONNECT FAIL" GSM_NL),
 | 
			
		||||
                           GF("ALREADY CONNECT" GSM_NL));
 | 
			
		||||
    if ( rsp != 1 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return (1 == rsp);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISEND="), mux, ',', len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((uint8_t*)buff, len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool allAcknowledged = false;
 | 
			
		||||
    // bool failed = false;
 | 
			
		||||
    while ( !allAcknowledged ) {
 | 
			
		||||
      sendAT( GF("+QISACK"));
 | 
			
		||||
      if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        streamSkipUntil(','); /** Skip total */
 | 
			
		||||
        streamSkipUntil(','); /** Skip acknowledged data size */
 | 
			
		||||
        if ( stream.readStringUntil('\n').toInt() == 0 ) {
 | 
			
		||||
          allAcknowledged = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse(5000L);
 | 
			
		||||
 | 
			
		||||
    // streamSkipUntil(','); // Skip mux
 | 
			
		||||
    // return stream.readStringUntil('\n').toInt();
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, ',', size);
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    size_t len = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      while (!stream.available()) { TINY_GSM_YIELD(); }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    DBG("### READ:", mux, ",", len);
 | 
			
		||||
    return len;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, GF(",0"));
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) == 1) {
 | 
			
		||||
      streamSkipUntil(','); // Skip total received
 | 
			
		||||
      streamSkipUntil(','); // Skip have read
 | 
			
		||||
      result = stream.readStringUntil('\n').toInt();
 | 
			
		||||
      DBG("### STILL:", mux, "has", result);
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    if (!result) {
 | 
			
		||||
      sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISTATE=1,"), mux);
 | 
			
		||||
    //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+QISTATE:")))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil(','); // Skip mux
 | 
			
		||||
    streamSkipUntil(','); // Skip socket type
 | 
			
		||||
    streamSkipUntil(','); // Skip remote ip
 | 
			
		||||
    streamSkipUntil(','); // Skip remote port
 | 
			
		||||
    streamSkipUntil(','); // Skip local port
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt(); // socket state
 | 
			
		||||
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
 | 
			
		||||
    return 2 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    //DBG("### AT:", cmd...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: Optimize this!
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout, String& data,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /*String r1s(r1); r1s.trim();
 | 
			
		||||
    String r2s(r2); r2s.trim();
 | 
			
		||||
    String r3s(r3); r3s.trim();
 | 
			
		||||
    String r4s(r4); r4s.trim();
 | 
			
		||||
    String r5s(r5); r5s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    int index = 0;
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        int a = stream.read();
 | 
			
		||||
        if (a <= 0) continue; // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += (char)a;
 | 
			
		||||
        if (r1 && data.endsWith(r1)) {
 | 
			
		||||
          index = 1;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r2 && data.endsWith(r2)) {
 | 
			
		||||
          index = 2;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r3 && data.endsWith(r3)) {
 | 
			
		||||
          index = 3;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r4 && data.endsWith(r4)) {
 | 
			
		||||
          index = 4;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r5 && data.endsWith(r5)) {
 | 
			
		||||
          index = 5;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) {
 | 
			
		||||
          streamSkipUntil(',');  // Skip the context
 | 
			
		||||
          streamSkipUntil(',');  // Skip the role
 | 
			
		||||
          int mux = stream.readStringUntil('\n').toInt();
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int nl = data.lastIndexOf(GSM_NL, data.length()-8);
 | 
			
		||||
          int coma = data.indexOf(',', nl+2);
 | 
			
		||||
          int mux = data.substring(nl+2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout);
 | 
			
		||||
finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) {
 | 
			
		||||
        DBG("### Unhandled:", data);
 | 
			
		||||
      }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  GsmClient*    sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										874
									
								
								src/TinyGsmClientMC60.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										874
									
								
								src/TinyGsmClientMC60.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,874 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientMC60.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 *
 | 
			
		||||
 * @MC60 support added by Tamas Dajka 2017.10.15 - with fixes by Sara Damiano
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TinyGsmClientMC60_h
 | 
			
		||||
#define TinyGsmClientMC60_h
 | 
			
		||||
 | 
			
		||||
//#define TINY_GSM_DEBUG Serial
 | 
			
		||||
//#define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#if !defined(TINY_GSM_RX_BUFFER)
 | 
			
		||||
  #define TINY_GSM_RX_BUFFER 64
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 6
 | 
			
		||||
 | 
			
		||||
#include <TinyGsmCommon.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
 | 
			
		||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
 | 
			
		||||
 | 
			
		||||
enum SimStatus {
 | 
			
		||||
  SIM_ERROR = 0,
 | 
			
		||||
  SIM_READY = 1,
 | 
			
		||||
  SIM_LOCKED = 2,
 | 
			
		||||
  SIM_ANTITHEFT_LOCKED = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmMC60 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
class GsmClient : public Client
 | 
			
		||||
{
 | 
			
		||||
  friend class TinyGsmMC60;
 | 
			
		||||
  typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  GsmClient() {}
 | 
			
		||||
 | 
			
		||||
  GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) {
 | 
			
		||||
    init(&modem, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(TinyGsmMC60* modem, uint8_t mux = 1) {
 | 
			
		||||
    this->at = modem;
 | 
			
		||||
    this->mux = mux;
 | 
			
		||||
    sock_available = 0;
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    got_data = false;
 | 
			
		||||
 | 
			
		||||
    at->sockets[mux] = this;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int connect(IPAddress ip, uint16_t port) {
 | 
			
		||||
    String host; host.reserve(16);
 | 
			
		||||
    host += ip[0];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[1];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[2];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[3];
 | 
			
		||||
    return connect(host.c_str(), port);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual void stop() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->sendAT(GF("+QICLOSE="), mux);
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    at->waitResponse(60000L, GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
 | 
			
		||||
    rx.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    return at->modemSend(buf, size, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(uint8_t c) {
 | 
			
		||||
    return write(&c, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const char *str) {
 | 
			
		||||
    if (str == NULL) return 0;
 | 
			
		||||
    return write((const uint8_t *)str, strlen(str));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read(uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
        buf += chunk;
 | 
			
		||||
        cnt += chunk;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      // TODO: Read directly into user buffer?
 | 
			
		||||
      at->maintain();
 | 
			
		||||
      if (sock_available > 0) {
 | 
			
		||||
        at->modemRead(rx.free(), mux);
 | 
			
		||||
      } else {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return cnt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read() {
 | 
			
		||||
    uint8_t c;
 | 
			
		||||
    if (read(&c, 1) == 1) {
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int peek() { return -1; } //TODO
 | 
			
		||||
  virtual void flush() { at->stream.flush(); }
 | 
			
		||||
 | 
			
		||||
  virtual uint8_t connected() {
 | 
			
		||||
    if (available()) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
  virtual operator bool() { return connected(); }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Extended API
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  TinyGsmMC60*  at;
 | 
			
		||||
  uint8_t       mux;
 | 
			
		||||
  uint16_t      sock_available;
 | 
			
		||||
  bool          sock_connected;
 | 
			
		||||
  bool          got_data;
 | 
			
		||||
  RxFifo        rx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmMC60(Stream& stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("&FZ"));  // Factory + Reset
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("E0"));   // Echo Off
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    getSimStatus();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_MC60)
 | 
			
		||||
      return "Quectel MC60";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
      return "Quectel MC60E";
 | 
			
		||||
    #endif
 | 
			
		||||
      return "Quectel MC60";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool testAT(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF(""));
 | 
			
		||||
      if (waitResponse(200) == 1) {
 | 
			
		||||
        delay(100);
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(100);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void maintain() {
 | 
			
		||||
    for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
 | 
			
		||||
      GsmClient* sock = sockets[mux];
 | 
			
		||||
      if (sock && sock->got_data) {
 | 
			
		||||
        sock->got_data = false;
 | 
			
		||||
        sock->sock_available = modemGetAvailable(mux);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    while (stream.available()) {
 | 
			
		||||
      waitResponse(10, NULL, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefault() {
 | 
			
		||||
    sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+IPR=0"));   // Auto-baud
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("&W"));       // Write configuration
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemInfo() {
 | 
			
		||||
    sendAT(GF("I"));
 | 
			
		||||
    String res;
 | 
			
		||||
    if (waitResponse(1000L, res) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    res.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res.replace(GSM_NL, " ");
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
  * under development
 | 
			
		||||
  */
 | 
			
		||||
  // bool hasSSL() {
 | 
			
		||||
  //   sendAT(GF("+QIPSSL=?"));
 | 
			
		||||
  //   if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
 | 
			
		||||
  //     return false;
 | 
			
		||||
  //   }
 | 
			
		||||
  //   return waitResponse() == 1;
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  bool hasSSL() {
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool restart() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=1,1"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool poweroff() {
 | 
			
		||||
    sendAT(GF("+QPOWD=1"));
 | 
			
		||||
    return waitResponse(GF("NORMAL POWER DOWN")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool radioOff() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool simUnlock(const char *pin) {
 | 
			
		||||
    sendAT(GF("+CPIN=\""), pin, GF("\""));
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getSimCCID() {
 | 
			
		||||
    sendAT(GF("+ICCID"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getIMEI() {
 | 
			
		||||
    sendAT(GF("+GSN"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL)) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SimStatus getSimStatus(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF("+CPIN?"));
 | 
			
		||||
      if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
 | 
			
		||||
        delay(1000);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      switch (status) {
 | 
			
		||||
        case 2:
 | 
			
		||||
        case 3:  return SIM_LOCKED;
 | 
			
		||||
        case 5:
 | 
			
		||||
        case 6:  return SIM_ANTITHEFT_LOCKED;
 | 
			
		||||
        case 1:  return SIM_READY;
 | 
			
		||||
        default: return SIM_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return SIM_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    sendAT(GF("+CREG?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
 | 
			
		||||
      return REG_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip format (0)
 | 
			
		||||
    int status = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return (RegStatus)status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getOperator() {
 | 
			
		||||
    sendAT(GF("+COPS?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil('"'); // Skip mode and format
 | 
			
		||||
    String res = stream.readStringUntil('"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int getSignalQuality() {
 | 
			
		||||
    sendAT(GF("+CSQ"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
 | 
			
		||||
      return 99;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isNetworkConnected() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // select foreground context 0 = VIRTUAL_UART_1
 | 
			
		||||
    sendAT(GF("+QIFGCNT=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Select GPRS (=1) as the Bearer
 | 
			
		||||
    sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Define PDP context - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Activate PDP context - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGACT=1,1"));
 | 
			
		||||
    waitResponse(60000L);
 | 
			
		||||
 | 
			
		||||
    //Start TCPIP Task and Set APN, User Name and Password
 | 
			
		||||
    sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" );
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Enable multiple TCP/IP connections
 | 
			
		||||
    sendAT(GF("+QIMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Request an IP header for received data ("IPD(data length):")
 | 
			
		||||
    sendAT(GF("+QIHEAD=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
 | 
			
		||||
    sendAT(GF("+QINDI=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check that we have a local IP address
 | 
			
		||||
    if (localIP() != 0) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnect() {
 | 
			
		||||
    sendAT(GF("+QIDEACT"));
 | 
			
		||||
    return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isGprsConnected() {
 | 
			
		||||
    sendAT(GF("+CGATT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    if (res != 1)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String sendUSSD(const String& code) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CUSD=1,\""), code, GF("\""));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil('"');
 | 
			
		||||
    String hex = stream.readStringUntil('"');
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int dcs = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dcs == 15) {
 | 
			
		||||
      return TinyGsmDecodeHex8bit(hex);
 | 
			
		||||
    } else if (dcs == 72) {
 | 
			
		||||
      return TinyGsmDecodeHex16bit(hex);
 | 
			
		||||
    } else {
 | 
			
		||||
      return hex;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS(const String& number, const String& text) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    //Set GSM 7 bit default alphabet (3GPP TS 23.038)
 | 
			
		||||
    sendAT(GF("+CSCS=\"GSM\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.print(text);
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t* t = (uint16_t*)text;
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      uint8_t c = t[i] >> 8;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
      c = t[i] & 0xFF;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Delete all SMS */
 | 
			
		||||
  bool deleteAllSMS() {
 | 
			
		||||
    sendAT(GF("+QMGDA=6"));
 | 
			
		||||
    if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() {
 | 
			
		||||
    sendAT(GF("+CIPGSMLOC=1,1"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    sendAT(GF("+QIOPEN="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
 | 
			
		||||
    int rsp = waitResponse(75000L,
 | 
			
		||||
                           GF("CONNECT OK" GSM_NL),
 | 
			
		||||
                           GF("CONNECT FAIL" GSM_NL),
 | 
			
		||||
                           GF("ALREADY CONNECT" GSM_NL));
 | 
			
		||||
    if ( rsp != 1 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return (1 == rsp);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISEND="), mux, ',', len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((uint8_t*)buff, len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool allAcknowledged = false;
 | 
			
		||||
    // bool failed = false;
 | 
			
		||||
    while ( !allAcknowledged ) {
 | 
			
		||||
      sendAT( GF("+QISACK"));
 | 
			
		||||
      if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        streamSkipUntil(','); /** Skip total */
 | 
			
		||||
        streamSkipUntil(','); /** Skip acknowledged data size */
 | 
			
		||||
        if ( stream.readStringUntil('\n').toInt() == 0 ) {
 | 
			
		||||
          allAcknowledged = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse(5000L);
 | 
			
		||||
 | 
			
		||||
    // streamSkipUntil(','); // Skip mux
 | 
			
		||||
    // return stream.readStringUntil('\n').toInt();
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, ',', size);
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    size_t len = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      while (!stream.available()) { TINY_GSM_YIELD(); }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    DBG("### READ:", mux, ",", len);
 | 
			
		||||
    return len;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, GF(",0"));
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) == 1) {
 | 
			
		||||
      streamSkipUntil(','); // Skip total received
 | 
			
		||||
      streamSkipUntil(','); // Skip have read
 | 
			
		||||
      result = stream.readStringUntil('\n').toInt();
 | 
			
		||||
      DBG("### STILL:", mux, "has", result);
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    if (!result) {
 | 
			
		||||
      sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISTATE=1,"), mux);
 | 
			
		||||
    //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+QISTATE:")))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil(','); // Skip mux
 | 
			
		||||
    streamSkipUntil(','); // Skip socket type
 | 
			
		||||
    streamSkipUntil(','); // Skip remote ip
 | 
			
		||||
    streamSkipUntil(','); // Skip remote port
 | 
			
		||||
    streamSkipUntil(','); // Skip local port
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt(); // socket state
 | 
			
		||||
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
 | 
			
		||||
    return 2 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    //DBG("### AT:", cmd...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: Optimize this!
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout, String& data,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /*String r1s(r1); r1s.trim();
 | 
			
		||||
    String r2s(r2); r2s.trim();
 | 
			
		||||
    String r3s(r3); r3s.trim();
 | 
			
		||||
    String r4s(r4); r4s.trim();
 | 
			
		||||
    String r5s(r5); r5s.trim();
 | 
			
		||||
    String r6s(r6); r6s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    int index = 0;
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        int a = stream.read();
 | 
			
		||||
        if (a <= 0) continue; // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += (char)a;
 | 
			
		||||
        if (r1 && data.endsWith(r1)) {
 | 
			
		||||
          index = 1;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r2 && data.endsWith(r2)) {
 | 
			
		||||
          index = 2;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r3 && data.endsWith(r3)) {
 | 
			
		||||
          index = 3;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r4 && data.endsWith(r4)) {
 | 
			
		||||
          index = 4;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r5 && data.endsWith(r5)) {
 | 
			
		||||
          index = 5;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r6 && data.endsWith(r6)) {
 | 
			
		||||
          index = 6;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) {
 | 
			
		||||
          streamSkipUntil(',');  // Skip the context
 | 
			
		||||
          streamSkipUntil(',');  // Skip the role
 | 
			
		||||
          int mux = stream.readStringUntil('\n').toInt();
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int nl = data.lastIndexOf(GSM_NL, data.length()-8);
 | 
			
		||||
          int coma = data.indexOf(',', nl+2);
 | 
			
		||||
          int mux = data.substring(nl+2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout);
 | 
			
		||||
finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) {
 | 
			
		||||
        DBG("### Unhandled:", data);
 | 
			
		||||
      }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout, data, r1, r2, r3, r4, r5, r6);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5, r6);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  GsmClient*    sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -45,8 +45,7 @@ enum TinyGSMDateTimeFormat {
 | 
			
		||||
  DATE_DATE = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmSim800
 | 
			
		||||
class TinyGsmSim800 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -217,7 +216,7 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmSim800(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -225,11 +224,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -243,6 +239,19 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_SIM800)
 | 
			
		||||
      return "SIMCom SIM800";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM808)
 | 
			
		||||
      return "SIMCom SIM808";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM868)
 | 
			
		||||
      return "SIMCom SIM868";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM900)
 | 
			
		||||
      return "SIMCom SIM900";
 | 
			
		||||
    #endif
 | 
			
		||||
    return "SIMCom SIM800";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -312,6 +321,14 @@ public:
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -455,22 +472,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -591,6 +592,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIFSR;E0"));
 | 
			
		||||
    String res;
 | 
			
		||||
@@ -603,9 +608,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
@@ -800,6 +802,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
@@ -894,30 +900,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(const char c, const unsigned long timeout = 3000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  // enable GPS
 | 
			
		||||
  bool enableGPS() {
 | 
			
		||||
    uint16_t state;
 | 
			
		||||
    // uint16_t state;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSPWR=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
@@ -38,7 +38,7 @@ public:
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool disableGPS() {
 | 
			
		||||
    uint16_t state;
 | 
			
		||||
    // uint16_t state;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSPWR=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
@@ -65,7 +65,7 @@ public:
 | 
			
		||||
  // works only with ans SIM808 V2
 | 
			
		||||
  bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
 | 
			
		||||
    //String buffer = "";
 | 
			
		||||
    char chr_buffer[12];
 | 
			
		||||
    // char chr_buffer[12];
 | 
			
		||||
    bool fix = false;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSINF"));
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmUBLOX
 | 
			
		||||
class TinyGsmUBLOX : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -123,7 +123,7 @@ public:
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size) {
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
@@ -201,7 +201,7 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmUBLOX(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -209,9 +209,6 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin(const char* pin = NULL) {
 | 
			
		||||
    return init(pin);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
@@ -228,6 +225,10 @@ public:
 | 
			
		||||
    return (getSimStatus() == SIM_READY);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "u-blox Cellular Modem";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -280,6 +281,14 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -400,22 +409,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -481,6 +474,10 @@ public:
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+UPSND=0,0"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
 | 
			
		||||
@@ -495,10 +492,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -566,6 +559,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) {
 | 
			
		||||
@@ -659,30 +656,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ enum XBeeType {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmXBee
 | 
			
		||||
class TinyGsmXBee : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -207,17 +207,14 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmXBee(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    guardTime = 1100;  // Start with a default guard time of 1 second
 | 
			
		||||
 | 
			
		||||
    if (!commandMode(10)) return false;  // Try up to 10 times for the init
 | 
			
		||||
@@ -242,6 +239,10 @@ public:
 | 
			
		||||
    return ret_val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return getBeeName();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    if (!commandMode()) return;
 | 
			
		||||
    switch(baud)
 | 
			
		||||
@@ -309,6 +310,16 @@ public:
 | 
			
		||||
    else return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    if (beeType == XBEE_S6B_WIFI) return true;
 | 
			
		||||
    else return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    if (beeType == XBEE_S6B_WIFI) return false;
 | 
			
		||||
    else return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  XBeeType getBeeType() {
 | 
			
		||||
    return beeType;
 | 
			
		||||
  }
 | 
			
		||||
@@ -321,6 +332,7 @@ public:
 | 
			
		||||
      case XBEE3_LTE1_ATT: return "Digi XBee3™ Cellular LTE CAT 1";
 | 
			
		||||
      case XBEE3_LTEM_ATT: return "Digi XBee3™ Cellular LTE-M";
 | 
			
		||||
      case XBEE3_LTENB: return "Digi XBee3™ Cellular NB-IoT";
 | 
			
		||||
      default:  return "Digi XBee®";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -555,6 +567,10 @@ fail:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    if (!commandMode()) return "";  // Return immediately
 | 
			
		||||
    sendAT(GF("MY"));
 | 
			
		||||
@@ -566,10 +582,6 @@ fail:
 | 
			
		||||
    return IPaddr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -639,6 +651,10 @@ fail:
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) {
 | 
			
		||||
@@ -704,63 +720,15 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  void streamClear(void) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    while (stream.available()) { stream.read(); }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool commandMode(int retries = 2) {
 | 
			
		||||
    int triesMade = 0;
 | 
			
		||||
    bool success = false;
 | 
			
		||||
    streamClear();  // Empty everything in the buffer before starting
 | 
			
		||||
    while (!success and triesMade < retries) {
 | 
			
		||||
      // Cannot send anything for 1 "guard time" before entering command mode
 | 
			
		||||
      // Default guard time is 1s, but the init fxn decreases it to 250 ms
 | 
			
		||||
      delay(guardTime);
 | 
			
		||||
      streamWrite(GF("+++"));  // enter command mode
 | 
			
		||||
      DBG("+++");
 | 
			
		||||
      success = (1 == waitResponse(guardTime*2));
 | 
			
		||||
      triesMade ++;
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool writeChanges(void) {
 | 
			
		||||
    sendAT(GF("WR"));  // Write changes to flash
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    sendAT(GF("AC"));  // Apply changes
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void exitCommand(void) {
 | 
			
		||||
    sendAT(GF("CN"));  // Exit command mode
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String readResponse(uint32_t timeout = 1000) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (!stream.available() && millis() - startMillis < timeout) {};
 | 
			
		||||
    String res = stream.readStringUntil('\r');  // lines end with carriage returns
 | 
			
		||||
    res.trim();
 | 
			
		||||
    DBG("<<< ", res);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
@@ -825,6 +793,7 @@ finish:
 | 
			
		||||
        // DBG("<<< ", data);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -842,6 +811,45 @@ finish:
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool commandMode(int retries = 2) {
 | 
			
		||||
    int triesMade = 0;
 | 
			
		||||
    bool success = false;
 | 
			
		||||
    streamClear();  // Empty everything in the buffer before starting
 | 
			
		||||
    while (!success and triesMade < retries) {
 | 
			
		||||
      // Cannot send anything for 1 "guard time" before entering command mode
 | 
			
		||||
      // Default guard time is 1s, but the init fxn decreases it to 250 ms
 | 
			
		||||
      delay(guardTime);
 | 
			
		||||
      streamWrite(GF("+++"));  // enter command mode
 | 
			
		||||
      DBG("+++");
 | 
			
		||||
      success = (1 == waitResponse(guardTime*2));
 | 
			
		||||
      triesMade ++;
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool writeChanges(void) {
 | 
			
		||||
    sendAT(GF("WR"));  // Write changes to flash
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    sendAT(GF("AC"));  // Apply changes
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void exitCommand(void) {
 | 
			
		||||
    sendAT(GF("CN"));  // Exit command mode
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String readResponse(uint32_t timeout = 1000) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (!stream.available() && millis() - startMillis < timeout) {};
 | 
			
		||||
    String res = stream.readStringUntil('\r');  // lines end with carriage returns
 | 
			
		||||
    res.trim();
 | 
			
		||||
    DBG("<<< ", res);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ namespace {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
  #define DBG_PLAIN(...)
 | 
			
		||||
  #define DBG(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -194,4 +195,135 @@ String TinyGsmDecodeHex16bit(String &instr) {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmModem(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Prepare the modem for further functionality
 | 
			
		||||
  virtual bool init(const char* pin = NULL) = 0;
 | 
			
		||||
  // Begin is redundant with init
 | 
			
		||||
  virtual bool begin(const char* pin = NULL) {
 | 
			
		||||
    return init(pin);
 | 
			
		||||
  }
 | 
			
		||||
  // Returns a string with the chip name
 | 
			
		||||
  virtual String getModemName() = 0;
 | 
			
		||||
  // Sets the serial communication baud rate
 | 
			
		||||
  virtual void setBaud(unsigned long baud) = 0;
 | 
			
		||||
  // Checks that the modem is responding to standard AT commands
 | 
			
		||||
  virtual bool testAT(unsigned long timeout = 10000L) = 0;
 | 
			
		||||
  // Holds open communication with the modem waiting for data to come in
 | 
			
		||||
  virtual void maintain() = 0;
 | 
			
		||||
  // Resets all modem chip settings to factor defaults
 | 
			
		||||
  virtual bool factoryDefault() = 0;
 | 
			
		||||
  // Returns the response to a get info request.  The format varies by modem.
 | 
			
		||||
  virtual String getModemInfo() = 0;
 | 
			
		||||
  // Answers whether types of communication are available on this modem
 | 
			
		||||
  virtual bool hasSSL() = 0;
 | 
			
		||||
  virtual bool hasWifi() = 0;
 | 
			
		||||
  virtual bool hasGPRS() = 0;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool restart() = 0;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions - only apply to cellular modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool simUnlock(const char *pin) { return false; }
 | 
			
		||||
  virtual String getSimCCID() { return ""; }
 | 
			
		||||
  virtual String getIMEI() { return ""; }
 | 
			
		||||
  virtual String getOperator() { return ""; }
 | 
			
		||||
 | 
			
		||||
 /*
 | 
			
		||||
  * Generic network functions
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
  virtual int getSignalQuality() = 0;
 | 
			
		||||
  // NOTE:  this returns whether the modem is registered on the cellular or WiFi
 | 
			
		||||
  // network NOT whether GPRS or other internet connections are available
 | 
			
		||||
  virtual bool isNetworkConnected() = 0;
 | 
			
		||||
  virtual bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions - only apply to WiFi modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool networkConnect(const char* ssid, const char* pwd) { return false; }
 | 
			
		||||
  virtual bool networkDisconnect() { return false; }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions - only apply to cellular modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  virtual bool gprsDisconnect() { return false; }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual String getLocalIP() = 0;
 | 
			
		||||
  virtual IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     Utilities
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void streamWrite(T last) {
 | 
			
		||||
      stream.print(last);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename... Args>
 | 
			
		||||
    void streamWrite(T head, Args... tail) {
 | 
			
		||||
      stream.print(head);
 | 
			
		||||
      streamWrite(tail...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool streamSkipUntil(const char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
      unsigned long startMillis = millis();
 | 
			
		||||
      while (millis() - startMillis < timeout) {
 | 
			
		||||
        while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
          TINY_GSM_YIELD();
 | 
			
		||||
        }
 | 
			
		||||
        if (stream.read() == c)
 | 
			
		||||
          return true;
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user