9 #ifndef TinyGsmClientA6_h
10 #define TinyGsmClientA6_h
14 #if !defined(TINY_GSM_RX_BUFFER)
15 #define TINY_GSM_RX_BUFFER 256
18 #define TINY_GSM_MUX_COUNT 8
20 #include "TinyGsmCommon.h"
23 static const char GSM_OK[] TINY_GSM_PROGMEM =
"OK" GSM_NL;
24 static const char GSM_ERROR[] TINY_GSM_PROGMEM =
"ERROR" GSM_NL;
64 sock_connected =
false;
70 virtual int connect(
const char *host, uint16_t port)
76 sock_connected = at->modemConnect(host, port, &newMux);
79 at->sockets[mux] =
this;
81 return sock_connected;
84 virtual int connect(
IPAddress ip, uint16_t port)
95 return connect(host.c_str(), port);
101 at->sendAT(GF(
"+CIPCLOSE="), mux);
102 sock_connected =
false;
107 virtual size_t write(
const uint8_t *buf,
size_t size)
111 return at->modemSend(buf, size, mux);
114 virtual size_t write(uint8_t c)
119 virtual int available()
122 if (!rx.size() && sock_connected) {
128 virtual int read(uint8_t *buf,
size_t size)
133 size_t chunk = TinyGsmMin(size-cnt, rx.size());
141 if (!rx.size() && sock_connected) {
152 if (read(&c, 1) == 1) {
167 virtual uint8_t connected()
172 return sock_connected;
174 virtual operator bool()
183 String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
194 explicit TinyGsm(Stream& stream)
197 memset(sockets, 0,
sizeof(sockets));
214 if (waitResponse() != 1) {
217 sendAT(GF(
"+CMEE=0"));
220 sendAT(GF(
"+CMER=3,0,0,2"));
227 void setBaud(
unsigned long baud)
229 sendAT(GF(
"+IPR="), baud);
232 bool testAT(
unsigned long timeout = 10000L)
234 for (
unsigned long start = millis(); millis() - start < timeout; ) {
236 if (waitResponse(200) == 1) {
247 waitResponse(10, NULL, NULL);
250 bool factoryDefault()
252 sendAT(GF(
"&FZE0&W"));
255 return waitResponse() == 1;
258 String getModemInfo()
262 if (waitResponse(1000L, res) != 1) {
265 res.replace(GSM_NL
"OK" GSM_NL,
"");
266 res.replace(GSM_NL,
" ");
285 sendAT(GF(
"+RST=1"));
293 return waitResponse() == 1;
296 bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
298 bool sleepEnable(
bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
304 bool simUnlock(const
char *pin)
306 sendAT(GF(
"+CPIN=\""), pin, GF(
"\""));
307 return waitResponse() == 1;
313 if (waitResponse(GF(GSM_NL
"+SCID: SIM Card ID:")) != 1) {
316 String res = stream.readStringUntil(
'\n');
325 if (waitResponse(GF(GSM_NL)) != 1) {
328 String res = stream.readStringUntil(
'\n');
334 SimStatus getSimStatus(
unsigned long timeout = 10000L)
336 for (
unsigned long start = millis(); millis() - start < timeout; ) {
337 sendAT(GF(
"+CPIN?"));
338 if (waitResponse(GF(GSM_NL
"+CPIN:")) != 1) {
342 int status = waitResponse(GF(
"READY"), GF(
"SIM PIN"), GF(
"SIM PUK"));
357 RegStatus getRegistrationStatus()
359 sendAT(GF(
"+CREG?"));
360 if (waitResponse(GF(GSM_NL
"+CREG:")) != 1) {
363 streamSkipUntil(
',');
364 int status = stream.readStringUntil(
'\n').toInt();
366 return (RegStatus)status;
371 sendAT(GF(
"+COPS=3,0"));
374 sendAT(GF(
"+COPS?"));
375 if (waitResponse(GF(GSM_NL
"+COPS:")) != 1) {
378 streamSkipUntil(
'"');
379 String res = stream.readStringUntil(
'"');
388 int getSignalQuality()
391 if (waitResponse(GF(GSM_NL
"+CSQ:")) != 1) {
394 int res = stream.readStringUntil(
',').toInt();
399 bool isNetworkConnected()
401 RegStatus s = getRegistrationStatus();
402 return (s == REG_OK_HOME || s == REG_OK_ROAMING);
405 bool waitForNetwork(
unsigned long timeout = 60000L)
407 for (
unsigned long start = millis(); millis() - start < timeout; ) {
408 if (isNetworkConnected()) {
419 bool gprsConnect(
const char* apn,
const char* user = NULL,
const char* pwd = NULL)
423 sendAT(GF(
"+CGATT=1"));
424 if (waitResponse(60000L) != 1) {
430 sendAT(GF(
"+CGDCONT=1,\"IP\",\""), apn,
'"');
439 sendAT(GF(
"+CSTT=\""), apn, GF(
"\",\""), user, GF(
"\",\""), pwd, GF(
"\""));
440 if (waitResponse(60000L) != 1) {
444 sendAT(GF(
"+CGACT=1,1"));
445 waitResponse(60000L);
447 sendAT(GF(
"+CIPMUX=1"));
448 if (waitResponse() != 1) {
455 bool gprsDisconnect()
458 sendAT(GF(
"+CIPSHUT"));
459 if (waitResponse(60000L) != 1) {
463 for (
int i = 0; i<3; i++) {
464 sendAT(GF(
"+CGATT=0"));
465 if (waitResponse(5000L) == 1) {
473 bool isGprsConnected()
475 sendAT(GF(
"+CGATT?"));
476 if (waitResponse(GF(GSM_NL
"+CGATT:")) != 1) {
479 int res = stream.readStringUntil(
'\n').toInt();
486 sendAT(GF(
"+CIFSR"));
488 if (waitResponse(10000L, res) != 1) {
491 res.replace(GSM_NL
"OK" GSM_NL,
"");
492 res.replace(GSM_NL,
"");
499 return TinyGsmIpFromString(getLocalIP());
506 bool setGsmBusy(
bool busy =
true) TINY_GSM_ATTR_NOT_AVAILABLE;
511 return waitResponse() == 1;
515 bool callNumber(
const String& number)
517 if (number == GF(
"last")) {
520 sendAT(GF(
"D\""), number,
"\";");
523 if (waitResponse(5000L) != 1) {
527 if (waitResponse(60000L,
528 GF(GSM_NL
"+CIEV: \"CALL\",1"),
529 GF(GSM_NL
"+CIEV: \"CALL\",0"),
530 GFP(GSM_ERROR)) != 1) {
534 int rsp = waitResponse(60000L,
535 GF(GSM_NL
"+CIEV: \"SOUNDER\",0"),
536 GF(GSM_NL
"+CIEV: \"CALL\",0"));
538 int rsp2 = waitResponse(300L, GF(GSM_NL
"BUSY" GSM_NL), GF(GSM_NL
"NO ANSWER" GSM_NL));
540 return rsp == 1 && rsp2 == 0;
546 return waitResponse() == 1;
550 bool dtmfSend(
char cmd,
unsigned duration_ms = 100)
552 duration_ms = constrain(duration_ms, 100, 1000);
560 sendAT(GF(
"+VTS="), cmd);
561 if (waitResponse(10000L) == 1) {
572 bool audioSetHeadphones()
574 sendAT(GF(
"+SNFS=0"));
575 return waitResponse() == 1;
578 bool audioSetSpeaker()
580 sendAT(GF(
"+SNFS=1"));
581 return waitResponse() == 1;
584 bool audioMuteMic(
bool mute)
586 sendAT(GF(
"+CMUT="), mute);
587 return waitResponse() == 1;
594 String sendUSSD(
const String& code)
596 sendAT(GF(
"+CMGF=1"));
598 sendAT(GF(
"+CSCS=\"HEX\""));
600 sendAT(GF(
"+CUSD=1,\""), code, GF(
"\",15"));
601 if (waitResponse(10000L) != 1) {
604 if (waitResponse(GF(GSM_NL
"+CUSD:")) != 1) {
607 stream.readStringUntil(
'"');
608 String hex = stream.readStringUntil(
'"');
609 stream.readStringUntil(
',');
610 int dcs = stream.readStringUntil(
'\n').toInt();
613 return TinyGsmDecodeHex7bit(hex);
614 }
else if (dcs == 72) {
615 return TinyGsmDecodeHex16bit(hex);
621 bool sendSMS(
const String& number,
const String& text)
623 sendAT(GF(
"+CMGF=1"));
625 sendAT(GF(
"+CMGS=\""), number, GF(
"\""));
626 if (waitResponse(GF(
">")) != 1) {
630 stream.write((
char)0x1A);
632 return waitResponse(60000L) == 1;
640 String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
646 uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
651 if (waitResponse(GF(GSM_NL
"+CBC:")) != 1) {
654 stream.readStringUntil(
',');
655 int res = stream.readStringUntil(
'\n').toInt();
662 bool modemConnect(
const char* host, uint16_t port, uint8_t* mux)
664 sendAT(GF(
"+CIPSTART="), GF(
"\"TCP"), GF(
"\",\""), host, GF(
"\","), port);
666 if (waitResponse(75000L, GF(GSM_NL
"+CIPNUM:")) != 1) {
669 int newMux = stream.readStringUntil(
'\n').toInt();
671 int rsp = waitResponse(75000L,
672 GF(
"CONNECT OK" GSM_NL),
673 GF(
"CONNECT FAIL" GSM_NL),
674 GF(
"ALREADY CONNECT" GSM_NL));
675 if (waitResponse() != 1) {
683 int modemSend(
const void* buff,
size_t len, uint8_t mux)
685 sendAT(GF(
"+CIPSEND="), mux,
',', len);
686 if (waitResponse(2000L, GF(GSM_NL
">")) != 1) {
689 stream.write((uint8_t*)buff, len);
691 if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL
"FAIL")) != 1) {
697 bool modemGetConnected(uint8_t mux)
699 sendAT(GF(
"+CIPSTATUS"));
700 int res = waitResponse(GF(
",\"CONNECTED\""), GF(
",\"CLOSED\""), GF(
",\"CLOSING\""),
711 void streamWrite(T
last)
716 template<
typename T,
typename... Args>
717 void streamWrite(T head, Args... tail)
720 streamWrite(tail...);
723 bool streamSkipUntil(
char c)
726 while (!stream.available()) {
729 if (stream.read() == c) {
736 template<
typename... Args>
737 void sendAT(Args... cmd)
739 streamWrite(
"AT", cmd..., GSM_NL);
746 uint8_t waitResponse(uint32_t timeout, String&
data,
747 GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
748 GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
758 unsigned long startMillis = millis();
761 while (stream.available() > 0) {
762 int a = stream.read();
767 if (r1 &&
data.endsWith(r1)) {
770 }
else if (r2 &&
data.endsWith(r2)) {
773 }
else if (r3 &&
data.endsWith(r3)) {
776 }
else if (r4 &&
data.endsWith(r4)) {
779 }
else if (r5 &&
data.endsWith(r5)) {
782 }
else if (
data.endsWith(GF(
"+CIPRCV:"))) {
783 int mux = stream.readStringUntil(
',').toInt();
784 int len = stream.readStringUntil(
',').toInt();
786 if (len > sockets[mux]->rx.free()) {
787 DBG(
"### Buffer overflow: ", len,
"->", sockets[mux]->rx.free());
789 DBG(
"### Got: ", len,
"->", sockets[mux]->rx.free());
792 while (!stream.available()) {
795 sockets[mux]->rx.put(stream.read());
797 if (len_orig > sockets[mux]->available()) {
798 DBG(
"### Fewer characters received than expected: ", sockets[mux]->available(),
" vs ", len_orig);
801 }
else if (
data.endsWith(GF(
"+TCPCLOSED:"))) {
802 int mux = stream.readStringUntil(
'\n').toInt();
803 if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
804 sockets[mux]->sock_connected =
false;
807 DBG(
"### Closed: ", mux);
810 }
while (millis() - startMillis < timeout);
815 DBG(
"### Unhandled:",
data);
822 uint8_t waitResponse(uint32_t timeout,
823 GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
824 GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
827 return waitResponse(timeout,
data, r1, r2, r3, r4, r5);
830 uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
831 GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
833 return waitResponse(1000, r1, r2, r3, r4, r5);
840 GsmClient* sockets[TINY_GSM_MUX_COUNT];