@ -24,6 +24,20 @@
static const char GSM_OK [ ] TINY_GSM_PROGMEM = " OK " 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 {
SIM_ERROR = 0 ,
SIM_READY = 1 ,
@ -49,7 +63,7 @@ enum XBeeType {
} ;
class TinyGsmXBee : public TinyGsmModem
class TinyGsmXBee
{
public :
@ -77,31 +91,30 @@ 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
/ / 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_s ) {
/ / NOTE : Not caling stop ( ) or yeild ( ) here
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 , false , timeout_s ) ;
return sock_connected ;
}
virtual int connect ( const char * host , uint16_t port ) {
return connect ( host , port , 75 ) ;
}
virtual int connect ( IPAddress ip , uint16_t port ) {
virtual int connect ( IPAddress ip , uint16_t port , int timeout_s ) {
/ / NOTE : Not caling stop ( ) or yeild ( ) here
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_s ) ;
return sock_connected ;
}
virtual int connect ( IPAddress ip , uint16_t port ) {
return connect ( ip , port , 75 ) ;
}
virtual void stop ( ) {
at - > streamClear ( ) ; / / Empty anything in the buffer
@ -196,12 +209,6 @@ public:
if ( available ( ) ) {
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 ;
}
virtual operator bool ( ) { return connected ( ) ; }
@ -230,23 +237,17 @@ public:
{ }
public :
virtual int connect ( const char * host , uint16_t port ) {
virtual int connect ( const char * host , uint16_t port , int timeout_s ) {
/ / NOTE : Not caling stop ( ) or yeild ( ) here
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_s ) ;
return sock_connected ;
}
virtual int connect ( IPAddress ip , uint16_t port ) {
virtual int connect ( IPAddress ip , uint16_t port , int timeout_s ) {
/ / NOTE : Not caling stop ( ) or yeild ( ) here
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_s ) ;
return sock_connected ;
}
} ;
@ -255,24 +256,26 @@ public:
public :
TinyGsmXBee ( Stream & stream )
: TinyGsmModem ( stream ) , stream ( stream )
: stream ( stream )
{
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 ;
savedIP = IPAddress ( 0 , 0 , 0 , 0 ) ;
savedHost = " " ;
inCommandMode = false ;
memset ( sockets , 0 , sizeof ( sockets ) ) ;
}
TinyGsmXBee ( Stream & stream , int8_t resetPin )
: TinyGsmModem ( stream ) , stream ( stream )
: stream ( stream )
{
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 ;
savedIP = IPAddress ( 0 , 0 , 0 , 0 ) ;
savedHost = " " ;
inCommandMode = false ;
memset ( sockets , 0 , sizeof ( sockets ) ) ;
}
@ -280,6 +283,10 @@ public:
* Basic functions
*/
bool begin ( const char * pin = NULL ) {
return init ( pin ) ;
}
bool init ( const char * pin = NULL ) {
DBG ( GF ( " ### TinyGSM Version: " ) , TINYGSM_VERSION ) ;
@ -288,20 +295,26 @@ public:
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
bool ret_val = waitResponse ( ) = = 1 ;
ret_val & = writeChanges ( ) ;
sendAT ( GF ( " GT64 " ) ) ; / / shorten the guard time to 100 ms
ret_val & = waitResponse ( ) ;
ret_val & = writeChanges ( ) ;
ret_val & = waitResponse ( ) = = 1 ;
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 100 ms ( 10 seconds )
sendAT ( GF ( " CT64 " ) ) ;
ret_val & = waitResponse ( ) = = 1 ;
ret_val & = writeChanges ( ) ;
getSeries ( ) ; / / Get the " Hardware Series " ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
return ret_val ;
}
@ -310,7 +323,7 @@ public:
}
void setBaud ( unsigned long baud ) {
if ( ! commandMode ( ) ) return ;
XBEE_COMMAND_START_DECORATOR ( 5 , )
switch ( baud )
{
case 2400 : sendAT ( GF ( " BD1 " ) ) ; break ;
@ -331,40 +344,48 @@ public:
}
waitResponse ( ) ;
writeChanges ( ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
}
bool testAT ( unsigned long timeout = 10000L ) {
for ( unsigned long start = millis ( ) ; millis ( ) - start < timeout ; ) {
if ( commandMode ( ) )
{
bool testAT ( unsigned long timeout_ms = 10000L ) {
unsigned long start = millis ( ) ;
bool success = false ;
while ( ! success & & millis ( ) - start < timeout_ms ) {
if ( ! inCommandMode ) {
success = commandMode ( ) ;
if ( success ) exitCommand ( ) ;
}
else {
sendAT ( ) ;
if ( waitResponse ( 200 ) = = 1 ) {
exitCommand ( ) ;
return true ;
success = true ;
}
/ / if we didn ' t respond to the AT , assume we ' re not in command mode
else inCommandMode = false ;
}
delay ( 100 ) ;
delay ( 25 0) ;
}
return fal se;
return succ ess ;
}
void maintain ( ) {
/ / this only happens OUTSIDE command mode , so if we ' re getting characters
/ / they should be data received from the TCP connection
/ / TINY_GSM_YIELD ( ) ;
/ / while ( stream . available ( ) ) {
/ / char c = stream . read ( ) ;
/ / if ( c > 0 ) sockets [ 0 ] - > rx . put ( c ) ;
/ / if ( ! inCommandMode ) {
/ / while ( stream . available ( ) ) {
/ / char c = stream . read ( ) ;
/ / if ( c > 0 ) sockets [ 0 ] - > rx . put ( c ) ;
/ / }
/ / }
}
bool factoryDefault ( ) {
if ( ! commandMode ( ) ) return false ; / / Return immediately
XBEE_COMMAND_START_DECORATOR ( 5 , false )
sendAT ( GF ( " RE " ) ) ;
bool ret_val = waitResponse ( ) = = 1 ;
ret_val & = writeChanges ( ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
/ / Make sure the guard time for the modem object is set back to default
/ / otherwise communication would fail after the reset
guardTime = 1010 ;
@ -372,14 +393,7 @@ public:
}
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 ( ) {
@ -428,7 +442,9 @@ public:
}
bool restart ( ) {
if ( ! commandMode ( ) ) return false ; / / Return immediately
if ( beeType = = XBEE_UNKNOWN ) getSeries ( ) ; / / how we restart depends on this
if ( beeType ! = XBEE_S6B_WIFI ) {
@ -440,9 +456,10 @@ public:
sendAT ( GF ( " FR " ) ) ;
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
else delay ( 100 ) ; / / cellular modules wait 100 ms before reset happes
else delay ( 100 ) ; / / cellular modules wait 100 ms before reset happen s
/ / Wait until reboot complete and responds to command mode call again
for ( unsigned long start = millis ( ) ; millis ( ) - start < 60000L ; ) {
@ -462,7 +479,7 @@ public:
}
void setupPinSleep ( bool maintainAssociation = false ) {
if ( ! commandMode ( ) ) return ; / / Return immediately
XBEE_COMMAND_START_DECORATOR ( 5 , )
if ( beeType = = XBEE_UNKNOWN ) getSeries ( ) ; / / Command depends on series
@ -481,7 +498,7 @@ public:
}
writeChanges ( ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
}
bool poweroff ( ) { / / Not supported
@ -501,32 +518,27 @@ public:
}
String getSimCCID ( ) {
if ( ! commandMode ( ) ) return " " ; / / Return immediately
sendAT ( GF ( " S# " ) ) ;
String res = readResponseString ( ) ;
exitCommand ( ) ;
return res ;
return sendATGetString ( GF ( " S# " ) ) ;
}
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_ms = 10000L ) {
return SIM_READY ; / / unsupported
}
RegStatus getRegistrationStatus ( ) {
if ( ! commandMode ( ) ) return REG_UNKNOWN ; / / Return immediately
XBEE_COMMAND_START_DECORATOR ( 5 , REG_UNKNOWN )
if ( ! inCommandMode ) return REG_UNKNOWN ; / / Return immediately
if ( beeType = = XBEE_UNKNOWN ) getSeries ( ) ; / / Need to know the bee type to interpret response
sendAT ( GF ( " AI " ) ) ;
int16_t intRes = readResponseInt ( ) ;
int16_t intRes = readResponseInt ( 10000L ) ;
RegStatus stat = REG_UNKNOWN ;
switch ( beeType ) {
@ -598,16 +610,12 @@ public:
}
}
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
return stat ;
}
String getOperator ( ) {
if ( ! commandMode ( ) ) return " " ; / / Return immediately
sendAT ( GF ( " MN " ) ) ;
String res = readResponseString ( ) ;
exitCommand ( ) ;
return res ;
return sendATGetString ( GF ( " MN " ) ) ;
}
/*
@ -615,12 +623,17 @@ public:
*/
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_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
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 = = XBEE_S6B_WIFI ) return - 93 + intRes ; / / the maximum sensitivity is - 93 dBm
else return - 1 * intRes ; / / need to convert to negative number
@ -631,52 +644,60 @@ public:
return ( s = = REG_OK ) ;
}
bool waitForNetwork ( unsigned long timeout = 60000L ) {
for ( unsigned long start = millis ( ) ; millis ( ) - start < timeout ; ) {
bool waitForNetwork ( unsigned long timeout_ms = 60000L ) {
bool retVal = false ;
XBEE_COMMAND_START_DECORATOR ( 5 , false )
for ( unsigned long start = millis ( ) ; millis ( ) - start < timeout_ms ; ) {
if ( isNetworkConnected ( ) ) {
return true ;
retVal = true ;
break ;
}
delay ( 250 ) ; / / per Neil H . - more stable with delay
}
return false ;
XBEE_COMMAND_END_DECORATOR
return retVal ;
}
/*
* WiFi functions
*/
bool networkConnect ( const char * ssid , const char * pwd ) {
if ( ! commandMode ( ) ) return false ; / / return immediately
bool retVal = true ;
XBEE_COMMAND_START_DECORATOR ( 5 , false )
/ / nh For no pwd don ' t set setscurity or pwd
if ( NULL = = ssid ) return exitAndFail ( ) ;
if ( ssid = = NULL ) retVal = false ; ;
if ( NULL ! = pwd )
if ( pwd ! = NULL )
{
sendAT ( GF ( " EE " ) , 2 ) ; / / Set security to WPA2
if ( waitResponse ( ) ! = 1 ) return exitAndFail ( ) ;
if ( waitResponse ( ) ! = 1 ) retVal = false ;
sendAT ( GF ( " PK " ) , pwd ) ;
} else {
sendAT ( GF ( " EE " ) , 0 ) ; / / Set No security
}
if ( waitResponse ( ) ! = 1 ) return exitAndFail ( ) ;
if ( waitResponse ( ) ! = 1 ) retVal = false ;
sendAT ( GF ( " ID " ) , ssid ) ;
if ( waitResponse ( ) ! = 1 ) return exitAndFail ( ) ;
if ( waitResponse ( ) ! = 1 ) retVal = false ;
if ( ! writeChanges ( ) ) return exitAndFail ( ) ;
exitCommand ( ) ;
if ( ! writeChanges ( ) ) retVal = false ;
return true ;
XBEE_COMMAND_END_DECORATOR
return retVal ;
}
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
/ / 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 .
int8_t res = ( 1 = = waitResponse ( 5000 ) ) ;
writeChanges ( ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
return res ;
}
@ -685,37 +706,42 @@ public:
*/
String getLocalIP ( ) {
if ( ! commandMode ( ) ) return " " ; / / Return immediately
XBEE_COMMAND_START_DECORATOR ( 5 , " " )
sendAT ( GF ( " MY " ) ) ;
String IPaddr ; IPaddr . reserve ( 16 ) ;
/ / wait for the response - this response can be very slow
IPaddr = readResponseString ( 30000 ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
IPaddr . trim ( ) ;
return IPaddr ;
}
IPAddress localIP ( ) {
return TinyGsmIpFromString ( getLocalIP ( ) ) ;
}
/*
* GPRS functions
*/
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
waitResponse ( ) ;
bool success = waitResponse ( ) = = 1 ;
writeChanges ( ) ;
exitCommand ( ) ;
return true ;
XBEE_COMMAND_END_DECORATOR
return success ;
}
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
int8_t res = ( 1 = = waitResponse ( 5000 ) ) ;
writeChanges ( ) ;
sendAT ( GF ( " AM0 " ) ) ; / / Airplane mode off
waitResponse ( 5000 ) ;
writeChanges ( ) ;
exitCommand ( ) ;
XBEE_COMMAND_END_DECORATOR
return res ;
}
@ -738,11 +764,14 @@ public:
if ( waitResponse ( ) ! = 1 ) return exitAndFail ( ) ;
sendAT ( GF ( " TDD " ) ) ; / / Set the text delimiter to the standard 0x0D ( carriage return )
if ( waitResponse ( ) ! = 1 ) return exitAndFail ( ) ;
if ( ! writeChanges ( ) ) return exitAndFail ( ) ;
if ( ! writeChanges ( ) ) return exitAndFail ( ) ;
/ / Get out of command mode to actually send the text
exitCommand ( ) ;
streamWrite ( text ) ;
stream . write ( ( char ) 0x0D ) ; / / close off with the carriage return
return true ;
}
@ -753,12 +782,25 @@ public:
String getGsmLocation ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
/*
* Battery functions
* Battery & temperature functions
*/
/ / Use : float vBatt = modem . getBattVoltage ( ) / 1000.0 ;
uint16_t getBattVoltage ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
int8_t getBattPercent ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
uint8_t getBattChargeState ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
bool getBattStats ( uint8_t & chargeState , int8_t & percent , uint16_t & milliVolts ) TINY_GSM_ATTR_NOT_AVAILABLE ;
float getTemperature ( ) {
String res = sendATGetString ( GF ( " TP " ) ) ;
if ( res = = " " ) {
return ( float ) - 9999 ;
}
char buf [ 5 ] = { 0 , } ;
res . toCharArray ( buf , 5 ) ;
int8_t intRes = ( int8_t ) strtol ( buf , 0 , 16 ) ; / / degrees Celsius displayed in 8 - bit two ' s complement format .
return ( float ) intRes ;
}
/*
* Client related functions
@ -766,51 +808,66 @@ public:
protected :
IPAddress getHostIP ( const char * host ) {
IPAddress getHostIP ( const char * host , int timeout_s = 45 ) {
String strIP ; strIP . reserve ( 16 ) ;
unsigned long startMillis = millis ( ) ;
uint32_t timeout_ms = ( ( uint32_t ) timeout_s ) * 1000 ;
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
/ / 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_ms ) / / the lookup can take a while
{
sendAT ( GF ( " LA " ) , host ) ;
while ( stream . available ( ) < 4 & & ( millis ( ) - startMillis < 45000L ) ) { } ; / / wait for any response
while ( stream . available ( ) < 4 & & ( millis ( ) - startMillis < timeout_ms ) ) { TINY_GSM_YIELD ( ) } ;
strIP = stream . readStringUntil ( ' \r ' ) ; / / read result
strIP . trim ( ) ;
if ( ! strIP . endsWith ( GF ( " ERROR " ) ) ) {
if ( strIP ! = " " & & strIP ! = GF ( " ERROR " ) ) {
gotIP = true ;
break ;
}
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 ) ;
}
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_s = 75 )
{
unsigned long startMillis = millis ( ) ;
uint32_t timeout_ms = ( ( uint32_t ) timeout_s ) * 1000 ;
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_s ) ; / / 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 ( 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_ms - ( 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_s = 75 ) {
savedIP = ip ; / / Set the newly requested IP address
bool success = true ;
uint32_t timeout_ms = ( ( uint32_t ) timeout_s ) * 1000 ;
XBEE_COMMAND_START_DECORATOR ( 5 , false )
String host ; host . reserve ( 16 ) ;
host + = ip [ 0 ] ;
host + = " . " ;
@ -819,6 +876,7 @@ protected:
host + = ip [ 2 ] ;
host + = " . " ;
host + = ip [ 3 ] ;
if ( ssl ) {
sendAT ( GF ( " IP " ) , 4 ) ; / / Put in SSL over TCP communication mode
success & = ( 1 = = waitResponse ( ) ) ;
@ -826,10 +884,21 @@ protected:
sendAT ( GF ( " IP " ) , 1 ) ; / / Put in TCP mode
success & = ( 1 = = waitResponse ( ) ) ;
}
sendAT ( GF ( " DL " ) , host ) ; / / Set the " Destination Address Low "
success & = ( 1 = = waitResponse ( ) ) ;
sendAT ( GF ( " DE " ) , String ( port , HEX ) ) ; / / Set the destination port
success & = ( 1 = = waitResponse ( ) ) ;
for ( unsigned long start = millis ( ) ; millis ( ) - start < timeout_ms ; ) {
if ( modemGetConnected ( ) ) {
sockets [ mux ] - > sock_connected = true ;
break ;
}
}
XBEE_COMMAND_END_DECORATOR
return success ;
}
@ -844,36 +913,37 @@ protected:
/ / really be open , but no data has yet been sent . We return this unknown value
/ / as true so there ' s a possibility it ' s wrong .
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 ( savedIP = = IPAddress ( 0 , 0 , 0 , 0 ) ) return 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 ( ) ;
/ / 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
case XBEE_S6B_WIFI : {
RegStatus s = getRegistrationStatus ( ) ;
XBEE_COMMAND_END_DECORATOR
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
}
default : { / / Cellular XBee ' s
sendAT ( GF ( " CI " ) ) ;
int16_t intRes = readResponseInt ( ) ;
exitCommand ( ) ;
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
return true ;
case 0x02 : / / 0x02 = Invalid parameters ( bad IP / host )
@ -901,19 +971,13 @@ public:
}
}
template < typename . . . Args >
void sendAT ( Args . . . cmd ) {
streamWrite ( " AT " , cmd . . . , GSM_NL ) ;
stream . flush ( ) ;
TINY_GSM_YIELD ( ) ;
/ / DBG ( " ### AT: " , cmd . . . ) ;
}
TINY_GSM_MODEM_STREAM_UTILITIES ( )
/ / TODO : Optimize this !
/ / 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 .
uint8_t waitResponse ( uint32_t timeout , String & data ,
uint8_t waitResponse ( 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 )
{
@ -949,7 +1013,7 @@ public:
goto finish ;
}
}
} while ( millis ( ) - startMillis < timeout ) ;
} while ( millis ( ) - startMillis < timeout_ms ) ;
finish :
if ( ! index ) {
data . trim ( ) ;
@ -971,12 +1035,12 @@ finish:
return index ;
}
uint8_t waitResponse ( uint32_t timeout ,
uint8_t waitResponse ( 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 , data , r1 , r2 , r3 , r4 , r5 ) ;
return waitResponse ( timeout_ms , data , r1 , r2 , r3 , r4 , r5 ) ;
}
uint8_t waitResponse ( GsmConstStr r1 = GFP ( GSM_OK ) , GsmConstStr r2 = GFP ( GSM_ERROR ) ,
@ -985,28 +1049,39 @@ finish:
return waitResponse ( 1000 , r1 , r2 , r3 , r4 , r5 ) ;
}
bool commandMode ( uint8_t retries = 3 ) {
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 triesUntilReset = 2 ; / / only reset after 2 failures
uint8_t triesUntilReset = 4 ; / / only reset after 4 failures
bool success = false ;
streamClear ( ) ; / / Empty everything in the buffer before starting
while ( ! success and triesMade < retries ) {
/ / Cannot send anything for 1 " guard time " before entering command mode
/ / Default guard time is 1 s , but the init fxn decreases it to 100 ms
delay ( guardTime + 5 0) ;
delay ( guardTime + 1 0) ;
streamWrite ( GF ( " +++ " ) ) ; / / enter command mode
int res = waitResponse ( guardTime * 2 ) ;
success = ( 1 = = res ) ;
if ( 0 = = res ) {
triesUntilReset - - ;
if ( triesUntilReset = = 0 ) {
triesUntilReset = 2 ;
triesUntilReset = 4 ;
pinReset ( ) ; / / if it ' s unresponsive , reset
delay ( 250 ) ; / / a short delay to allow it to come back up TODO - optimize this
delay ( 250 ) ; / / a short delay to allow it to come back up
/ / TODO - optimize this
}
}
triesMade + + ;
}
if ( success ) {
inCommandMode = true ;
lastCommandModeMillis = millis ( ) ;
}
return success ;
}
@ -1019,8 +1094,11 @@ finish:
}
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
waitResponse ( ) ;
inCommandMode = false ;
}
bool exitAndFail ( void ) {
@ -1035,23 +1113,37 @@ finish:
DBG ( GF ( " ### Modem: " ) , getModemName ( ) ) ;
}
String readResponseString ( uint32_t timeout = 1000 ) {
String readResponseString ( uint32_t timeout_ms = 1000 ) {
TINY_GSM_YIELD ( ) ;
unsigned long startMillis = millis ( ) ;
while ( ! stream . available ( ) & & millis ( ) - startMillis < timeout ) { } ;
while ( ! stream . available ( ) & & millis ( ) - startMillis < timeout_ms ) { } ;
String res = stream . readStringUntil ( ' \r ' ) ; / / lines end with carriage returns
res . trim ( ) ;
return res ;
}
int16_t readResponseInt ( uint32_t timeout = 1000 ) {
String res = readResponseString ( timeout ) ; / / it just works better reading a string first
int16_t readResponseInt ( uint32_t timeout_ms = 1000 ) {
String res = readResponseString ( timeout_ms ) ; / / it just works better reading a string first
if ( res = = " " ) res = " FF " ;
char buf [ 5 ] = { 0 , } ;
res . toCharArray ( buf , 5 ) ;
int16_t intRes = strtol ( buf , 0 , 16 ) ;
return intRes ;
}
String sendATGetString ( GsmConstStr cmd ) {
XBEE_COMMAND_START_DECORATOR ( 5 , " " )
sendAT ( cmd ) ;
String res = readResponseString ( ) ;
XBEE_COMMAND_END_DECORATOR
return res ;
}
bool gotIPforSavedHost ( ) {
if ( savedHost ! = " " & & savedIP ! = IPAddress ( 0 , 0 , 0 , 0 ) ) return true ;
else return false ;
}
public :
Stream & stream ;
@ -1061,6 +1153,8 @@ protected:
XBeeType beeType ;
IPAddress savedIP ;
String savedHost ;
bool inCommandMode ;
uint32_t lastCommandModeMillis ;
GsmClient * sockets [ TINY_GSM_MUX_COUNT ] ;
} ;