diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 95febbe..c72d233 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -78,6 +78,12 @@ public: } public: + // NOTE: The XBee saves all paramter information in flash. When you turn it + // on it immediately begins to re-connect to whatever was last connected to. + // All the modemConnect() function does is tell it the paramters to put into + // flash. The connection itself happens automatically after that. + // Because everything is saved, it is possible (or likely) that you will be + // connected even if you haven't "made" any connection virtual int connect(const char *host, uint16_t port) { at->streamClear(); // Empty anything in the buffer before starting if (at->commandMode()) { // Don't try if we didn't successfully get into command mode @@ -85,8 +91,8 @@ public: at->writeChanges(); at->exitCommand(); } - else - sock_connected = false; + // After setting connection information, check if we're actually connected + sock_connected = at->modemGetConnected(); return sock_connected; } @@ -97,8 +103,8 @@ public: at->writeChanges(); at->exitCommand(); } - else - sock_connected = false; + // After setting connection information, check if we're actually connected + sock_connected = at->modemGetConnected(); return sock_connected; } @@ -119,7 +125,8 @@ public: at->writeChanges(); at->exitCommand(); at->streamClear(); // Empty anything remaining in the buffer - sock_connected = false; + // sock_connected = false; + // Note: because settings are saved in flash, the XBEE may immediately attempt to reconnect } virtual size_t write(const uint8_t *buf, size_t size) { @@ -139,51 +146,57 @@ public: virtual int available() { TINY_GSM_YIELD(); return at->stream.available(); - // if (!rx.size() || at->stream.available()) { - // at->maintain(); - // } - // return at->stream.available() + rx.size(); + /* + if (!rx.size() || at->stream.available()) { + at->maintain(); + } + return at->stream.available() + rx.size(); + */ } virtual int read(uint8_t *buf, size_t size) { TINY_GSM_YIELD(); return at->stream.readBytes((char *)buf, size); - // size_t cnt = 0; - // 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); - // buf += chunk; - // cnt += chunk; - // continue; - // } - // // TODO: Read directly into user buffer? - // if (!rx.size() || at->stream.available()) { - // at->maintain(); - // } - // } - // return cnt; + /* + size_t cnt = 0; + 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); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + if (!rx.size() || at->stream.available()) { + at->maintain(); + } + } + return cnt; + */ } virtual int read() { TINY_GSM_YIELD(); return at->stream.read(); - // uint8_t c; - // if (read(&c, 1) == 1) { - // return c; - // } - // return -1; + /* + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + */ } virtual int peek() { return at->stream.peek(); } - // virtual int peek() { return -1; } //TODO virtual void flush() { at->stream.flush(); } virtual uint8_t connected() { if (available()) { return true; } + sock_connected = at->modemGetConnected(); return sock_connected; } virtual operator bool() { return connected(); } @@ -219,8 +232,8 @@ public: at->writeChanges(); at->exitCommand(); } - else - sock_connected = false; + // After setting connection information, check if we're actually connected + sock_connected = at->modemGetConnected(); return sock_connected; } @@ -231,8 +244,8 @@ public: at->writeChanges(); at->exitCommand(); } - else - sock_connected = false; + // After setting connection information, check if we're actually connected + sock_connected = at->modemGetConnected(); return sock_connected; } }; @@ -246,6 +259,8 @@ public: beeType = XBEE_UNKNOWN; // Start not knowing what kind of bee it is guardTime = TINY_GSM_XBEE_GUARD_TIME; // Start with the default guard time of 1 second resetPin = -1; + ipAddr = IPAddress(0,0,0,0); + host = ""; memset(sockets, 0, sizeof(sockets)); } @@ -255,6 +270,8 @@ public: beeType = XBEE_UNKNOWN; // Start not knowing what kind of bee it is guardTime = TINY_GSM_XBEE_GUARD_TIME; // Start with the default guard time of 1 second this->resetPin = resetPin; + ipAddr = IPAddress(0,0,0,0); + host = ""; memset(sockets, 0, sizeof(sockets)); } @@ -742,7 +759,7 @@ public: protected: - bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) { + IPAddress getHostIP(const char* host) { String strIP; strIP.reserve(16); unsigned long startMillis = millis(); bool gotIP = false; @@ -758,13 +775,31 @@ protected: delay(2500); // wait a bit 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); + return TinyGsmIpFromString(strIP); + } + else return IPAddress(0,0,0,0); + } + + bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) { + // If requested host is the same as the previous one and we already + // have a valid IP address, we don't have to do anything. + if (this->host == String(host) && ipAddr != IPAddress(0,0,0,0)) { + return true; + } + + // Otherwise, set the new host and mark the IP as invalid + this->host = String(host); + ipAddr == getHostIP(host); // This will return 0.0.0.0 if lookup fails + + // If we now have a valid IP address, use it to connect + if (ipAddr != IPAddress(0,0,0,0)) { // Only re-set connection information if we have an IP address + return modemConnect(ipAddr, port, mux, ssl); } else return false; } bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) { + ipAddr = ip; // Set the newly requested IP address bool success = true; String host; host.reserve(16); host += ip[0]; @@ -794,12 +829,41 @@ protected: return len; } - bool modemGetConnected(uint8_t mux = 0) { - if (!commandMode()) return false; - sendAT(GF("AI")); - int16_t res = waitResponse(GF("0")); - exitCommand(); - return 1 == res; + bool modemGetConnected() { + + if (!commandMode()) return false; // Return immediately + + // If the IP address is 0, it's not valid so we can't be connected + if (ipAddr == IPAddress(0,0,0,0)) return false; + + // Verify that we're connected to the *right* IP address + // We might be connected - but to the wrong thing + // NOTE: In transparent mode, there is only one connection possible - no multiplex + String strIP; strIP.reserve(16); + sendAT(GF("DL")); + strIP = stream.readStringUntil('\r'); // read result + if (TinyGsmIpFromString(strIP) != ipAddr) return exitAndFail(); + + if (beeType == XBEE_UNKNOWN) getSeries(); // Need to know the bee type to interpret response + + switch (beeType){ // The wifi be can only say if it's connected to the netowrk + case XBEE_S6B_WIFI: { + RegStatus s = getRegistrationStatus(); + if (s != REG_OK) { + sockets[0]->sock_connected = false; + } + return (s == REG_OK); // if it's connected, we hope the sockets are too + } + default: { + sendAT(GF("CI")); + int16_t intRes = readResponseInt(); + exitCommand(); + if (intRes != 0) { + sockets[0]->sock_connected = false; + } + return (0 == intRes); + } + } } public: @@ -968,6 +1032,8 @@ protected: int16_t guardTime; int8_t resetPin; XBeeType beeType; + IPAddress ipAddr; + String host; GsmClient* sockets[TINY_GSM_MUX_COUNT]; };