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) {
|
virtual void stop(uint32_t maxWaitMs) {
|
||||||
at->streamClear(); // Empty anything in the buffer
|
at->streamClear(); // Empty anything in the buffer
|
||||||
|
// empty the saved currently-in-use destination address
|
||||||
|
at->savedOperatingIP = IPAddress(0, 0, 0, 0);
|
||||||
at->commandMode();
|
at->commandMode();
|
||||||
// For WiFi models, there's no direct way to close the socket. This is a
|
// 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.
|
// hack to shut the socket by setting the timeout to zero.
|
||||||
@@ -216,6 +218,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return sock_connected;
|
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(); }
|
virtual operator bool() { return connected(); }
|
||||||
|
|
||||||
@@ -834,6 +840,30 @@ public:
|
|||||||
|
|
||||||
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) {
|
IPAddress lookupHostIP(const char* host, int timeout_s = 45) {
|
||||||
String strIP;
|
String strIP;
|
||||||
strIP.reserve(16);
|
strIP.reserve(16);
|
||||||
@@ -867,8 +897,6 @@ protected:
|
|||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0,
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0,
|
||||||
bool ssl = false, int timeout_s = 75)
|
bool ssl = false, int timeout_s = 75)
|
||||||
{
|
{
|
||||||
unsigned long startMillis = millis();
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
|
||||||
bool retVal = false;
|
bool retVal = false;
|
||||||
XBEE_COMMAND_START_DECORATOR(5, 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 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
|
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
|
XBEE_COMMAND_END_DECORATOR
|
||||||
@@ -893,13 +921,19 @@ protected:
|
|||||||
return retVal;
|
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;
|
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)
|
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
|
savedIP = ip; // Set the newly requested IP address
|
||||||
String host; host.reserve(16);
|
String host; host.reserve(16);
|
||||||
host += ip[0];
|
host += ip[0];
|
||||||
@@ -926,11 +960,12 @@ protected:
|
|||||||
success &= writeChanges();
|
success &= writeChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
// we'll accept either unknown or connected
|
||||||
if (modemGetConnected()) {
|
uint16_t ci = getConnectionIndicator();
|
||||||
|
success &= (ci == 0x00 || ci == 0xFF || ci == 0x28);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
sockets[mux]->sock_connected = true;
|
sockets[mux]->sock_connected = true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XBEE_COMMAND_END_DECORATOR
|
XBEE_COMMAND_END_DECORATOR
|
||||||
@@ -942,6 +977,17 @@ protected:
|
|||||||
if (mux != 0) DBG("XBee only supports 1 IP channel in transparent mode!");
|
if (mux != 0) DBG("XBee only supports 1 IP channel in transparent mode!");
|
||||||
stream.write((uint8_t*)buff, len);
|
stream.write((uint8_t*)buff, len);
|
||||||
stream.flush();
|
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;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,17 +1001,11 @@ protected:
|
|||||||
|
|
||||||
XBEE_COMMAND_START_DECORATOR(5, false)
|
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
|
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: {
|
case XBEE_S6B_WIFI: {
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
XBEE_COMMAND_END_DECORATOR
|
XBEE_COMMAND_END_DECORATOR
|
||||||
@@ -974,23 +1014,112 @@ protected:
|
|||||||
}
|
}
|
||||||
return (s == REG_OK); // if it's connected, we hope the sockets are too
|
return (s == REG_OK); // if it's connected, we hope the sockets are too
|
||||||
}
|
}
|
||||||
default: { // Cellular XBee's
|
|
||||||
sendAT(GF("CI"));
|
// Cellular XBee's
|
||||||
int16_t intRes = readResponseInt();
|
default: {
|
||||||
|
int16_t ci = getConnectionIndicator();
|
||||||
|
// Get the operating destination address
|
||||||
|
IPAddress od = getOperatingIP();
|
||||||
XBEE_COMMAND_END_DECORATOR
|
XBEE_COMMAND_END_DECORATOR
|
||||||
switch(intRes) {
|
|
||||||
case 0x00: // 0x00 = The socket is definitely open
|
switch(ci) {
|
||||||
case 0x28: // 0x28 = "Unknown."
|
|
||||||
case 0xFF: // 0xFF = No known status - this is always returned prior to sending data
|
// 0x00 = The socket is definitely open
|
||||||
return true;
|
case 0x00: {
|
||||||
case 0x02: // 0x02 = Invalid parameters (bad IP/host)
|
savedOperatingIP = od;
|
||||||
case 0x12: // 0x12 = DNS query lookup failure
|
// but it's possible the socket is set to the wrong place
|
||||||
case 0x25: // 0x25 = Unknown server - DNS lookup failed (0x22 for UDP socket!)
|
if (od != IPAddress(0, 0, 0, 0) && od != savedIP) {
|
||||||
savedIP = IPAddress(0,0,0,0); // force a lookup next time!
|
sockets[0]->stop();
|
||||||
default: // If it's anything else (inc 0x02, 0x12, and 0x25)...
|
|
||||||
sockets[0]->sock_connected = false; // ...it's definitely NOT connected
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
IPAddress savedIP;
|
||||||
String savedHost;
|
String savedHost;
|
||||||
IPAddress savedHostIP;
|
IPAddress savedHostIP;
|
||||||
|
IPAddress savedOperatingIP;
|
||||||
bool inCommandMode;
|
bool inCommandMode;
|
||||||
uint32_t lastCommandModeMillis;
|
uint32_t lastCommandModeMillis;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
|||||||
Reference in New Issue
Block a user