|
@ -389,6 +389,7 @@ String TinyGsmDecodeHex16bit(String &instr) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The peek, flush, and connected functions |
|
|
#define TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() \ |
|
|
#define TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() \ |
|
|
virtual int peek() { return -1; } /* TODO */ \ |
|
|
virtual int peek() { return -1; } /* TODO */ \ |
|
|
\ |
|
|
\ |
|
@ -402,4 +403,209 @@ String TinyGsmDecodeHex16bit(String &instr) { |
|
|
} \ |
|
|
} \ |
|
|
virtual operator bool() { return connected(); } |
|
|
virtual operator bool() { return connected(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set baud rate via the V.25TER standard IPR command |
|
|
|
|
|
#define TINY_GSM_MODEM_SET_BAUD_IPR() \ |
|
|
|
|
|
void setBaud(unsigned long baud) { \ |
|
|
|
|
|
sendAT(GF("+IPR="), baud); \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test response to AT commands |
|
|
|
|
|
#define TINY_GSM_MODEM_TEST_AT() \ |
|
|
|
|
|
bool testAT(unsigned long timeout = 10000L) { \ |
|
|
|
|
|
for (unsigned long start = millis(); millis() - start < timeout; ) { \ |
|
|
|
|
|
sendAT(GF("")); \ |
|
|
|
|
|
if (waitResponse(200) == 1) return true; \ |
|
|
|
|
|
delay(100); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
return false; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Keeps listening for modem URC's and iterates through sockets |
|
|
|
|
|
// to see if any data is avaiable |
|
|
|
|
|
#define TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() \ |
|
|
|
|
|
void maintain() { \ |
|
|
|
|
|
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { \ |
|
|
|
|
|
GsmClient* sock = sockets[mux]; \ |
|
|
|
|
|
if (sock && sock->got_data) { \ |
|
|
|
|
|
sock->got_data = false; \ |
|
|
|
|
|
sock->sock_available = modemGetAvailable(mux); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
} \ |
|
|
|
|
|
while (stream.available()) { \ |
|
|
|
|
|
waitResponse(15, NULL, NULL); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Keeps listening for modem URC's - doesn't check socks because |
|
|
|
|
|
// modem has no internal fifo |
|
|
|
|
|
#define TINY_GSM_MODEM_MAINTAIN_LISTEN() \ |
|
|
|
|
|
void maintain() { \ |
|
|
|
|
|
waitResponse(10, NULL, NULL); \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Asks for modem information via the V.25TER standard ATI command |
|
|
|
|
|
// NOTE: The actual value and style of the response is quite varied |
|
|
|
|
|
#define TINY_GSM_MODEM_GET_INFO_ATI() \ |
|
|
|
|
|
String getModemInfo() { \ |
|
|
|
|
|
sendAT(GF("I")); \ |
|
|
|
|
|
String res; \ |
|
|
|
|
|
if (waitResponse(1000L, res) != 1) { \ |
|
|
|
|
|
return ""; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
res.replace(GSM_NL "OK" GSM_NL, ""); \ |
|
|
|
|
|
res.replace(GSM_NL, " "); \ |
|
|
|
|
|
res.trim(); \ |
|
|
|
|
|
return res; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unlocks a sim via the 3GPP TS command AT+CPIN |
|
|
|
|
|
#define TINY_GSM_MODEM_SIM_UNLOCK_CPIN() \ |
|
|
|
|
|
bool simUnlock(const char *pin) { \ |
|
|
|
|
|
sendAT(GF("+CPIN=\""), pin, GF("\"")); \ |
|
|
|
|
|
return waitResponse() == 1; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gets the CCID of a sim card via AT+CCID |
|
|
|
|
|
#define TINY_GSM_MODEM_GET_SIMCCID_CCID() \ |
|
|
|
|
|
String getSimCCID() { \ |
|
|
|
|
|
sendAT(GF("+CCID")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL "+CCID:")) != 1) { \ |
|
|
|
|
|
return ""; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
String res = stream.readStringUntil('\n'); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
res.trim(); \ |
|
|
|
|
|
return res; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Asks for TA Serial Number Identification (IMEI) via the V.25TER standard AT+GSN command |
|
|
|
|
|
#define TINY_GSM_MODEM_GET_IMEI_GSN() \ |
|
|
|
|
|
String getIMEI() { \ |
|
|
|
|
|
sendAT(GF("+GSN")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL)) != 1) { \ |
|
|
|
|
|
return ""; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
String res = stream.readStringUntil('\n'); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
res.trim(); \ |
|
|
|
|
|
return res; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gets the modem's registration status via CREG/CGREG/CEREG |
|
|
|
|
|
// CREG = Generic network registration |
|
|
|
|
|
// CGREG = GPRS service registration |
|
|
|
|
|
// CEREG = EPS registration for LTE modules |
|
|
|
|
|
#define TINY_GSM_MODEM_GET_REGISTRATION_XREG(regCommand) \ |
|
|
|
|
|
RegStatus getRegistrationStatus() { \ |
|
|
|
|
|
sendAT(GF("+" #regCommand "?")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL "+" #regCommand ":")) != 1) { \ |
|
|
|
|
|
return REG_UNKNOWN; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
streamSkipUntil(','); /* Skip format (0) */ \ |
|
|
|
|
|
int status = stream.readStringUntil('\n').toInt(); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
return (RegStatus)status; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gets the current network operator via the 3GPP TS command AT+COPS |
|
|
|
|
|
#define TINY_GSM_MODEM_GET_OPERATOR_COPS() \ |
|
|
|
|
|
String getOperator() { \ |
|
|
|
|
|
sendAT(GF("+COPS?")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { \ |
|
|
|
|
|
return ""; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
streamSkipUntil('"'); /* Skip mode and format */ \ |
|
|
|
|
|
String res = stream.readStringUntil('"'); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
return res; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Waits for network attachment |
|
|
|
|
|
#define TINY_GSM_MODEM_WAIT_FOR_NETWORK() \ |
|
|
|
|
|
bool waitForNetwork(unsigned long timeout = 60000L) { \ |
|
|
|
|
|
for (unsigned long start = millis(); millis() - start < timeout; ) { \ |
|
|
|
|
|
if (isNetworkConnected()) { \ |
|
|
|
|
|
return true; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
delay(250); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
return false; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Checks if current attached to GPRS/EPS service |
|
|
|
|
|
#define TINY_GSP_MODEM_GET_GPRS_IP_CONNECTED() \ |
|
|
|
|
|
bool isGprsConnected() { \ |
|
|
|
|
|
sendAT(GF("+CGATT?")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { \ |
|
|
|
|
|
return false; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
int res = stream.readStringUntil('\n').toInt(); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
if (res != 1) \ |
|
|
|
|
|
return false; \ |
|
|
|
|
|
\ |
|
|
|
|
|
return localIP() != IPAddress(0,0,0,0); \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gets signal quality report according to 3GPP TS command AT+CSQ |
|
|
|
|
|
#define TINY_GSP_MODEM_GET_CSQ() \ |
|
|
|
|
|
int16_t getSignalQuality() { \ |
|
|
|
|
|
sendAT(GF("+CSQ")); \ |
|
|
|
|
|
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { \ |
|
|
|
|
|
return 99; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
int res = stream.readStringUntil(',').toInt(); \ |
|
|
|
|
|
waitResponse(); \ |
|
|
|
|
|
return res; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Utility templates for writing/skipping characters on a stream |
|
|
|
|
|
#define TINY_GSP_MODEM_STREAM_UTILITIES() \ |
|
|
|
|
|
template<typename T> \ |
|
|
|
|
|
void streamWrite(T last) { \ |
|
|
|
|
|
stream.print(last); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
\ |
|
|
|
|
|
template<typename T, typename... Args> \ |
|
|
|
|
|
void streamWrite(T head, Args... tail) { \ |
|
|
|
|
|
stream.print(head); \ |
|
|
|
|
|
streamWrite(tail...); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
\ |
|
|
|
|
|
template<typename... Args> \ |
|
|
|
|
|
void sendAT(Args... cmd) { \ |
|
|
|
|
|
streamWrite("AT", cmd..., GSM_NL); \ |
|
|
|
|
|
stream.flush(); \ |
|
|
|
|
|
TINY_GSM_YIELD(); \ |
|
|
|
|
|
/* DBG("### AT:", cmd...); */ \ |
|
|
|
|
|
} \ |
|
|
|
|
|
\ |
|
|
|
|
|
bool streamSkipUntil(const char c, const unsigned long timeout = 1000L) { \ |
|
|
|
|
|
unsigned long startMillis = millis(); \ |
|
|
|
|
|
while (millis() - startMillis < timeout) { \ |
|
|
|
|
|
while (millis() - startMillis < timeout && !stream.available()) { \ |
|
|
|
|
|
TINY_GSM_YIELD(); \ |
|
|
|
|
|
} \ |
|
|
|
|
|
if (stream.read() == c) { \ |
|
|
|
|
|
return true; \ |
|
|
|
|
|
} \ |
|
|
|
|
|
} \ |
|
|
|
|
|
return false; \ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
#endif |