|
@ -24,6 +24,20 @@ |
|
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; |
|
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; |
|
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; |
|
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; |
|
|
|
|
|
|
|
|
|
|
|
// Use this to avoid too many entrances and exits from command mode. |
|
|
|
|
|
// The cellular Bee's often freeze up and won't respond when attempting |
|
|
|
|
|
// to enter command mode too many times. |
|
|
|
|
|
#define XBEE_COMMAND_START_DECORATOR(nAttempts, failureReturn) \ |
|
|
|
|
|
bool wasInCommandMode = inCommandMode; \ |
|
|
|
|
|
if (!wasInCommandMode) { /* don't re-enter command mode if already in it */ \ |
|
|
|
|
|
if (!commandMode(nAttempts)) return failureReturn; /* Return immediately if fails */ \ |
|
|
|
|
|
} |
|
|
|
|
|
#define XBEE_COMMAND_END_DECORATOR \ |
|
|
|
|
|
if (!wasInCommandMode) { /* only exit if we weren't in command mode */ \ |
|
|
|
|
|
exitCommand(); \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum SimStatus { |
|
|
enum SimStatus { |
|
|
SIM_ERROR = 0, |
|
|
SIM_ERROR = 0, |
|
|
SIM_READY = 1, |
|
|
SIM_READY = 1, |
|
@ -77,31 +91,30 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
// NOTE: The XBee saves all paramter information in flash. When you turn it |
|
|
|
|
|
// on it immediately prepares 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 is not opened until you attempt to send data. |
|
|
|
|
|
|
|
|
// 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 itself is not opened until you attempt to send data. |
|
|
// Because all settings are saved to flash, it is possible (or likely) that |
|
|
// Because all settings are saved to flash, it is possible (or likely) that |
|
|
// you could send out data even if you haven't "made" any connection. |
|
|
|
|
|
virtual int connect(const char *host, uint16_t port) { |
|
|
|
|
|
|
|
|
// you could send data even if you haven't "made" any connection. |
|
|
|
|
|
virtual int connect(const char *host, uint16_t port, int timeout) { |
|
|
|
|
|
// NOTE: Not caling stop() or yeild() here |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode |
|
|
|
|
|
sock_connected = at->modemConnect(host, port, mux, false); |
|
|
|
|
|
at->writeChanges(); |
|
|
|
|
|
at->exitCommand(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
sock_connected = at->modemConnect(host, port, mux, timeout); |
|
|
return sock_connected; |
|
|
return sock_connected; |
|
|
} |
|
|
} |
|
|
|
|
|
virtual int connect(const char *host, uint16_t port) { |
|
|
|
|
|
return connect(host, port, 75000L); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
virtual int connect(IPAddress ip, uint16_t port) { |
|
|
|
|
|
|
|
|
virtual int connect(IPAddress ip, uint16_t port, int timeout) { |
|
|
|
|
|
// NOTE: Not caling stop() or yeild() here |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode |
|
|
|
|
|
sock_connected = at->modemConnect(ip, port, mux, false); |
|
|
|
|
|
at->writeChanges(); |
|
|
|
|
|
at->exitCommand(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
sock_connected = at->modemConnect(ip, port, mux, timeout); |
|
|
return sock_connected; |
|
|
return sock_connected; |
|
|
} |
|
|
} |
|
|
|
|
|
virtual int connect(IPAddress ip, uint16_t port) { |
|
|
|
|
|
return connect(ip, port, 75000L); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
virtual void stop() { |
|
|
virtual void stop() { |
|
|
at->streamClear(); // Empty anything in the buffer |
|
|
at->streamClear(); // Empty anything in the buffer |
|
@ -196,12 +209,6 @@ public: |
|
|
if (available()) { |
|
|
if (available()) { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
// Double check that we don't know it's closed |
|
|
|
|
|
// NOTE: modemGetConnected() is likely to return a "false" true because |
|
|
|
|
|
// it will return unknown until after data is sent over the connection. |
|
|
|
|
|
// If the socket is definitely closed, modemGetConnected() will set |
|
|
|
|
|
// sock_connected to false; |
|
|
|
|
|
at->modemGetConnected(); |
|
|
|
|
|
return sock_connected; |
|
|
return sock_connected; |
|
|
} |
|
|
} |
|
|
virtual operator bool() { return connected(); } |
|
|
virtual operator bool() { return connected(); } |
|
@ -230,23 +237,17 @@ public: |
|
|
{} |
|
|
{} |
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
virtual int connect(const char *host, uint16_t port) { |
|
|
|
|
|
|
|
|
virtual int connect(const char *host, uint16_t port, int timeout) { |
|
|
|
|
|
// NOTE: Not caling stop() or yeild() here |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode |
|
|
|
|
|
sock_connected = at->modemConnect(host, port, mux, true); |
|
|
|
|
|
at->writeChanges(); |
|
|
|
|
|
at->exitCommand(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
sock_connected = at->modemConnect(host, port, mux, true, timeout); |
|
|
return sock_connected; |
|
|
return sock_connected; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
virtual int connect(IPAddress ip, uint16_t port) { |
|
|
|
|
|
|
|
|
virtual int connect(IPAddress ip, uint16_t port, int timeout) { |
|
|
|
|
|
// NOTE: Not caling stop() or yeild() here |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
at->streamClear(); // Empty anything in the buffer before starting |
|
|
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode |
|
|
|
|
|
sock_connected = at->modemConnect(ip, port, mux, false); |
|
|
|
|
|
at->writeChanges(); |
|
|
|
|
|
at->exitCommand(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
sock_connected = at->modemConnect(ip, port, mux, timeout); |
|
|
return sock_connected; |
|
|
return sock_connected; |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
@ -294,20 +295,26 @@ public: |
|
|
digitalWrite(resetPin, HIGH); |
|
|
digitalWrite(resetPin, HIGH); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!commandMode(10)) return false; // Try up to 10 times for the init |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(10, false) |
|
|
|
|
|
|
|
|
sendAT(GF("AP0")); // Put in transparent mode |
|
|
sendAT(GF("AP0")); // Put in transparent mode |
|
|
bool ret_val = waitResponse() == 1; |
|
|
bool ret_val = waitResponse() == 1; |
|
|
ret_val &= writeChanges(); |
|
|
|
|
|
|
|
|
|
|
|
sendAT(GF("GT64")); // shorten the guard time to 100ms |
|
|
sendAT(GF("GT64")); // shorten the guard time to 100ms |
|
|
ret_val &= waitResponse(); |
|
|
|
|
|
ret_val &= writeChanges(); |
|
|
|
|
|
|
|
|
ret_val &= waitResponse() == 1; |
|
|
if (ret_val) guardTime = 110; |
|
|
if (ret_val) guardTime = 110; |
|
|
|
|
|
|
|
|
|
|
|
// Make sure the command mode drop-out time is long enough that we won't fall |
|
|
|
|
|
// out of command mode without intentionally leaving it. This is the default |
|
|
|
|
|
// drop out time of 0x64 x 100ms (10 seconds) |
|
|
|
|
|
sendAT(GF("CT64")); |
|
|
|
|
|
ret_val &= waitResponse() == 1; |
|
|
|
|
|
ret_val &= writeChanges(); |
|
|
|
|
|
|
|
|
getSeries(); // Get the "Hardware Series"; |
|
|
getSeries(); // Get the "Hardware Series"; |
|
|
|
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
return ret_val; |
|
|
return ret_val; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -316,7 +323,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void setBaud(unsigned long baud) { |
|
|
void setBaud(unsigned long baud) { |
|
|
if (!commandMode()) return; |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, ) |
|
|
switch(baud) |
|
|
switch(baud) |
|
|
{ |
|
|
{ |
|
|
case 2400: sendAT(GF("BD1")); break; |
|
|
case 2400: sendAT(GF("BD1")); break; |
|
@ -337,7 +344,7 @@ public: |
|
|
} |
|
|
} |
|
|
waitResponse(); |
|
|
waitResponse(); |
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool testAT(unsigned long timeout = 10000L) { |
|
|
bool testAT(unsigned long timeout = 10000L) { |
|
@ -352,9 +359,8 @@ public: |
|
|
sendAT(); |
|
|
sendAT(); |
|
|
if (waitResponse(200) == 1) { |
|
|
if (waitResponse(200) == 1) { |
|
|
success = true; |
|
|
success = true; |
|
|
exitCommand(); |
|
|
|
|
|
} |
|
|
} |
|
|
// if we didn't respond to the AT, must not be in command mode |
|
|
|
|
|
|
|
|
// if we didn't respond to the AT, assume we're not in command mode |
|
|
else inCommandMode = false; |
|
|
else inCommandMode = false; |
|
|
} |
|
|
} |
|
|
delay(250); |
|
|
delay(250); |
|
@ -375,11 +381,11 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool factoryDefault() { |
|
|
bool factoryDefault() { |
|
|
if (!commandMode()) return false; // Return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
sendAT(GF("RE")); |
|
|
sendAT(GF("RE")); |
|
|
bool ret_val = waitResponse() == 1; |
|
|
bool ret_val = waitResponse() == 1; |
|
|
ret_val &= writeChanges(); |
|
|
ret_val &= writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
// Make sure the guard time for the modem object is set back to default |
|
|
// Make sure the guard time for the modem object is set back to default |
|
|
// otherwise communication would fail after the reset |
|
|
// otherwise communication would fail after the reset |
|
|
guardTime = 1010; |
|
|
guardTime = 1010; |
|
@ -387,14 +393,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String getModemInfo() { |
|
|
String getModemInfo() { |
|
|
String modemInf = ""; |
|
|
|
|
|
if (!commandMode()) return modemInf; // Try up to 10 times for the init |
|
|
|
|
|
|
|
|
|
|
|
sendAT(GF("HS")); // Get the "Hardware Series" |
|
|
|
|
|
modemInf += readResponseString(); |
|
|
|
|
|
|
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
return modemInf; |
|
|
|
|
|
|
|
|
return sendATGetString(GF("HS")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool hasSSL() { |
|
|
bool hasSSL() { |
|
@ -443,7 +442,9 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool restart() { |
|
|
bool restart() { |
|
|
|
|
|
|
|
|
if (!commandMode()) return false; // Return immediately |
|
|
if (!commandMode()) return false; // Return immediately |
|
|
|
|
|
|
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // how we restart depends on this |
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // how we restart depends on this |
|
|
|
|
|
|
|
|
if (beeType != XBEE_S6B_WIFI) { |
|
|
if (beeType != XBEE_S6B_WIFI) { |
|
@ -455,9 +456,10 @@ public: |
|
|
|
|
|
|
|
|
sendAT(GF("FR")); |
|
|
sendAT(GF("FR")); |
|
|
if (waitResponse() != 1) return exitAndFail(); |
|
|
if (waitResponse() != 1) return exitAndFail(); |
|
|
|
|
|
else inCommandMode = false; // Reset effectively exits command mode |
|
|
|
|
|
|
|
|
if (beeType == XBEE_S6B_WIFI) delay(2000); // Wifi module actually resets about 2 seconds later |
|
|
if (beeType == XBEE_S6B_WIFI) delay(2000); // Wifi module actually resets about 2 seconds later |
|
|
else delay(100); // cellular modules wait 100ms before reset happes |
|
|
|
|
|
|
|
|
else delay(100); // cellular modules wait 100ms before reset happens |
|
|
|
|
|
|
|
|
// Wait until reboot complete and responds to command mode call again |
|
|
// Wait until reboot complete and responds to command mode call again |
|
|
for (unsigned long start = millis(); millis() - start < 60000L; ) { |
|
|
for (unsigned long start = millis(); millis() - start < 60000L; ) { |
|
@ -477,7 +479,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void setupPinSleep(bool maintainAssociation = false) { |
|
|
void setupPinSleep(bool maintainAssociation = false) { |
|
|
if (!commandMode()) return; // Return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, ) |
|
|
|
|
|
|
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // Command depends on series |
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // Command depends on series |
|
|
|
|
|
|
|
@ -496,7 +498,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool poweroff() { // Not supported |
|
|
bool poweroff() { // Not supported |
|
@ -516,19 +518,11 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String getSimCCID() { |
|
|
String getSimCCID() { |
|
|
if (!commandMode()) return ""; // Return immediately |
|
|
|
|
|
sendAT(GF("S#")); |
|
|
|
|
|
String res = readResponseString(); |
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
return res; |
|
|
|
|
|
|
|
|
return sendATGetString(GF("S#")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String getIMEI() { |
|
|
String getIMEI() { |
|
|
if (!commandMode()) return ""; // Return immediately |
|
|
|
|
|
sendAT(GF("IM")); |
|
|
|
|
|
String res = readResponseString(); |
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
return res; |
|
|
|
|
|
|
|
|
return sendATGetString(GF("IM")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
SimStatus getSimStatus(unsigned long timeout = 10000L) { |
|
|
SimStatus getSimStatus(unsigned long timeout = 10000L) { |
|
@ -537,10 +531,7 @@ public: |
|
|
|
|
|
|
|
|
RegStatus getRegistrationStatus() { |
|
|
RegStatus getRegistrationStatus() { |
|
|
|
|
|
|
|
|
bool wasInCommandMode = inCommandMode; |
|
|
|
|
|
if (!wasInCommandMode) { // don't re-enter command mode if already in it |
|
|
|
|
|
commandMode(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, REG_UNKNOWN) |
|
|
|
|
|
|
|
|
if (!inCommandMode) return REG_UNKNOWN; // Return immediately |
|
|
if (!inCommandMode) return REG_UNKNOWN; // Return immediately |
|
|
|
|
|
|
|
@ -619,18 +610,12 @@ public: |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (!wasInCommandMode) { // only exit if we weren't in command mode |
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
return stat; |
|
|
return stat; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String getOperator() { |
|
|
String getOperator() { |
|
|
if (!commandMode()) return ""; // Return immediately |
|
|
|
|
|
sendAT(GF("MN")); |
|
|
|
|
|
String res = readResponseString(); |
|
|
|
|
|
exitCommand(); |
|
|
|
|
|
return res; |
|
|
|
|
|
|
|
|
return sendATGetString(GF("MN")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
@ -638,12 +623,17 @@ public: |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
int16_t getSignalQuality() { |
|
|
int16_t getSignalQuality() { |
|
|
if (!commandMode()) return 0; // Return immediately |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, 0); |
|
|
|
|
|
|
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // Need to know what type of bee so we know how to ask |
|
|
if (beeType == XBEE_UNKNOWN) getSeries(); // Need to know what type of bee so we know how to ask |
|
|
|
|
|
|
|
|
if (beeType == XBEE_S6B_WIFI) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity |
|
|
if (beeType == XBEE_S6B_WIFI) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity |
|
|
else sendAT(GF("DB")); // ask for the cell strength in dBm |
|
|
else sendAT(GF("DB")); // ask for the cell strength in dBm |
|
|
int16_t intRes = readResponseInt(); |
|
|
int16_t intRes = readResponseInt(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
if (beeType == XBEE3_LTEM_ATT && intRes == 105) intRes = 0; // tends to reply with "69" when signal is unknown |
|
|
if (beeType == XBEE3_LTEM_ATT && intRes == 105) intRes = 0; // tends to reply with "69" when signal is unknown |
|
|
if (beeType == XBEE_S6B_WIFI) return -93 + intRes; // the maximum sensitivity is -93dBm |
|
|
if (beeType == XBEE_S6B_WIFI) return -93 + intRes; // the maximum sensitivity is -93dBm |
|
|
else return -1*intRes; // need to convert to negative number |
|
|
else return -1*intRes; // need to convert to negative number |
|
@ -655,17 +645,14 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool waitForNetwork(unsigned long timeout = 60000L) { |
|
|
bool waitForNetwork(unsigned long timeout = 60000L) { |
|
|
// Enter command mode at the start so we don't have to go in and out of it |
|
|
|
|
|
// The cellular Bee's often freeze up and won't respond when attempting |
|
|
|
|
|
// to enter command mode too many times. |
|
|
|
|
|
commandMode(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
for (unsigned long start = millis(); millis() - start < timeout; ) { |
|
|
for (unsigned long start = millis(); millis() - start < timeout; ) { |
|
|
if (isNetworkConnected()) { |
|
|
if (isNetworkConnected()) { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
delay(250); // per Neil H. - more stable with delay |
|
|
delay(250); // per Neil H. - more stable with delay |
|
|
} |
|
|
} |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -675,7 +662,8 @@ public: |
|
|
|
|
|
|
|
|
bool networkConnect(const char* ssid, const char* pwd) { |
|
|
bool networkConnect(const char* ssid, const char* pwd) { |
|
|
|
|
|
|
|
|
if (!commandMode()) return false; // return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
|
|
|
|
|
|
//nh For no pwd don't set setscurity or pwd |
|
|
//nh For no pwd don't set setscurity or pwd |
|
|
if (NULL == ssid ) return exitAndFail(); |
|
|
if (NULL == ssid ) return exitAndFail(); |
|
|
|
|
|
|
|
@ -693,19 +681,19 @@ public: |
|
|
if (waitResponse() != 1) return exitAndFail(); |
|
|
if (waitResponse() != 1) return exitAndFail(); |
|
|
|
|
|
|
|
|
if (!writeChanges()) return exitAndFail(); |
|
|
if (!writeChanges()) return exitAndFail(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool networkDisconnect() { |
|
|
bool networkDisconnect() { |
|
|
if (!commandMode()) return false; // return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
sendAT(GF("NR0")); // Do a network reset in order to disconnect |
|
|
sendAT(GF("NR0")); // Do a network reset in order to disconnect |
|
|
// NOTE: On wifi modules, using a network reset will not |
|
|
|
|
|
|
|
|
// WARNING: On wifi modules, using a network reset will not |
|
|
// allow the same ssid to re-join without rebooting the module. |
|
|
// allow the same ssid to re-join without rebooting the module. |
|
|
int8_t res = (1 == waitResponse(5000)); |
|
|
int8_t res = (1 == waitResponse(5000)); |
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
return res; |
|
|
return res; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -714,12 +702,12 @@ public: |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
String getLocalIP() { |
|
|
String getLocalIP() { |
|
|
if (!commandMode()) return ""; // Return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, "") |
|
|
sendAT(GF("MY")); |
|
|
sendAT(GF("MY")); |
|
|
String IPaddr; IPaddr.reserve(16); |
|
|
String IPaddr; IPaddr.reserve(16); |
|
|
// wait for the response - this response can be very slow |
|
|
// wait for the response - this response can be very slow |
|
|
IPaddr = readResponseString(30000); |
|
|
IPaddr = readResponseString(30000); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
IPaddr.trim(); |
|
|
IPaddr.trim(); |
|
|
return IPaddr; |
|
|
return IPaddr; |
|
|
} |
|
|
} |
|
@ -733,23 +721,23 @@ public: |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { |
|
|
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { |
|
|
if (!commandMode()) return false; // Return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
sendAT(GF("AN"), apn); // Set the APN |
|
|
sendAT(GF("AN"), apn); // Set the APN |
|
|
waitResponse(); |
|
|
|
|
|
|
|
|
bool success = waitResponse() == 1; |
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
return success; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool gprsDisconnect() { |
|
|
bool gprsDisconnect() { |
|
|
if (!commandMode()) return false; // return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
sendAT(GF("AM1")); // Cheating and disconnecting by turning on airplane mode |
|
|
sendAT(GF("AM1")); // Cheating and disconnecting by turning on airplane mode |
|
|
int8_t res = (1 == waitResponse(5000)); |
|
|
int8_t res = (1 == waitResponse(5000)); |
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
sendAT(GF("AM0")); // Airplane mode off |
|
|
sendAT(GF("AM0")); // Airplane mode off |
|
|
waitResponse(5000); |
|
|
waitResponse(5000); |
|
|
writeChanges(); |
|
|
writeChanges(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
return res; |
|
|
return res; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -772,11 +760,14 @@ public: |
|
|
if (waitResponse() !=1) return exitAndFail(); |
|
|
if (waitResponse() !=1) return exitAndFail(); |
|
|
sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage return) |
|
|
sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage return) |
|
|
if (waitResponse() !=1) return exitAndFail(); |
|
|
if (waitResponse() !=1) return exitAndFail(); |
|
|
if (!writeChanges()) return exitAndFail(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!writeChanges()) return exitAndFail(); |
|
|
|
|
|
// Get out of command mode to actually send the text |
|
|
exitCommand(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
streamWrite(text); |
|
|
streamWrite(text); |
|
|
stream.write((char)0x0D); // close off with the carriage return |
|
|
stream.write((char)0x0D); // close off with the carriage return |
|
|
|
|
|
|
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -800,16 +791,17 @@ public: |
|
|
|
|
|
|
|
|
protected: |
|
|
protected: |
|
|
|
|
|
|
|
|
IPAddress getHostIP(const char* host) { |
|
|
|
|
|
|
|
|
IPAddress getHostIP(const char* host, int timeout = 45000L) { |
|
|
String strIP; strIP.reserve(16); |
|
|
String strIP; strIP.reserve(16); |
|
|
unsigned long startMillis = millis(); |
|
|
unsigned long startMillis = millis(); |
|
|
bool gotIP = false; |
|
|
bool gotIP = false; |
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, IPAddress(0,0,0,0)) |
|
|
// XBee's require a numeric IP address for connection, but do provide the |
|
|
// XBee's require a numeric IP address for connection, but do provide the |
|
|
// functionality to look up the IP address from a fully qualified domain name |
|
|
// functionality to look up the IP address from a fully qualified domain name |
|
|
while (millis() - startMillis < 45000L) // the lookup can take a while |
|
|
|
|
|
|
|
|
while (millis() - startMillis < timeout) // the lookup can take a while |
|
|
{ |
|
|
{ |
|
|
sendAT(GF("LA"), host); |
|
|
sendAT(GF("LA"), host); |
|
|
while (stream.available() < 4 && (millis() - startMillis < 45000L)) {}; // wait for any response |
|
|
|
|
|
|
|
|
while (stream.available() < 4 && (millis() - startMillis < timeout)) {}; // wait for any response |
|
|
strIP = stream.readStringUntil('\r'); // read result |
|
|
strIP = stream.readStringUntil('\r'); // read result |
|
|
strIP.trim(); |
|
|
strIP.trim(); |
|
|
if (!strIP.endsWith(GF("ERROR"))) { |
|
|
if (!strIP.endsWith(GF("ERROR"))) { |
|
@ -818,33 +810,44 @@ protected: |
|
|
} |
|
|
} |
|
|
delay(2500); // wait a bit before trying again |
|
|
delay(2500); // wait a bit before trying again |
|
|
} |
|
|
} |
|
|
if (gotIP) { // No reason to continue if we don't know the IP address |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
|
|
|
if (gotIP) { |
|
|
return TinyGsmIpFromString(strIP); |
|
|
return TinyGsmIpFromString(strIP); |
|
|
} |
|
|
} |
|
|
else return IPAddress(0,0,0,0); |
|
|
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->savedHost == String(host) && savedIP != IPAddress(0,0,0,0)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, |
|
|
|
|
|
bool ssl = false, int timeout = 75000L) |
|
|
|
|
|
{ |
|
|
|
|
|
unsigned long startMillis = millis(); |
|
|
|
|
|
bool retVal = false; |
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
|
|
|
|
|
|
|
|
|
// If it's a new host or we dont' have a good IP, we need to do a DNS |
|
|
|
|
|
// search for the IP to connect to |
|
|
|
|
|
if (this->savedHost != String(host) || savedIP == IPAddress(0,0,0,0)) { |
|
|
|
|
|
this->savedHost = String(host); |
|
|
|
|
|
savedIP = getHostIP(host, timeout); // This will return 0.0.0.0 if lookup fails |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Otherwise, set the new host and mark the IP as invalid |
|
|
|
|
|
this->savedHost = String(host); |
|
|
|
|
|
savedIP = 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 we now have a valid IP address, use it to connect |
|
|
if (savedIP != IPAddress(0,0,0,0)) { // Only re-set connection information if we have an IP address |
|
|
if (savedIP != IPAddress(0,0,0,0)) { // Only re-set connection information if we have an IP address |
|
|
return modemConnect(savedIP, port, mux, ssl); |
|
|
|
|
|
|
|
|
retVal = modemConnect(savedIP, port, mux, ssl, timeout - (millis() - startMillis)); |
|
|
} |
|
|
} |
|
|
else return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
|
|
|
return retVal; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) { |
|
|
|
|
|
|
|
|
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false, int timeout = 75000L) { |
|
|
|
|
|
|
|
|
savedIP = ip; // Set the newly requested IP address |
|
|
savedIP = ip; // Set the newly requested IP address |
|
|
bool success = true; |
|
|
bool success = true; |
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
String host; host.reserve(16); |
|
|
String host; host.reserve(16); |
|
|
host += ip[0]; |
|
|
host += ip[0]; |
|
|
host += "."; |
|
|
host += "."; |
|
@ -853,6 +856,7 @@ protected: |
|
|
host += ip[2]; |
|
|
host += ip[2]; |
|
|
host += "."; |
|
|
host += "."; |
|
|
host += ip[3]; |
|
|
host += ip[3]; |
|
|
|
|
|
|
|
|
if (ssl) { |
|
|
if (ssl) { |
|
|
sendAT(GF("IP"), 4); // Put in SSL over TCP communication mode |
|
|
sendAT(GF("IP"), 4); // Put in SSL over TCP communication mode |
|
|
success &= (1 == waitResponse()); |
|
|
success &= (1 == waitResponse()); |
|
@ -860,10 +864,21 @@ protected: |
|
|
sendAT(GF("IP"), 1); // Put in TCP mode |
|
|
sendAT(GF("IP"), 1); // Put in TCP mode |
|
|
success &= (1 == waitResponse()); |
|
|
success &= (1 == waitResponse()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
sendAT(GF("DL"), host); // Set the "Destination Address Low" |
|
|
sendAT(GF("DL"), host); // Set the "Destination Address Low" |
|
|
success &= (1 == waitResponse()); |
|
|
success &= (1 == waitResponse()); |
|
|
sendAT(GF("DE"), String(port, HEX)); // Set the destination port |
|
|
sendAT(GF("DE"), String(port, HEX)); // Set the destination port |
|
|
success &= (1 == waitResponse()); |
|
|
success &= (1 == waitResponse()); |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned long start = millis(); millis() - start < timeout; ) { |
|
|
|
|
|
if (modemGetConnected()) { |
|
|
|
|
|
sockets[mux]->sock_connected = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
|
|
|
return success; |
|
|
return success; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -879,7 +894,7 @@ protected: |
|
|
// as true so there's a possibility it's wrong. |
|
|
// as true so there's a possibility it's wrong. |
|
|
bool modemGetConnected() { |
|
|
bool modemGetConnected() { |
|
|
|
|
|
|
|
|
if (!commandMode()) return false; // Return immediately |
|
|
|
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, false) |
|
|
|
|
|
|
|
|
// If the IP address is 0, it's not valid so we can't be connected |
|
|
// If the IP address is 0, it's not valid so we can't be connected |
|
|
if (savedIP == IPAddress(0,0,0,0)) return false; |
|
|
if (savedIP == IPAddress(0,0,0,0)) return false; |
|
@ -898,14 +913,14 @@ protected: |
|
|
case XBEE_S6B_WIFI: { |
|
|
case XBEE_S6B_WIFI: { |
|
|
RegStatus s = getRegistrationStatus(); |
|
|
RegStatus s = getRegistrationStatus(); |
|
|
if (s != REG_OK) { |
|
|
if (s != REG_OK) { |
|
|
sockets[0]->sock_connected = false; |
|
|
|
|
|
|
|
|
sockets[0]->sock_connected = false; // no multiplex |
|
|
} |
|
|
} |
|
|
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 |
|
|
default: { // Cellular XBee's |
|
|
sendAT(GF("CI")); |
|
|
sendAT(GF("CI")); |
|
|
int16_t intRes = readResponseInt(); |
|
|
int16_t intRes = readResponseInt(); |
|
|
exitCommand(); |
|
|
|
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
switch(intRes) { |
|
|
switch(intRes) { |
|
|
case 0x00: // 0x00 = The socket is definitely open |
|
|
case 0x00: // 0x00 = The socket is definitely open |
|
|
case 0xFF: // 0xFF = No known status - this is always returned prior to sending data |
|
|
case 0xFF: // 0xFF = No known status - this is always returned prior to sending data |
|
@ -1014,10 +1029,15 @@ finish: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool commandMode(uint8_t retries = 5) { |
|
|
bool commandMode(uint8_t retries = 5) { |
|
|
|
|
|
|
|
|
|
|
|
// If we're already in command mode, move on |
|
|
|
|
|
if (inCommandMode && (millis() - lastCommandModeMillis) < 10000L) return true; |
|
|
|
|
|
|
|
|
uint8_t triesMade = 0; |
|
|
uint8_t triesMade = 0; |
|
|
uint8_t triesUntilReset = 4; // only reset after 4 failures |
|
|
uint8_t triesUntilReset = 4; // only reset after 4 failures |
|
|
bool success = false; |
|
|
bool success = false; |
|
|
streamClear(); // Empty everything in the buffer before starting |
|
|
streamClear(); // Empty everything in the buffer before starting |
|
|
|
|
|
|
|
|
while (!success and triesMade < retries) { |
|
|
while (!success and triesMade < retries) { |
|
|
// Cannot send anything for 1 "guard time" before entering command mode |
|
|
// Cannot send anything for 1 "guard time" before entering command mode |
|
|
// Default guard time is 1s, but the init fxn decreases it to 100 ms |
|
|
// Default guard time is 1s, but the init fxn decreases it to 100 ms |
|
@ -1036,7 +1056,11 @@ finish: |
|
|
} |
|
|
} |
|
|
triesMade ++; |
|
|
triesMade ++; |
|
|
} |
|
|
} |
|
|
if (success) inCommandMode = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (success) { |
|
|
|
|
|
inCommandMode = true; |
|
|
|
|
|
lastCommandModeMillis = millis(); |
|
|
|
|
|
} |
|
|
return success; |
|
|
return success; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1049,6 +1073,8 @@ finish: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void exitCommand(void) { |
|
|
void exitCommand(void) { |
|
|
|
|
|
// NOTE: Here we explicitely try to exit command mode |
|
|
|
|
|
// even if the internal flag inCommandMode was already false |
|
|
sendAT(GF("CN")); // Exit command mode |
|
|
sendAT(GF("CN")); // Exit command mode |
|
|
waitResponse(); |
|
|
waitResponse(); |
|
|
inCommandMode = false; |
|
|
inCommandMode = false; |
|
@ -1083,6 +1109,14 @@ finish: |
|
|
return intRes; |
|
|
return intRes; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String sendATGetString(GsmConstStr cmd) { |
|
|
|
|
|
XBEE_COMMAND_START_DECORATOR(5, "") |
|
|
|
|
|
sendAT(cmd); |
|
|
|
|
|
String res = readResponseString(); |
|
|
|
|
|
XBEE_COMMAND_END_DECORATOR |
|
|
|
|
|
return res; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
bool gotIPforSavedHost() { |
|
|
bool gotIPforSavedHost() { |
|
|
if (savedHost != "" && savedIP != IPAddress(0,0,0,0)) return true; |
|
|
if (savedHost != "" && savedIP != IPAddress(0,0,0,0)) return true; |
|
|
else return false; |
|
|
else return false; |
|
@ -1098,6 +1132,7 @@ protected: |
|
|
IPAddress savedIP; |
|
|
IPAddress savedIP; |
|
|
String savedHost; |
|
|
String savedHost; |
|
|
bool inCommandMode; |
|
|
bool inCommandMode; |
|
|
|
|
|
uint32_t lastCommandModeMillis; |
|
|
GsmClient* sockets[TINY_GSM_MUX_COUNT]; |
|
|
GsmClient* sockets[TINY_GSM_MUX_COUNT]; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|