diff --git a/extras/doc/Digi XBee 3G Global Users Guide - 90001541.pdf b/extras/doc/Digi XBee 3G Global Users Guide - 90001541.pdf new file mode 100644 index 0000000..7cb00e1 Binary files /dev/null and b/extras/doc/Digi XBee 3G Global Users Guide - 90001541.pdf differ diff --git a/extras/doc/Digi XBee3 LTEC1 Users Guide - 90002253.pdf b/extras/doc/Digi XBee3 LTEC1 Users Guide - 90002253.pdf new file mode 100644 index 0000000..67a395a Binary files /dev/null and b/extras/doc/Digi XBee3 LTEC1 Users Guide - 90002253.pdf differ diff --git a/extras/doc/ESP8266 - AT Command Examples 1.3.pdf b/extras/doc/ESP8266 - AT Command Examples 1.3.pdf new file mode 100644 index 0000000..9d0087b Binary files /dev/null and b/extras/doc/ESP8266 - AT Command Examples 1.3.pdf differ diff --git a/extras/doc/ESP8266 - AT Instruction Set v2.0.0.pdf b/extras/doc/ESP8266 - AT Instruction Set v2.0.0.pdf new file mode 100644 index 0000000..ab75959 Binary files /dev/null and b/extras/doc/ESP8266 - AT Instruction Set v2.0.0.pdf differ diff --git a/extras/doc/Gemalto ELS31 AT Commands.pdf b/extras/doc/Gemalto ELS31 AT Commands.pdf new file mode 100644 index 0000000..75f970a Binary files /dev/null and b/extras/doc/Gemalto ELS31 AT Commands.pdf differ diff --git a/extras/doc/SIM800 Series AT Command Manual V1.09.pdf b/extras/doc/SIM800 Series AT Command Manual V1.09.pdf new file mode 100644 index 0000000..aabadf4 Binary files /dev/null and b/extras/doc/SIM800 Series AT Command Manual V1.09.pdf differ diff --git a/extras/doc/SIM800 Series AT Command Manual V1.10.pdf b/extras/doc/SIM800 Series AT Command Manual V1.10.pdf new file mode 100644 index 0000000..0ec8983 Binary files /dev/null and b/extras/doc/SIM800 Series AT Command Manual V1.10.pdf differ diff --git a/extras/doc/SIM800 Series Software Upgrade Application Note V1.00.pdf b/extras/doc/SIM800 Series Software Upgrade Application Note V1.00.pdf new file mode 100644 index 0000000..e3b3460 Binary files /dev/null and b/extras/doc/SIM800 Series Software Upgrade Application Note V1.00.pdf differ diff --git a/extras/doc/SIM800+Series Bluetooth Application Note V1.04.pdf b/extras/doc/SIM800+Series Bluetooth Application Note V1.04.pdf new file mode 100644 index 0000000..b0ed6c6 Binary files /dev/null and b/extras/doc/SIM800+Series Bluetooth Application Note V1.04.pdf differ diff --git a/extras/doc/SIM800+Series Email Application Note V1.00.pdf b/extras/doc/SIM800+Series Email Application Note V1.00.pdf new file mode 100644 index 0000000..3664f5e Binary files /dev/null and b/extras/doc/SIM800+Series Email Application Note V1.00.pdf differ diff --git a/extras/doc/Sequans Monarch AT Commands.pdf b/extras/doc/Sequans Monarch AT Commands.pdf new file mode 100644 index 0000000..88bb4f1 Binary files /dev/null and b/extras/doc/Sequans Monarch AT Commands.pdf differ diff --git a/extras/doc/Telit 3G Modules AT Commands Reference Guide r11-1.pdf b/extras/doc/Telit 3G Modules AT Commands Reference Guide r11-1.pdf new file mode 100644 index 0000000..5651699 Binary files /dev/null and b/extras/doc/Telit 3G Modules AT Commands Reference Guide r11-1.pdf differ diff --git a/extras/doc/Telit CE910 AT Commands Reference Guide r5.pdf b/extras/doc/Telit CE910 AT Commands Reference Guide r5.pdf new file mode 100644 index 0000000..d17b57a Binary files /dev/null and b/extras/doc/Telit CE910 AT Commands Reference Guide r5.pdf differ diff --git a/extras/doc/Telit HE910 AT Command Reference Guide r0.pdf b/extras/doc/Telit HE910 AT Command Reference Guide r0.pdf new file mode 100644 index 0000000..012865e Binary files /dev/null and b/extras/doc/Telit HE910 AT Command Reference Guide r0.pdf differ diff --git a/extras/doc/Telit_LE866_AT_Commands_Reference_Guide_r5.pdf b/extras/doc/Telit LE866 AT Commands Reference Guide r5.pdf similarity index 100% rename from extras/doc/Telit_LE866_AT_Commands_Reference_Guide_r5.pdf rename to extras/doc/Telit LE866 AT Commands Reference Guide r5.pdf diff --git a/extras/doc/Telit LE910 AT Commands Reference Guide r14.1.pdf b/extras/doc/Telit LE910 AT Commands Reference Guide r14.1.pdf new file mode 100644 index 0000000..be776b6 Binary files /dev/null and b/extras/doc/Telit LE910 AT Commands Reference Guide r14.1.pdf differ diff --git a/extras/doc/Telit ME910C1 AT Commands Reference Guide r2.pdf b/extras/doc/Telit ME910C1 AT Commands Reference Guide r2.pdf new file mode 100644 index 0000000..3cfe781 Binary files /dev/null and b/extras/doc/Telit ME910C1 AT Commands Reference Guide r2.pdf differ diff --git a/extras/doc/Telit Modules Software User Guide 2G3G4G r20.pdf b/extras/doc/Telit Modules Software User Guide 2G3G4G r20.pdf new file mode 100644 index 0000000..e8787fe Binary files /dev/null and b/extras/doc/Telit Modules Software User Guide 2G3G4G r20.pdf differ diff --git a/extras/doc/u-blox-CEL_ATCommands_(UBX-13002752).pdf b/extras/doc/u-blox Cellular ATCommands (UBX-13002752).pdf similarity index 100% rename from extras/doc/u-blox-CEL_ATCommands_(UBX-13002752).pdf rename to extras/doc/u-blox Cellular ATCommands (UBX-13002752).pdf diff --git a/extras/doc/UBlox SARA-R4 AT Commands Manual (UBX-17003787).pdf b/extras/doc/u-blox SARA-R4 AT Commands Manual (UBX-17003787).pdf similarity index 100% rename from extras/doc/UBlox SARA-R4 AT Commands Manual (UBX-17003787).pdf rename to extras/doc/u-blox SARA-R4 AT Commands Manual (UBX-17003787).pdf diff --git a/library.json b/library.json index fc40cfd..73c633f 100644 --- a/library.json +++ b/library.json @@ -1,18 +1,25 @@ { "name": "TinyGSM", - "version": "0.3.3", + "version": "0.3.30", "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports GSM modules with AT command interface: SIM800, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900, SIM900A, SIM900D, SIM908, SIM968", "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968", "authors": - { - "name": "Volodymyr Shymanskyy", - "url": "https://github.com/vshymanskyy", - "maintainer": true - }, + [ + { + "name": "Sara Damiano", + "email": "sdamiano@stroudcenter.org", + "url": "https://envirodiy.org/", + "maintainer": true + }, + { + "name": "Volodymyr Shymanskyy", + "url": "https://github.com/vshymanskyy" + } +], "repository": { "type": "git", - "url": "https://github.com/vshymanskyy/TinyGSM.git" + "url": "https://github.com/EnviroDIY/TinyGSM.git" }, "homepage": "https://github.com/vshymanskyy/TinyGSM", "export": { diff --git a/library.properties b/library.properties index 383fb0f..fa6e0da 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TinyGSM -version=0.3.3 +version=0.3.30 author=Volodymyr Shymanskyy maintainer=Volodymyr Shymanskyy sentence=A small Arduino library for GPRS modules, that just works. diff --git a/src/TinyGsmClient.h b/src/TinyGsmClient.h index 32f3c23..de6de0f 100644 --- a/src/TinyGsmClient.h +++ b/src/TinyGsmClient.h @@ -34,11 +34,13 @@ #elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) #define TINY_GSM_MODEM_HAS_GPRS #include + typedef TinyGsmA6 TinyGsm; typedef TinyGsm::GsmClient TinyGsmClient; #elif defined(TINY_GSM_MODEM_M590) #define TINY_GSM_MODEM_HAS_GPRS #include + typedef TinyGsmM590 TinyGsm; typedef TinyGsm::GsmClient TinyGsmClient; #elif defined(TINY_GSM_MODEM_U201) @@ -51,6 +53,7 @@ #elif defined(TINY_GSM_MODEM_ESP8266) #define TINY_GSM_MODEM_HAS_WIFI #include + typedef TinyGsmESP8266 TinyGsm; typedef TinyGsm::GsmClient TinyGsmClient; typedef TinyGsm::GsmClientSecure TinyGsmClientSecure; @@ -58,7 +61,9 @@ #define TINY_GSM_MODEM_HAS_GPRS #define TINY_GSM_MODEM_HAS_WIFI #include - typedef TinyGsm::GsmClient TinyGsmClient; + typedef TinyGsmXBee TinyGsm; + typedef TinyGsmXBee::GsmClient TinyGsmClient; + typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure; #else #error "Please define GSM modem model" diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index a53890b..3d87d29 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -39,24 +39,40 @@ enum RegStatus { }; -class TinyGsm +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmA6 Class +//============================================================================// +//============================================================================// + + + +class TinyGsmA6 { public: + +//============================================================================// +//============================================================================// +// The A6 Client Class +//============================================================================// +//============================================================================// + + class GsmClient : public Client { - friend class TinyGsm; + friend class TinyGsmA6; typedef TinyGsmFifo RxFifo; public: GsmClient() {} - GsmClient(TinyGsm& modem) { + GsmClient(TinyGsmA6& modem) { init(&modem); } - bool init(TinyGsm* modem) { + bool init(TinyGsmA6* modem) { this->at = modem; this->mux = -1; sock_connected = false; @@ -119,7 +135,8 @@ public: virtual int read(uint8_t *buf, size_t size) { TINY_GSM_YIELD(); size_t cnt = 0; - while (cnt < size) { + uint32_t _startMillis = millis(); + while (cnt < size && millis() - _startMillis < _timeout) { size_t chunk = TinyGsmMin(size-cnt, rx.size()); if (chunk > 0) { rx.get(buf, chunk); @@ -162,15 +179,34 @@ public: String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsm* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; + TinyGsmA6* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; }; +//============================================================================// +//============================================================================// +// The A6 Does not have a secure client! +//============================================================================// +//============================================================================// + + + +//============================================================================// +//============================================================================// +// The A6 Modem Functions +//============================================================================// +//============================================================================// + + public: - TinyGsm(Stream& stream) +#ifdef GSM_DEFAULT_STREAM + TinyGsmA6(Stream& stream = GSM_DEFAULT_STREAM) +#else + TinyGsmA6(Stream& stream) +#endif : stream(stream) { memset(sockets, 0, sizeof(sockets)); @@ -316,17 +352,6 @@ public: 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=3,0")); // Set format waitResponse(); @@ -345,6 +370,17 @@ public: * Generic network functions */ + 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; + } + int getSignalQuality() { sendAT(GF("+CSQ")); if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { @@ -370,6 +406,26 @@ public: return false; } + String getLocalIP() { + sendAT(GF("+CIFSR")); + String res; + if (waitResponse(10000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, ""); + res.trim(); + return res; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * WiFi functions + */ + /* * GPRS functions */ @@ -428,104 +484,6 @@ public: return (res == 1); } - String getLocalIP() { - sendAT(GF("+CIFSR")); - String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } - res.replace(GSM_NL "OK" GSM_NL, ""); - res.replace(GSM_NL, ""); - res.trim(); - return res; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - - /* - * Phone Call functions - */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() { - sendAT(GF("A")); - return waitResponse() == 1; - } - - // Returns true on pick-up, false on error/busy - bool callNumber(const String& number) { - if (number == GF("last")) { - sendAT(GF("DLST")); - } else { - sendAT(GF("D\""), number, "\";"); - } - - if (waitResponse(5000L) != 1) { - return false; - } - - if (waitResponse(60000L, - GF(GSM_NL "+CIEV: \"CALL\",1"), - GF(GSM_NL "+CIEV: \"CALL\",0"), - GFP(GSM_ERROR)) != 1) - { - return false; - } - - int rsp = waitResponse(60000L, - GF(GSM_NL "+CIEV: \"SOUNDER\",0"), - GF(GSM_NL "+CIEV: \"CALL\",0")); - - int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL)); - - return rsp == 1 && rsp2 == 0; - } - - bool callHangup() { - sendAT(GF("H")); - return waitResponse() == 1; - } - - // 0-9,*,#,A,B,C,D - bool dtmfSend(char cmd, unsigned duration_ms = 100) { - duration_ms = constrain(duration_ms, 100, 1000); - - // The duration parameter is not working, so we simulate it using delay.. - // TODO: Maybe there's another way... - - //sendAT(GF("+VTD="), duration_ms / 100); - //waitResponse(); - - sendAT(GF("+VTS="), cmd); - if (waitResponse(10000L) == 1) { - delay(duration_ms); - return true; - } - return false; - } - - /* - * Audio functions - */ - - bool audioSetHeadphones() { - sendAT(GF("+SNFS=0")); - return waitResponse() == 1; - } - - bool audioSetSpeaker() { - sendAT(GF("+SNFS=1")); - return waitResponse() == 1; - } - - bool audioMuteMic(bool mute) { - sendAT(GF("+CMUT="), mute); - return waitResponse() == 1; - } - /* * Messaging functions */ @@ -650,9 +608,13 @@ public: streamWrite(tail...); } - bool streamSkipUntil(char c) { //TODO: timeout - while (true) { - while (!stream.available()) { TINY_GSM_YIELD(); } + 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; } @@ -664,7 +626,7 @@ public: streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -672,12 +634,12 @@ public: 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 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);*/ + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); data.reserve(64); int index = 0; unsigned long startMillis = millis(); @@ -737,6 +699,7 @@ finish: } data = ""; } + DBG('<', index, '>'); return index; } diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 44ed149..3652277 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -9,7 +9,7 @@ #ifndef TinyGsmClientESP8266_h #define TinyGsmClientESP8266_h -//#define TINY_GSM_DEBUG Serial +// #define TINY_GSM_DEBUG Serial #if !defined(TINY_GSM_RX_BUFFER) #define TINY_GSM_RX_BUFFER 512 @@ -24,24 +24,51 @@ static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; -class TinyGsm +// status of ESP8266 station interface +// 2 : ESP8266 station connected to an AP and has obtained IP +// 3 : ESP8266 station created a TCP or UDP transmission +// 4 : the TCP or UDP transmission of ESP8266 station disconnected +// 5 : ESP8266 station did NOT connect to an AP +enum RegStatus { + REG_OK_IP = 2, + REG_OK_TCP = 3, + REG_UNREGISTERED = 4, + REG_DENIED = 5, + REG_UNKNOWN = 6, +}; + + +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmESP8266 Class +//============================================================================// +//============================================================================// + + +class TinyGsmESP8266 { + //============================================================================// + //============================================================================// + // The ESP8266 Client Class + //============================================================================// + //============================================================================// + public: class GsmClient : public Client { - friend class TinyGsm; + friend class TinyGsmESP8266; typedef TinyGsmFifo RxFifo; public: GsmClient() {} - GsmClient(TinyGsm& modem, uint8_t mux = 1) { + GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) { init(&modem, mux); } - bool init(TinyGsm* modem, uint8_t mux = 1) { + bool init(TinyGsmESP8266* modem, uint8_t mux = 1) { this->at = modem; this->mux = mux; sock_connected = false; @@ -101,7 +128,8 @@ public: virtual int read(uint8_t *buf, size_t size) { TINY_GSM_YIELD(); size_t cnt = 0; - while (cnt < size) { + uint32_t _startMillis = millis(); + while (cnt < size && millis() - _startMillis < _timeout) { size_t chunk = TinyGsmMin(size-cnt, rx.size()); if (chunk > 0) { rx.get(buf, chunk); @@ -144,18 +172,25 @@ public: String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsm* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; + TinyGsmESP8266* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; }; +//============================================================================// +//============================================================================// +// The Secure ESP8266 Client Class +//============================================================================// +//============================================================================// + + class GsmClientSecure : public GsmClient { public: GsmClientSecure() {} - GsmClientSecure(TinyGsm& modem, uint8_t mux = 1) + GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1) : GsmClient(modem, mux) {} @@ -169,9 +204,20 @@ public: } }; + +//============================================================================// +//============================================================================// +// The ESP8266 Modem Functions +//============================================================================// +//============================================================================// + public: - TinyGsm(Stream& stream) +#ifdef GSM_DEFAULT_STREAM + TinyGsmESP8266(Stream& stream = GSM_DEFAULT_STREAM) +#else + TinyGsmESP8266(Stream& stream) +#endif : stream(stream) { memset(sockets, 0, sizeof(sockets)); @@ -192,6 +238,14 @@ public: if (waitResponse() != 1) { return false; } + sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections + if (waitResponse() != 1) { + return false; + } + sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode + if (waitResponse() != 1) { + return false; + } return true; } @@ -232,9 +286,7 @@ public: return res; } - bool hasSSL() { - return true; - } + bool hasSSL() { return true; } /* * Power functions @@ -255,11 +307,30 @@ public: return init(); } + bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + + /* + * SIM card functions + */ + /* * Generic network functions */ + RegStatus getRegistrationStatus() { + sendAT(GF("+CIPSTATUS")); + if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN; + int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + waitResponse(); // Returns an OK after the status + return (RegStatus)status; + } + int getSignalQuality() { sendAT(GF("+CWJAP_CUR?")); int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); @@ -275,21 +346,9 @@ public: return res2; } - bool isNetworkConnected() { - sendAT(GF("+CIPSTATUS")); - int res1 = waitResponse(3000, GF("STATUS:")); - int res2 = 0; - if (res1 == 1) { - res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); - } - // status of ESP8266 station interface - // 2 : ESP8266 station connected to an AP and has obtained IP - // 3 : ESP8266 station created a TCP or UDP transmission - // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected) - // 5 : ESP8266 station did NOT connect to an AP - waitResponse(); // Returns an OK after the status - if (res2 == 2 || res2 == 3 || res2 == 4) return true; - else return false; + bool isNetworkConnected() { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_IP || s == REG_OK_TCP); } bool waitForNetwork(unsigned long timeout = 60000L) { @@ -298,7 +357,7 @@ public: int res1 = waitResponse(3000, GF("busy p..."), GF("STATUS:")); if (res1 == 2) { int res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); - if (res2 == 2 || res2 == 3 || res2 == 4) { + if (res2 == 2 || res2 == 3) { waitResponse(); return true; } @@ -308,26 +367,29 @@ public: return false; } + String getLocalIP() { + sendAT(GF("+CIPSTA_CUR??")); + int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + return ""; + } + String res2 = stream.readStringUntil('"'); + waitResponse(); + return res2; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + /* * WiFi functions */ bool networkConnect(const char* ssid, const char* pwd) { - - sendAT(GF("+CIPMUX=1")); - if (waitResponse() != 1) { - return false; - } - - sendAT(GF("+CWMODE_CUR=1")); - if (waitResponse() != 1) { - return false; - } - sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\"")); if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) { return false; } - return true; } @@ -338,20 +400,27 @@ public: return retVal; } - String getLocalIP() { - sendAT(GF("+CIPSTA_CUR??")); - int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); - if (res1 != 2) { - return ""; - } - String res2 = stream.readStringUntil('"'); - waitResponse(); - return res2; - } + /* + * GPRS functions + */ - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + /* + * 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: @@ -384,21 +453,8 @@ protected: } bool modemGetConnected(uint8_t mux) { - // TODO: re-check this - sendAT(GF("+CIPSTATUS="), mux); - int res1 = waitResponse(3000, GF("STATUS:")); - int res2; - if (res1 == 1) { - res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); - } - // status of ESP8266 station interface - // 2 : ESP8266 station connected to an AP and has obtained IP - // 3 : ESP8266 station created a TCP or UDP transmission - // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected) - // 5 : ESP8266 station did NOT connect to an AP - waitResponse(); // Returns an OK after the status - if (res2 == 2 || res2 == 3 || res2 == 4) return true; - else return false; + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_IP || s == REG_OK_TCP); } public: @@ -416,9 +472,13 @@ public: streamWrite(tail...); } - bool streamSkipUntil(char c) { //TODO: timeout - while (true) { - while (!stream.available()) { TINY_GSM_YIELD(); } + 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; } @@ -430,7 +490,7 @@ public: streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -438,12 +498,12 @@ public: 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 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);*/ + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); data.reserve(64); int index = 0; unsigned long startMillis = millis(); @@ -505,6 +565,7 @@ finish: } data = ""; } + DBG('<', index, '>'); return index; } diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index 21539ae..cbe95b6 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -9,7 +9,7 @@ #ifndef TinyGsmClientM590_h #define TinyGsmClientM590_h -//#define TINY_GSM_DEBUG Serial +// #define TINY_GSM_DEBUG Serial #if !defined(TINY_GSM_RX_BUFFER) #define TINY_GSM_RX_BUFFER 256 @@ -39,24 +39,36 @@ enum RegStatus { }; -class TinyGsm +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmM590 Class +//============================================================================// +//============================================================================// + +class TinyGsmM590 { +//============================================================================// +//============================================================================// +// The M590 Client Class +//============================================================================// +//============================================================================// + public: class GsmClient : public Client { - friend class TinyGsm; + friend class TinyGsmM590; typedef TinyGsmFifo RxFifo; public: GsmClient() {} - GsmClient(TinyGsm& modem, uint8_t mux = 1) { + GsmClient(TinyGsmM590& modem, uint8_t mux = 1) { init(&modem, mux); } - bool init(TinyGsm* modem, uint8_t mux = 1) { + bool init(TinyGsmM590* modem, uint8_t mux = 1) { this->at = modem; this->mux = mux; sock_connected = false; @@ -116,7 +128,8 @@ public: virtual int read(uint8_t *buf, size_t size) { TINY_GSM_YIELD(); size_t cnt = 0; - while (cnt < size) { + uint32_t _startMillis = millis(); + while (cnt < size && millis() - _startMillis < _timeout) { size_t chunk = TinyGsmMin(size-cnt, rx.size()); if (chunk > 0) { rx.get(buf, chunk); @@ -159,15 +172,33 @@ public: String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsm* at; + TinyGsmM590* at; uint8_t mux; bool sock_connected; RxFifo rx; }; +//============================================================================// +//============================================================================// +// The M590 Has no Secure client! +//============================================================================// +//============================================================================// + + + +//============================================================================// +//============================================================================// +// The M590 Modem Functions +//============================================================================// +//============================================================================// + public: - TinyGsm(Stream& stream) +#ifdef GSM_DEFAULT_STREAM + TinyGsmM590(Stream& stream = GSM_DEFAULT_STREAM) +#else + TinyGsmM590(Stream& stream) +#endif : stream(stream) { memset(sockets, 0, sizeof(sockets)); @@ -327,17 +358,6 @@ public: 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) { @@ -353,6 +373,17 @@ public: * Generic network functions */ + 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; + } + int getSignalQuality() { sendAT(GF("+CSQ")); if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { @@ -378,6 +409,26 @@ public: return false; } + String getLocalIP() { + sendAT(GF("+XIIC?")); + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { + return ""; + } + stream.readStringUntil(','); + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * WiFi functions + */ + /* * GPRS functions */ @@ -408,12 +459,12 @@ public: } return false; -set_dns: - sendAT(GF("+DNSSERVER=1,8.8.8.8")); - waitResponse(); - - sendAT(GF("+DNSSERVER=2,8.8.4.4")); - waitResponse(); +// set_dns: // TODO +// sendAT(GF("+DNSSERVER=1,8.8.8.8")); +// waitResponse(); +// +// sendAT(GF("+DNSSERVER=2,8.8.4.4")); +// waitResponse(); return true; } @@ -434,34 +485,6 @@ set_dns: return res == 1; } - String getLocalIP() { - sendAT(GF("+XIIC?")); - if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { - return ""; - } - stream.readStringUntil(','); - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - - /* - * 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; - /* * Messaging functions */ @@ -595,9 +618,13 @@ public: streamWrite(tail...); } - bool streamSkipUntil(char c) { //TODO: timeout - while (true) { - while (!stream.available()) { TINY_GSM_YIELD(); } + 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; } @@ -609,7 +636,7 @@ public: streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -617,12 +644,12 @@ public: 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 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);*/ + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); data.reserve(64); int index = 0; unsigned long startMillis = millis(); @@ -683,6 +710,7 @@ finish: } data = ""; } + DBG('<', index, '>'); return index; } diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index 13a62a9..b4c16cd 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -9,8 +9,8 @@ #ifndef TinyGsmClientSIM800_h #define TinyGsmClientSIM800_h -//#define TINY_GSM_DEBUG Serial -//#define TINY_GSM_USE_HEX +// #define TINY_GSM_DEBUG Serial +// #define TINY_GSM_USE_HEX #if !defined(TINY_GSM_RX_BUFFER) #define TINY_GSM_RX_BUFFER 64 @@ -40,9 +40,22 @@ enum RegStatus { }; +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmSim800 Class +//============================================================================// +//============================================================================// + class TinyGsmSim800 { +//============================================================================// +//============================================================================// +// The Sim800 Client Class +//============================================================================// +//============================================================================// + + public: class GsmClient : public Client @@ -173,15 +186,22 @@ public: String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsmSim800* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; + TinyGsmSim800* at; + uint8_t mux; + uint16_t sock_available; + uint32_t prev_check; + bool sock_connected; + bool got_data; + RxFifo rx; }; +//============================================================================// +//============================================================================// +// The SIM800 Secure Client +//============================================================================// +//============================================================================// + + class GsmClientSecure : public GsmClient { public: @@ -201,9 +221,19 @@ public: } }; +//============================================================================// +//============================================================================// +// The SIM800 Modem Functions +//============================================================================// +//============================================================================// + public: +#ifdef GSM_DEFAULT_STREAM + TinyGsmSim800(Stream& stream = GSM_DEFAULT_STREAM) +#else TinyGsmSim800(Stream& stream) +#endif : stream(stream) { memset(sockets, 0, sizeof(sockets)); @@ -226,6 +256,11 @@ public: if (waitResponse() != 1) { return false; } + + // PREFERRED SMS STORAGE + sendAT(GF("+CPMS="), GF("\"SM\""), GF(","), GF("\"SM\""), GF(","), GF("\"SM\"")); + waitResponse(); + getSimStatus(); return true; } @@ -393,17 +428,6 @@ public: 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) { @@ -419,6 +443,17 @@ public: * Generic network functions */ + 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; + } + int getSignalQuality() { sendAT(GF("+CSQ")); if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { @@ -444,6 +479,26 @@ public: return false; } + String getLocalIP() { + 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; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * WiFi functions + */ + /* * GPRS functions */ @@ -564,72 +619,6 @@ public: return true; } - String getLocalIP() { - 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; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - - /* - * Phone Call functions - */ - - bool setGsmBusy(bool busy = true) { - sendAT(GF("+GSMBUSY="), busy ? 1 : 0); - return waitResponse() == 1; - } - - bool callAnswer() { - sendAT(GF("A")); - return waitResponse() == 1; - } - - // Returns true on pick-up, false on error/busy - bool callNumber(const String& number) { - if (number == GF("last")) { - sendAT(GF("DL")); - } else { - sendAT(GF("D"), number, ";"); - } - int status = waitResponse(60000L, - GFP(GSM_OK), - GF("BUSY" GSM_NL), - GF("NO ANSWER" GSM_NL), - GF("NO CARRIER" GSM_NL)); - switch (status) { - case 1: return true; - case 2: - case 3: return false; - default: return false; - } - } - - bool callHangup() { - sendAT(GF("H")); - return waitResponse() == 1; - } - - // 0-9,*,#,A,B,C,D - bool dtmfSend(char cmd, int duration_ms = 100) { - duration_ms = constrain(duration_ms, 100, 1000); - - sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second - waitResponse(); - - sendAT(GF("+VTS="), cmd); - return waitResponse(10000L) == 1; - } - /* * Messaging functions */ @@ -722,6 +711,7 @@ public: /* * Battery functions */ + // Use: float vBatt = modem.getBattVoltage() / 1000.0; uint16_t getBattVoltage() { sendAT(GF("+CBC")); @@ -854,9 +844,13 @@ public: streamWrite(tail...); } - bool streamSkipUntil(char c) { //TODO: timeout - while (true) { - while (!stream.available()) { TINY_GSM_YIELD(); } + 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; } @@ -868,7 +862,7 @@ public: streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -876,12 +870,12 @@ public: 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 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);*/ + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); data.reserve(64); int index = 0; unsigned long startMillis = millis(); @@ -937,6 +931,7 @@ finish: } data = ""; } + DBG('<', index, '>'); return index; } diff --git a/src/TinyGsmClientSIM808.h b/src/TinyGsmClientSIM808.h index 2b9c49a..b49ab85 100644 --- a/src/TinyGsmClientSIM808.h +++ b/src/TinyGsmClientSIM808.h @@ -11,6 +11,13 @@ #include + +//============================================================================// +//============================================================================// +// Declaration and Definitio of the TinyGsmSim808 Class +//============================================================================// +//============================================================================// + class TinyGsmSim808: public TinyGsmSim800 { diff --git a/src/TinyGsmClientU201.h b/src/TinyGsmClientU201.h index 4466058..910f21b 100644 --- a/src/TinyGsmClientU201.h +++ b/src/TinyGsmClientU201.h @@ -9,7 +9,7 @@ #ifndef TinyGsmClientU201_h #define TinyGsmClientU201_h -//#define TINY_GSM_DEBUG Serial +// #define TINY_GSM_DEBUG Serial #if !defined(TINY_GSM_RX_BUFFER) #define TINY_GSM_RX_BUFFER 64 @@ -39,9 +39,22 @@ enum RegStatus { }; +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmU201 Class +//============================================================================// +//============================================================================// + class TinyGsmU201 { +//============================================================================// +//============================================================================// +// The U201 Client Class +//============================================================================// +//============================================================================// + + public: class GsmClient : public Client @@ -171,6 +184,13 @@ private: RxFifo rx; }; +//============================================================================// +//============================================================================// +// The Secure U201 Client Class +//============================================================================// +//============================================================================// + + class GsmClientSecure : public GsmClient { public: @@ -191,6 +211,13 @@ public: } }; + +//============================================================================// +//============================================================================// +// The U201 Modem Functions +//============================================================================// +//============================================================================// + public: #ifdef GSM_DEFAULT_STREAM @@ -285,6 +312,10 @@ public: bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + /* * SIM card functions */ @@ -335,17 +366,6 @@ public: return SIM_ERROR; } - RegStatus getRegistrationStatus() { - sendAT(GF("+CGREG?")); - if (waitResponse(GF(GSM_NL "+CGREG:")) != 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) { @@ -361,6 +381,17 @@ public: * Generic network functions */ + RegStatus getRegistrationStatus() { + sendAT(GF("+CGREG?")); + if (waitResponse(GF(GSM_NL "+CGREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); // Skip format (0) + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } + int getSignalQuality() { sendAT(GF("+CSQ")); if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { @@ -386,6 +417,24 @@ public: return false; } + String getLocalIP() { + sendAT(GF("+CIFSR;E0")); + String res; + if (waitResponse(10000L, res) != 1) { + return ""; + } + res.trim(); + return res; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * WiFi functions + */ + /* * GPRS functions */ @@ -450,32 +499,6 @@ public: return true; } - String getLocalIP() { - sendAT(GF("+CIFSR;E0")); - String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } - res.trim(); - return res; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - - /* - * Phone Call functions - */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; - /* * Messaging functions */ @@ -505,6 +528,7 @@ public: /* * Battery functions */ + // Use: float vBatt = modem.getBattVoltage() / 1000.0; uint16_t getBattVoltage() { sendAT(GF("+CIND")); @@ -615,9 +639,13 @@ public: streamWrite(tail...); } - bool streamSkipUntil(char c) { //TODO: timeout - while (true) { - while (!stream.available()) { TINY_GSM_YIELD(); } + 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; } @@ -629,7 +657,7 @@ public: streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -637,12 +665,12 @@ public: 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 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);*/ + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); data.reserve(64); int index = 0; unsigned long startMillis = millis(); @@ -650,7 +678,7 @@ public: TINY_GSM_YIELD(); while (stream.available() > 0) { int a = stream.read(); - if (a < 0) continue; + if (a <= 0) continue; // Skip 0x00 bytes, just in case data += (char)a; if (r1 && data.endsWith(r1)) { index = 1; @@ -691,6 +719,7 @@ finish: } data = ""; } + DBG('<', index, '>'); return index; } diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 87dbcda..622944a 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -11,9 +11,6 @@ //#define TINY_GSM_DEBUG Serial -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 256 -#endif #define TINY_GSM_MUX_COUNT 1 // Multi-plexing isn't supported using command mode @@ -29,38 +26,55 @@ enum SimStatus { SIM_LOCKED = 2, }; -enum XBeeType { - S6B = 0, - LTEC1 = 1, -}; - enum RegStatus { - REG_UNREGISTERED = 0, + REG_OK = 0, + REG_UNREGISTERED = 1, REG_SEARCHING = 2, REG_DENIED = 3, - REG_OK_HOME = 1, - REG_OK_ROAMING = 5, REG_UNKNOWN = 4, }; +// These are responses to the HS command to get "hardware series" +enum XBeeType { + XBEE_S6B_WIFI = 0x601, // Digi XBee® Wi-Fi + XBEE_LTE1_VZN = 0xB01, // Digi XBee® Cellular LTE Cat 1 + XBEE_3G = 0xB02, // Digi XBee® Cellular 3G + XBEE3_LTE1_ATT = 1, // Digi XBee3™ Cellular LTE CAT 1 -- HS unknown to SRGD + XBEE3_LTEM_ATT = 2, // Digi XBee3™ Cellular LTE-M -- HS unknown to SRGD + XBEE3_LTENB = 3, // Digi XBee3™ Cellular NB-IoT -- HS unknown to SRGD +}; + + +//============================================================================// +//============================================================================// +// Declaration of the TinyGsmXBee Class +//============================================================================// +//============================================================================// -class TinyGsm +class TinyGsmXBee { +//============================================================================// +//============================================================================// +// The XBee Client Class +//============================================================================// +//============================================================================// + + public: class GsmClient : public Client { - friend class TinyGsm; + friend class TinyGsmXBee; public: GsmClient() {} - GsmClient(TinyGsm& modem, uint8_t mux = 0) { + GsmClient(TinyGsmXBee& modem, uint8_t mux = 0) { init(&modem, mux); } - bool init(TinyGsm* modem, uint8_t mux = 0) { + bool init(TinyGsmXBee* modem, uint8_t mux = 0) { this->at = modem; this->mux = mux; sock_connected = false; @@ -73,19 +87,25 @@ public: public: virtual int connect(const char *host, uint16_t port) { at->streamClear(); // Empty anything remaining in the buffer; - at->commandMode(); - sock_connected = at->modemConnect(host, port, mux, false); - at->writeChanges(); - at->exitCommand(); + bool sock_connected = false; + if (at->commandMode()) { // Don't try if we didn't successfully get into command mode + sock_connected = at->modemConnect(host, port, mux, false); + at->writeChanges(); + at->exitCommand(); + } + at->streamClear(); // Empty anything remaining in the buffer; return sock_connected; } virtual int connect(IPAddress ip, uint16_t port) { at->streamClear(); // Empty anything remaining in the buffer; - at->commandMode(); - sock_connected = at->modemConnect(ip, port, mux, false); - at->writeChanges(); - at->exitCommand(); + bool sock_connected = false; + if (at->commandMode()) { // Don't try if we didn't successfully get into command mode + sock_connected = at->modemConnect(ip, port, mux, false); + at->writeChanges(); + at->exitCommand(); + } + at->streamClear(); // Empty anything remaining in the buffer; return sock_connected; } @@ -100,7 +120,7 @@ public: at->exitCommand(); at->modemSend("", 1, mux); at->commandMode(); - at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds; + at->sendAT(GF("TM64")); // Set socket timeout back to 10 seconds; at->waitResponse(); at->writeChanges(); at->exitCommand(); @@ -110,7 +130,6 @@ public: virtual size_t write(const uint8_t *buf, size_t size) { TINY_GSM_YIELD(); - //at->maintain(); return at->modemSend(buf, size, mux); } @@ -125,7 +144,7 @@ public: virtual int read(uint8_t *buf, size_t size) { TINY_GSM_YIELD(); - return at->stream.readBytes(buf, size); + return at->stream.readBytes((char*)buf, size); } virtual int read() { @@ -151,47 +170,69 @@ public: String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsm* at; + TinyGsmXBee* at; uint8_t mux; bool sock_connected; }; +//============================================================================// +//============================================================================// +// The Secure XBee Client Class +//============================================================================// +//============================================================================// + + class GsmClientSecure : public GsmClient { public: GsmClientSecure() {} - GsmClientSecure(TinyGsm& modem, uint8_t mux = 1) + GsmClientSecure(TinyGsmXBee& modem, uint8_t mux = 1) : GsmClient(modem, mux) {} public: virtual int connect(const char *host, uint16_t port) { at->streamClear(); // Empty anything remaining in the buffer; - at->commandMode(); - sock_connected = at->modemConnect(host, port, mux, true); - at->writeChanges(); - at->exitCommand(); + bool sock_connected = false; + if (at->commandMode()) { // Don't try if we didn't successfully get into command mode + sock_connected = at->modemConnect(host, port, mux, true); + at->writeChanges(); + at->exitCommand(); + } + at->streamClear(); // Empty anything remaining in the buffer; return sock_connected; } virtual int connect(IPAddress ip, uint16_t port) { at->streamClear(); // Empty anything remaining in the buffer; - at->commandMode(); - sock_connected = at->modemConnect(ip, port, mux, true); - at->writeChanges(); - at->exitCommand(); + bool sock_connected = false; + if (at->commandMode()) { // Don't try if we didn't successfully get into command mode + sock_connected = at->modemConnect(ip, port, mux, true); + at->writeChanges(); + at->exitCommand(); + } + at->streamClear(); // Empty anything remaining in the buffer; return sock_connected; } }; + +//============================================================================// +//============================================================================// +// The XBee Modem Functions +//============================================================================// +//============================================================================// + public: - TinyGsm(Stream& stream) +#ifdef GSM_DEFAULT_STREAM + TinyGsmXBee(Stream& stream = GSM_DEFAULT_STREAM) +#else + TinyGsmXBee(Stream& stream) +#endif : stream(stream) - { - memset(sockets, 0, sizeof(sockets)); - } + {} /* * Basic functions @@ -201,23 +242,53 @@ public: } bool init() { - guardTime = 1100; - commandMode(); + guardTime = 1100; // Start with a default guard time of 1 second + + if (!commandMode(10)) return false; // Try up to 10 times for the init + sendAT(GF("AP0")); // Put in transparent mode - waitResponse(); + bool ret_val = waitResponse() == 1; + ret_val &= writeChanges(); + sendAT(GF("GT64")); // shorten the guard time to 100ms + ret_val &= waitResponse(); + ret_val &= writeChanges(); + if (ret_val) guardTime = 125; + + sendAT(GF("HS")); // Get the "Hardware Series"; + String res = readResponse(); + char buf[4] = {0,}; // Set up buffer for response + res.toCharArray(buf, 4); + int intRes = strtol(buf, 0, 16); + beeType = (XBeeType)intRes; + + exitCommand(); + return ret_val; + } + + void setBaud(unsigned long baud) { + if (!commandMode()) return; + switch(baud) + { + case 2400: sendAT(GF("BD1")); break; + case 4800: sendAT(GF("BD2")); break; + case 9600: sendAT(GF("BD3")); break; + case 19200: sendAT(GF("BD4")); break; + case 38400: sendAT(GF("BD5")); break; + case 57600: sendAT(GF("BD6")); break; + case 115200: sendAT(GF("BD7")); break; + case 230400: sendAT(GF("BD8")); break; + case 460800: sendAT(GF("BD9")); break; + case 921600: sendAT(GF("BDA")); break; + default: { + DBG(GF("Specified baud rate is unsupported! Setting to 9600 baud.")); + sendAT(GF("BD3")); // Set to default of 9600 + break; + } + } waitResponse(); writeChanges(); - sendAT(GF("HS")); // Get the "Hardware Series"; 0x601 for S6B (Wifi) - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - String res = streamReadUntil('\r'); // Does not send an OK, just the result exitCommand(); - if (res == "601") beeType = S6B; - else beeType = LTEC1; - guardTime = 125; - return true; } bool testAT(unsigned long timeout = 10000L) { @@ -238,52 +309,100 @@ public: void maintain() {} bool factoryDefault() { - commandMode(); + if (!commandMode()) return false; // Return immediately sendAT(GF("RE")); bool ret_val = waitResponse() == 1; - writeChanges(); + ret_val &= writeChanges(); exitCommand(); return ret_val; } + String getModemInfo() { + String modemInf = ""; + if (!commandMode()) return modemInf; // Try up to 10 times for the init + + sendAT(GF("HS")); // Get the "Hardware Series" + modemInf += readResponse(); + + exitCommand(); + return modemInf; + } + bool hasSSL() { - if (beeType == S6B) return false; + if (beeType == XBEE_S6B_WIFI) return false; else return true; } + XBeeType getBeeType() { + return beeType; + } + + String getBeeName() { + switch (beeType){ + case XBEE_S6B_WIFI: return "Digi XBee® Wi-Fi"; + case XBEE_LTE1_VZN: return "Digi XBee® Cellular LTE Cat 1"; + case XBEE_3G: return "Digi XBee® Cellular 3G"; + 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"; + } + } + /* * Power functions */ bool restart() { - commandMode(); + if (!commandMode()) return false; // Return immediately + sendAT(GF("AM1")); // Digi suggests putting into airplane mode before restarting + // This allows the sockets and connections to close cleanly + writeChanges(); + if (waitResponse() != 1) goto fail; sendAT(GF("FR")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) goto fail; + delay (2000); // Actually resets about 2 seconds later + + // Wait until reboot complete and responds to command mode call again for (unsigned long start = millis(); millis() - start < 60000L; ) { - if (commandMode()) { + if (commandMode(1)) { + sendAT(GF("AM0")); // Turn off airplane mode + writeChanges(); exitCommand(); - return true; + delay(250); // wait a litle before trying again } } - exitCommand(); - return false;; + return true; + + + fail: + exitCommand(); + return false; } - void setupPinSleep() { - commandMode(); - sendAT(GF("SM"),1); + void setupPinSleep(bool maintainAssociation = false) { + if (!commandMode()) return; // Return immediately + sendAT(GF("SM"),1); // Pin sleep waitResponse(); - if (beeType == S6B) { - sendAT(GF("SO"),200); + if (beeType == XBEE_S6B_WIFI && !maintainAssociation) { + sendAT(GF("SO"),200); // For lowest power, dissassociated deep sleep + waitResponse(); + } + else if (!maintainAssociation){ + sendAT(GF("SO"),1); // For lowest power, dissassociated deep sleep + // Not supported by all modules, will return "ERROR" waitResponse(); } writeChanges(); exitCommand(); } + bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + /* * SIM card functions */ @@ -293,23 +412,17 @@ public: } String getSimCCID() { - commandMode(); + if (!commandMode()) return ""; // Return immediately sendAT(GF("S#")); - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - String res = streamReadUntil('\r'); // Does not send an OK, just the result + String res = readResponse(); exitCommand(); return res; } String getIMEI() { - commandMode(); + if (!commandMode()) return ""; // Return immediately sendAT(GF("IM")); - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - String res = streamReadUntil('\r'); // Does not send an OK, just the result + String res = readResponse(); exitCommand(); return res; } @@ -318,38 +431,10 @@ public: return SIM_READY; // unsupported } - RegStatus getRegistrationStatus() { - commandMode(); - sendAT(GF("AI")); - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - String res = streamReadUntil('\r'); // Does not send an OK, just the result - exitCommand(); - - if(res == GF("0")) - return REG_OK_HOME; - - else if(res == GF("13") || res == GF("2A")) - return REG_UNREGISTERED; - - else if(res == GF("FF") || res == GF("22") || res == GF("23") || - res == GF("40") || res == GF("41") || res == GF("42")) - return REG_SEARCHING; - - else if(res == GF("24") || res == GF("25") || res == GF("27")) - return REG_DENIED; - - else return REG_UNKNOWN; - } - String getOperator() { - commandMode(); + if (!commandMode()) return ""; // Return immediately sendAT(GF("MN")); - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - String res = streamReadUntil('\r'); // Does not send an OK, just the result + String res = readResponse(); exitCommand(); return res; } @@ -358,26 +443,95 @@ public: * Generic network functions */ + RegStatus getRegistrationStatus() { + if (!commandMode()) return REG_UNKNOWN; // Return immediately + + sendAT(GF("AI")); + String res = readResponse(); + char buf[3] = {0,}; // Set up buffer for response + res.toCharArray(buf, 3); + int intRes = strtol(buf, 0, 16); + RegStatus stat = REG_UNKNOWN; + + switch (beeType){ + case XBEE_S6B_WIFI: { + if(intRes == 0x00) // 0x00 Successfully joined an access point, established IP addresses and IP listening sockets + stat = REG_OK; + else if(intRes == 0x01) // 0x01 Wi-Fi transceiver initialization in progress. + stat = REG_SEARCHING; + else if(intRes == 0x02) // 0x02 Wi-Fi transceiver initialized, but not yet scanning for access point. + stat = REG_SEARCHING; + else if(intRes == 0x13) { // 0x13 Disconnecting from access point. + restart(); // Restart the device; the S6B tends to get stuck "disconnecting" + stat = REG_UNREGISTERED; + } + else if(intRes == 0x23) // 0x23 SSID not configured. + stat = REG_UNREGISTERED; + else if(intRes == 0x24) // 0x24 Encryption key invalid (either NULL or invalid length for WEP). + stat = REG_DENIED; + else if(intRes == 0x27) // 0x27 SSID was found, but join failed. + stat = REG_DENIED; + else if(intRes == 0x40) // 0x40 Waiting for WPA or WPA2 Authentication. + stat = REG_SEARCHING; + else if(intRes == 0x41) // 0x41 Device joined a network and is waiting for IP configuration to complete + stat = REG_SEARCHING; + else if(intRes == 0x42) // 0x42 Device is joined, IP is configured, and listening sockets are being set up. + stat = REG_SEARCHING; + else if(intRes == 0xFF) // 0xFF Device is currently scanning for the configured SSID. + stat = REG_SEARCHING; + else stat = REG_UNKNOWN; + break; + } + default: { + if(intRes == 0x00) // 0x00 Connected to the Internet. + stat = REG_OK; + else if(intRes == 0x22) // 0x22 Registering to cellular network. + stat = REG_SEARCHING; + else if(intRes == 0x23) // 0x23 Connecting to the Internet. + stat = REG_SEARCHING; + else if(intRes == 0x24) // 0x24 The cellular component is missing, corrupt, or otherwise in error. + stat = REG_UNKNOWN; + else if(intRes == 0x25) // 0x25 Cellular network registration denied. + stat = REG_DENIED; + else if(intRes == 0x2A) { // 0x2A Airplane mode. + sendAT(GF("AM0")); // Turn off airplane mode + waitResponse(); + writeChanges(); + stat = REG_UNKNOWN; + } + else if(intRes == 0x2F) { // 0x2F Bypass mode active. + sendAT(GF("AP0")); // Set back to transparent mode + waitResponse(); + writeChanges(); + stat = REG_UNKNOWN; + } + else if(intRes == 0xFF) // 0xFF Device is currently scanning for the configured SSID. + stat = REG_SEARCHING; + else stat = REG_UNKNOWN; + break; + } + } + + exitCommand(); + return stat; + } + int getSignalQuality() { - commandMode(); - if (beeType == S6B) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity + if (!commandMode()) return 0; // Return immediately + if (beeType == XBEE_S6B_WIFI) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity else sendAT(GF("DB")); // ask for the cell strength in dBm - // wait for the response - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < 1000) {}; - char buf[2] = {0}; // Set up buffer for response - buf[0] = streamRead(); - buf[1] = streamRead(); - // DBG(buf[0], buf[1], "\n"); + String res = readResponse(); // it works better if we read in as a string exitCommand(); - int intr = strtol(buf, 0, 16); - if (beeType == S6B) return -93 + intr; // the maximum sensitivity is -93dBm - else return -1*intr; // need to convert to negative number + char buf[3] = {0,}; // Set up buffer for response + res.toCharArray(buf, 3); + int intRes = strtol(buf, 0, 16); + if (beeType == XBEE_S6B_WIFI) return -93 + intRes; // the maximum sensitivity is -93dBm + else return -1*intRes; // need to convert to negative number } bool isNetworkConnected() { RegStatus s = getRegistrationStatus(); - return (s == REG_OK_HOME || s == REG_OK_ROAMING); + return (s == REG_OK); } bool waitForNetwork(unsigned long timeout = 60000L) { @@ -385,30 +539,41 @@ public: if (isNetworkConnected()) { return true; } - delay(250); + // delay(250); // Enough delay going in and out of command mode } return false; } + String getLocalIP() { + if (!commandMode()) return ""; // Return immediately + sendAT(GF("MY")); + String IPaddr; IPaddr.reserve(16); + // wait for the response - this response can be very slow + IPaddr = readResponse(30000); + exitCommand(); + IPaddr.trim(); + return IPaddr; + } + + IPAddress localIP() { + return TinyGsmIpFromString(getLocalIP()); + } + /* * WiFi functions */ bool networkConnect(const char* ssid, const char* pwd) { - commandMode(); + if (!commandMode()) return false; // return immediately sendAT(GF("EE"), 2); // Set security to WPA2 - waitResponse(); + if (waitResponse() != 1) goto fail; sendAT(GF("ID"), ssid); - if (waitResponse() != 1) { - goto fail; - } + if (waitResponse() != 1) goto fail; sendAT(GF("PK"), pwd); - if (waitResponse() != 1) { - goto fail; - } + if (waitResponse() != 1) goto fail; writeChanges(); exitCommand(); @@ -421,29 +586,19 @@ fail: } bool networkDisconnect() { - return false; // Doesn't support disconnecting - } - - String getLocalIP() { - commandMode(); - sendAT(GF("MY")); - String IPaddr; IPaddr.reserve(16); - // wait for the response - unsigned long startMillis = millis(); - while (stream.available() < 8 && millis() - startMillis < 30000) {}; - IPaddr = streamReadUntil('\r'); // read result - return IPaddr; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); + if (!commandMode()) return false; // return immediately + sendAT(GF("NR0")); // Do a network reset in order to disconnect + int res = (1 == waitResponse(5000)); + writeChanges(); + exitCommand(); + return res; } /* * GPRS functions */ bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { - commandMode(); + if (!commandMode()) return false; // Return immediately sendAT(GF("AN"), apn); // Set the APN waitResponse(); writeChanges(); @@ -451,8 +606,20 @@ fail: return true; } - bool gprsDisconnect() { // TODO - return false; + bool gprsDisconnect() { + if (!commandMode()) return false; // return immediately + sendAT(GF("AM1")); // Cheating and disconnecting by turning on airplane mode + int res = (1 == waitResponse(5000)); + writeChanges(); + sendAT(GF("AM0")); // Airplane mode off + waitResponse(5000); + writeChanges(); + exitCommand(); + return res; + } + + bool isGprsConnected() { + return isNetworkConnected(); } /* @@ -462,35 +629,69 @@ fail: String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; bool sendSMS(const String& number, const String& text) { - commandMode(); + if (!commandMode()) return false; // Return immediately + sendAT(GF("IP"), 2); // Put in text messaging mode - waitResponse(); + if (waitResponse() !=1) goto fail; sendAT(GF("PH"), number); // Set the phone number - waitResponse(); - sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return) - waitResponse(); - writeChanges(); + if (waitResponse() !=1) goto fail; + sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage return) + if (waitResponse() !=1) goto fail; + if (!writeChanges()) goto fail; + exitCommand(); - stream.print(text); + streamWrite(text); stream.write((char)0x0D); // close off with the carriage return return true; + + fail: + exitCommand(); + return false; } + /* + * 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: private: - int modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) { - sendAT(GF("LA"), host); + bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) { String strIP; strIP.reserve(16); - // wait for the response unsigned long startMillis = millis(); - while (stream.available() < 8 && millis() - startMillis < 30000) {}; - strIP = streamReadUntil('\r'); // read result - IPAddress ip = TinyGsmIpFromString(strIP); - return modemConnect(ip, port, mux, ssl); + bool gotIP = false; + // XBee's require a numeric IP address for connection, but do provide the + // functionality to look up the IP address from a fully qualified domain name + while (!gotIP && millis() - startMillis < 45000L) // the lookup can take a while + { + sendAT(GF("LA"), host); + while (stream.available() < 4) {}; // wait for any response + strIP = stream.readStringUntil('\r'); // read result + strIP.trim(); + DBG("<<< ", strIP); + if (!strIP.endsWith(GF("ERROR"))) gotIP = true; + delay(100); // short wait before trying again + } + if (gotIP) { // No reason to continue if we don't know the IP address + IPAddress ip = TinyGsmIpFromString(strIP); + return modemConnect(ip, port, mux, ssl); + } + else return false; } - int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) { + bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) { + bool success = true; String host; host.reserve(16); host += ip[0]; host += "."; @@ -500,17 +701,17 @@ private: host += "."; host += ip[3]; if (ssl) { - sendAT(GF("IP"), 4); // Put in TCP mode - waitResponse(); + sendAT(GF("IP"), 4); // Put in SSL over TCP communication mode + success &= (1 == waitResponse()); } else { sendAT(GF("IP"), 1); // Put in TCP mode - waitResponse(); + success &= (1 == waitResponse()); } sendAT(GF("DL"), host); // Set the "Destination Address Low" - waitResponse(); + success &= (1 == waitResponse()); sendAT(GF("DE"), String(port, HEX)); // Set the destination port - int rsp = waitResponse(); - return rsp; + success &= (1 == waitResponse()); + return success; } int modemSend(const void* buff, size_t len, uint8_t mux = 0) { @@ -520,7 +721,7 @@ private: } bool modemGetConnected(uint8_t mux = 0) { - commandMode(); + if (!commandMode()) return false; sendAT(GF("AI")); int res = waitResponse(GF("0")); exitCommand(); @@ -542,32 +743,33 @@ public: streamWrite(tail...); } - int streamRead() { return stream.read(); } - - String streamReadUntil(char c) { - TINY_GSM_YIELD(); - String return_string = stream.readStringUntil(c); - return_string.trim(); - // DBG(return_string, c); - return return_string; - } - void streamClear(void) { - while (stream.available()) { streamRead(); } - } - - bool commandMode(void) { - delay(guardTime); // cannot send anything for 1 second before entering command mode - streamWrite(GF("+++")); // enter command mode - // DBG("\r\n+++\r\n"); - return 1 == waitResponse(guardTime*2); + 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("\r\n+++"); + success = (1 == waitResponse(guardTime*2)); + triesMade ++; + } + return success; } - void writeChanges(void) { + bool writeChanges(void) { sendAT(GF("WR")); // Write changes to flash - waitResponse(); + if (1 != waitResponse()) return false; sendAT(GF("AC")); // Apply changes - waitResponse(); + if (1 != waitResponse()) return false; + return true; } void exitCommand(void) { @@ -575,12 +777,22 @@ public: 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 void sendAT(Args... cmd) { streamWrite("AT", cmd..., GSM_NL); stream.flush(); TINY_GSM_YIELD(); - //DBG("### AT:", cmd...); + DBG("### AT:", cmd...); } // TODO: Optimize this! @@ -588,19 +800,19 @@ public: 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 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); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); + data.reserve(16); // Should never be getting much here for the XBee int index = 0; unsigned long startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { - int a = streamRead(); + int a = stream.read(); if (a <= 0) continue; // Skip 0x00 bytes, just in case data += (char)a; if (r1 && data.endsWith(r1)) { @@ -625,7 +837,7 @@ finish: if (!index) { data.trim(); data.replace(GSM_NL GSM_NL, GSM_NL); - data.replace(GSM_NL, "\r\n" " "); + data.replace(GSM_NL, "\r\n "); if (data.length()) { DBG("### Unhandled:", data, "\r\n"); } else { @@ -636,7 +848,7 @@ finish: data.replace(GSM_NL GSM_NL, GSM_NL); data.replace(GSM_NL, "\r\n "); if (data.length()) { - // DBG("<<< ", data); + DBG("<<< ", data); } } return index;