diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 6200f52a..dc2ab41d 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -41,340 +41,77 @@ class TinyGsmSim7000 : public TinyGsmSim70xx, friend class TinyGsmNTP; friend class TinyGsmBattery; - /* - * Inner Client - */ - public: - class GsmClientSim7000 : public GsmClient { - friend class TinyGsmSim7000; - - public: - GsmClientSim7000() {} - - explicit GsmClientSim7000(TinyGsmSim7000& modem, uint8_t mux = 0) { - init(&modem, mux); - } - - bool init(TinyGsmSim7000* modem, uint8_t mux = 0) { - this->at = modem; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; - - if (mux < TINY_GSM_MUX_COUNT) { - this->mux = mux; - } else { - this->mux = (mux % TINY_GSM_MUX_COUNT); - } - at->sockets[this->mux] = this; - - return true; - } - - public: - virtual int connect(const char* host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } - TINY_GSM_CLIENT_CONNECT_OVERRIDES - - void stop(uint32_t maxWaitMs) { - dumpModemBuffer(maxWaitMs); - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(3000); - } - void stop() override { - stop(15000L); - } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - }; - - /* - * Inner Secure Client - */ - // NOTE: Use modem TINYGSMSIM7000SSL for a secure client! - - public: - boolean isValidNumber(String str) { - if (!(str.charAt(0) == '+' || str.charAt(0) == '-' || - isDigit(str.charAt(0)))) { - return false; - } + /* + * Inner Client + */ + public: + class GsmClientSim7000 : public GsmClient { + friend class TinyGsmSim7000; - for (byte i = 1; i < str.length(); i++) { - if (!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) { - return false; - } - } - return true; - } + public: + GsmClientSim7000() {} - String ShowNTPError(byte error) { - switch (error) { - case 1: - return "Network time synchronization is successful"; - case 61: - return "Network error"; - case 62: - return "DNS resolution error"; - case 63: - return "Connection error"; - case 64: - return "Service response error"; - case 65: - return "Service response timeout"; - default: - return "Unknown error: " + String(error); - } + explicit GsmClientSim7000(TinyGsmSim7000& modem, uint8_t mux = 0) { + init(&modem, mux); } - byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) { - // Set GPRS bearer profile to associate with NTP sync - sendAT(GF("+CNTPCID=1")); - if (waitResponse(10000L) != 1) { - return -1; - } - - // Set NTP server and timezone - sendAT(GF("+CNTP="), server, ',', String(TimeZone)); - if (waitResponse(10000L) != 1) { - return -1; - } + bool init(TinyGsmSim7000* modem, uint8_t mux = 0) { + this->at = modem; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - // Request network synchronization - sendAT(GF("+CNTP")); - if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) { - String result = stream.readStringUntil('\n'); - result.trim(); - if (isValidNumber(result)) { - return result.toInt(); - } + if (mux < TINY_GSM_MUX_COUNT) { + this->mux = mux; } else { - return -1; - } - return -1; - } - - /* - * Constructor - */ - public: - explicit TinyGsmSim7000(Stream& stream) - : TinyGsmSim70xx(stream) { - memset(sockets, 0, sizeof(sockets)); - } - - /* - * Basic functions - */ - protected: - bool initImpl(const char* pin = NULL) { - DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); - DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7000")); - - if (!testAT()) { - return false; - } - - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } - - #ifdef TINY_GSM_DEBUG - sendAT(GF("+CMEE=2")); // turn on verbose error codes - #else - sendAT(GF("+CMEE=0")); // turn off error codes - #endif - waitResponse(); - - DBG(GF("### Modem:"), getModemName()); - - // Enable Local Time Stamp for getting network time - sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { - return false; - } - - // Enable battery checks - sendAT(GF("+CBATCHK=1")); - if (waitResponse() != 1) { - return false; + this->mux = (mux % TINY_GSM_MUX_COUNT); } + at->sockets[this->mux] = this; - SimStatus ret = getSimStatus(); - // if the sim isn't ready and a pin has been provided, try to unlock the sim - if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { - simUnlock(pin); - return (getSimStatus() == SIM_READY); - } else { - // if the sim is ready, or it's locked but no pin has been provided, - // return true - return (ret == SIM_READY || ret == SIM_LOCKED); - } + return true; } - /* - * Power functions - */ - protected: - // Follows the SIM70xx template - - /* - * Generic network functions - */ - protected: - String getLocalIPImpl() { - sendAT(GF("+CIFSR;E0")); - String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } - res.replace(GSM_NL "OK" GSM_NL, ""); - res.replace(GSM_NL, ""); - res.trim(); - return res; + public: + virtual int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - /* - * GPRS functions - */ - protected: - bool gprsConnectImpl(const char* apn, const char* user = NULL, - const char* pwd = NULL) { - gprsDisconnect(); - - // Bearer settings for applications based on IP - // Set the connection type to GPRS - sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); - waitResponse(); - - // Set the APN - sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); - waitResponse(); - - // Set the user name - if (user && strlen(user) > 0) { - sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); - waitResponse(); - } - // Set the password - if (pwd && strlen(pwd) > 0) { - sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); - waitResponse(); - } - - // Define the PDP context - sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); - waitResponse(); - - // Attach to GPRS - sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) { - return false; - } - - // Activate the PDP context - sendAT(GF("+CGACT=1,1")); - waitResponse(60000L); - - // Open the definied GPRS bearer context - sendAT(GF("+SAPBR=1,1")); - waitResponse(85000L); - // Query the GPRS bearer context status - sendAT(GF("+SAPBR=2,1")); - if (waitResponse(30000L) != 1) { - return false; - } - - // Set the TCP application toolkit to multi-IP - sendAT(GF("+CIPMUX=1")); - if (waitResponse() != 1) { - return false; - } - - // Put the TCP application toolkit in "quick send" mode - // (thus no extra "Send OK") - sendAT(GF("+CIPQSEND=1")); - if (waitResponse() != 1) { - return false; - } - - // Set the TCP application toolkit to get data manually - sendAT(GF("+CIPRXGET=1")); - if (waitResponse() != 1) { - return false; - } - - // Start the TCP application toolkit task and set APN, USER NAME, PASSWORD - sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse(60000L) != 1) { - return false; - } - - // Bring up the TCP application toolkit wireless connection with GPRS or CSD - sendAT(GF("+CIICR")); - if (waitResponse(60000L) != 1) { - return false; - } - - // Get local IP address for the TCP application toolkit - // only assigned after connection - sendAT(GF("+CIFSR;E0")); - if (waitResponse(10000L) != 1) { - return false; - } - - return true; + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(3000); } - - bool gprsDisconnectImpl() { - // Shut the TCP application toolkit connection - // CIPSHUT will close *all* open TCP application toolkit connections - sendAT(GF("+CIPSHUT")); - if (waitResponse(60000L) != 1) { - return false; - } - - sendAT(GF("+CGATT=0")); // Deactivate the bearer context - if (waitResponse(60000L) != 1) { - return false; - } - - return true; + void stop() override { + stop(15000L); } /* - * SIM card functions + * Extended API */ - protected: - // Follows the SIM70xx template - /* - * Messaging functions - */ - protected: - // Follows all messaging functions per template + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* * Inner Secure Client */ // NOTE: Use modem TinyGsmSim7000SSL for a secure client! - /* - * Time functions - */ - // Can follow CCLK as per template + /* + * Constructor + */ + public: + explicit TinyGsmSim7000(Stream& stream) + : TinyGsmSim70xx(stream) { + memset(sockets, 0, sizeof(sockets)); + } /* * Basic functions @@ -384,11 +121,7 @@ class TinyGsmSim7000 : public TinyGsmSim70xx, DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7000")); - /* - * Battery functions - */ - protected: - // Follows all battery functions per template + if (!testAT()) { return false; } sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } @@ -667,73 +400,43 @@ class TinyGsmSim7000 : public TinyGsmSim70xx, #endif sockets[mux]->rx.put(c); } + // DBG("### READ:", len_requested, "from", mux); + // sockets[mux]->sock_available = modemGetAvailable(mux); + sockets[mux]->sock_available = len_confirmed; + waitResponse(); + return len_requested; + } - int16_t modemSend(const void* buff, size_t len, uint8_t mux) { - sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - - stream.write(reinterpret_cast(buff), len); - stream.flush(); + size_t modemGetAvailable(uint8_t mux) { + if (!sockets[mux]) return 0; - if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { - return 0; - } + sendAT(GF("+CIPRXGET=4,"), mux); + size_t result = 0; + if (waitResponse(GF("+CIPRXGET:")) == 1) { + streamSkipUntil(','); // Skip mode 4 streamSkipUntil(','); // Skip mux - return streamGetIntBefore('\n'); + result = streamGetIntBefore('\n'); + waitResponse(); } + // DBG("### Available:", result, "on", mux); + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } + return result; + } - size_t modemRead(size_t size, uint8_t mux) { - if (!sockets[mux]) { - return 0; - } + bool modemGetConnected(uint8_t mux) { + sendAT(GF("+CIPSTATUS="), mux); + waitResponse(GF("+CIPSTATUS")); + int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), + GF(",\"CLOSING\""), GF(",\"REMOTE CLOSING\""), + GF(",\"INITIAL\"")); + waitResponse(); + return 1 == res; + } /* * Utilities */ public: - - uint8_t getNetworkSystemMode() { - sendAT(GF("+CNSMOD?")); - if (waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { - return 0; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res = res.substring(3); - return atoi(res.c_str()); - } - - String getGnssSystemMode() { - sendAT(GF("+CGNSMOD?")); - if (waitResponse(GF(GSM_NL "+CGNSMOD:")) != 1) { - return "Gnss system mode not available"; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - - return res; - } - - bool enableGpio(uint8_t gpio, bool enable){ - //AT+SGPIO=,,, - // 0 Set the GPIO function including the GPIO output. 1 Read the GPIO level. - // Please note that only when the gpioisset asinput, user can use parameter 1 to read the GPIO level, otherwisethemodule will return "ERROR". - // The GPIO you want to be set. (It has relations with the hardware, please refer to the hardware manual) - // Only when is set to 0, this option takes effect. 0 Set the GPIO to input. 1 Set the GPIO to output - // 0 GPIO low level 1 GPIO high level - if(gpio > 7){ - log_w("invalid gpio"); - return false; - } - char msg[20] = {}; - sprintf(msg, "+SGPIO=0,%d,1,%d", gpio, enable); - sendAT(GF(msg)); - - return waitResponse(10000L, GF("OK")) == 1; - } - bool handleURCs(String& data) { if (data.endsWith(GF(AT_NL "+CIPRXGET:"))) { int8_t mode = streamGetIntBefore(','); @@ -798,8 +501,8 @@ class TinyGsmSim7000 : public TinyGsmSim70xx, return false; } - protected: - GsmClientSim7000* sockets[TINY_GSM_MUX_COUNT]; + protected: + GsmClientSim7000* sockets[TINY_GSM_MUX_COUNT]; }; #endif // SRC_TINYGSMCLIENTSIM7000_H_ diff --git a/src/TinyGsmClientSIM7080.h b/src/TinyGsmClientSIM7080.h index d39cb861..8af5465e 100644 --- a/src/TinyGsmClientSIM7080.h +++ b/src/TinyGsmClientSIM7080.h @@ -44,656 +44,60 @@ class TinyGsmSim7080 : public TinyGsmSim70xx, friend class TinyGsmNTP; friend class TinyGsmBattery; - /* - * Inner Client - */ - public: - class GsmClientSim7080 : public GsmClient { - friend class TinyGsmSim7080; - - public: - GsmClientSim7080() {} - - explicit GsmClientSim7080(TinyGsmSim7080& modem, uint8_t mux = 0) { - init(&modem, mux); - } - - bool init(TinyGsmSim7080* modem, uint8_t mux = 0) { - this->at = modem; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; - - if (mux < TINY_GSM_MUX_COUNT) { - this->mux = mux; - } else { - this->mux = (mux % TINY_GSM_MUX_COUNT); - } - at->sockets[this->mux] = this; - - return true; - } - - public: - virtual int connect(const char* host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } - TINY_GSM_CLIENT_CONNECT_OVERRIDES - - void stop(uint32_t maxWaitMs) { - dumpModemBuffer(maxWaitMs); - at->sendAT(GF("+CACLOSE="), mux); - sock_connected = false; - at->waitResponse(3000); - } - void stop() override { - stop(15000L); - } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - }; - - /* - * Inner Secure Client - */ - - class GsmClientSecureSIM7080 : public GsmClientSim7080 { - public: - GsmClientSecureSIM7080() {} - - explicit GsmClientSecureSIM7080(TinyGsmSim7080& modem, uint8_t mux = 0) - : GsmClientSim7080(modem, mux) {} - - public: - bool setCertificate(const String& certificateName) { - return at->setCertificate(certificateName, mux); - } - - virtual int connect(const char* host, uint16_t port, - int timeout_s) override { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } - TINY_GSM_CLIENT_CONNECT_OVERRIDES - }; - - /* - * Constructor - */ - public: - explicit TinyGsmSim7080(Stream& stream) - : TinyGsmSim70xx(stream), - certificates() { - memset(sockets, 0, sizeof(sockets)); - } - - /* - * Basic functions - */ - protected: - bool initImpl(const char* pin = NULL) { - DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); - DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7080")); - - if (!testAT()) { - return false; - } - - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } - - #ifdef TINY_GSM_DEBUG - sendAT(GF("+CMEE=2")); // turn on verbose error codes - #else - sendAT(GF("+CMEE=0")); // turn off error codes - #endif - waitResponse(); - - DBG(GF("### Modem:"), getModemName()); - - // Enable Local Time Stamp for getting network time - sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { - return false; - } - - // Enable battery checks - sendAT(GF("+CBATCHK=1")); - if (waitResponse() != 1) { - return false; - } - - SimStatus ret = getSimStatus(); - // if the sim isn't ready and a pin has been provided, try to unlock the sim - if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { - simUnlock(pin); - return (getSimStatus() == SIM_READY); - } else { - // if the sim is ready, or it's locked but no pin has been provided, - // return true - return (ret == SIM_READY || ret == SIM_LOCKED); - } - } - - void maintainImpl() { - // Keep listening for modem URC's and proactively iterate through - // sockets asking if any data is avaiable - bool check_socks = false; - for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { - GsmClientSim7080* sock = sockets[mux]; - if (sock && sock->got_data) { - sock->got_data = false; - check_socks = true; - } - } - // modemGetAvailable checks all socks, so we only want to do it once - // modemGetAvailable calls modemGetConnected(), which also checks allf - if (check_socks) { - modemGetAvailable(0); - } - while (stream.available()) { - waitResponse(15, NULL, NULL); - } - } - - /* - * Power functions - */ - protected: - // Follows the SIM70xx template + /* + * Inner Client + */ + public: + class GsmClientSim7080 : public GsmClient { + friend class TinyGsmSim7080; - /* - * Generic network functions - */ - protected: - String getLocalIPImpl() { - sendAT(GF("+CNACT?")); - if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { - return ""; - } - streamSkipUntil('\"'); - String res = stream.readStringUntil('\"'); - waitResponse(); - return res; - } + public: + GsmClientSim7080() {} - /* - * Secure socket layer functions - */ - protected: - bool setCertificate(const String& certificateName, const uint8_t mux = 0) { - if (mux >= TINY_GSM_MUX_COUNT) { - return false; - } - certificates[mux] = certificateName; - return true; + explicit GsmClientSim7080(TinyGsmSim7080& modem, uint8_t mux = 0) { + init(&modem, mux); } - /* - * GPRS functions - */ - protected: - bool gprsConnectImpl(const char* apn, const char* user = NULL, - const char* pwd = NULL) { - gprsDisconnect(); - - // Define the PDP context - sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); - waitResponse(); - - // Attach to GPRS - sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) { - return false; - } + bool init(TinyGsmSim7080* modem, uint8_t mux = 0) { + this->at = modem; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - // NOTE: **DO NOT** activate the PDP context - // For who only knows what reason, doing so screws up the rest of the - // process - - // Check the APN returned by the server - // not sure why, but the connection is more consistent with this - sendAT(GF("+CGNAPN")); - waitResponse(); - - // Bearer settings for applications based on IP - // Set the user name and password - // AT+CNCFG=,,[,[,,[]]] - // PDP Context Identifier - for reasons not understood by me, - // use PDP context identifier of 0 for what we defined as 1 above - // 0: Dual PDN Stack - // 1: Internet Protocol Version 4 - // 2: Internet Protocol Version 6 - // 0: NONE - // 1: PAP - // 2: CHAP - // 3: PAP or CHAP - if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) { - sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, "\",\"", pwd, '"'); - waitResponse(); - } else if (user && strlen(user) > 0) { - // Set the user name only - sendAT(GF("+CNCFG=0,1,\""), apn, "\",\"", user, '"'); - waitResponse(); + if (mux < TINY_GSM_MUX_COUNT) { + this->mux = mux; } else { - // Set the APN only - sendAT(GF("+CNCFG=0,1,\""), apn, '"'); - waitResponse(); - } - - // Activate application network connection - // AT+CNACT=, - // PDP Context Identifier - for reasons not understood by me, - // use PDP context identifier of 0 for what we defined as 1 above - // 0: Deactive - // 1: Active - // 2: Auto Active - bool res = false; - int ntries = 0; - while (!res && ntries < 5) { - sendAT(GF("+CNACT=0,1")); - res = waitResponse(60000L, GF(GSM_NL "+APP PDP: 0,ACTIVE"), - GF(GSM_NL "+APP PDP: 0,DEACTIVE")); - waitResponse(); - ntries++; - } - - return res; - } - - bool gprsDisconnectImpl() { - // Shut down the general application TCP/IP connection - // CNACT will close *all* open application connections - sendAT(GF("+CNACT=0,0")); - if (waitResponse(60000L) != 1) { - return false; - } - - sendAT(GF("+CGATT=0")); // Deactivate the bearer context - if (waitResponse(60000L) != 1) { - return false; + this->mux = (mux % TINY_GSM_MUX_COUNT); } + at->sockets[this->mux] = this; return true; } - /* - * SIM card functions - */ - protected: - // Follows the SIM70xx template - - /* - * Messaging functions - */ - protected: - // Follows all messaging functions per template - - /* - * GPS/GNSS/GLONASS location functions - */ - protected: - // Follows the SIM70xx template - - /* - * Time functions - */ - // Can follow CCLK as per template - - /* - * NTP server functions - */ - // Can sync with server using CNTP as per template - - /* - * Battery functions - */ - protected: - // Follows all battery functions per template - - /* - * Client related functions - */ - - public: - uint8_t getNetworkSystemMode() { - sendAT(GF("+CNSMOD?")); - if (waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { - return 0; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res = res.substring(3); - return atoi(res.c_str()); - } - - String getGnssSystemMode() { - sendAT(GF("+CGNSMOD?")); - if (waitResponse(GF(GSM_NL "+CGNSMOD:")) != 1) { - return "Gnss system mode not available"; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - - return res; - } - - bool enableGpio(uint8_t gpio, bool enable) { - //AT+SGPIO=,,, - // 0 Set the GPIO function including the GPIO output. 1 Read the GPIO level. - // Please note that only when the gpioisset asinput, user can use parameter 1 to read the GPIO level, otherwisethemodule will return "ERROR". - // The GPIO you want to be set. (It has relations with the hardware, please refer to the hardware manual) - // Only when is set to 0, this option takes effect. 0 Set the GPIO to input. 1 Set the GPIO to output - // 0 GPIO low level 1 GPIO high level - if (gpio > 7) { - log_w("invalid gpio"); - return false; - } - char msg[20] = {}; - sprintf(msg, "+SGPIO=0,%d,1,%d", gpio, enable); - sendAT(GF(msg)); - - return waitResponse(10000L, GF("OK")) == 1; - } - - protected: - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) { - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - - // set the connection (mux) identifier to use - sendAT(GF("+CACID="), mux); - if (waitResponse(timeout_ms) != 1) { - return false; - } - - - if (ssl) { - // set the ssl version - // AT+CSSLCFG="SSLVERSION",, - // PDP context identifier - // 0: QAPI_NET_SSL_PROTOCOL_UNKNOWN - // 1: QAPI_NET_SSL_PROTOCOL_TLS_1_0 - // 2: QAPI_NET_SSL_PROTOCOL_TLS_1_1 - // 3: QAPI_NET_SSL_PROTOCOL_TLS_1_2 - // 4: QAPI_NET_SSL_PROTOCOL_DTLS_1_0 - // 5: QAPI_NET_SSL_PROTOCOL_DTLS_1_2 - // NOTE: despite docs using caps, "sslversion" must be in lower case - sendAT(GF("+CSSLCFG=\"sslversion\",0,3")); // TLS 1.2 - if (waitResponse(5000L) != 1) { - return false; - } - } - - // enable or disable ssl - // AT+CASSLCFG=,"SSL", - // Application connection ID (set with AT+CACID above) - // 0: Not support SSL - // 1: Support SSL - sendAT(GF("+CASSLCFG="), mux, ',', GF("SSL,"), ssl); - waitResponse(); - - if (ssl) { - // set the PDP context to apply SSL to - // AT+CSSLCFG="CTXINDEX", - // PDP context identifier - // NOTE: despite docs using "CRINDEX" in all caps, the module only - // accepts the command "ctxindex" and it must be in lower case - sendAT(GF("+CSSLCFG=\"ctxindex\",0")); - if (waitResponse(5000L, GF("+CSSLCFG:")) != 1) { - return false; - } - streamSkipUntil('\n'); // read out the certificate information - waitResponse(); - - if (certificates[mux] != "") { - // apply the correct certificate to the connection - // AT+CASSLCFG=,"CACERT", - // Application connection ID (set with AT+CACID above) - // certificate name - sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(), - "\""); - if (waitResponse(5000L) != 1) { - return false; - } - } - - // set the SSL SNI (server name indication) - // NOTE: despite docs using caps, "sni" must be in lower case - sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\"")); - waitResponse(); - } - - // actually open the connection - // AT+CAOPEN=,,,,[,] - // TCP/UDP identifier - // Index of PDP connection; we set up PCP context 1 above - // "TCP" or "UDP" - // 0: The received data can only be read manually using - // AT+CARECV= - // 1: After receiving the data, it will automatically report - // URC: - // +CAURC: - // "recv",,,, - // NOTE: including the fails - sendAT(GF("+CAOPEN="), mux, GF(",0,\"TCP\",\""), host, GF("\","), port); - if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { - return 0; - } - // returns OK/r/n/r/n+CAOPEN: , - // 0: Success - // 1: Socket error - // 2: No memory - // 3: Connection limit - // 4: Parameter invalid - // 6: Invalid IP address - // 7: Not support the function - // 12: Can’t bind the port - // 13: Can’t listen the port - // 20: Can’t resolve the host - // 21: Network not active - // 23: Remote refuse - // 24: Certificate’s time expired - // 25: Certificate’s common name does not match - // 26: Certificate’s common name does not match and time expired - // 27: Connect failed - streamSkipUntil(','); // Skip mux - - // make sure the connection really opened - int8_t res = streamGetIntBefore('\n'); - waitResponse(); - - return 0 == res; - } - - int16_t modemSend(const void* buff, size_t len, uint8_t mux) { - // send data on prompt - sendAT(GF("+CASEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - - stream.write(reinterpret_cast(buff), len); - stream.flush(); - - // OK after posting data - if (waitResponse() != 1) { - return 0; - } - - return len; - } - - size_t modemRead(size_t size, uint8_t mux) { - if (!sockets[mux]) { - return 0; - } - - sendAT(GF("+CARECV="), mux, ',', (uint16_t)size); - - if (waitResponse(GF("+CARECV:")) != 1) { - return 0; - } - - // uint8_t ret_mux = stream.parseInt(); - // streamSkipUntil(','); - // const int16_t len_confirmed = streamGetIntBefore('\n'); - // DBG("### READING:", len_confirmed, "from", ret_mux); - - // if (ret_mux != mux) { - // DBG("### Data from wrong mux! Got", ret_mux, "expected", mux); - // waitResponse(); - // sockets[mux]->sock_available = modemGetAvailable(mux); - // return 0; - // } - - // NOTE: manual says the mux number is returned before the number of - // characters available, but in tests only the number is returned - - int16_t len_confirmed = stream.parseInt(); - streamSkipUntil(','); // skip the comma - if (len_confirmed <= 0) { - waitResponse(); - sockets[mux]->sock_available = modemGetAvailable(mux); - return 0; - } - - for (int i = 0; i < len_confirmed; i++) { - uint32_t startMillis = millis(); - while (!stream.available() && - (millis() - startMillis < sockets[mux]->_timeout)) { - TINY_GSM_YIELD(); - } - char c = stream.read(); - sockets[mux]->rx.put(c); - } - waitResponse(); - // make sure the sock available number is accurate again - sockets[mux]->sock_available = modemGetAvailable(mux); - return len_confirmed; + public: + virtual int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - size_t modemGetAvailable(uint8_t mux) { - // Reset all sock_available values to 0 - for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { - GsmClientSim7080* sock = sockets[muxNo]; - if (sock) { - sock->sock_available = 0; - } - } - - // Request awaiting data, will return zero or more +CARECV: answers, ending with an OK - sendAT(GF("+CARECV?")); - - while (int result = waitResponse(3000, GF("+CARECV:"), GFP(GSM_OK), GFP(GSM_ERROR))) { - if (result == 1) { - // if we get the +CARECV: response, read the mux number and the number of - // characters available - int ret_mux = streamGetIntBefore(','); - size_t charsAvailable = streamGetIntBefore('\n'); - if (0 <= ret_mux && ret_mux < TINY_GSM_MUX_COUNT) { - GsmClientSim7080* sock = sockets[ret_mux]; - if (sock) { - sock->sock_available = charsAvailable; - } - } - } else { - // Ok, timeout or Error -> we're done - break; - } - } - - modemGetConnected(mux); // check the state of all connections - if (!sockets[mux]) { - return 0; - } - return sockets[mux]->sock_available; + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CACLOSE="), mux); + sock_connected = false; + at->waitResponse(3000); } - - bool modemGetConnected(uint8_t mux) { - // NOTE: This gets the state of all connections that have been opened - // since the last connection - sendAT(GF("+CASTATE?")); - - for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { - // after the last connection, there's an ok, so we catch it right away - int res = waitResponse(3000, GF("+CASTATE:"), GFP(GSM_OK), - GFP(GSM_ERROR)); - // if we get the +CASTATE: response, read the mux number and the status - if (res == 1) { - int ret_mux = streamGetIntBefore(','); - size_t status = streamGetIntBefore('\n'); - // 0: Closed by remote server or internal error - // 1: Connected to remote server - // 2: Listening (server mode) - GsmClientSim7080* sock = sockets[ret_mux]; - if (sock) { - sock->sock_connected = (status == 1); - } - // if the first returned mux isn't 0 (or is higher than expected) - // we need to fill in the missing muxes - if (ret_mux > muxNo) { - for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) { - GsmClientSim7080* isock = sockets[extra_mux]; - if (isock) { - isock->sock_connected = false; - } - } - muxNo = ret_mux; - } - } else if (res == 2) { - // if we get an OK, we've reached the last socket with available data - // so we set any we haven't gotten to yet to 0 - for (int extra_mux = muxNo; extra_mux < TINY_GSM_MUX_COUNT; - extra_mux++) { - GsmClientSim7080* isock = sockets[extra_mux]; - if (isock) { - isock->sock_connected = false; - } - } - break; - } else { - // if we got an error, give up - break; - } - // Should be a final OK at the end. - // If every connection was returned, catch the OK here. - // If only a portion were returned, catch it above. - if (muxNo == TINY_GSM_MUX_COUNT - 1) { - waitResponse(); - } - } - return sockets[mux]->sock_connected; + void stop() override { + stop(15000L); } /* - * Utilities + * Extended API */ - public: - uint8_t getNetworkSystemMode() { - sendAT(GF("+CNSMOD?")); - if (waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { - return 0; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res = res.substring(3); - return atoi(res.c_str()); - } String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; }; @@ -1190,13 +594,41 @@ class TinyGsmSim7080 : public TinyGsmSim70xx, for (int i = 0; i < len_confirmed; i++) { uint32_t startMillis = millis(); - do { + while (!stream.available() && + (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); - while (stream.available() > 0) { - TINY_GSM_YIELD(); - int8_t a = stream.read(); - if (a <= 0) { - continue; // Skip 0x00 bytes, just in case + } + char c = stream.read(); + sockets[mux]->rx.put(c); + } + waitResponse(); + // make sure the sock available number is accurate again + sockets[mux]->sock_available = modemGetAvailable(mux); + return len_confirmed; + } + + size_t modemGetAvailable(uint8_t mux) { + // If the socket doesn't exist, just return + if (!sockets[mux]) { return 0; } + // NOTE: This gets how many characters are available on all connections that + // have data. It does not return all the connections, just those with data. + sendAT(GF("+CARECV?")); + for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { + // after the last connection, there's an ok, so we catch it right away + int res = waitResponse(3000, GF("+CARECV:"), GFP(GSM_OK), GFP(GSM_ERROR)); + // if we get the +CARECV: response, read the mux number and the number of + // characters available + if (res == 1) { + int ret_mux = streamGetIntBefore(','); + size_t result = streamGetIntBefore('\n'); + GsmClientSim7080* sock = sockets[ret_mux]; + if (sock) { sock->sock_available = result; } + // if the first returned mux isn't 0 (or is higher than expected) + // we need to fill in the missing muxes + if (ret_mux > muxNo) { + for (int extra_mux = muxNo; extra_mux < ret_mux; extra_mux++) { + GsmClientSim7080* isock = sockets[extra_mux]; + if (isock) { isock->sock_available = 0; } } muxNo = ret_mux; } @@ -1302,14 +734,6 @@ class TinyGsmSim7080 : public TinyGsmSim70xx, sockets[mux]->sock_connected = false; DBG("### Closed: ", mux); } - } while (millis() - startMillis < timeout_ms); -finish: - if (!index) { - data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } - data = ""; } data = ""; return true; @@ -1343,9 +767,9 @@ class TinyGsmSim7080 : public TinyGsmSim70xx, return false; } - protected: - GsmClientSim7080* sockets[TINY_GSM_MUX_COUNT]; - String certificates[TINY_GSM_MUX_COUNT]; + protected: + GsmClientSim7080* sockets[TINY_GSM_MUX_COUNT]; + String certificates[TINY_GSM_MUX_COUNT]; }; #endif // SRC_TINYGSMCLIENTSIM7080_H_ diff --git a/src/TinyGsmClientSIM70xx.h b/src/TinyGsmClientSIM70xx.h index 70e02551..568ffd04 100644 --- a/src/TinyGsmClientSIM70xx.h +++ b/src/TinyGsmClientSIM70xx.h @@ -39,21 +39,8 @@ #include "TinyGsmModem.tpp" #include "TinyGsmGPRS.tpp" #include "TinyGsmGPS.tpp" -#include "TinyGsmModem.tpp" -#include "TinyGsmSMS.tpp" -#include "TinyGsmTime.tpp" -#include "TinyGsmNTP.tpp" -#include "TinyGsmGSMLocation.tpp" - -#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; -#if defined TINY_GSM_DEBUG -static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; -static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:"; -#endif -enum RegStatus { +enum SIM70xxRegStatus { REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, @@ -63,83 +50,45 @@ enum RegStatus { REG_UNKNOWN = 4, }; -template -class TinyGsmSim70xx : public TinyGsmModem>, - public TinyGsmGPRS>, - public TinyGsmSMS>, - public TinyGsmGPS>, - public TinyGsmTime>, - public TinyGsmNTP>, - public TinyGsmBattery>, - public TinyGsmGSMLocation> { - friend class TinyGsmModem>; - friend class TinyGsmGPRS>; - friend class TinyGsmSMS>; - friend class TinyGsmGPS>; - friend class TinyGsmTime>; - friend class TinyGsmNTP>; - friend class TinyGsmBattery>; - friend class TinyGsmGSMLocation>; +template +class TinyGsmSim70xx : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmGPS { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmGPS; /* * CRTP Helper */ protected: - inline const modemType& thisModem() const { - return static_cast(*this); + inline const SIM70xxType& thisModem() const { + return static_cast(*this); } - inline modemType& thisModem() { - return static_cast(*this); + inline SIM70xxType& thisModem() { + return static_cast(*this); } + ~TinyGsmSim70xx() {} - /* - * Constructor - */ - public: - explicit TinyGsmSim70xx(Stream& stream) : stream(stream) {} + /* + * Constructor + */ + public: + explicit TinyGsmSim70xx(Stream& stream) : stream(stream) {} /* * Basic functions */ protected: - bool initImpl(const char* pin = NULL) { - return thisModem().initImpl(pin); - } - - String getModemNameImpl() { - String name = "SIMCom SIM7000"; - - thisModem().sendAT(GF("+GMM")); - String res2; - if (thisModem().waitResponse(5000L, res2) != 1) { return name; } - res2.replace(GSM_NL "OK" GSM_NL, ""); - res2.replace("_", " "); - res2.trim(); - - name = res2; - return name; - } - - bool factoryDefaultImpl() { // these commands aren't supported - thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - thisModem().waitResponse(); - thisModem().sendAT(GF("+IPR=0")); // Auto-baud - thisModem().waitResponse(); - thisModem().sendAT(GF("+IFC=0,0")); // No Flow Control - thisModem().waitResponse(); - thisModem().sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop - thisModem().waitResponse(); - thisModem().sendAT(GF("+CSCLK=0")); // Disable Slow Clock - thisModem().waitResponse(); - thisModem().sendAT(GF("&W")); // Write configuration - return thisModem().waitResponse() == 1; + bool factoryDefaultImpl() { + return false; } /* * Power functions */ protected: - bool restartImpl(const char* pin = NULL) { + bool restartImpl(const char* pin = nullptr) { thisModem().sendAT(GF("E0")); // Echo Off thisModem().waitResponse(); if (!thisModem().setPhoneFunctionality(0)) { return false; } @@ -148,45 +97,45 @@ class TinyGsmSim70xx : public TinyGsmModem>, return thisModem().initImpl(pin); } - bool powerOffImpl() { - thisModem().sendAT(GF("+CPOWD=1")); - return thisModem().waitResponse(GF("NORMAL POWER DOWN")) == 1; - } + bool powerOffImpl() { + thisModem().sendAT(GF("+CPOWD=1")); + return thisModem().waitResponse(GF("NORMAL POWER DOWN")) == 1; + } - // During sleep, the SIM70xx module has its serial communication disabled. - // In order to reestablish communication pull the DRT-pin of the SIM70xx - // module LOW for at least 50ms. Then use this function to disable sleep - // mode. The DTR-pin can then be released again. - bool sleepEnableImpl(bool enable = true) { - thisModem().sendAT(GF("+CSCLK="), enable); - return thisModem().waitResponse() == 1; - } + // During sleep, the SIM70xx module has its serial communication disabled. + // In order to reestablish communication pull the DRT-pin of the SIM70xx + // module LOW for at least 50ms. Then use this function to disable sleep + // mode. The DTR-pin can then be released again. + bool sleepEnableImpl(bool enable = true) { + thisModem().sendAT(GF("+CSCLK="), enable); + return thisModem().waitResponse() == 1; + } - bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) { - thisModem().sendAT(GF("+CFUN="), fun, reset ? ",1" : ""); - return thisModem().waitResponse(10000L) == 1; - } + bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) { + thisModem().sendAT(GF("+CFUN="), fun, reset ? ",1" : ""); + return thisModem().waitResponse(10000L) == 1; + } /* * Generic network functions */ public: - RegStatus getRegistrationStatus() { - RegStatus epsStatus = - (RegStatus)thisModem().getRegistrationStatusXREG("CEREG"); + SIM70xxRegStatus getRegistrationStatus() { + SIM70xxRegStatus epsStatus = + (SIM70xxRegStatus)thisModem().getRegistrationStatusXREG("CEREG"); // If we're connected on EPS, great! if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) { return epsStatus; } else { // Otherwise, check GPRS network status // We could be using GPRS fall-back or the board could be being moody - return (RegStatus)thisModem().getRegistrationStatusXREG("CGREG"); + return (SIM70xxRegStatus)thisModem().getRegistrationStatusXREG("CGREG"); } } protected: bool isNetworkConnectedImpl() { - RegStatus s = getRegistrationStatus(); + SIM70xxRegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } @@ -194,7 +143,7 @@ class TinyGsmSim70xx : public TinyGsmModem>, String getNetworkModes() { // Get the help string, not the setting value thisModem().sendAT(GF("+CNMP=?")); - if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } + if (thisModem().waitResponse(GF(AT_NL "+CNMP:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); thisModem().waitResponse(); return res; @@ -202,25 +151,25 @@ class TinyGsmSim70xx : public TinyGsmModem>, int16_t getNetworkMode() { thisModem().sendAT(GF("+CNMP?")); - if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; } + if (thisModem().waitResponse(GF(AT_NL "+CNMP:")) != 1) { return false; } int16_t mode = thisModem().streamGetIntBefore('\n'); thisModem().waitResponse(); return mode; } - bool setNetworkMode(uint8_t mode) { - // 2 Automatic - // 13 GSM only - // 38 LTE only - // 51 GSM and LTE only - thisModem().sendAT(GF("+CNMP="), mode); - return thisModem().waitResponse() == 1; - } + bool setNetworkMode(uint8_t mode) { + // 2 Automatic + // 13 GSM only + // 38 LTE only + // 51 GSM and LTE only + thisModem().sendAT(GF("+CNMP="), mode); + return thisModem().waitResponse() == 1; + } String getPreferredModes() { // Get the help string, not the setting value thisModem().sendAT(GF("+CMNB=?")); - if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; } + if (thisModem().waitResponse(GF(AT_NL "+CMNB:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); thisModem().waitResponse(); return res; @@ -228,25 +177,25 @@ class TinyGsmSim70xx : public TinyGsmModem>, int16_t getPreferredMode() { thisModem().sendAT(GF("+CMNB?")); - if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return false; } + if (thisModem().waitResponse(GF(AT_NL "+CMNB:")) != 1) { return false; } int16_t mode = thisModem().streamGetIntBefore('\n'); thisModem().waitResponse(); return mode; } - bool setPreferredMode(uint8_t mode) { - // 1 CAT-M - // 2 NB-IoT - // 3 CAT-M and NB-IoT - thisModem().sendAT(GF("+CMNB="), mode); - return thisModem().waitResponse() == 1; - } + bool setPreferredMode(uint8_t mode) { + // 1 CAT-M + // 2 NB-IoT + // 3 CAT-M and NB-IoT + thisModem().sendAT(GF("+CMNB="), mode); + return thisModem().waitResponse() == 1; + } bool getNetworkSystemMode(bool& n, int16_t& stat) { // n: whether to automatically report the system mode info // stat: the current service. 0 if it not connected thisModem().sendAT(GF("+CNSMOD?")); - if (thisModem().waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { return false; } + if (thisModem().waitResponse(GF(AT_NL "+CNSMOD:")) != 1) { return false; } n = thisModem().streamGetIntBefore(',') != 0; stat = thisModem().streamGetIntBefore('\n'); thisModem().waitResponse(); @@ -259,23 +208,11 @@ class TinyGsmSim70xx : public TinyGsmModem>, return thisModem().waitResponse() == 1; } - String getLocalIPImpl() { - return thisModem().getLocalIPImpl(); - } - /* * GPRS functions */ protected: // should implement in sub-classes - bool gprsConnectImpl(const char* apn, const char* user = NULL, - const char* pwd = NULL) { - return thisModem().gprsConnectImpl(apn, user, pwd); - } - - bool gprsDisconnectImpl() { - return thisModem().gprsDisconnectImpl(); - } /* * SIM card functions @@ -284,7 +221,7 @@ class TinyGsmSim70xx : public TinyGsmModem>, // Doesn't return the "+CCID" before the number String getSimCCIDImpl() { thisModem().sendAT(GF("+CCID")); - if (thisModem().waitResponse(GF(GSM_NL)) != 1) { return ""; } + if (thisModem().waitResponse(GF(AT_NL)) != 1) { return ""; } String res = stream.readStringUntil('\n'); thisModem().waitResponse(); res.trim(); @@ -292,44 +229,26 @@ class TinyGsmSim70xx : public TinyGsmModem>, } /* - * Messaging functions + * GPS/GNSS/GLONASS location functions */ protected: - // Follows all messaging functions per template - - /* - * GPS/GNSS/GLONASS location functions - */ - protected: - // enable GPS - bool enableGPSImpl() { - thisModem().sendAT(GF("+CGNSPWR=1")); - if (thisModem().waitResponse() != 1) { - return false; - } - return true; - } - - bool disableGPSImpl() { - thisModem().sendAT(GF("+CGNSPWR=0")); - if (thisModem().waitResponse() != 1) { - return false; - } - return true; - } + // enable GPS + bool enableGPSImpl() { + thisModem().sendAT(GF("+CGNSPWR=1")); + if (thisModem().waitResponse() != 1) { return false; } + return true; + } - bool gpsEnabledImpl() { - thisModem().sendAT(GF("+CGNSPWR?")); - if (thisModem().waitResponse() != 1) { - return false; - } - return true; - } + bool disableGPSImpl() { + thisModem().sendAT(GF("+CGNSPWR=0")); + if (thisModem().waitResponse() != 1) { return false; } + return true; + } // get the RAW GPS output String getGPSrawImpl() { thisModem().sendAT(GF("+CGNSINF")); - if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { + if (thisModem().waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); @@ -344,152 +263,88 @@ class TinyGsmSim70xx : public TinyGsmModem>, int* year = 0, int* month = 0, int* day = 0, int* hour = 0, int* minute = 0, int* second = 0) { thisModem().sendAT(GF("+CGNSINF")); - if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { + if (thisModem().waitResponse(10000L, GF(AT_NL "+CGNSINF:")) != 1) { return false; } - thisModem().streamSkipUntil(','); // GNSS run status - if (thisModem().streamGetIntBefore(',') == 1) { // fix status - // init variables - float ilat = 0; - float ilon = 0; - float ispeed = 0; - float ialt = 0; - int ivsat = 0; - int iusat = 0; - float iaccuracy = 0; - int iyear = 0; - int imonth = 0; - int iday = 0; - int ihour = 0; - int imin = 0; - float secondWithSS = 0; - - // UTC date & Time - iyear = thisModem().streamGetIntLength(4); // Four digit year - imonth = thisModem().streamGetIntLength(2); // Two digit month - iday = thisModem().streamGetIntLength(2); // Two digit day - ihour = thisModem().streamGetIntLength(2); // Two digit hour - imin = thisModem().streamGetIntLength(2); // Two digit minute - secondWithSS = thisModem().streamGetFloatBefore( - ','); // 6 digit second with subseconds - - ilat = thisModem().streamGetFloatBefore(','); // Latitude - ilon = thisModem().streamGetFloatBefore(','); // Longitude - ialt = thisModem().streamGetFloatBefore( - ','); // MSL Altitude. Unit is meters - ispeed = thisModem().streamGetFloatBefore( - ','); // Speed Over Ground. Unit is knots. - thisModem().streamSkipUntil(','); // Course Over Ground. Degrees. - thisModem().streamSkipUntil(','); // Fix Mode - thisModem().streamSkipUntil(','); // Reserved1 - iaccuracy = thisModem().streamGetFloatBefore( - ','); // Horizontal Dilution Of Precision - thisModem().streamSkipUntil(','); // Position Dilution Of Precision - thisModem().streamSkipUntil(','); // Vertical Dilution Of Precision - thisModem().streamSkipUntil(','); // Reserved2 - ivsat = thisModem().streamGetIntBefore(','); // GNSS Satellites in View - iusat = thisModem().streamGetIntBefore(','); // GNSS Satellites Used - thisModem().streamSkipUntil(','); // GLONASS Satellites Used - thisModem().streamSkipUntil(','); // Reserved3 - thisModem().streamSkipUntil(','); // C/N0 max - thisModem().streamSkipUntil(','); // HPA - thisModem().streamSkipUntil('\n'); // VPA + thisModem().streamSkipUntil(','); // GNSS run status + if (thisModem().streamGetIntBefore(',') == 1) { // fix status + // init variables + float ilat = 0; + float ilon = 0; + float ispeed = 0; + float ialt = 0; + int ivsat = 0; + int iusat = 0; + float iaccuracy = 0; + int iyear = 0; + int imonth = 0; + int iday = 0; + int ihour = 0; + int imin = 0; + float secondWithSS = 0; + + // UTC date & Time + iyear = thisModem().streamGetIntLength(4); // Four digit year + imonth = thisModem().streamGetIntLength(2); // Two digit month + iday = thisModem().streamGetIntLength(2); // Two digit day + ihour = thisModem().streamGetIntLength(2); // Two digit hour + imin = thisModem().streamGetIntLength(2); // Two digit minute + secondWithSS = thisModem().streamGetFloatBefore( + ','); // 6 digit second with subseconds + + ilat = thisModem().streamGetFloatBefore(','); // Latitude + ilon = thisModem().streamGetFloatBefore(','); // Longitude + ialt = thisModem().streamGetFloatBefore( + ','); // MSL Altitude. Unit is meters + ispeed = thisModem().streamGetFloatBefore( + ','); // Speed Over Ground. Unit is knots. + thisModem().streamSkipUntil(','); // Course Over Ground. Degrees. + thisModem().streamSkipUntil(','); // Fix Mode + thisModem().streamSkipUntil(','); // Reserved1 + iaccuracy = thisModem().streamGetFloatBefore( + ','); // Horizontal Dilution Of Precision + thisModem().streamSkipUntil(','); // Position Dilution Of Precision + thisModem().streamSkipUntil(','); // Vertical Dilution Of Precision + thisModem().streamSkipUntil(','); // Reserved2 + ivsat = thisModem().streamGetIntBefore(','); // GNSS Satellites in View + iusat = thisModem().streamGetIntBefore(','); // GNSS Satellites Used + thisModem().streamSkipUntil(','); // GLONASS Satellites Used + thisModem().streamSkipUntil(','); // Reserved3 + thisModem().streamSkipUntil(','); // C/N0 max + thisModem().streamSkipUntil(','); // HPA + thisModem().streamSkipUntil('\n'); // VPA // Set pointers - if (lat != NULL) *lat = ilat; - if (lon != NULL) *lon = ilon; - if (speed != NULL) *speed = ispeed; - if (alt != NULL) *alt = ialt; - if (vsat != NULL) *vsat = ivsat; - if (usat != NULL) *usat = iusat; - if (accuracy != NULL) *accuracy = iaccuracy; + if (lat != nullptr) *lat = ilat; + if (lon != nullptr) *lon = ilon; + if (speed != nullptr) *speed = ispeed; + if (alt != nullptr) *alt = ialt; + if (vsat != nullptr) *vsat = ivsat; + if (usat != nullptr) *usat = iusat; + if (accuracy != nullptr) *accuracy = iaccuracy; if (iyear < 2000) iyear += 2000; - if (year != NULL) *year = iyear; - if (month != NULL) *month = imonth; - if (day != NULL) *day = iday; - if (hour != NULL) *hour = ihour; - if (minute != NULL) *minute = imin; - if (second != NULL) *second = static_cast(secondWithSS); - - thisModem().waitResponse(); - return true; - } + if (year != nullptr) *year = iyear; + if (month != nullptr) *month = imonth; + if (day != nullptr) *day = iday; + if (hour != nullptr) *hour = ihour; + if (minute != nullptr) *minute = imin; + if (second != nullptr) *second = static_cast(secondWithSS); + + thisModem().waitResponse(); + return true; + } thisModem().streamSkipUntil('\n'); // toss the row of commas thisModem().waitResponse(); return false; } - - /* - * Time functions - */ - // Can follow CCLK as per template - - /* - * NTP server functions - */ - // Can sync with server using CNTP as per template - - /* - * Battery functions - */ - protected: - // Follows all battery functions per template - - /* - * Client related functions - */ - // should implement in sub-classes - - /* - * Utilities - */ - public: - // should implement in sub-classes - int8_t waitResponse(uint32_t timeout_ms, String& data, - GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), -#if defined TINY_GSM_DEBUG - GsmConstStr r3 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = GFP(GSM_CMS_ERROR), -#else - GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, -#endif - GsmConstStr r5 = NULL) { - return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); - } - - int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), -#if defined TINY_GSM_DEBUG - GsmConstStr r3 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = GFP(GSM_CMS_ERROR), -#else - GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, -#endif - GsmConstStr r5 = NULL) { - String data; - return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); - } - - int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), -#if defined TINY_GSM_DEBUG - GsmConstStr r3 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = GFP(GSM_CMS_ERROR), -#else - GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, -#endif - GsmConstStr r5 = NULL) { - return thisModem().waitResponse(1000, r1, r2, r3, r4, r5); + bool handleURCs(String& data) { + return thisModem().handleURCs(data); } public: Stream& stream; - - protected: - const char* gsmNL = GSM_NL; }; #endif // SRC_TINYGSMCLIENTSIM70XX_H_ diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index c3100d3f..0a27f235 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -59,131 +59,85 @@ enum SIM7600RegStatus { }; class TinyGsmSim7600 : public TinyGsmModem, - public TinyGsmGPRS, - public TinyGsmTCP, - public TinyGsmSMS, - public TinyGsmGSMLocation, - public TinyGsmGPS, - public TinyGsmTime, - public TinyGsmNTP, - public TinyGsmBattery, - public TinyGsmTemperature, - public TinyGsmCalling { - friend class TinyGsmModem; - friend class TinyGsmGPRS; - friend class TinyGsmTCP; - friend class TinyGsmSMS; - friend class TinyGsmGPS; - friend class TinyGsmGSMLocation; - friend class TinyGsmTime; - friend class TinyGsmNTP; - friend class TinyGsmBattery; - friend class TinyGsmTemperature; - friend class TinyGsmCalling; + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSMS, + public TinyGsmGSMLocation, + public TinyGsmGPS, + public TinyGsmTime, + public TinyGsmNTP, + public TinyGsmBattery, + public TinyGsmTemperature, + public TinyGsmCalling { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSMS; + friend class TinyGsmGPS; + friend class TinyGsmGSMLocation; + friend class TinyGsmTime; + friend class TinyGsmNTP; + friend class TinyGsmBattery; + friend class TinyGsmTemperature; + friend class TinyGsmCalling; - /* - * Inner Client - */ - public: - class GsmClientSim7600 : public GsmClient { - friend class TinyGsmSim7600; - - public: - GsmClientSim7600() {} - - explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) { - init(&modem, mux); - } - - bool init(TinyGsmSim7600* modem, uint8_t mux = 0) { - this->at = modem; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; - - if (mux < TINY_GSM_MUX_COUNT) { - this->mux = mux; - } else { - this->mux = (mux % TINY_GSM_MUX_COUNT); - } - at->sockets[this->mux] = this; - - return true; - } - - public: - virtual int connect(const char* host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } - TINY_GSM_CLIENT_CONNECT_OVERRIDES - - void stop(uint32_t maxWaitMs) { - dumpModemBuffer(maxWaitMs); - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(); - } - void stop() override { - stop(15000L); - } + /* + * Inner Client + */ + public: + class GsmClientSim7600 : public GsmClient { + friend class TinyGsmSim7600; - /* - * Extended API - */ + public: + GsmClientSim7600() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - }; + explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) { + init(&modem, mux); + } - /* - * Inner Secure Client - */ + bool init(TinyGsmSim7600* modem, uint8_t mux = 0) { + this->at = modem; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - /*TODO(?)) - class GsmClientSecureSIM7600 : public GsmClientSim7600 - { - public: - GsmClientSecure() {} + if (mux < TINY_GSM_MUX_COUNT) { + this->mux = mux; + } else { + this->mux = (mux % TINY_GSM_MUX_COUNT); + } + at->sockets[this->mux] = this; - GsmClientSecure(TinyGsmSim7600& modem, uint8_t mux = 0) - : public GsmClient(modem, mux) - {} + return true; + } - public: - int connect(const char* host, uint16_t port, int timeout_s) override { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } - TINY_GSM_CLIENT_CONNECT_OVERRIDES - }; - */ + public: + virtual int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - /* - * Constructor - */ - public: - explicit TinyGsmSim7600(Stream& stream) : stream(stream) { - memset(sockets, 0, sizeof(sockets)); + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); } /* - * Basic functions + * Extended API */ - protected: - bool initImpl(const char* pin = NULL) { - DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); - DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7600")); - if (!testAT()) { - return false; - } + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* * Inner Secure Client @@ -361,74 +315,43 @@ class TinyGsmSim7600 : public TinyGsmModem, if (user && strlen(user) > 0) { sendAT(GF("+CGAUTH=1,0,\""), pwd, GF("\",\""), user, '"'); waitResponse(); - - DBG(GF("### Modem:"), getModemName()); - - // Disable time and time zone URC's - sendAT(GF("+CTZR=0")); - if (waitResponse(10000L) != 1) { - return false; - } - - // Enable automatic time zome update - sendAT(GF("+CTZU=1")); - if (waitResponse(10000L) != 1) { - return false; - } - - SimStatus ret = getSimStatus(); - // if the sim isn't ready and a pin has been provided, try to unlock the sim - if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { - simUnlock(pin); - return (getSimStatus() == SIM_READY); - } else { - // if the sim is ready, or it's locked but no pin has been provided, - // return true - return (ret == SIM_READY || ret == SIM_LOCKED); - } } - String getModemNameImpl() { - String name = "SIMCom SIM7600"; + // Define external PDP context 1 + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"', ",\"0.0.0.0\",0,0"); + waitResponse(); - sendAT(GF("+CGMM")); - String res2; - if (waitResponse(1000L, res2) != 1) { - return name; - } - res2.replace(GSM_NL "OK" GSM_NL, ""); - res2.replace("_", " "); - res2.trim(); + // Configure TCP parameters - name = res2; - DBG("### Modem:", name); - return name; - } + // Select TCP/IP application mode (command mode) + sendAT(GF("+CIPMODE=0")); + waitResponse(); - bool factoryDefaultImpl() { // these commands aren't supported - return false; - } + // Set Sending Mode - send without waiting for peer TCP ACK + sendAT(GF("+CIPSENDMODE=0")); + waitResponse(); - /* - * Power functions - */ - protected: - bool restartImpl(const char* pin = NULL) { - if (!testAT()) { - return false; - } - sendAT(GF("+CRESET")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(5000L); // TODO(?): Test this delay! - return init(pin); - } + // Configure socket parameters + // AT+CIPCCFG= , , , , , + // , + // NmRetry = number of retransmission to be made for an IP packet + // = 10 (default) + // DelayTm = number of milliseconds to delay before outputting received data + // = 0 (default) + // Ack = sets whether reporting a string "Send ok" = 0 (don't report) + // errMode = mode of reporting error result code = 0 (numberic values) + // HeaderType = which data header of receiving data in multi-client mode + // = 1 (+RECEIVE,,) + // AsyncMode = sets mode of executing commands + // = 0 (synchronous command executing) + // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 + sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); + if (waitResponse() != 1) { return false; } - bool powerOffImpl() { - sendAT(GF("+CPOF")); - return waitResponse() == 1; - } + // Configure timeouts for opening and closing sockets + // AT+CIPTIMEOUT= , + sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); + waitResponse(); // Start the socket service @@ -780,46 +703,43 @@ class TinyGsmSim7600 : public TinyGsmModem, #endif sockets[mux]->rx.put(c); } + // DBG("### READ:", len_requested, "from", mux); + // sockets[mux]->sock_available = modemGetAvailable(mux); + sockets[mux]->sock_available = len_confirmed; + waitResponse(); + return len_requested; + } - bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) { - sendAT(GF("+CFUN="), fun, reset ? ",1" : ""); - return waitResponse(10000L) == 1; - } - - /* - * Generic network functions - */ - public: - RegStatus getRegistrationStatus() { - return (RegStatus)getRegistrationStatusXREG("CGREG"); - } - - protected: - bool isNetworkConnectedImpl() { - RegStatus s = getRegistrationStatus(); - return (s == REG_OK_HOME || s == REG_OK_ROAMING); - } - - public: - String getNetworkModes() { - sendAT(GF("+CNMP=?")); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); + size_t modemGetAvailable(uint8_t mux) { + if (!sockets[mux]) return 0; + sendAT(GF("+CIPRXGET=4,"), mux); + size_t result = 0; + if (waitResponse(GF("+CIPRXGET:")) == 1) { + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux + result = streamGetIntBefore('\n'); waitResponse(); - return res; } + // DBG("### Available:", result, "on", mux); + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } + return result; + } - int16_t getNetworkMode() { - sendAT(GF("+CNMP?")); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return false; - } - int16_t mode = streamGetIntBefore('\n'); - waitResponse(); - return mode; + bool modemGetConnected(uint8_t mux) { + // Read the status of all sockets at once + sendAT(GF("+CIPCLOSE?")); + if (waitResponse(GF("+CIPCLOSE:")) != 1) { + // return false; // TODO: Why does this not read correctly? } + for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { + // +CIPCLOSE:,,..., + bool muxState = stream.parseInt(); + if (sockets[muxNo]) { sockets[muxNo]->sock_connected = muxState; } + } + waitResponse(); // Should be an OK at the end + if (!sockets[mux]) return false; + return sockets[mux]->sock_connected; + } /* * Utilities @@ -870,17 +790,8 @@ class TinyGsmSim7600 : public TinyGsmModem, return false; } - int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - #if defined TINY_GSM_DEBUG - GsmConstStr r3 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = GFP(GSM_CMS_ERROR), - #else - GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, - #endif - GsmConstStr r5 = NULL) { - return waitResponse(1000, r1, r2, r3, r4, r5); - } + public: + Stream& stream; protected: GsmClientSim7600* sockets[TINY_GSM_MUX_COUNT]; diff --git a/src/TinyGsmGPS.tpp b/src/TinyGsmGPS.tpp index 17c366c0..22355100 100644 --- a/src/TinyGsmGPS.tpp +++ b/src/TinyGsmGPS.tpp @@ -48,13 +48,13 @@ class TinyGsmGPS { hour, minute, second); } - String setGNSSMode(uint8_t mode, bool dpo) { - return thisModem().setGNSSModeImpl(mode, dpo); - } + String setGNSSMode(uint8_t mode, bool dpo) { + return thisModem().setGNSSModeImpl(mode, dpo); + } - uint8_t getGNSSMode() { - return thisModem().getGNSSModeImpl(); - } + uint8_t getGNSSMode() { + return thisModem().getGNSSModeImpl(); + } /* * CRTP Helper @@ -74,21 +74,20 @@ class TinyGsmGPS { * Define the default function implementations */ - /* - * GPS/GNSS/GLONASS location functions - */ + /* + * GPS/GNSS/GLONASS location functions + */ - bool enableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool disableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool gpsEnabledImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - String getGPSrawImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0, - int* vsat = 0, int* usat = 0, float* accuracy = 0, - int* year = 0, int* month = 0, int* day = 0, int* hour = 0, - int* minute = 0, - int* second = 0) TINY_GSM_ATTR_NOT_IMPLEMENTED; - String setGNSSModeImpl(uint8_t mode, bool dpo) TINY_GSM_ATTR_NOT_IMPLEMENTED; - uint8_t getGNSSModeImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool enableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool disableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + String getGPSrawImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0, + int* vsat = 0, int* usat = 0, float* accuracy = 0, + int* year = 0, int* month = 0, int* day = 0, int* hour = 0, + int* minute = 0, + int* second = 0) TINY_GSM_ATTR_NOT_IMPLEMENTED; + String setGNSSModeImpl(uint8_t mode, bool dpo) TINY_GSM_ATTR_NOT_IMPLEMENTED; + uint8_t getGNSSModeImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; };