Doing a better job of detecting XBee socket state
This commit is contained in:
@@ -120,6 +120,8 @@ public:
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
at->streamClear(); // Empty anything in the buffer
|
||||
// empty the saved currently-in-use destination address
|
||||
at->savedOperatingIP = IPAddress(0, 0, 0, 0);
|
||||
at->commandMode();
|
||||
// For WiFi models, there's no direct way to close the socket. This is a
|
||||
// hack to shut the socket by setting the timeout to zero.
|
||||
@@ -216,6 +218,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
return sock_connected;
|
||||
// NOTE: We dont't check or return
|
||||
// modemGetConnected() because we don't
|
||||
// want to go into command mode.
|
||||
// return at->modemGetConnected();
|
||||
}
|
||||
virtual operator bool() { return connected(); }
|
||||
|
||||
@@ -832,7 +838,31 @@ public:
|
||||
* Client related functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
int16_t getConnectionIndicator() {
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
sendAT(GF("CI"));
|
||||
int16_t intRes = readResponseInt();
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
return intRes;
|
||||
}
|
||||
|
||||
IPAddress getOperatingIP() {
|
||||
String strIP;
|
||||
strIP.reserve(16);
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, IPAddress(0, 0, 0, 0))
|
||||
sendAT(GF("OD"));
|
||||
strIP = stream.readStringUntil('\r'); // read result
|
||||
strIP.trim();
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
|
||||
if (strIP != "" && strIP != GF("ERROR")) {
|
||||
return TinyGsmIpFromString(strIP);
|
||||
} else
|
||||
return IPAddress(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
IPAddress lookupHostIP(const char* host, int timeout_s = 45) {
|
||||
String strIP;
|
||||
@@ -867,8 +897,6 @@ protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0,
|
||||
bool ssl = false, int timeout_s = 75)
|
||||
{
|
||||
unsigned long startMillis = millis();
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
||||
bool retVal = false;
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
|
||||
@@ -885,7 +913,7 @@ protected:
|
||||
|
||||
// If we now have a valid IP address, use it to connect
|
||||
if (savedHostIP != IPAddress(0,0,0,0)) { // Only re-set connection information if we have an IP address
|
||||
retVal = modemConnect(savedHostIP, port, mux, ssl, timeout_ms - (millis() - startMillis));
|
||||
retVal = modemConnect(savedHostIP, port, mux, ssl);
|
||||
}
|
||||
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
@@ -893,13 +921,19 @@ protected:
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false, int timeout_s = 75) {
|
||||
|
||||
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0,
|
||||
bool ssl = false, int timeout_s = 75) {
|
||||
bool success = true;
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
||||
|
||||
if (timeout_s != 75) DBG("Timeout doesn't apply here.");
|
||||
|
||||
// empty the saved currelty-in-use destination address
|
||||
savedOperatingIP = IPAddress(0, 0, 0, 0);
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
||||
|
||||
if (ip != savedIP) { // Can skip almost everything if there's no change in the IP address
|
||||
if (ip != savedIP) { // Can skip almost everything if there's no
|
||||
// change in the IP address
|
||||
savedIP = ip; // Set the newly requested IP address
|
||||
String host; host.reserve(16);
|
||||
host += ip[0];
|
||||
@@ -926,11 +960,12 @@ protected:
|
||||
success &= writeChanges();
|
||||
}
|
||||
|
||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
||||
if (modemGetConnected()) {
|
||||
sockets[mux]->sock_connected = true;
|
||||
break;
|
||||
}
|
||||
// we'll accept either unknown or connected
|
||||
uint16_t ci = getConnectionIndicator();
|
||||
success &= (ci == 0x00 || ci == 0xFF || ci == 0x28);
|
||||
|
||||
if (success) {
|
||||
sockets[mux]->sock_connected = true;
|
||||
}
|
||||
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
@@ -942,6 +977,17 @@ protected:
|
||||
if (mux != 0) DBG("XBee only supports 1 IP channel in transparent mode!");
|
||||
stream.write((uint8_t*)buff, len);
|
||||
stream.flush();
|
||||
|
||||
// After a send, verify the outgoing ip if it isn't set
|
||||
if (savedOperatingIP == IPAddress(0, 0, 0, 0)) {
|
||||
modemGetConnected();
|
||||
}
|
||||
// After sending several characters, also re-check
|
||||
// NOTE: I'm intentionally not checking after every single character!
|
||||
else if (len > 5) {
|
||||
modemGetConnected();
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -955,17 +1001,11 @@ protected:
|
||||
|
||||
XBEE_COMMAND_START_DECORATOR(5, 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) != savedIP) 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
|
||||
switch (beeType){
|
||||
|
||||
// The wifi be can only say if it's connected to the netowrk
|
||||
case XBEE_S6B_WIFI: {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
@@ -974,22 +1014,111 @@ protected:
|
||||
}
|
||||
return (s == REG_OK); // if it's connected, we hope the sockets are too
|
||||
}
|
||||
default: { // Cellular XBee's
|
||||
sendAT(GF("CI"));
|
||||
int16_t intRes = readResponseInt();
|
||||
|
||||
// Cellular XBee's
|
||||
default: {
|
||||
int16_t ci = getConnectionIndicator();
|
||||
// Get the operating destination address
|
||||
IPAddress od = getOperatingIP();
|
||||
XBEE_COMMAND_END_DECORATOR
|
||||
switch(intRes) {
|
||||
case 0x00: // 0x00 = The socket is definitely open
|
||||
case 0x28: // 0x28 = "Unknown."
|
||||
case 0xFF: // 0xFF = No known status - this is always returned prior to sending data
|
||||
|
||||
switch(ci) {
|
||||
|
||||
// 0x00 = The socket is definitely open
|
||||
case 0x00: {
|
||||
savedOperatingIP = od;
|
||||
// but it's possible the socket is set to the wrong place
|
||||
if (od != IPAddress(0, 0, 0, 0) && od != savedIP) {
|
||||
sockets[0]->stop();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case 0x02: // 0x02 = Invalid parameters (bad IP/host)
|
||||
case 0x12: // 0x12 = DNS query lookup failure
|
||||
case 0x25: // 0x25 = Unknown server - DNS lookup failed (0x22 for UDP socket!)
|
||||
savedIP = IPAddress(0,0,0,0); // force a lookup next time!
|
||||
default: // If it's anything else (inc 0x02, 0x12, and 0x25)...
|
||||
sockets[0]->sock_connected = false; // ...it's definitely NOT connected
|
||||
}
|
||||
|
||||
// 0x28 = "Unknown."
|
||||
// 0xFF = No known status - always returned prior to sending data
|
||||
case 0x28:
|
||||
case 0xFF: {
|
||||
// If we previously had an operating destination and we no longer do,
|
||||
// the socket must have closed
|
||||
if (od == IPAddress(0, 0, 0, 0) && savedOperatingIP != IPAddress(0, 0, 0, 0)) {
|
||||
savedOperatingIP = od;
|
||||
sockets[0]->sock_connected = false;
|
||||
return false;
|
||||
}
|
||||
// else if the operating destination exists, but is wrong
|
||||
// we need to close and re-open
|
||||
else if (od != IPAddress(0, 0, 0, 0) && od != savedIP) {
|
||||
sockets[0]->stop();
|
||||
return false;
|
||||
}
|
||||
// else if the operating destination exists and matches, we're
|
||||
// good to go
|
||||
else if (od != IPAddress(0, 0, 0, 0) && od == savedIP) {
|
||||
savedOperatingIP = od;
|
||||
return true;
|
||||
}
|
||||
// If we never had an operating destination, then sock may be open
|
||||
// but data never sent - this is the dreaded "we don't know"
|
||||
else {
|
||||
savedOperatingIP = od;
|
||||
return true;
|
||||
}
|
||||
|
||||
// // Ask for information about any open sockets
|
||||
// sendAT(GF("SI"));
|
||||
// String open_socks = stream.readStringUntil('\r');
|
||||
// open_socks.replace(GSM_NL, "");
|
||||
// open_socks.trim();
|
||||
// if (open_socks != "") {
|
||||
// // In transparent mode, only socket 0 should be possible
|
||||
// sendAT(GF("SI0"));
|
||||
// // read socket it
|
||||
// String sock_id = stream.readStringUntil('\r');
|
||||
// // read socket state
|
||||
// String sock_state = stream.readStringUntil('\r');
|
||||
// // read socket protocol (TCP/UDP)
|
||||
// String sock_protocol = stream.readStringUntil('\r');
|
||||
// // read local port number
|
||||
// String local_port = stream.readStringUntil('\r');
|
||||
// // read remote port number
|
||||
// String remote_port = stream.readStringUntil('\r');
|
||||
// // read remote ip address
|
||||
// String remoted_address =
|
||||
// stream.readStringUntil('\r'); // read result
|
||||
// stream.readStringUntil('\r'); // final carriage return
|
||||
// }
|
||||
}
|
||||
|
||||
// 0x21 = User closed
|
||||
// 0x27 = Connection lost
|
||||
// If the connection is lost or timed out on our side,
|
||||
// we force close so it can reopen
|
||||
case 0x21 :
|
||||
case 0x27 : {
|
||||
Serial.println("Here!");
|
||||
sendAT(GF("TM")); // Get socket timeout
|
||||
String timeoutUsed = readResponseString(5000L);
|
||||
sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout
|
||||
waitResponse(5000L); // This response can be slow
|
||||
}
|
||||
|
||||
// 0x02 = Invalid parameters (bad IP/host)
|
||||
// 0x12 = DNS query lookup failure
|
||||
// 0x25 = Unknown server - DNS lookup failed (0x22 for UDP socket!)
|
||||
case 0x02:
|
||||
case 0x12:
|
||||
case 0x25: {
|
||||
savedIP = IPAddress(0, 0, 0, 0); // force a lookup next time!
|
||||
}
|
||||
|
||||
// If it's anything else (inc 0x02, 0x12, and 0x25)...
|
||||
// it's definitely NOT connected
|
||||
default: {
|
||||
sockets[0]->sock_connected = false;
|
||||
savedOperatingIP = od;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1193,6 +1322,7 @@ protected:
|
||||
IPAddress savedIP;
|
||||
String savedHost;
|
||||
IPAddress savedHostIP;
|
||||
IPAddress savedOperatingIP;
|
||||
bool inCommandMode;
|
||||
uint32_t lastCommandModeMillis;
|
||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
||||
|
Reference in New Issue
Block a user