diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 496c6177..8413fb4e 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -32,6 +32,11 @@ #include "TinyGsmTemperature.tpp" #include "TinyGsmWifi.tpp" +//Debug TinyGsm WaitResponse callerID offsets +#define TGWRIDH 10 //header file base +#define TGWRIDW 50 //WiFi file base +#define TGWRIDT 100 //Transparent file base + #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; @@ -110,9 +115,10 @@ class TinyGsmXBee : public TinyGsmModem, } public: - // NOTE: The XBee saves all connection information (ssid/pwd or apn AND - // last used IP address) in flash (NVM). When you turn it on it immediately - // prepares to re-connect to whatever was last set. The TCP connection + // NOTE: The XBee saves all connection information (ssid/pwd etc) except + // IP address and port number, in flash (NVM). + // The NVM is be updated only when it is initialized. + // The TCP connection // itself is not opened until you attempt to send data. Because all settings // are saved to flash, it is possible (or likely) that you could send data // even if you haven't "made" any connection. @@ -244,7 +250,10 @@ class TinyGsmXBee : public TinyGsmModem, * Extended API */ - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + String remoteIP() { + IPAddress savedIP = at->savedIP; + return TinyGsmStringFromIp(savedIP); + } }; /* @@ -339,7 +348,7 @@ class TinyGsmXBee : public TinyGsmModem, // if there's a pin, we need to re-write to flash each time if (pin && strlen(pin) > 0) { sendAT(GF("PN"), pin); - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x01) != 1) { ret_val = false; } else { changesMade = true; @@ -353,7 +362,7 @@ class TinyGsmXBee : public TinyGsmModem, sendAT(GF("GT")); if (readResponseInt() != 0x64) { sendAT(GF("GT"), 64); - ret_val &= waitResponse() == 1; + ret_val &= waitResponse(TGWRIDH+0x02) == 1; if (ret_val) { guardTime = 110; changesMade = true; @@ -414,7 +423,7 @@ class TinyGsmXBee : public TinyGsmModem, if (success) exitCommand(); } else { sendAT(); - if (waitResponse(200) == 1) { + if (waitResponse(TGWRIDH+0x03,200) == 1) { success = true; } else { // if we didn't respond to the AT, assume we're not in command mode @@ -441,7 +450,7 @@ class TinyGsmXBee : public TinyGsmModem, bool factoryDefaultImpl() { XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("RE")); - bool ret_val = waitResponse() == 1; + bool ret_val = waitResponse(TGWRIDH+0x04) == 1; ret_val &= writeChanges(); XBEE_COMMAND_END_DECORATOR // Make sure the guard time for the modem object is set back to default @@ -505,24 +514,31 @@ class TinyGsmXBee : public TinyGsmModem, digitalWrite(resetPin, LOW); delay(1); digitalWrite(resetPin, HIGH); + } else { + DBG("pinReset - using software restart"); + restartImpl(); } } bool restartImpl(const char* pin = NULL) { - if (!commandMode()) { return false; } // Return immediately + if (!commandMode()) { + DBG("restartImpl not in commandMode. Exit"); + return false; + } // Return immediately if (beeType == XBEE_UNKNOWN) getSeries(); // how we restart depends on this + DBG("restartImpl",beeType ); if (beeType != XBEE_S6B_WIFI) { sendAT(GF("AM1")); // Digi suggests putting cellular modules into // airplane mode before restarting This allows the // sockets and connections to close cleanly - if (waitResponse() != 1) return exitAndFail(); + if (waitResponse(TGWRIDH+0x05) != 1) return exitAndFail(); if (!writeChanges()) return exitAndFail(); } sendAT(GF("FR")); - if (waitResponse() != 1) + if (waitResponse(TGWRIDH+0x06) != 1) return exitAndFail(); else inCommandMode = false; // Reset effectively exits command mode @@ -540,7 +556,7 @@ class TinyGsmXBee : public TinyGsmModem, if (beeType != XBEE_S6B_WIFI) { sendAT(GF("AM0")); // Turn off airplane mode - if (waitResponse() != 1) return exitAndFail(); + if (waitResponse(TGWRIDH+0x07) != 1) return exitAndFail(); if (!writeChanges()) return exitAndFail(); } @@ -576,7 +592,7 @@ class TinyGsmXBee : public TinyGsmModem, powerOffImpl() { // NOTE: Not supported for WiFi or older cellular firmware XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("SD")); - bool ret_val = waitResponse(120000L) == 1; + bool ret_val = waitResponse(TGWRIDH+0x08,120000L) == 1; // make sure we're really shut down if (ret_val) { ret_val &= (sendATGetString(GF("AI")) == "2D"); } XBEE_COMMAND_END_DECORATOR @@ -649,6 +665,7 @@ class TinyGsmXBee : public TinyGsmModem, break; default: stat = REG_UNKNOWN; break; } + DBG("Digi WiFi regStatus",stat,",",intRes); break; } default: { // Cellular XBee's @@ -672,13 +689,13 @@ class TinyGsmXBee : public TinyGsmModem, break; case 0x2A: // 0x2A Airplane mode. sendAT(GF("AM0")); // Turn off airplane mode - waitResponse(); + waitResponse(TGWRIDH+0x09); writeChanges(); stat = REG_UNKNOWN; break; case 0x2F: // 0x2F Bypass mode active. sendAT(GF("AP0")); // Set back to transparent mode - waitResponse(); + waitResponse(TGWRIDH+0x0a); writeChanges(); stat = REG_UNKNOWN; break; @@ -785,7 +802,7 @@ class TinyGsmXBee : public TinyGsmModem, // so we have no way of knowing if the passwords has changed // and must re-write to flash each time sendAT(GF("PK"), pwd); - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x0b) != 1) { retVal = false; } else { changesMade = true; @@ -806,7 +823,7 @@ class TinyGsmXBee : public TinyGsmModem, sendAT(GF("NR0")); // Do a network reset in order to disconnect // WARNING: On wifi modules, using a network reset will not // allow the same ssid to re-join without rebooting the module. - int8_t res = (1 == waitResponse(5000)); + int8_t res = (1 == waitResponse(TGWRIDH+0x0c,5000)); writeChanges(); XBEE_COMMAND_END_DECORATOR return res; @@ -827,7 +844,7 @@ class TinyGsmXBee : public TinyGsmModem, // and must re-write to flash each time if (user && strlen(user) > 0) { sendAT(GF("CU"), user); // Set the user for the APN - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x0d) != 1) { success = false; } else { changesMade = true; @@ -835,7 +852,7 @@ class TinyGsmXBee : public TinyGsmModem, } if (pwd && strlen(pwd) > 0) { sendAT(GF("CW"), pwd); // Set the password for the APN - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x0e) != 1) { success = false; } else { changesMade = true; @@ -877,7 +894,7 @@ class TinyGsmXBee : public TinyGsmModem, bool simUnlockImpl(const char* pin) { if (pin && strlen(pin) > 0) { sendAT(GF("PN"), pin); - return waitResponse() == 1; + return waitResponse(TGWRIDH+0x0f) == 1; } return false; } @@ -911,7 +928,7 @@ class TinyGsmXBee : public TinyGsmModem, sendAT(GF("IP")); // check mode if (readResponseInt() != 2) { sendAT(GF("IP"), 2); // Put in text messaging mode - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x10) != 1) { return exitAndFail(); } else { changesMade = true; @@ -921,7 +938,7 @@ class TinyGsmXBee : public TinyGsmModem, sendAT(GF("PH")); // check last number if (readResponseString() != String(number)) { sendAT(GF("PH"), number); // Set the phone number - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x11) != 1) { return exitAndFail(); } else { changesMade = true; @@ -932,7 +949,7 @@ class TinyGsmXBee : public TinyGsmModem, if (readResponseString() != String("D")) { sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D //(carriage return) - if (waitResponse() != 1) { + if (waitResponse(TGWRIDH+0x12) != 1) { return exitAndFail(); } else { changesMade = true; @@ -1125,12 +1142,18 @@ class TinyGsmXBee : public TinyGsmModem, // Put in TCP mode changesMade |= changeSettingIfNeeded(GF("IP"), 0x1); } + bool changesMadeCpy=changesMade; changesMade |= changeSettingIfNeeded( GF("DL"), String(host)); // Set the "Destination Address Low" changesMade |= changeSettingIfNeeded( GF("DE"), String(port, HEX)); // Set the destination port + if (beeType == XBEE_S6B_WIFI) { + DBG("modemConnect IP changes not saved"); + changesMade = changesMadeCpy; + } + if (changesMade) { success &= writeChanges(); } } @@ -1152,30 +1175,27 @@ class TinyGsmXBee : public TinyGsmModem, } bool modemStop(uint32_t maxWaitMs) { + DBG("modemStop WaitMs=",maxWaitMs); streamClear(); // Empty anything in the buffer // empty the saved currently-in-use destination address savedOperatingIP = IPAddress(0, 0, 0, 0); XBEE_COMMAND_START_DECORATOR(5, false) - // Get the current socket timeout - sendAT(GF("TM")); - String timeoutUsed = readResponseString(5000L); - - // For WiFi models, there's no direct way to close the socket. This is a + // This is a // hack to shut the socket by setting the timeout to zero. - if (beeType == XBEE_S6B_WIFI) { - sendAT(GF("TM0")); // Set socket timeout to 0 - waitResponse(maxWaitMs); // This response can be slow - writeChanges(); - } + // For WiFi use DigiXBeeWifi::disconnectInternet(void) + if (beeType != XBEE_S6B_WIFI) { + // Get the current socket timeout + sendAT(GF("TM")); + String timeoutUsed = readResponseString(5000L); - // For cellular models, per documentation: If you write the TM (socket - // timeout) value while in Transparent Mode, the current connection is - // immediately closed - this works even if the TM values is unchanged - sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout - waitResponse(maxWaitMs); // This response can be slow - writeChanges(); + // For cellular models, per documentation: If you write the TM (socket + // timeout) value while in Transparent Mode, the current connection is + // immediately closed - this works even if the TM values is unchanged + sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout + waitResponse(TGWRIDH+0x13,maxWaitMs); // This response can be slow + } XBEE_COMMAND_END_DECORATOR return true; @@ -1307,7 +1327,7 @@ class TinyGsmXBee : public TinyGsmModem, 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 + waitResponse(TGWRIDH+0x14,5000L); // This response can be slow } // 0x02 = Invalid parameters (bad IP/host) @@ -1348,7 +1368,7 @@ class TinyGsmXBee : public TinyGsmModem, // NOTE: This function is used while INSIDE command mode, so we're only // waiting for requested responses. The XBee has no unsoliliced responses // (URC's) when in command mode. - int8_t waitResponse(uint32_t timeout_ms, String& data, + int8_t waitResponse(uint8_t callerId,uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { @@ -1392,9 +1412,9 @@ class TinyGsmXBee : public TinyGsmModem, data.replace(GSM_NL GSM_NL, GSM_NL); data.replace(GSM_NL, "\r\n "); if (data.length()) { - DBG("### Unhandled:", data, "\r\n"); + DBG("### waitResponse",callerId," ms",timeout_ms," Unhandled:", data.c_str(), "\r\n"); } else { - DBG("### NO RESPONSE FROM MODEM!\r\n"); + DBG("### waitResponse",callerId," ms",timeout_ms," NO RESPONSE FROM MODEM!\r\n"); } } else { data.trim(); @@ -1406,17 +1426,17 @@ class TinyGsmXBee : public TinyGsmModem, return index; } - int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + int8_t waitResponse(uint8_t callerId,uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; - return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); + return waitResponse(callerId,timeout_ms, data, r1, r2, r3, r4, r5); } - int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + int8_t waitResponse(uint8_t callerId,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); + return waitResponse(callerId,1000, r1, r2, r3, r4, r5); } bool commandMode(uint8_t retries = 5) { @@ -1425,8 +1445,12 @@ class TinyGsmXBee : public TinyGsmModem, return true; uint8_t triesMade = 0; - uint8_t triesUntilReset = 4; // only reset after 4 failures + uint8_t triesUntilReset = 4; // reset after number of tries + int8_t res ; bool success = false; + if (beeType == XBEE_S6B_WIFI) { + triesUntilReset=9; + } streamClear(); // Empty everything in the buffer before starting while (!success && triesMade < retries) { @@ -1434,16 +1458,27 @@ class TinyGsmXBee : public TinyGsmModem, // Default guard time is 1s, but the init fxn decreases it to 100 ms delay(guardTime + 10); streamWrite(GF("+++")); // enter command mode - int8_t res = waitResponse(guardTime * 2); + + + if (beeType != XBEE_S6B_WIFI) { + res = waitResponse(TGWRIDH+0x15,guardTime * 2); + } else { + //S6B used longer guard time, to allow to recover + res = waitResponse(TGWRIDH+0x15); + } success = (1 == res); if (0 == res) { triesUntilReset--; if (triesUntilReset == 0) { + DBG("commandMode Module PinReset"); triesUntilReset = 4; pinReset(); // if it's unresponsive, reset delay(250); // a short delay to allow it to come back up // TODO(SRGDamia1) optimize this } + if (beeType == XBEE_S6B_WIFI) { + delay(5000); // WiFi module frozen, wait longer + } } triesMade++; } @@ -1457,9 +1492,9 @@ class TinyGsmXBee : public TinyGsmModem, bool writeChanges(void) { sendAT(GF("WR")); // Write changes to flash - if (1 != waitResponse()) { return false; } + if (1 != waitResponse(TGWRIDH+0x16)) { return false; } sendAT(GF("AC")); // Apply changes - if (1 != waitResponse()) { return false; } + if (1 != waitResponse(TGWRIDH+0x17)) { return false; } return true; } @@ -1467,7 +1502,7 @@ class TinyGsmXBee : public TinyGsmModem, // NOTE: Here we explicitely try to exit command mode // even if the internal flag inCommandMode was already false sendAT(GF("CN")); // Exit command mode - waitResponse(); + waitResponse(TGWRIDH+0x18); inCommandMode = false; } @@ -1528,7 +1563,7 @@ class TinyGsmXBee : public TinyGsmModem, if (readResponseInt() != newValue) { sendAT(cmd, newValue); // return false if we attempted to change but failed - if (waitResponse(timeout_ms) != 1) { return false; } + if (waitResponse(TGWRIDH+0x19,timeout_ms) != 1) { return false; } // return true if we succeeded in staging a change return true; } @@ -1542,8 +1577,14 @@ class TinyGsmXBee : public TinyGsmModem, if (readResponseString() != newValue) { sendAT(cmd, newValue); // return false if we attempted to change but failed - if (waitResponse(timeout_ms) != 1) { return false; } - // return true if we succeeded in staging a change + if (waitResponse(TGWRIDH+0x1a,timeout_ms) != 1) { return false; } + // check if we succeeded in staging a change + sendAT(cmd); + if (readResponseString() != newValue) { + sendAT(cmd, newValue); + if (waitResponse(TGWRIDH+0x1a,timeout_ms) != 1) { return false; } + DBG("changeSettingIfNeeded try2",cmd,newValue); + } return true; } // return false if no change is needed