@ -6,31 +6,32 @@
* @ date Nov 2016
* @ date Nov 2016
*/
*/
# ifndef TinyGsmClientA6_h
# define TinyGsmClientA6_h
/ / # pragma message ( " TinyGSM: TinyGsmClientA6 " )
# ifndef SRC_TINYGSMCLIENTA6_H_
# define SRC_TINYGSMCLIENTA6_H_
/ / # pragma message ( " TinyGSM: TinyGsmClientA6 " )
/ / # define TINY_GSM_DEBUG Serial
# if !defined(TINY_GSM_RX_BUFFER)
# define TINY_GSM_RX_BUFFER 256
# endif
/ / # define TINY_GSM_DEBUG Serial
# define TINY_GSM_MUX_COUNT 8
# define TINY_GSM_MUX_COUNT 8
# define TINY_GSM_NO_MODEM_BUFFER
# include <TinyGsmCommon.h>
# include "TinyGsmBattery.tpp"
# include "TinyGsmCalling.tpp"
# include "TinyGsmGPRS.tpp"
# include "TinyGsmModem.tpp"
# include "TinyGsmSMS.tpp"
# include "TinyGsmTCP.tpp"
# include "TinyGsmTime.tpp"
# define GSM_NL "\r\n"
# define GSM_NL "\r\n"
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 ;
enum SimStatus {
SIM_ERROR = 0 ,
SIM_READY = 1 ,
SIM_LOCKED = 2 ,
} ;
# if defined TINY_GSM_DEBUG
static const char GSM_CME_ERROR [ ] TINY_GSM_PROGMEM = GSM_NL " +CME ERROR: " ;
# endif
enum RegStatus {
enum RegStatus {
REG_NO_RESULT = - 1 ,
REG_UNREGISTERED = 0 ,
REG_UNREGISTERED = 0 ,
REG_SEARCHING = 2 ,
REG_SEARCHING = 2 ,
REG_DENIED = 3 ,
REG_DENIED = 3 ,
@ -39,114 +40,104 @@ enum RegStatus {
REG_UNKNOWN = 4 ,
REG_UNKNOWN = 4 ,
} ;
} ;
class TinyGsmA6 : public TinyGsmModem < TinyGsmA6 > ,
public TinyGsmGPRS < TinyGsmA6 > ,
public TinyGsmTCP < TinyGsmA6 , TINY_GSM_MUX_COUNT > ,
public TinyGsmCalling < TinyGsmA6 > ,
public TinyGsmSMS < TinyGsmA6 > ,
public TinyGsmTime < TinyGsmA6 > ,
public TinyGsmBattery < TinyGsmA6 > {
friend class TinyGsmModem < TinyGsmA6 > ;
friend class TinyGsmGPRS < TinyGsmA6 > ;
friend class TinyGsmTCP < TinyGsmA6 , TINY_GSM_MUX_COUNT > ;
friend class TinyGsmCalling < TinyGsmA6 > ;
friend class TinyGsmSMS < TinyGsmA6 > ;
friend class TinyGsmTime < TinyGsmA6 > ;
friend class TinyGsmBattery < TinyGsmA6 > ;
class TinyGsmA6
{
public :
class GsmClient : public Client
{
friend class TinyGsmA6 ;
typedef TinyGsmFifo < uint8_t , TINY_GSM_RX_BUFFER > RxFifo ;
public :
GsmClient ( ) { }
GsmClient ( TinyGsmA6 & modem ) {
init ( & modem ) ;
}
virtual ~ GsmClient ( ) { }
bool init ( TinyGsmA6 * modem ) {
this - > at = modem ;
this - > mux = - 1 ;
sock_connected = false ;
/*
* Inner Client
*/
public :
class GsmClientA6 : public GsmClient {
friend class TinyGsmA6 ;
return true ;
}
public :
GsmClientA6 ( ) { }
public :
virtual int connect ( const char * host , uint16_t port , int timeout_s ) {
stop ( ) ;
TINY_GSM_YIELD ( ) ;
rx . clear ( ) ;
uint8_t newMux = - 1 ;
sock_connected = at - > modemConnect ( host , port , & newMux , timeout_s ) ;
if ( sock_connected ) {
mux = newMux ;
at - > sockets [ mux ] = this ;
explicit GsmClientA6 ( TinyGsmA6 & modem , uint8_t = 0 ) {
init ( & modem , - 1 ) ;
}
}
return sock_connected ;
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS ( )
virtual void stop ( uint32_t maxWaitMs ) {
TINY_GSM_YIELD ( ) ;
at - > sendAT ( GF ( " +CIPCLOSE= " ) , mux ) ;
sock_connected = false ;
at - > waitResponse ( maxWaitMs ) ;
rx . clear ( ) ;
}
bool init ( TinyGsmA6 * modem , uint8_t = 0 ) {
this - > at = modem ;
this - > mux = - 1 ;
sock_connected = false ;
virtual void stop ( ) { stop ( 1000L ) ; }
return true ;
}
TINY_GSM_CLIENT_WRITE ( )
public :
int connect ( const char * host , uint16_t port , int timeout_s ) {
stop ( ) ;
TINY_GSM_YIELD ( ) ;
rx . clear ( ) ;
uint8_t newMux = - 1 ;
sock_connected = at - > modemConnect ( host , port , & newMux , timeout_s ) ;
if ( sock_connected ) {
mux = newMux ;
at - > sockets [ mux ] = this ;
}
return sock_connected ;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO ( )
void stop ( uint32_t maxWaitMs ) {
TINY_GSM_YIELD ( ) ;
at - > sendAT ( GF ( " +CIPCLOSE= " ) , mux ) ;
sock_connected = false ;
at - > waitResponse ( maxWaitMs ) ;
rx . clear ( ) ;
}
void stop ( ) override {
stop ( 1000L ) ;
}
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO ( )
/*
* Extended API
*/
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED ( )
String remoteIP ( ) TINY_GSM_ATTR_NOT_IMPLEMENTED ;
} ;
/*
/*
* Extended API
* Inner Secure Client
*/
*/
String remoteIP ( ) TINY_GSM_ATTR_NOT_IMPLEMENTED ;
private :
TinyGsmA6 * at ;
uint8_t mux ;
bool sock_connected ;
RxFifo rx ;
} ;
/ / Doesn ' t support SSL
public :
TinyGsmA6 ( Stream & stream )
: stream ( stream )
{
/*
* Constructor
*/
public :
explicit TinyGsmA6 ( Stream & stream ) : stream ( stream ) {
memset ( sockets , 0 , sizeof ( sockets ) ) ;
memset ( sockets , 0 , sizeof ( sockets ) ) ;
}
}
virtual ~ TinyGsmA6 ( ) { }
/*
/*
* Basic functions
* Basic functions
*/
*/
bool begin ( const char * pin = NULL ) {
return init ( pin ) ;
}
bool init ( const char * pin = NULL ) {
protected :
bool initImpl ( const char * pin = NULL ) {
DBG ( GF ( " ### TinyGSM Version: " ) , TINYGSM_VERSION ) ;
DBG ( GF ( " ### TinyGSM Version: " ) , TINYGSM_VERSION ) ;
if ( ! testAT ( ) ) {
return false ;
}
if ( ! testAT ( ) ) { return false ; }
/ / sendAT ( GF ( " &FZ " ) ) ; / / Factory + Reset
/ / sendAT ( GF ( " &FZ " ) ) ; / / Factory + Reset
/ / waitResponse ( ) ;
/ / waitResponse ( ) ;
sendAT ( GF ( " E0 " ) ) ; / / Echo Off
sendAT ( GF ( " E0 " ) ) ; / / Echo Off
if ( waitResponse ( ) ! = 1 ) {
return false ;
}
if ( waitResponse ( ) ! = 1 ) { return false ; }
# ifdef TINY_GSM_DEBUG
# ifdef TINY_GSM_DEBUG
sendAT ( GF ( " +CMEE=2 " ) ) ; / / turn on verbose error codes
sendAT ( GF ( " +CMEE=2 " ) ) ; / / turn on verbose error codes
@ -154,282 +145,179 @@ public:
sendAT ( GF ( " +CMEE=0 " ) ) ; / / turn off error codes
sendAT ( GF ( " +CMEE=0 " ) ) ; / / turn off error codes
# endif
# endif
waitResponse ( ) ;
waitResponse ( ) ;
sendAT ( GF ( " +CMER=3,0,0,2 " ) ) ; / / Set unsolicited result code output destination
sendAT (
GF ( " +CMER=3,0,0,2 " ) ) ; / / Set unsolicited result code output destination
waitResponse ( ) ;
waitResponse ( ) ;
DBG ( GF ( " ### Modem: " ) , getModemName ( ) ) ;
DBG ( GF ( " ### Modem: " ) , getModemName ( ) ) ;
int ret = getSimStatus ( ) ;
SimStatus ret = getSimStatus ( ) ;
/ / if the sim isn ' t ready and a pin has been provided , try to unlock the sim
/ / if the sim isn ' t ready and a pin has been provided , try to unlock the sim
if ( ret ! = SIM_READY & & pin ! = NULL & & strlen ( pin ) > 0 ) {
if ( ret ! = SIM_READY & & pin ! = NULL & & strlen ( pin ) > 0 ) {
simUnlock ( pin ) ;
simUnlock ( pin ) ;
return ( getSimStatus ( ) = = SIM_READY ) ;
return ( getSimStatus ( ) = = SIM_READY ) ;
}
/ / if the sim is ready , or it ' s locked but no pin has been provided , return
/ / true
else {
} else {
/ / if the sim is ready , or it ' s locked but no pin has been provided ,
/ / return true
return ( ret = = SIM_READY | | ret = = SIM_LOCKED ) ;
return ( ret = = SIM_READY | | ret = = SIM_LOCKED ) ;
}
}
}
}
String getModemName ( ) {
# if defined(TINY_GSM_MODEM_A6)
return " AI-Thinker A6 " ;
# elif defined(TINY_GSM_MODEM_A7)
return " AI-Thinker A7 " ;
# endif
return " AI-Thinker A6 " ;
}
TINY_GSM_MODEM_SET_BAUD_IPR ( )
TINY_GSM_MODEM_TEST_AT ( )
TINY_GSM_MODEM_MAINTAIN_LISTEN ( )
bool factoryDefault ( ) {
bool factoryDefaultImpl ( ) {
sendAT ( GF ( " &FZE0&W " ) ) ; / / Factory + Reset + Echo Off + Write
sendAT ( GF ( " &FZE0&W " ) ) ; / / Factory + Reset + Echo Off + Write
waitResponse ( ) ;
waitResponse ( ) ;
sendAT ( GF ( " &W " ) ) ; / / Write configuration
sendAT ( GF ( " &W " ) ) ; / / Write configuration
return waitResponse ( ) = = 1 ;
return waitResponse ( ) = = 1 ;
}
}
TINY_GSM_MODEM_GET_INFO_ATI ( )
bool hasSSL ( ) {
return false ;
}
bool hasWifi ( ) {
return false ;
}
bool hasGPRS ( ) {
return true ;
}
/*
/*
* Power functions
* Power functions
*/
*/
bool restart ( ) {
if ( ! testAT ( ) ) {
return false ;
}
protected :
bool restartImpl ( ) {
if ( ! testAT ( ) ) { return false ; }
sendAT ( GF ( " +RST=1 " ) ) ;
sendAT ( GF ( " +RST=1 " ) ) ;
delay ( 3000 ) ;
delay ( 3000 ) ;
return init ( ) ;
return init ( ) ;
}
}
bool poweroff ( ) {
bool powerOffImpl ( ) {
sendAT ( GF ( " +CPOF " ) ) ;
sendAT ( GF ( " +CPOF " ) ) ;
/ / + CPOF : MS OFF OK
return waitResponse ( ) = = 1 ;
return waitResponse ( ) = = 1 ;
}
}
bool radioOff ( ) TINY_GSM_ATTR_NOT_IMPLEMENTED ;
bool sleepEnable ( bool enable = true ) TINY_GSM_ATTR_NOT_IMPLEMENTED ;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN ( )
String getSimCCID ( ) {
sendAT ( GF ( " +CCID " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +SCID: SIM Card ID: " ) ) ! = 1 ) {
return " " ;
}
String res = stream . readStringUntil ( ' \n ' ) ;
waitResponse ( ) ;
res . trim ( ) ;
return res ;
}
TINY_GSM_MODEM_GET_IMEI_GSN ( )
SimStatus getSimStatus ( unsigned long timeout_ms = 10000L ) {
for ( unsigned long start = millis ( ) ; millis ( ) - start < timeout_ms ; ) {
sendAT ( GF ( " +CPIN? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +CPIN: " ) ) ! = 1 ) {
delay ( 1000 ) ;
continue ;
}
int status = waitResponse ( GF ( " READY " ) , GF ( " SIM PIN " ) , GF ( " SIM PUK " ) ) ;
waitResponse ( ) ;
switch ( status ) {
case 2 :
case 3 : return SIM_LOCKED ;
case 1 : return SIM_READY ;
default : return SIM_ERROR ;
}
}
return SIM_ERROR ;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG ( CREG )
String getOperator ( ) {
sendAT ( GF ( " +COPS=3,0 " ) ) ; / / Set format
waitResponse ( ) ;
sendAT ( GF ( " +COPS? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +COPS: " ) ) ! = 1 ) {
return " " ;
}
streamSkipUntil ( ' " ' ) ; / / Skip mode and format
String res = stream . readStringUntil ( ' " ' ) ;
waitResponse ( ) ;
return res ;
}
bool sleepEnableImpl ( bool enable = true ) TINY_GSM_ATTR_NOT_AVAILABLE ;
/*
/*
* Generic network functions
* Generic network functions
*/
*/
public :
RegStatus getRegistrationStatus ( ) {
return ( RegStatus ) getRegistrationStatusXREG ( " CREG " ) ;
}
TINY_GSM_MODEM_GET_CSQ ( )
bool isNetworkConnected ( ) {
protected :
bool isNetworkConnectedImpl ( ) {
RegStatus s = getRegistrationStatus ( ) ;
RegStatus s = getRegistrationStatus ( ) ;
return ( s = = REG_OK_HOME | | s = = REG_OK_ROAMING ) ;
return ( s = = REG_OK_HOME | | s = = REG_OK_ROAMING ) ;
}
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK ( )
String getLocalIPImpl ( ) {
sendAT ( GF ( " +CIFSR " ) ) ;
String res ;
if ( waitResponse ( 10000L , res ) ! = 1 ) { return " " ; }
res . replace ( GSM_NL " OK " GSM_NL , " " ) ;
res . replace ( GSM_NL , " " ) ;
res . trim ( ) ;
return res ;
}
/*
/*
* GPRS functions
* GPRS functions
*/
*/
bool gprsConnect ( const char * apn , const char * user = NULL , const char * pwd = NULL ) {
protected :
bool gprsConnectImpl ( const char * apn , const char * user = NULL ,
const char * pwd = NULL ) {
gprsDisconnect ( ) ;
gprsDisconnect ( ) ;
sendAT ( GF ( " +CGATT=1 " ) ) ;
sendAT ( GF ( " +CGATT=1 " ) ) ;
if ( waitResponse ( 60000L ) ! = 1 )
return false ;
if ( waitResponse ( 60000L ) ! = 1 ) { return false ; }
/ / TODO : wait AT + CGATT ?
/ / TODO ( ? ) : wait AT + CGATT ?
sendAT ( GF ( " +CGDCONT=1, \" IP \" , \" " ) , apn , ' " ' ) ;
sendAT ( GF ( " +CGDCONT=1, \" IP \" , \" " ) , apn , ' " ' ) ;
waitResponse ( ) ;
waitResponse ( ) ;
if ( ! user ) user = " " ;
if ( ! user ) user = " " ;
if ( ! pwd ) pwd = " " ;
if ( ! pwd ) pwd = " " ;
sendAT ( GF ( " +CSTT= \" " ) , apn , GF ( " \" , \" " ) , user , GF ( " \" , \" " ) , pwd , GF ( " \" " ) ) ;
sendAT ( GF ( " +CSTT= \" " ) , apn , GF ( " \" , \" " ) , user , GF ( " \" , \" " ) , pwd , GF ( " \" " ) ) ;
if ( waitResponse ( 60000L ) ! = 1 ) {
return false ;
}
if ( waitResponse ( 60000L ) ! = 1 ) { return false ; }
sendAT ( GF ( " +CGACT=1,1 " ) ) ;
sendAT ( GF ( " +CGACT=1,1 " ) ) ;
waitResponse ( 60000L ) ;
waitResponse ( 60000L ) ;
sendAT ( GF ( " +CIPMUX=1 " ) ) ;
sendAT ( GF ( " +CIPMUX=1 " ) ) ;
if ( waitResponse ( ) ! = 1 ) {
return false ;
}
if ( waitResponse ( ) ! = 1 ) { return false ; }
return true ;
return true ;
}
}
bool gprsDisconnect ( ) {
bool gprsDisconnectImpl ( ) {
/ / Shut the TCP / IP connection
/ / Shut the TCP / IP connection
sendAT ( GF ( " +CIPSHUT " ) ) ;
sendAT ( GF ( " +CIPSHUT " ) ) ;
if ( waitResponse ( 60000L ) ! = 1 )
return false ;
if ( waitResponse ( 60000L ) ! = 1 ) { return false ; }
for ( int i = 0 ; i < 3 ; i + + ) {
for ( int i = 0 ; i < 3 ; i + + ) {
sendAT ( GF ( " +CGATT=0 " ) ) ;
sendAT ( GF ( " +CGATT=0 " ) ) ;
if ( waitResponse ( 5000L ) = = 1 )
return true ;
if ( waitResponse ( 5000L ) = = 1 ) { return true ; }
}
}
return false ;
return false ;
}
}
bool isGprsConnected ( ) {
sendAT ( GF ( " +CGATT? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +CGATT: " ) ) ! = 1 ) {
return false ;
}
int res = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
String getOperatorImpl ( ) {
sendAT ( GF ( " +COPS=3,0 " ) ) ; / / Set format
waitResponse ( ) ;
sendAT ( GF ( " +COPS? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +COPS: " ) ) ! = 1 ) { return " " ; }
streamSkipUntil ( ' " ' ) ; / / Skip mode and format
String res = stream . readStringUntil ( ' " ' ) ;
waitResponse ( ) ;
waitResponse ( ) ;
return ( res = = 1 ) ;
return res ;
}
}
/*
/*
* IP Address functions
* SIM card functions
*/
*/
String getLocalIP ( ) {
sendAT ( GF ( " +CIFSR " ) ) ;
String res ;
if ( waitResponse ( 10000L , res ) ! = 1 ) {
return " " ;
}
res . replace ( GSM_NL " OK " GSM_NL , " " ) ;
res . replace ( GSM_NL , " " ) ;
protected :
String getSimCCIDImpl ( ) {
sendAT ( GF ( " +CCID " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +SCID: SIM Card ID: " ) ) ! = 1 ) { return " " ; }
String res = stream . readStringUntil ( ' \n ' ) ;
waitResponse ( ) ;
res . trim ( ) ;
res . trim ( ) ;
return res ;
return res ;
}
}
IPAddress localIP ( ) {
return TinyGsmIpFromString ( getLocalIP ( ) ) ;
}
/*
/*
* Phone Call functions
* Phone Call functions
*/
*/
bool setGsmBusy ( bool busy = true ) TINY_GSM_ATTR_NOT_AVAILABLE ;
bool callAnswer ( ) {
sendAT ( GF ( " A " ) ) ;
return waitResponse ( ) = = 1 ;
}
protected :
/ / Returns true on pick - up , false on error / busy
/ / Returns true on pick - up , false on error / busy
bool callNumber ( const String & number ) {
bool callNumberImpl ( const String & number ) {
if ( number = = GF ( " last " ) ) {
if ( number = = GF ( " last " ) ) {
sendAT ( GF ( " DLST " ) ) ;
sendAT ( GF ( " DLST " ) ) ;
} else {
} else {
sendAT ( GF ( " D \" " ) , number , " \" ; " ) ;
sendAT ( GF ( " D \" " ) , number , " \" ; " ) ;
}
}
if ( waitResponse ( 5000L ) ! = 1 ) {
return false ;
}
if ( waitResponse ( 5000L ) ! = 1 ) { return false ; }
if ( waitResponse ( 60000L ,
GF ( GSM_NL " +CIEV: \" CALL \" ,1 " ) ,
GF ( GSM_NL " +CIEV: \" CALL \" ,0 " ) ,
GFP ( GSM_ERROR ) ) ! = 1 )
{
if ( waitResponse ( 60000L , GF ( GSM_NL " +CIEV: \" CALL \" ,1 " ) ,
GF ( GSM_NL " +CIEV: \" CALL \" ,0 " ) , GFP ( GSM_ERROR ) ) ! = 1 ) {
return false ;
return false ;
}
}
int rsp = waitResponse ( 60000L ,
GF ( GSM_NL " +CIEV: \" SOUNDER \" ,0 " ) ,
GF ( GSM_NL " +CIEV: \" CALL \" ,0 " ) ) ;
int8_t rsp = waitResponse ( 60000L , GF ( GSM_NL " +CIEV: \" SOUNDER \" ,0 " ) ,
GF ( GSM_NL " +CIEV: \" CALL \" ,0 " ) ) ;
int rsp2 = waitResponse ( 300L , GF ( GSM_NL " BUSY " GSM_NL ) , GF ( GSM_NL " NO ANSWER " GSM_NL ) ) ;
int8_t rsp2 = waitResponse ( 300L , GF ( GSM_NL " BUSY " GSM_NL ) ,
GF ( GSM_NL " NO ANSWER " GSM_NL ) ) ;
return rsp = = 1 & & rsp2 = = 0 ;
return rsp = = 1 & & rsp2 = = 0 ;
}
}
bool callHangup ( ) {
sendAT ( GF ( " H " ) ) ;
return waitResponse ( ) = = 1 ;
}
/ / 0 - 9 , * , # , A , B , C , D
/ / 0 - 9 , * , # , A , B , C , D
bool dtmfSend ( char cmd , unsigned duration_ms = 100 ) {
bool dtmfSendImpl ( char cmd , uint8_t duration_ms = 100 ) {
duration_ms = constrain ( duration_ms , 100 , 1000 ) ;
duration_ms = constrain ( duration_ms , 100 , 1000 ) ;
/ / The duration parameter is not working , so we simulate it using delay . .
/ / The duration parameter is not working , so we simulate it using delay . .
/ / TODO : Maybe there ' s another way . . .
/ / TODO ( ? ) : Maybe there ' s another way . . .
/ / sendAT ( GF ( " +VTD= " ) , duration_ms / 100 ) ;
/ / waitResponse ( ) ;
/ / sendAT ( GF ( " +VTD= " ) , duration_ms / 100 ) ;
/ / waitResponse ( ) ;
sendAT ( GF ( " +VTS= " ) , cmd ) ;
sendAT ( GF ( " +VTS= " ) , cmd ) ;
if ( waitResponse ( 10000L ) = = 1 ) {
if ( waitResponse ( 10000L ) = = 1 ) {
@ -442,7 +330,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
/*
* Audio functions
* Audio functions
*/
*/
public :
bool audioSetHeadphones ( ) {
bool audioSetHeadphones ( ) {
sendAT ( GF ( " +SNFS=0 " ) ) ;
sendAT ( GF ( " +SNFS=0 " ) ) ;
return waitResponse ( ) = = 1 ;
return waitResponse ( ) = = 1 ;
@ -461,23 +349,19 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
/*
* Messaging functions
* Messaging functions
*/
*/
String sendUSSD ( const String & code ) {
protected :
String sendUSSDImpl ( const String & code ) {
sendAT ( GF ( " +CMGF=1 " ) ) ;
sendAT ( GF ( " +CMGF=1 " ) ) ;
waitResponse ( ) ;
waitResponse ( ) ;
sendAT ( GF ( " +CSCS= \" HEX \" " ) ) ;
sendAT ( GF ( " +CSCS= \" HEX \" " ) ) ;
waitResponse ( ) ;
waitResponse ( ) ;
sendAT ( GF ( " +CUSD=1, \" " ) , code , GF ( " \" ,15 " ) ) ;
sendAT ( GF ( " +CUSD=1, \" " ) , code , GF ( " \" ,15 " ) ) ;
if ( waitResponse ( 10000L ) ! = 1 ) {
return " " ;
}
if ( waitResponse ( GF ( GSM_NL " +CUSD: " ) ) ! = 1 ) {
return " " ;
}
stream . readStringUntil ( ' " ' ) ;
if ( waitResponse ( 10000L ) ! = 1 ) { return " " ; }
if ( waitResponse ( GF ( GSM_NL " +CUSD: " ) ) ! = 1 ) { return " " ; }
streamSkipUntil ( ' " ' ) ;
String hex = stream . readStringUntil ( ' " ' ) ;
String hex = stream . readStringUntil ( ' " ' ) ;
stream . readString Until( ' , ' ) ;
int dcs = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
streamSkipUntil ( ' , ' ) ;
int8_t dcs = streamGetIntBefore ( ' \n ' ) ;
if ( dcs = = 15 ) {
if ( dcs = = 15 ) {
return TinyGsmDecodeHex7bit ( hex ) ;
return TinyGsmDecodeHex7bit ( hex ) ;
@ -488,96 +372,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
}
}
}
}
bool sendSMS ( const String & number , const String & text ) {
sendAT ( GF ( " +CMGF=1 " ) ) ;
waitResponse ( ) ;
sendAT ( GF ( " +CMGS= \" " ) , number , GF ( " \" " ) ) ;
if ( waitResponse ( GF ( " > " ) ) ! = 1 ) {
return false ;
}
stream . print ( text ) ;
stream . write ( ( char ) 0x1A ) ;
stream . flush ( ) ;
return waitResponse ( 60000L ) = = 1 ;
}
/*
/*
* Location functions
* Time functions
*/
*/
String getGsmLocation ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
protected :
/ / Can follow the standard CCLK function in the template
/ / Note - the clock probably has to be set manaually first
/*
/*
* Battery & temperature functions
* Battery functions
*/
*/
protected :
uint16_t getBattVoltageImpl ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
uint16_t getBattVoltage ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
int8_t getBattPercent ( ) {
/ / Needs a ' ? ' after CBC , unlike most
int8_t getBattPercentImpl ( ) {
sendAT ( GF ( " +CBC? " ) ) ;
sendAT ( GF ( " +CBC? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +CBC: " ) ) ! = 1 ) {
return false ;
}
streamSkipUntil ( ' , ' ) ; / / Skip battery charge status
if ( waitResponse ( GF ( GSM_NL " +CBC: " ) ) ! = 1 ) { return false ; }
streamSkipUntil ( ' , ' ) ; / / Skip battery charge status
/ / Read battery charge level
/ / Read battery charge level
int res = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
/ / Wait for final OK
waitResponse ( ) ;
return res ;
}
uint8_t getBattChargeState ( ) {
sendAT ( GF ( " +CBC? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +CBC: " ) ) ! = 1 ) {
return false ;
}
/ / Read battery charge status
int res = stream . readStringUntil ( ' , ' ) . toInt ( ) ;
int8_t res = streamGetIntBefore ( ' \n ' ) ;
/ / Wait for final OK
/ / Wait for final OK
waitResponse ( ) ;
waitResponse ( ) ;
return res ;
return res ;
}
}
bool getBattStats ( uint8_t & chargeState , int8_t & percent , uint16_t & milliVolts ) {
/ / Needs a ' ? ' after CBC , unlike most
bool getBattStatsImpl ( uint8_t & chargeState , int8_t & percent ,
uint16_t & milliVolts ) {
sendAT ( GF ( " +CBC? " ) ) ;
sendAT ( GF ( " +CBC? " ) ) ;
if ( waitResponse ( GF ( GSM_NL " +CBC: " ) ) ! = 1 ) {
return false ;
}
chargeState = stream . readStringUntil ( ' , ' ) . toInt ( ) ;
percent = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
milliVolts = 0 ;
if ( waitResponse ( GF ( GSM_NL " +CBC: " ) ) ! = 1 ) { return false ; }
chargeState = streamGetIntBefore ( ' , ' ) ;
percent = streamGetIntBefore ( ' \n ' ) ;
milliVolts = 0 ;
/ / Wait for final OK
/ / Wait for final OK
waitResponse ( ) ;
waitResponse ( ) ;
return true ;
return true ;
}
}
float getTemperature ( ) TINY_GSM_ATTR_NOT_AVAILABLE ;
/*
/*
* Client related functions
* Client related functions
*/
*/
protected :
bool modemConnect ( const char * host , uint16_t port , uint8_t * mux , int timeout_s = 75 ) {
unsigned long startMillis = millis ( ) ;
uint32_t timeout_ms = ( ( uint32_t ) timeout_s ) * 1000 ;
sendAT ( GF ( " +CIPSTART= " ) , GF ( " \" TCP " ) , GF ( " \" , \" " ) , host , GF ( " \" , " ) , port ) ;
if ( waitResponse ( timeout_ms , GF ( GSM_NL " +CIPNUM: " ) ) ! = 1 ) {
return false ;
}
int newMux = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
int rsp = waitResponse ( ( timeout_ms - ( millis ( ) - startMillis ) ) ,
GF ( " CONNECT OK " GSM_NL ) ,
GF ( " CONNECT FAIL " GSM_NL ) ,
GF ( " ALREADY CONNECT " GSM_NL ) ) ;
if ( waitResponse ( ) ! = 1 ) {
return false ;
}
protected :
bool modemConnect ( const char * host , uint16_t port , uint8_t * mux ,
int timeout_s = 75 ) {
uint32_t startMillis = millis ( ) ;
uint32_t timeout_ms = ( ( uint32_t ) timeout_s ) * 1000 ;
sendAT ( GF ( " +CIPSTART= " ) , GF ( " \" TCP " ) , GF ( " \" , \" " ) , host , GF ( " \" , " ) , port ) ;
if ( waitResponse ( timeout_ms , GF ( GSM_NL " +CIPNUM: " ) ) ! = 1 ) { return false ; }
int8_t newMux = streamGetIntBefore ( ' \n ' ) ;
int8_t rsp = waitResponse (
( timeout_ms - ( millis ( ) - startMillis ) ) , GF ( " CONNECT OK " GSM_NL ) ,
GF ( " CONNECT FAIL " GSM_NL ) , GF ( " ALREADY CONNECT " GSM_NL ) ) ;
if ( waitResponse ( ) ! = 1 ) { return false ; }
* mux = newMux ;
* mux = newMux ;
return ( 1 = = rsp ) ;
return ( 1 = = rsp ) ;
@ -585,37 +434,35 @@ protected:
int16_t modemSend ( const void * buff , size_t len , uint8_t mux ) {
int16_t modemSend ( const void * buff , size_t len , uint8_t mux ) {
sendAT ( GF ( " +CIPSEND= " ) , mux , ' , ' , ( uint16_t ) len ) ;
sendAT ( GF ( " +CIPSEND= " ) , mux , ' , ' , ( uint16_t ) len ) ;
if ( waitResponse ( 2000L , GF ( GSM_NL " > " ) ) ! = 1 ) {
return 0 ;
}
stream . write ( ( uint8_t * ) buff , len ) ;
if ( waitResponse ( 2000L , GF ( GSM_NL " > " ) ) ! = 1 ) { return 0 ; }
stream . write ( reinterpret_cast < const uint8_t * > ( buff ) , len ) ;
stream . flush ( ) ;
stream . flush ( ) ;
if ( waitResponse ( 10000L , GFP ( GSM_OK ) , GF ( GSM_NL " FAIL " ) ) ! = 1 ) {
return 0 ;
}
if ( waitResponse ( 10000L , GFP ( GSM_OK ) , GF ( GSM_NL " FAIL " ) ) ! = 1 ) { return 0 ; }
return len ;
return len ;
}
}
bool modemGetConnected ( uint8_t ) {
bool modemGetConnected ( uint8_t ) {
sendAT ( GF ( " +CIPSTATUS " ) ) ; / / TODO mux ?
int res = waitResponse ( GF ( " , \" CONNECTED \" " ) , GF ( " , \" CLOSED \" " ) , GF ( " , \" CLOSING \" " ) , GF ( " , \" INITIAL \" " ) ) ;
sendAT ( GF ( " +CIPSTATUS " ) ) ; / / TODO ( ? ) mux ?
int8_t res = waitResponse ( GF ( " , \" CONNECTED \" " ) , GF ( " , \" CLOSED \" " ) ,
GF ( " , \" CLOSING \" " ) , GF ( " , \" INITIAL \" " ) ) ;
waitResponse ( ) ;
waitResponse ( ) ;
return 1 = = res ;
return 1 = = res ;
}
}
public :
/*
/*
Utilities
* Utilities
*/
*/
TINY_GSM_MODEM_STREAM_UTILITIES ( )
/ / TODO : Optimize this !
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 )
{
public :
/ / TODO ( vshymanskyy ) : Optimize this !
int8_t waitResponse ( uint32_t timeout_ms , String & data ,
GsmConstStr r1 = GFP ( GSM_OK ) ,
GsmConstStr r2 = GFP ( GSM_ERROR ) ,
# if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP ( GSM_CME_ERROR ) ,
# else
GsmConstStr r3 = NULL ,
# endif
GsmConstStr r4 = NULL , GsmConstStr r5 = NULL ) {
/*String r1s(r1); r1s.trim();
/*String r1s(r1); r1s.trim();
String r2s ( r2 ) ; r2s . trim ( ) ;
String r2s ( r2 ) ; r2s . trim ( ) ;
String r3s ( r3 ) ; r3s . trim ( ) ;
String r3s ( r3 ) ; r3s . trim ( ) ;
@ -623,15 +470,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s ( r5 ) ; r5s . trim ( ) ;
String r5s ( r5 ) ; r5s . trim ( ) ;
DBG ( " ### ..: " , r1s , " , " , r2s , " , " , r3s , " , " , r4s , " , " , r5s ) ; */
DBG ( " ### ..: " , r1s , " , " , r2s , " , " , r3s , " , " , r4s , " , " , r5s ) ; */
data . reserve ( 64 ) ;
data . reserve ( 64 ) ;
int index = 0 ;
unsigned long startMillis = millis ( ) ;
uint8_t index = 0 ;
uint32_t startMillis = millis ( ) ;
do {
do {
TINY_GSM_YIELD ( ) ;
TINY_GSM_YIELD ( ) ;
while ( stream . available ( ) > 0 ) {
while ( stream . available ( ) > 0 ) {
TINY_GSM_YIELD ( ) ;
TINY_GSM_YIELD ( ) ;
in t a = stream . read ( ) ;
if ( a < = 0 ) continue ; / / Skip 0x00 bytes , just in case
data + = ( char ) a ;
int8_ t a = stream . read ( ) ;
if ( a < = 0 ) continue ; / / Skip 0x00 bytes , just in case
data + = static_cast < char > ( a ) ;
if ( r1 & & data . endsWith ( r1 ) ) {
if ( r1 & & data . endsWith ( r1 ) ) {
index = 1 ;
index = 1 ;
goto finish ;
goto finish ;
@ -639,6 +486,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 2 ;
index = 2 ;
goto finish ;
goto finish ;
} else if ( r3 & & data . endsWith ( r3 ) ) {
} else if ( r3 & & data . endsWith ( r3 ) ) {
# if defined TINY_GSM_DEBUG
if ( r3 = = GFP ( GSM_CME_ERROR ) ) {
streamSkipUntil ( ' \n ' ) ; / / Read out the error
}
# endif
index = 3 ;
index = 3 ;
goto finish ;
goto finish ;
} else if ( r4 & & data . endsWith ( r4 ) ) {
} else if ( r4 & & data . endsWith ( r4 ) ) {
@ -648,23 +500,23 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5 ;
index = 5 ;
goto finish ;
goto finish ;
} else if ( data . endsWith ( GF ( " +CIPRCV: " ) ) ) {
} else if ( data . endsWith ( GF ( " +CIPRCV: " ) ) ) {
int mux = stream . readStringUntil ( ' , ' ) . toInt ( ) ;
int len = stream . readStringUntil ( ' , ' ) . toInt ( ) ;
in t len_orig = len ;
int8_t mux = streamGetIntBefore ( ' , ' ) ;
int16_t len = streamGetIntBefore ( ' , ' ) ;
int16_ t len_orig = len ;
if ( len > sockets [ mux ] - > rx . free ( ) ) {
if ( len > sockets [ mux ] - > rx . free ( ) ) {
DBG ( " ### Buffer overflow: " , len , " -> " , sockets [ mux ] - > rx . free ( ) ) ;
DBG ( " ### Buffer overflow: " , len , " -> " , sockets [ mux ] - > rx . free ( ) ) ;
} else {
} else {
DBG ( " ### Got: " , len , " -> " , sockets [ mux ] - > rx . free ( ) ) ;
DBG ( " ### Got: " , len , " -> " , sockets [ mux ] - > rx . free ( ) ) ;
}
}
while ( len - - ) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
}
if ( len_orig > sockets [ mux ] - > available ( ) ) { / / TODO
DBG ( " ### Fewer characters received than expected: " , sockets [ mux ] - > available ( ) , " vs " , len_orig ) ;
while ( len - - ) { moveCharFromStreamToFifo ( mux ) ; }
/ / TODO ( ? ) Deal with missing characters
if ( len_orig > sockets [ mux ] - > available ( ) ) {
DBG ( " ### Fewer characters received than expected: " ,
sockets [ mux ] - > available ( ) , " vs " , len_orig ) ;
}
}
data = " " ;
data = " " ;
} else if ( data . endsWith ( GF ( " +TCPCLOSED: " ) ) ) {
} else if ( data . endsWith ( GF ( " +TCPCLOSED: " ) ) ) {
int mux = stream . readStringUntil ( ' \n ' ) . toInt ( ) ;
int8_t mux = streamGetIntBefore ( ' \n ' ) ;
if ( mux > = 0 & & mux < TINY_GSM_MUX_COUNT ) {
if ( mux > = 0 & & mux < TINY_GSM_MUX_COUNT ) {
sockets [ mux ] - > sock_connected = false ;
sockets [ mux ] - > sock_connected = false ;
}
}
@ -673,38 +525,44 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
}
}
} while ( millis ( ) - startMillis < timeout_ms ) ;
} while ( millis ( ) - startMillis < timeout_ms ) ;
finish :
finish :
if ( ! index ) {
if ( ! index ) {
data . trim ( ) ;
data . trim ( ) ;
if ( data . length ( ) ) {
DBG ( " ### Unhandled: " , data ) ;
}
if ( data . length ( ) ) { DBG ( " ### Unhandled: " , data ) ; }
data = " " ;
data = " " ;
}
}
/ / data . replace ( GSM_NL , " / " ) ;
/ / DBG ( ' < ' , index , ' > ' , data ) ;
/ / data . replace ( GSM_NL , " / " ) ;
/ / DBG ( ' < ' , index , ' > ' , data ) ;
return index ;
return index ;
}
}
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 )
{
int8_t waitResponse ( uint32_t timeout_ms , GsmConstStr r1 = GFP ( GSM_OK ) ,
GsmConstStr r2 = GFP ( GSM_ERROR ) ,
# if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP ( GSM_CME_ERROR ) ,
# else
GsmConstStr r3 = NULL ,
# endif
GsmConstStr r4 = NULL , GsmConstStr r5 = NULL ) {
String data ;
String data ;
return waitResponse ( timeout_ms , 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 ) ,
GsmConstStr r3 = NULL , GsmConstStr r4 = NULL , GsmConstStr r5 = NULL )
{
int8_t waitResponse ( GsmConstStr r1 = GFP ( GSM_OK ) ,
GsmConstStr r2 = GFP ( GSM_ERROR ) ,
# if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP ( GSM_CME_ERROR ) ,
# else
GsmConstStr r3 = NULL ,
# endif
GsmConstStr r4 = NULL , GsmConstStr r5 = NULL ) {
return waitResponse ( 1000 , r1 , r2 , r3 , r4 , r5 ) ;
return waitResponse ( 1000 , r1 , r2 , r3 , r4 , r5 ) ;
}
}
public :
Stream & stream ;
protected :
GsmClient * sockets [ TINY_GSM_MUX_COUNT ] ;
protected :
Stream & stream ;
GsmClientA6 * sockets [ TINY_GSM_MUX_COUNT ] ;
const char * gsmNL = GSM_NL ;
} ;
} ;
# endif
# endif / / SRC_TINYGSMCLIENTA6_H_