diff --git a/.gitignore b/.gitignore index 6ec6ffb..9d2f753 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,9 @@ # Extras extras/docs/* +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json +platformio.ini +lib/readme.txt diff --git a/.travis.yml b/.travis.yml index 5b5120e..992c5e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,16 +18,26 @@ env: - PLATFORMIO_CI_SRC=tools/FactoryReset # Arduino test - - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=uno_pic32" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_SIM800' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=mayfly" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_A6' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=mayfly" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_M590' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=mayfly" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_ESP8266' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=mayfly" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_XBEE' --project-option='framework=arduino' --board=uno --board=leonardo --board=yun --board=megaatmega2560 --board=genuino101 --board=mkr1000USB --board=zero --board=teensy31 --board=bluepill_f103c8 --board=uno_pic32 --board=esp01 --board=nodemcuv2 --board=esp32dev --board=mayfly" # Energia test - - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='framework=energia' --board=lplm4f120h5qr" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_SIM800' --project-option='framework=energia' --board=lplm4f120h5qr" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_A6' --project-option='framework=energia' --board=lplm4f120h5qr" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_M590' --project-option='framework=energia' --board=lplm4f120h5qr" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_ESP8266' --project-option='framework=energia' --board=lplm4f120h5qr" + - PLATFORMIO_CI_SRC=tools/test_build PLATFORMIO_CI_ARGS="--project-option='build_flags=-D TINY_GSM_MODEM_XBEE' --project-option='framework=energia' --board=lplm4f120h5qr" install: # ChipKIT issue: install 32-bit support for GCC PIC32 - sudo apt-get install libc6-i386 - pip install -U https://github.com/platformio/platformio/archive/develop.zip + - platformio upgrade + - platformio update # # Libraries from PlatformIO Library Registry: @@ -38,5 +48,7 @@ install: # http://platformio.org/lib/show/1286/StreamDebugger - platformio lib -g install 89 415 1202 1286 + - platformio lib -g update + - platformio lib update script: make travis-build diff --git a/README.md b/README.md index 5722642..2fdc07d 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ A small Arduino library for GSM modules, that just works. [![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/TinyGSM.svg)](https://github.com/vshymanskyy/TinyGSM/stargazers) [![License](https://img.shields.io/badge/license-LGPL3-blue.svg)](https://github.com/vshymanskyy/TinyGSM/blob/master/LICENSE) -If you like **TinyGSM** - give it a star, or fork it and contribute! -[![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/TinyGSM.svg?style=social&label=Star)](https://github.com/vshymanskyy/TinyGSM/stargazers) +If you like **TinyGSM** - give it a star, or fork it and contribute! +[![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/TinyGSM.svg?style=social&label=Star)](https://github.com/vshymanskyy/TinyGSM/stargazers) [![GitHub forks](https://img.shields.io/github/forks/vshymanskyy/TinyGSM.svg?style=social&label=Fork)](https://github.com/vshymanskyy/TinyGSM/network) You can also join our chat: @@ -35,29 +35,29 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope ## Features -Feature \ Modem | SIM800 | SIM8x8 | A6/A7/A20 | M590 | ESP8266 ---- | --- | --- | --- | --- | --- +Feature \ Modem | SIM800 | SIM8x8 | A6/A7/A20 | M590 | ESP8266 | XBee +--- | --- | --- | --- | --- | --- | **Data connections** -TCP (HTTP, MQTT, Blynk, ...) | ✔ | ✔ | ✔ | ✔ | ✔ -UDP | | | | | -SSL/TLS (HTTPS) | ✔¹ | ✔¹ | 🅧 | 🅧 | ◌ +TCP (HTTP, MQTT, Blynk, ...) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ +UDP | | | | | | ◌ +SSL/TLS (HTTPS) | ✔¹ | ✔¹ | 🅧 | 🅧 | ◌ | **USSD** -Sending USSD requests | ✔ | ✔ | ✔ | ✔ | -Decoding 7,8,16-bit response | ✔ | ✔ | ✔ | ✔ | +Sending USSD requests | ✔ | ✔ | ✔ | ✔ | | +Decoding 7,8,16-bit response | ✔ | ✔ | ✔ | ✔ | | **SMS** -Sending | ✔ | ✔ | ✔ | ✔ | -Sending Unicode | ✔ | ✔ | ◌ | 🅧 | -Reading | | | | | -Incoming message event | | | | ? | +Sending | ✔ | ✔ | ✔ | ✔ | | ✔ +Sending Unicode | ✔ | ✔ | ◌ | 🅧 | | +Reading | | | | | | +Incoming message event | | | | ? | | **Calls** -Dial, hangup | ✔ | ✔ | ✔ | 🅧 | -Receiving calls | ✔ | ✔ | ✔ | 🅧 | -Incoming event (RING) | ◌ | ◌ | ◌ | 🅧 | -DTMF sending | ◌ | ◌ | ◌ | 🅧 | -DTMF decoding | ◌ | ◌ | 🅧 | 🅧 | +Dial, hangup | ✔ | ✔ | ✔ | 🅧 | | 🅧 +Receiving calls | ✔ | ✔ | ✔ | 🅧 | | 🅧 +Incoming event (RING) | ◌ | ◌ | ◌ | 🅧 | | 🅧 +DTMF sending | ◌ | ◌ | ◌ | 🅧 | | 🅧 +DTMF decoding | ◌ | ◌ | 🅧 | 🅧 | | 🅧 **Location** -GSM location service | ✔ | ✔ | 🅧 | 🅧 | -GPS/GNSS | 🅧 | ✔² | ◌¹ | 🅧 | +GSM location service | ✔ | ✔ | 🅧 | 🅧 | | 🅧 +GPS/GNSS | 🅧 | ✔² | ◌¹ | 🅧 | | 🅧 ✔ - implemented  ◌ - planned  🅧 - not available for this modem ¹ - only some device models or firmware revisions have this feature @@ -70,6 +70,7 @@ GPS/GNSS | 🅧 | ✔² | ◌¹ | 🅧 | - [x] AI-Thinker A6, A6C, A7 - [x] Neoway M590 - [x] ESP8266 (AT commands interface, similar to GSM modems) +- [x] Digi XBee WiFi and Cellular (using XBee command mode) ### Supported modules - [x] GPRSbee diff --git a/TinyGsmClient.h b/TinyGsmClient.h index 36cc919..07f1126 100644 --- a/TinyGsmClient.h +++ b/TinyGsmClient.h @@ -9,7 +9,7 @@ #ifndef TinyGsmClient_h #define TinyGsmClient_h -#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM900) +#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM900) #include typedef TinyGsmSim800 TinyGsm; typedef TinyGsmSim800::GsmClient TinyGsmClient; @@ -33,6 +33,10 @@ #include typedef TinyGsm::GsmClient TinyGsmClient; +#elif defined(TINY_GSM_MODEM_XBEE) + #include + typedef TinyGsm::GsmClient TinyGsmClient; + #else #error "Please define GSM modem model" #endif diff --git a/TinyGsmClientA6.h b/TinyGsmClientA6.h index c8c0db0..d511031 100644 --- a/TinyGsmClientA6.h +++ b/TinyGsmClientA6.h @@ -348,6 +348,17 @@ public: return false; } + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + return false; + } + + bool networkDisconnect() { + return false; + } + /* * GPRS functions */ @@ -397,8 +408,19 @@ public: } IPAddress localIP() { - IPAddress res; - res.fromString(getLocalIP()); + String strIP = getLocalIP(); + int Parts[4] = {0,0,0,0}; + int Part = 0; + for (uint8_t i=0; i sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); } else { @@ -673,6 +696,9 @@ public: while (!stream.available()) { TINY_GSM_YIELD(); } sockets[mux]->rx.put(stream.read()); } + if (len_orig > sockets[mux]->available()) { + DBG(GSM_NL, "### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } data = ""; } else if (data.endsWith(GF("+TCPCLOSED:"))) { int mux = stream.readStringUntil('\n').toInt(); @@ -684,7 +710,7 @@ public: } } } while (millis() - startMillis < timeout); -finish: + finish: if (!index) { data.trim(); if (data.length()) { diff --git a/TinyGsmClientESP8266.h b/TinyGsmClientESP8266.h index b15a70e..2931f57 100644 --- a/TinyGsmClientESP8266.h +++ b/TinyGsmClientESP8266.h @@ -212,8 +212,46 @@ public: return autoBaud(); } + /* + * SIM card functions + */ + + /* + * Generic network functions + */ + + int getSignalQuality() { + sendAT(GF("+CWJAP_CUR?")); + int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + waitResponse(); + return 0; + } + streamSkipUntil(','); // Skip SSID + streamSkipUntil(','); // Skip BSSID/MAC address + streamSkipUntil(','); // Skip Chanel number + int res2 = stream.parseInt(); // Read RSSI + DBG(res2); + waitResponse(); + return res2; + } + bool waitForNetwork(unsigned long timeout = 60000L) { - return true; + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CIPSTATUS")); + 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) return true; + } + // 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 + delay(1000); + } + return false; } /* @@ -244,9 +282,45 @@ public: return waitResponse(10000L) == 1; } - String getLocalIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + String getLocalIP() { + sendAT(GF("+CIPSTA_CUR??")); + int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + return ""; + } + String res2 = stream.readStringUntil('"'); + DBG(res2); + waitResponse(); + return res2; + } + + IPAddress localIP() { + String strIP = getLocalIP(); + int Parts[4] = {0,0,0,0}; + int Part = 0; + for (uint8_t i=0; i sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); } else { @@ -358,15 +434,17 @@ public: while (!stream.available()) { TINY_GSM_YIELD(); } sockets[mux]->rx.put(stream.read()); } + if (len_orig > sockets[mux]->available()) { + DBG(GSM_NL, "### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } data = ""; return index; } else if (data.endsWith(GF(GSM_NL "1,CLOSED" GSM_NL))) { //TODO: use mux sockets[1]->sock_connected = false; - data = ""; } } } while (millis() - startMillis < timeout); -finish: + finish: if (!index) { data.trim(); if (data.length()) { diff --git a/TinyGsmClientM590.h b/TinyGsmClientM590.h index d6a4e4c..8a9adda 100644 --- a/TinyGsmClientM590.h +++ b/TinyGsmClientM590.h @@ -357,6 +357,17 @@ public: return false; } + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + return false; + } + + bool networkDisconnect() { + return false; + } + /* * GPRS functions */ @@ -413,8 +424,19 @@ public: } IPAddress localIP() { - IPAddress res; - res.fromString(getLocalIP()); + String strIP = getLocalIP(); + int Parts[4] = {0,0,0,0}; + int Part = 0; + for (uint8_t i=0; i sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); } else { @@ -660,6 +683,9 @@ public: while (!stream.available()) { TINY_GSM_YIELD(); } sockets[mux]->rx.put(stream.read()); } + if (len_orig > sockets[mux]->available()) { + DBG(GSM_NL, "### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } data = ""; } else if (data.endsWith(GF("+TCPCLOSE:"))) { int mux = stream.readStringUntil(',').toInt(); @@ -672,7 +698,7 @@ public: } } } while (millis() - startMillis < timeout); -finish: + finish: if (!index) { data.trim(); if (data.length()) { diff --git a/TinyGsmClientSIM800.h b/TinyGsmClientSIM800.h index 0daaba7..c0c3544 100644 --- a/TinyGsmClientSIM800.h +++ b/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 @@ -426,6 +426,17 @@ public: return false; } + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + return false; + } + + bool networkDisconnect() { + return false; + } + /* * GPRS functions */ @@ -545,8 +556,19 @@ public: } IPAddress localIP() { - IPAddress res; - res.fromString(getLocalIP()); + String strIP = getLocalIP(); + int Parts[4] = {0,0,0,0}; + int Part = 0; + for (uint8_t i=0; i + +#define GSM_NL "\r" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum XBeeType { + S6B = 0, + LTEC1 = 1, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 2, + REG_DENIED = 3, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsm +{ + +public: + TinyGsm(Stream& stream) + : stream(stream) + {} + +public: + +class GsmClient : public Client +{ + friend class TinyGsm; + +public: + GsmClient() {} + + GsmClient(TinyGsm& modem, uint8_t mux = 0) { + init(&modem, mux); + } + + bool init(TinyGsm* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_connected = false; + + at->sockets[mux] = this; + + return true; + } + +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); + at->writeChanges(); + at->exitCommand(); + 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); + at->writeChanges(); + at->exitCommand(); + return sock_connected; + } + + // This is a hack to shut the socket by setting the timeout to zero and + // then sending an empty line to the server. + virtual void stop() { + at->commandMode(); + at->sendAT(GF("TM0")); // Set socket timeout to 0; + at->waitResponse(); + at->writeChanges(); + at->exitCommand(); + at->modemSend("", 1, mux); + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds; + at->waitResponse(); + at->writeChanges(); + at->exitCommand(); + at->streamClear(); // Empty anything remaining in the buffer; + sock_connected = false; + } + + virtual size_t write(const uint8_t *buf, size_t size) { + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) { + return write(&c, 1); + } + + virtual int available() { + return at->stream.available(); + } + + virtual int read(uint8_t *buf, size_t size) { + return available(); + } + + virtual int read() { + TINY_GSM_YIELD(); + return at->stream.read(); + } + + virtual int peek() { return at->stream.peek(); } + virtual void flush() { at->stream.flush(); } + + virtual uint8_t connected() { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() { return connected(); } +private: + TinyGsm* at; + uint8_t mux; + bool sock_connected; +}; + +public: + + /* + * Basic functions + */ + bool begin() { + return init(); + } + + bool init() { + guardTime = 1100; + commandMode(); + sendAT(GF("AP0")); // Put in transparent mode + waitResponse(); + sendAT(GF("GT64")); // shorten the guard time to 100ms + 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 autoBaud(unsigned long timeout = 10000L) { // not supported + return false; + } + + void maintain() {} + + bool factoryDefault() { + commandMode(); + sendAT(GF("RE")); + bool ret_val = waitResponse() == 1; + writeChanges(); + exitCommand(); + return ret_val; + } + + /* + * Power functions + */ + + bool restart() { + commandMode(); + sendAT(GF("FR")); + if (waitResponse() != 1) { + return false; + } + delay (2000); // Actually resets about 2 seconds later + for (unsigned long start = millis(); millis() - start < 60000L; ) { + if (commandMode()) { + exitCommand(); + return true; + } + } + exitCommand(); + return false;; + } + + void setupPinSleep() { + commandMode(); + sendAT(GF("SM"),1); + waitResponse(); + sendAT(GF("SO"),200); + waitResponse(); + writeChanges(); + exitCommand(); + } + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) { // Not supported + return false; + } + + String getSimCCID() { + commandMode(); + 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 + exitCommand(); + return res; + } + + String getIMEI() { + commandMode(); + 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 + exitCommand(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) { + return SIM_READY; // unsupported + } + + RegStatus getRegistrationStatus() { + commandMode(); + if (beeType == S6B) sendAT(GF("AI")); + else sendAT(GF("CI")); + // 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")) + return REG_DENIED; + + else return REG_UNKNOWN; + } + + String getOperator() { + commandMode(); + 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 + exitCommand(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() { + commandMode(); + if (beeType == S6B) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity + else sendAT(GF("DB")); // ask for the cell strenght 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"); + 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 + } + + bool waitForNetwork(unsigned long timeout = 60000L) { + for (unsigned long start = millis(); millis() - start < timeout; ) { + commandMode(); + if (beeType == S6B) sendAT(GF("AI")); + else sendAT(GF("CI")); + // 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 true; + } + delay(1000); + } + return false; + } + + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + + commandMode(); + + sendAT(GF("EE"), 2); // Set security to WPA2 + waitResponse(); + + sendAT(GF("ID"), ssid); + if (waitResponse() != 1) { + goto fail; + } + + sendAT(GF("PK"), pwd); + if (waitResponse() != 1) { + goto fail; + } + + writeChanges(); + exitCommand(); + + return true; + + fail: + exitCommand(); + return false; + } + + 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() { + String strIP = getLocalIP(); + int Parts[4] = {0,0,0,0}; + int Part = 0; + for (uint8_t i=0; i + void streamWrite(T last) { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) { + stream.print(head); + streamWrite(tail...); + } + + int streamRead() { return stream.read(); } + + String streamReadUntil(char c) { + TINY_GSM_YIELD(); + String return_string = stream.readStringUntil(c); + return_string.trim(); + if (String(c) == GSM_NL) { + DBG(return_string, "\r\n"); + } else 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); + } + + void writeChanges(void) { + sendAT(GF("WR")); // Write changes to flash + waitResponse(); + sendAT(GF("AC")); // Apply changes + waitResponse(); + } + + void exitCommand(void) { + sendAT(GF("CN")); // Exit command mode + waitResponse(); + } + + template + void sendAT(Args... cmd) { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + DBG(">>> AT ", cmd..., "\r\n"); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = streamRead(); + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } + } + } while (millis() - startMillis < timeout); + finish: + if (!index) { + data.trim(); + data.replace(GSM_NL GSM_NL, GSM_NL); + data.replace(GSM_NL, "\r\n" " "); + if (data.length()) { + DBG("### Unhandled:", data, "\r\n"); + } else DBG("### NO RESPONSE!\r\n"); + } + else { + data.trim(); + data.replace(GSM_NL GSM_NL, GSM_NL); + data.replace(GSM_NL, "\r\n "); + if (data.length()) { + DBG("<<< ", data, "\r\n"); + } + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +private: + int guardTime; + XBeeType beeType; + Stream& stream; + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/TinyGsmCommon.h b/TinyGsmCommon.h index e0a37aa..9b1596f 100644 --- a/TinyGsmCommon.h +++ b/TinyGsmCommon.h @@ -46,6 +46,7 @@ namespace { template static void DBG(T last) { TINY_GSM_DEBUG.println(last); + // TINY_GSM_DEBUG.print(last); } template diff --git a/doc/Digi XBee LTEC1 Users Guide - 90001525.pdf b/doc/Digi XBee LTEC1 Users Guide - 90001525.pdf new file mode 100644 index 0000000..6ea1729 Binary files /dev/null and b/doc/Digi XBee LTEC1 Users Guide - 90001525.pdf differ diff --git a/doc/Digi XBee S6B Users Guide - 90002180.pdf b/doc/Digi XBee S6B Users Guide - 90002180.pdf new file mode 100644 index 0000000..cdfacaf Binary files /dev/null and b/doc/Digi XBee S6B Users Guide - 90002180.pdf differ diff --git a/doc/ESP8266 - AT Instruction Set.pdf b/doc/ESP8266 - AT Instruction Set.pdf new file mode 100644 index 0000000..ab75959 Binary files /dev/null and b/doc/ESP8266 - AT Instruction Set.pdf differ diff --git a/doc/ESP8266 - Datasheet v4.3.pdf b/doc/ESP8266 - Datasheet v4.3.pdf new file mode 100644 index 0000000..a4e8411 Binary files /dev/null and b/doc/ESP8266 - Datasheet v4.3.pdf differ diff --git a/doc/ESP8266 - Low Power Solutions.pdf b/doc/ESP8266 - Low Power Solutions.pdf new file mode 100644 index 0000000..5e1bafb Binary files /dev/null and b/doc/ESP8266 - Low Power Solutions.pdf differ diff --git a/doc/SIM800 AT Commands v1.11.pdf b/doc/SIM800 AT Commands v1.11.pdf new file mode 100644 index 0000000..37c0a66 Binary files /dev/null and b/doc/SIM800 AT Commands v1.11.pdf differ diff --git a/examples/BlynkClient/BlynkClient.ino b/examples/BlynkClient/BlynkClient.ino index 2716612..c45dda1 100644 --- a/examples/BlynkClient/BlynkClient.ino +++ b/examples/BlynkClient/BlynkClient.ino @@ -36,6 +36,7 @@ // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE #include #include @@ -88,4 +89,3 @@ void loop() { Blynk.run(); } - diff --git a/examples/FileDownload/FileDownload.ino b/examples/FileDownload/FileDownload.ino index 2ee647b..bb10ac5 100644 --- a/examples/FileDownload/FileDownload.ino +++ b/examples/FileDownload/FileDownload.ino @@ -20,6 +20,7 @@ // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE // Increase RX buffer #define TINY_GSM_RX_BUFFER 1030 @@ -193,4 +194,3 @@ void loop() { delay(1000); } } - diff --git a/examples/MqttClient/MqttClient.ino b/examples/MqttClient/MqttClient.ino index 856eb05..3e1c9aa 100644 --- a/examples/MqttClient/MqttClient.ino +++ b/examples/MqttClient/MqttClient.ino @@ -33,6 +33,7 @@ // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE #include #include @@ -152,4 +153,3 @@ void mqttCallback(char* topic, byte* payload, unsigned int len) { mqtt.publish(topicLedStatus, ledStatus ? "1" : "0"); } } - diff --git a/examples/WebClient/WebClient.ino b/examples/WebClient/WebClient.ino index 6f65c93..6f03426 100644 --- a/examples/WebClient/WebClient.ino +++ b/examples/WebClient/WebClient.ino @@ -116,4 +116,3 @@ void loop() { delay(1000); } } - diff --git a/tools/AT_Debug/AT_Debug.ino b/tools/AT_Debug/AT_Debug.ino index f850f3b..d66b632 100644 --- a/tools/AT_Debug/AT_Debug.ino +++ b/tools/AT_Debug/AT_Debug.ino @@ -10,11 +10,15 @@ // Select your modem: #define TINY_GSM_MODEM_SIM800 +// #define TINY_GSM_MODEM_SIM808 // #define TINY_GSM_MODEM_SIM900 // #define TINY_GSM_MODEM_A6 // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE + +#include // Set serial for debug console (to the Serial Monitor, speed 115200) #define SerialMon Serial @@ -75,4 +79,3 @@ void loop() { delay(0); } } - diff --git a/tools/Diagnostics/Diagnostics.ino b/tools/Diagnostics/Diagnostics.ino index abef844..fe48c23 100644 --- a/tools/Diagnostics/Diagnostics.ino +++ b/tools/Diagnostics/Diagnostics.ino @@ -11,11 +11,13 @@ // Select your modem: #define TINY_GSM_MODEM_SIM800 +// #define TINY_GSM_MODEM_SIM808 // #define TINY_GSM_MODEM_SIM900 // #define TINY_GSM_MODEM_A6 // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE // Increase the buffer #define TINY_GSM_RX_BUFFER 512 @@ -153,4 +155,3 @@ void loop() { delay(1000); } } - diff --git a/tools/FactoryReset/FactoryReset.ino b/tools/FactoryReset/FactoryReset.ino index 4940c7d..2cba23b 100644 --- a/tools/FactoryReset/FactoryReset.ino +++ b/tools/FactoryReset/FactoryReset.ino @@ -11,11 +11,13 @@ // Select your modem: #define TINY_GSM_MODEM_SIM800 +// #define TINY_GSM_MODEM_SIM808 // #define TINY_GSM_MODEM_SIM900 // #define TINY_GSM_MODEM_A6 // #define TINY_GSM_MODEM_A7 // #define TINY_GSM_MODEM_M590 // #define TINY_GSM_MODEM_ESP8266 +// #define TINY_GSM_MODEM_XBEE #include diff --git a/tools/test_build/test_build.ino b/tools/test_build/test_build.ino index c29294d..f4e8573 100644 --- a/tools/test_build/test_build.ino +++ b/tools/test_build/test_build.ino @@ -4,8 +4,6 @@ * **************************************************************/ -#define TINY_GSM_MODEM_SIM800 - #include TinyGsm modem(Serial); @@ -21,26 +19,36 @@ void setup() { } void loop() { - modem.restart(); + // Test the start/restart functions + modem.restart(); modem.begin(); + modem.autoBaud(); + modem.factoryDefault(); - modem.getOperator(); - + // Test the SIM card functions + #if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_M590) || defined(TINY_GSM_MODEM_XBEE) modem.getSimCCID(); - + modem.getIMEI(); modem.getSimStatus(); + modem.getRegistrationStatus(); + modem.getOperator(); + #endif + + // Test the Networking functions + modem.getSignalQuality(); + + + #if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_M590) modem.waitForNetwork(); + modem.gprsConnect("YourAPN", "", ""); + #else + modem.networkConnect("YourSSID", "YourPWD"); + modem.waitForNetwork(); + #endif - if (!modem.gprsConnect("YourAPN", "", "")) { - delay(10000); - return; - } - if (!client.connect(server, 80)) { - delay(10000); - return; - } + client.connect(server, 80); // Make a HTTP GET request: client.print(String("GET ") + resource + " HTTP/1.0\r\n"); @@ -49,20 +57,17 @@ void loop() { unsigned long timeout = millis(); while (client.connected() && millis() - timeout < 10000L) { - // Print available data while (client.available()) { - char c = client.read(); + client.read(); timeout = millis(); } } client.stop(); + #if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_M590) modem.gprsDisconnect(); - - // Do nothing forevermore - while (true) { - delay(1000); - } + #else + modem.networkDisconnect(); + #endif } -