From a357bb559bce246d4be189e7bdf9ce5bf05f5971 Mon Sep 17 00:00:00 2001 From: Slavomir Hustaty Date: Thu, 5 Sep 2019 12:26:34 +0200 Subject: [PATCH 01/88] in case of erroneous return of device location the BTS location might help a little if getting errors via device reading --- src/TinyGsmClientSIM800.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index b5f2b6f..5a332c3 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -626,7 +626,18 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() res.trim(); return res; } - + + String getBaseStationGsmLocation() { + sendAT(GF("+CLBS=1,1")); + if (waitResponse(10000L, GF(GSM_NL "+CLBS:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + /* * Time functions */ From 55d668ad0d806a88dc9005043fbc767425a76a15 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 25 Sep 2019 17:33:12 -0400 Subject: [PATCH 02/88] Using CEREG for SARAR4, except R412 --- src/TinyGsmClientSaraR4.h | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index b37e75f..99dc5c9 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -125,7 +125,7 @@ TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; private: - TinyGsmSaraR4* at; + TinyGsmSaraR4* at; uint8_t mux; uint16_t sock_available; uint32_t prev_check; @@ -199,7 +199,13 @@ public: #endif waitResponse(); - DBG(GF("### Modem:"), getModemName()); + String modemName = getModemName(); + DBG(GF("### Modem:"), modemName); + if (modemName.startsWith("u-blox SARA-R412")) { + has2GFallback = true; + } else { + has2GFallback = false; + } int ret = getSimStatus(); // if the sim isn't ready and a pin has been provided, try to unlock the sim @@ -337,9 +343,25 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID() return SIM_ERROR; } -TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) + RegStatus getRegistrationStatus() { + if (has2GFallback) { + sendAT(GF("+CREG?")); + if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { + return REG_UNKNOWN; + } + } else { + sendAT(GF("+CEREG?")); + if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { + return REG_UNKNOWN; + } + } + streamSkipUntil(','); /* Skip format (0) */ + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } -TINY_GSM_MODEM_GET_OPERATOR_COPS() + TINY_GSM_MODEM_GET_OPERATOR_COPS() /* * Generic network functions @@ -779,6 +801,7 @@ public: protected: GsmClient* sockets[TINY_GSM_MUX_COUNT]; + bool has2GFallback; }; #endif From c10dfe0636ffe3d1ba291856353242835416bb84 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 25 Sep 2019 17:44:54 -0400 Subject: [PATCH 03/88] Version bump --- .github/ISSUE_TEMPLATE.md | 2 +- library.json | 2 +- library.properties | 2 +- src/TinyGsmCommon.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index fc39447..6870263 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,7 +22,7 @@ with your board before submitting any issues. Main processor board: Modem: -TinyGSM version: +TinyGSM version: Code: ### Scenario, steps to reproduce diff --git a/library.json b/library.json index 4fec615..abead61 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TinyGSM", - "version": "0.9.17", + "version": "0.9.18", "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.", "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M", "authors": diff --git a/library.properties b/library.properties index 549761f..c076660 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TinyGSM -version=0.9.17 +version=0.9.18 author=Volodymyr Shymanskyy maintainer=Volodymyr Shymanskyy sentence=A small Arduino library for GPRS modules, that just works. diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index bb2e541..8893088 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -10,7 +10,7 @@ #define TinyGsmCommon_h // The current library version number -#define TINYGSM_VERSION "0.9.17" +#define TINYGSM_VERSION "0.9.18" #if defined(SPARK) || defined(PARTICLE) #include "Particle.h" From bfd6055c4670dc17b3a069f257697437d30b9460 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Thu, 26 Sep 2019 16:38:15 -0400 Subject: [PATCH 04/88] NOT factory resetting in init --- .github/ISSUE_TEMPLATE.md | 2 +- library.json | 2 +- library.properties | 2 +- src/TinyGsmClientA6.h | 5 ++++- src/TinyGsmClientBG96.h | 5 ++++- src/TinyGsmClientM590.h | 5 ++++- src/TinyGsmClientM95.h | 5 ++++- src/TinyGsmClientMC60.h | 4 ++-- src/TinyGsmClientSIM800.h | 6 ++++-- src/TinyGsmCommon.h | 2 +- 10 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6870263..72063f1 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,7 +22,7 @@ with your board before submitting any issues. Main processor board: Modem: -TinyGSM version: +TinyGSM version: Code: ### Scenario, steps to reproduce diff --git a/library.json b/library.json index abead61..d16cda6 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TinyGSM", - "version": "0.9.18", + "version": "0.9.19", "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.", "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M", "authors": diff --git a/library.properties b/library.properties index c076660..aa8f193 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TinyGSM -version=0.9.18 +version=0.9.19 author=Volodymyr Shymanskyy maintainer=Volodymyr Shymanskyy sentence=A small Arduino library for GPRS modules, that just works. diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 449d330..ad09572 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -140,7 +140,10 @@ public: return false; } - sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); + + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index c9f4510..2a0bfa1 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -163,7 +163,10 @@ public: return false; } - sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); + + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index f312e59..3add9fe 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -138,7 +138,10 @@ public: return false; } - sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); + + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 3e108d0..290b575 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -160,7 +160,10 @@ public: return false; } - sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); + + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 6036e9c..ff28d81 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -164,8 +164,8 @@ public: return false; } - sendAT(GF("&FZ")); // Factory + Reset - waitResponse(); + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index c505eca..229e986 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -169,8 +169,10 @@ public: if (!testAT()) { return false; } - sendAT(GF("&FZ")); // Factory + Reset - waitResponse(); + + // sendAT(GF("&FZ")); // Factory + Reset + // waitResponse(); + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index 8893088..6e8bf37 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -10,7 +10,7 @@ #define TinyGsmCommon_h // The current library version number -#define TINYGSM_VERSION "0.9.18" +#define TINYGSM_VERSION "0.9.19" #if defined(SPARK) || defined(PARTICLE) #include "Particle.h" From a27d39c7f9b6e2df809573c20cd7312af6a7e821 Mon Sep 17 00:00:00 2001 From: Bernd Giesecke Date: Sat, 23 Nov 2019 12:28:28 +0800 Subject: [PATCH 05/88] Fix BG96 bugs - bool isGprsConnected() is now returning correct status - bool modemGetConnected() is now working as expected --- src/TinyGsmClientBG96.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index c9f4510..f21a56b 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -338,7 +338,21 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return true; } -TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() + // TINY_GSM_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 true; + } /* * IP Address functions @@ -587,7 +601,7 @@ protected: sendAT(GF("+QISTATE=1,"), mux); //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" - if (waitResponse(GF("+QISTATE:"))) + if (waitResponse(GF("+QISTATE:")) != 1) return false; streamSkipUntil(','); // Skip mux From 587be978b6532567a2805ba38649e15c096d47a6 Mon Sep 17 00:00:00 2001 From: Alexander Chernoskutov Date: Tue, 3 Dec 2019 11:29:53 +0500 Subject: [PATCH 06/88] remove vitrual dtors --- src/TinyGsmClientA6.h | 2 -- src/TinyGsmClientBG96.h | 1 - src/TinyGsmClientESP8266.h | 2 -- src/TinyGsmClientM590.h | 2 -- src/TinyGsmClientM95.h | 2 -- src/TinyGsmClientMC60.h | 2 -- src/TinyGsmClientSIM5360.h | 2 -- src/TinyGsmClientSIM7000.h | 2 -- src/TinyGsmClientSIM7600.h | 2 -- src/TinyGsmClientSIM800.h | 2 -- src/TinyGsmClientSIM808.h | 2 -- src/TinyGsmClientSaraR4.h | 2 -- src/TinyGsmClientSequansMonarch.h | 2 -- src/TinyGsmClientUBLOX.h | 2 -- src/TinyGsmClientXBee.h | 3 --- 15 files changed, 30 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 15a19f1..cd57ddc 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -123,8 +123,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmA6() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index c9f4510..9f17776 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -146,7 +146,6 @@ public: { memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmBG96() {} /* * Basic functions diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index b993805..3ea8e98 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -141,8 +141,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmESP8266() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index f312e59..7319afe 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -121,8 +121,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmM590() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 3e108d0..4cfdfca 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -143,8 +143,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmM95() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 6036e9c..8257ea0 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -147,8 +147,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmMC60() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 46b5eaf..bac8ee1 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -130,8 +130,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSim5360(){} - /* * Basic functions */ diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index ad13af1..21c1623 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -154,8 +154,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSim7000() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index b9d767a..e6fa461 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -130,8 +130,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSim7600(){} - /* * Basic functions */ diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index c505eca..f3a1206 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -153,8 +153,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSim800() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientSIM808.h b/src/TinyGsmClientSIM808.h index ecd07a1..35754a0 100644 --- a/src/TinyGsmClientSIM808.h +++ b/src/TinyGsmClientSIM808.h @@ -22,8 +22,6 @@ public: : TinyGsmSim800(stream) {} - virtual ~TinyGsmSim808(){} - /* * GPS location functions */ diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index b37e75f..cca5f5c 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -172,8 +172,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSaraR4(){} - /* * Basic functions */ diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index 6b44fbc..aba6043 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -183,8 +183,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmSequansMonarch() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientUBLOX.h b/src/TinyGsmClientUBLOX.h index 09702b1..c35f10f 100644 --- a/src/TinyGsmClientUBLOX.h +++ b/src/TinyGsmClientUBLOX.h @@ -164,8 +164,6 @@ public: memset(sockets, 0, sizeof(sockets)); } - virtual ~TinyGsmUBLOX() {} - /* * Basic functions */ diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 9662ee0..79e743e 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -287,9 +287,6 @@ public: inCommandMode = false; memset(sockets, 0, sizeof(sockets)); } - - virtual ~TinyGsmXBee() {} - /* * Basic functions */ From 1a326b94119da8874e596eb6ea9b4e7b4ba7193f Mon Sep 17 00:00:00 2001 From: Alexander Chernoskutov Date: Tue, 3 Dec 2019 19:31:47 +0500 Subject: [PATCH 07/88] use common TinyGsmUTFSMS calss --- src/TinyGsmClientBG96.h | 29 +-------------- src/TinyGsmClientM95.h | 29 +-------------- src/TinyGsmClientMC60.h | 29 +-------------- src/TinyGsmClientSIM5360.h | 32 +---------------- src/TinyGsmClientSIM7000.h | 29 +-------------- src/TinyGsmClientSIM7600.h | 32 +---------------- src/TinyGsmClientSIM800.h | 30 +--------------- src/TinyGsmCommon.h | 73 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 203 deletions(-) diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index 9f17776..33143d6 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -40,7 +40,7 @@ enum RegStatus { }; -class TinyGsmBG96 +class TinyGsmBG96: public TinyGsmUTFSMS { public: @@ -409,33 +409,6 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /* * Location functions diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 4cfdfca..d3e37d7 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -40,7 +40,7 @@ enum RegStatus { }; -class TinyGsmM95 +class TinyGsmM95: public TinyGsmUTFSMS { public: @@ -474,33 +474,6 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /** Delete all SMS */ bool deleteAllSMS() { sendAT(GF("+QMGDA=6")); diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 8257ea0..5a5251f 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -44,7 +44,7 @@ enum RegStatus { }; -class TinyGsmMC60 +class TinyGsmMC60: public TinyGsmUTFSMS { public: @@ -458,33 +458,6 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /** Delete all SMS */ bool deleteAllSMS() { sendAT(GF("+QMGDA=6")); diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index bac8ee1..e306a2e 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -45,7 +45,7 @@ enum TinyGSMDateTimeFormat { DATE_DATE = 2 }; -class TinyGsmSim5360 +class TinyGsmSim5360: public TinyGsmUTFSMS { public: @@ -520,36 +520,6 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - // Select TE character set - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - // Set text mode parameters - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - // Send the message - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /* * Location functions diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 21c1623..5f56091 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -45,7 +45,7 @@ enum TinyGSMDateTimeFormat { DATE_DATE = 2 }; -class TinyGsmSim7000 +class TinyGsmSim7000: public TinyGsmUTFSMS { public: @@ -562,33 +562,6 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /* * Location functions diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index e6fa461..c1ec12f 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -45,7 +45,7 @@ enum TinyGSMDateTimeFormat { DATE_DATE = 2 }; -class TinyGsmSim7600 +class TinyGsmSim7600: public TinyGsmUTFSMS { public: @@ -496,36 +496,6 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - // Select TE character set - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - // Set text mode parameters - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - // Send the message - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - /* * Location functions diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index f3a1206..d91e5d7 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -46,7 +46,7 @@ enum TinyGSMDateTimeFormat { DATE_DATE = 2 }; -class TinyGsmSim800 +class TinyGsmSim800 : public TinyGsmUTFSMS { public: @@ -593,34 +593,6 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return waitResponse(60000L) == 1; } - bool sendSMS_UTF16(const String& number, const void* text, size_t len) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CSMP=17,167,0,8")); - waitResponse(); - - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i> 8; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { stream.print('0'); } - stream.print(c, HEX); - } - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - - /* * Location functions */ diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index bb2e541..9803bb2 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -645,4 +645,77 @@ String TinyGsmDecodeHex16bit(String &instr) { } +//Common methods for UTF8/UTF16 SMS. +//Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800 +template +class TinyGsmUTFSMS { +public: + + class UTF8Print : public Print { + public: + UTF8Print(Print& p) : p(p) {} + virtual size_t write(const uint8_t c) override { + if(prv < 0xC0) { + if(c < 0xC0) printHex(c); + prv = c; + } else { + uint16_t v = uint16_t(prv)<<8 | c; + v -= (v>>8 == 0xD0)? 0xCC80 : 0xCD40; + printHex(v); + prv = 0; + } + return 1; + } + private: + Print& p; + uint8_t prv = 0; + void printHex(const uint16_t v) { + uint8_t c = v >> 8; + if (c < 0x10) p.print('0'); + p.print(c, HEX); + c = v & 0xFF; + if (c < 0x10) p.print('0'); + p.print(c, HEX); + } + }; + + bool sendSMS_UTF8_begin(const char* const number) { + static_cast(this)->sendAT(GF("+CMGF=1")); + static_cast(this)->waitResponse(); + static_cast(this)->sendAT(GF("+CSCS=\"HEX\"")); + static_cast(this)->waitResponse(); + static_cast(this)->sendAT(GF("+CSMP=17,167,0,8")); + static_cast(this)->waitResponse(); + + static_cast(this)->sendAT(GF("+CMGS=\""), number, GF("\"")); + return static_cast(this)->waitResponse(GF(">")) == 1; + } + bool sendSMS_UTF8_end() { + static_cast(this)->stream.write((char)0x1A); + static_cast(this)->stream.flush(); + return static_cast(this)->waitResponse(60000L) == 1; + } + UTF8Print sendSMS_UTF8_stream() { + return UTF8Print(static_cast(this)->stream); + } + + bool sendSMS_UTF16(const char* const number, const void* text, size_t len) { + if (!sendSMS_UTF8_begin(number)) { + return false; + } + + uint16_t* t = (uint16_t*)text; + for (size_t i=0; i> 8; + if (c < 0x10) { static_cast(this)->stream.print('0'); } + static_cast(this)->stream.print(c, HEX); + c = t[i] & 0xFF; + if (c < 0x10) { static_cast(this)->stream.print('0'); } + static_cast(this)->stream.print(c, HEX); + } + + return sendSMS_UTF8_end(); + } +}; + #endif From 58b7a5a1c79e6412bbfe7da249110862fe50160b Mon Sep 17 00:00:00 2001 From: Alexander Chernoskutov Date: Tue, 3 Dec 2019 19:45:07 +0500 Subject: [PATCH 08/88] update example: UTF8 SMS --- examples/AllFunctions/AllFunctions.ino | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/AllFunctions/AllFunctions.ino b/examples/AllFunctions/AllFunctions.ino index 7a8fb99..7164086 100644 --- a/examples/AllFunctions/AllFunctions.ino +++ b/examples/AllFunctions/AllFunctions.ino @@ -239,8 +239,15 @@ void loop() { DBG("SMS:", res ? "OK" : "fail"); // This is only supported on SIMxxx series - res = modem.sendSMS_UTF16(SMS_TARGET, u"Привіііт!", 9); - DBG("UTF16 SMS:", res ? "OK" : "fail"); + res = modem.sendSMS_UTF8_begin(SMS_TARGET); + if(res) { + auto stream = modem.sendSMS_UTF8_stream(); + stream.print(F("Привіііт! Print number: ")); + stream.print(595); + res = modem.sendSMS_UTF8_end(); + } + DBG("UTF8 SMS:", res ? "OK" : "fail"); + #endif #if TINY_GSM_TEST_CALL && defined(CALL_TARGET) From f1dba661b682389ee42b12d585d5724389651c89 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 10 Jan 2020 17:29:47 -0500 Subject: [PATCH 09/88] check if async is supported Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 73 ++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 99dc5c9..31319c8 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -94,18 +94,21 @@ TINY_GSM_CLIENT_CONNECT_OVERLOADS() virtual void stop(uint32_t maxWaitMs) { TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - // // synchronous close - // at->sendAT(GF("+USOCL="), mux); - // // NOTE: can take up to 120s to get a response - // at->waitResponse((maxWaitMs - (millis() - startMillis))); - // sock_connected = false; - - // faster asynchronous close - // NOT supported on SARA-R404M / SARA-R410M-01B - at->sendAT(GF("+USOCL="), mux, GF(",1")); - // NOTE: can take up to 120s to get a response - at->waitResponse((maxWaitMs - (millis() - startMillis))); - sock_connected = false; + if (at->supportsAsyncSockets) { + DBG("### Closing socket asynchronously! Socket might remain open until arrival of +UUSOCL: ", mux); + // faster asynchronous close + // NOT supported on SARA-R404M / SARA-R410M-01B + at->sendAT(GF("+USOCL="), mux, GF(",1")); + // NOTE: can take up to 120s to get a response + at->waitResponse((maxWaitMs - (millis() - startMillis))); + sock_connected = false; + } else { + // synchronous close + at->sendAT(GF("+USOCL="), mux); + // NOTE: can take up to 120s to get a response + at->waitResponse((maxWaitMs - (millis() - startMillis))); + sock_connected = false; + } } virtual void stop() { stop(135000L); } @@ -206,6 +209,12 @@ public: } else { has2GFallback = false; } + if (modemName.startsWith("u-blox SARA-R404M") || + modemName.startsWith("u-blox SARA-R410M-01B")) { + supportsAsyncSockets = false; + } else { + supportsAsyncSockets = true; + } int ret = getSimStatus(); // if the sim isn't ready and a pin has been provided, try to unlock the sim @@ -591,8 +600,11 @@ protected: } // Enable NODELAY - sendAT(GF("+USOSO="), *mux, GF(",6,1,1")); - waitResponse(); + // AT+USOSO=,,,[,] + // - 0 for IP, 6 for TCP, 65535 for socket level options + // TCP/1 = no delay (do not delay send to coalesce packets) + // sendAT(GF("+USOSO="), *mux, GF(",6,1,1")); + // waitResponse(); // Enable KEEPALIVE, 30 sec // sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); @@ -606,16 +618,21 @@ protected: // has a nasty habit of locking up when opening a socket, especially if // the cellular service is poor. // NOT supported on SARA-R404M / SARA-R410M-01B - sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); - waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")); - stream.readStringUntil(',').toInt(); // skip repeated mux - int connection_status = stream.readStringUntil('\n').toInt(); - return (0 == connection_status); - - // use synchronous open - // sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",0"); - // int rsp = waitResponse(timeout_ms); - // return (1 == rsp); + if (supportsAsyncSockets) { + DBG("### Opening socket asynchronously! Socket cannot be used until " + "arrival of +UUSOCO: ", + mux); + sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); + waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")); + stream.readStringUntil(',').toInt(); // skip repeated mux + int connection_status = stream.readStringUntil('\n').toInt(); + return (0 == connection_status); + } else { + // use synchronous open + sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); + int rsp = waitResponse(timeout_ms); + return (1 == rsp); + } } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { @@ -764,6 +781,13 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } data = ""; DBG("### URC Sock Closed: ", mux); + } else if (data.endsWith(GF("+UUSOCO:"))) { + int mux = stream.readStringUntil('\n').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->sock_connected = true; + } + data = ""; + DBG("### URC Sock Opened: ", mux); } } } while (millis() - startMillis < timeout_ms); @@ -802,6 +826,7 @@ public: protected: GsmClient* sockets[TINY_GSM_MUX_COUNT]; bool has2GFallback; + bool supportsAsyncSockets; }; #endif From 0e32caafb884047f7f09ba41337278c0d6ef66ec Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 10 Jan 2020 17:56:05 -0500 Subject: [PATCH 10/88] Need to check better for the URC Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 31319c8..3e2e6dd 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -623,10 +623,13 @@ protected: "arrival of +UUSOCO: ", mux); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); - waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")); - stream.readStringUntil(',').toInt(); // skip repeated mux - int connection_status = stream.readStringUntil('\n').toInt(); - return (0 == connection_status); + if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")) == 1) { + stream.readStringUntil(',').toInt(); // skip repeated mux + int connection_status = stream.readStringUntil('\n').toInt(); + return (0 == connection_status); + } else { + return false; + } } else { // use synchronous open sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); From 885f3058305531327aa239701b846c7eb2d9f160 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 10 Jan 2020 18:06:40 -0500 Subject: [PATCH 11/88] give the R4 2 minute default timeout. Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 3e2e6dd..4440617 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -88,8 +88,24 @@ public: return sock_connected; } - -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port, timeout_s); + } + virtual int connect(const char* host, uint16_t port) { + return connect(host, port, 120); + } + virtual int connect(IPAddress ip, uint16_t port) { + return connect(ip, port, 120); + } virtual void stop(uint32_t maxWaitMs) { TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() From 30f09b242980c907d3e08962e951f81081b8f1fe Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Thu, 16 Jan 2020 15:28:26 -0500 Subject: [PATCH 12/88] Fix debug print Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 4440617..b26dba9 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -636,8 +636,7 @@ protected: // NOT supported on SARA-R404M / SARA-R410M-01B if (supportsAsyncSockets) { DBG("### Opening socket asynchronously! Socket cannot be used until " - "arrival of +UUSOCO: ", - mux); + "the URC '+UUSOCO' appears."); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")) == 1) { stream.readStringUntil(',').toInt(); // skip repeated mux From 36a50c60da66848090f1a0de4d18a09ce70aa38b Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Mon, 20 Jan 2020 13:14:53 -0500 Subject: [PATCH 13/88] Missing socket open Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index b26dba9..fb19e05 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -117,6 +117,7 @@ public: at->sendAT(GF("+USOCL="), mux, GF(",1")); // NOTE: can take up to 120s to get a response at->waitResponse((maxWaitMs - (millis() - startMillis))); + // We set the sock as disconnected right away because it can no longer be used sock_connected = false; } else { // synchronous close @@ -600,7 +601,9 @@ protected: bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false, int timeout_s = 120) { - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + unsigned long startMillis = millis(); + // create a socket sendAT(GF("+USOCR=6")); // reply is +USOCR: ## of socket created @@ -619,6 +622,7 @@ protected: // AT+USOSO=,,,[,] // - 0 for IP, 6 for TCP, 65535 for socket level options // TCP/1 = no delay (do not delay send to coalesce packets) + // NOTE: Enabling this may increase data plan usage // sendAT(GF("+USOSO="), *mux, GF(",6,1,1")); // waitResponse(); @@ -638,19 +642,15 @@ protected: DBG("### Opening socket asynchronously! Socket cannot be used until " "the URC '+UUSOCO' appears."); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); - if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO: ")) == 1) { - stream.readStringUntil(',').toInt(); // skip repeated mux - int connection_status = stream.readStringUntil('\n').toInt(); - return (0 == connection_status); - } else { - return false; + while (millis() - startMillis < timeout_ms && + sockets[*mux]->sock_connected == false) {} + } + else { + // use synchronous open + sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); + int rsp = waitResponse(timeout_ms); + return (1 == rsp); } - } else { - // use synchronous open - sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); - int rsp = waitResponse(timeout_ms); - return (1 == rsp); - } } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { @@ -801,7 +801,9 @@ TINY_GSM_MODEM_STREAM_UTILITIES() DBG("### URC Sock Closed: ", mux); } else if (data.endsWith(GF("+UUSOCO:"))) { int mux = stream.readStringUntil('\n').toInt(); - if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + int socket_error = stream.readStringUntil('\n').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] && + socket_error == 0) { sockets[mux]->sock_connected = true; } data = ""; From 044ab269511b6ec8d6bd100ccd45e245b8d93647 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Mon, 20 Jan 2020 13:25:16 -0500 Subject: [PATCH 14/88] missed return Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index fb19e05..897e1c2 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -111,7 +111,7 @@ public: TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() if (at->supportsAsyncSockets) { - DBG("### Closing socket asynchronously! Socket might remain open until arrival of +UUSOCL: ", mux); + DBG("### Closing socket asynchronously! Socket might remain open until arrival of +UUSOCL:", mux); // faster asynchronous close // NOT supported on SARA-R404M / SARA-R410M-01B at->sendAT(GF("+USOCL="), mux, GF(",1")); @@ -643,14 +643,14 @@ protected: "the URC '+UUSOCO' appears."); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); while (millis() - startMillis < timeout_ms && - sockets[*mux]->sock_connected == false) {} - } - else { - // use synchronous open - sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); - int rsp = waitResponse(timeout_ms); - return (1 == rsp); - } + sockets[*mux]->sock_connected == false) {} + return sockets[*mux]->sock_connected == true; + } else { + // use synchronous open + sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); + int rsp = waitResponse(timeout_ms); + return (1 == rsp); + } } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { From 5efcc5a490d60ff00eafb2f67c4bd3f8eb32fc63 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Mon, 20 Jan 2020 18:07:24 -0500 Subject: [PATCH 15/88] Tweeking async open/close, alternate CEREG/CREG Signed-off-by: Sara Damiano --- src/TinyGsmClientSaraR4.h | 68 +++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 897e1c2..313ff2c 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -109,15 +109,25 @@ public: virtual void stop(uint32_t maxWaitMs) { TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - - if (at->supportsAsyncSockets) { - DBG("### Closing socket asynchronously! Socket might remain open until arrival of +UUSOCL:", mux); + // We want to use an async socket close because the syncrhonous close of an + // open socket is INCREDIBLY SLOW and the modem can freeze up. But we only + // attempt the async close if we already KNOW the socket is open because + // calling the async close on a closed socket and then attempting opening a + // new socket causes the board to lock up for 2-3 minutes and then finally + // return with a "new" socket that is immediately closed. + // Attempting to close a socket that is already closed with a synchronous + // close quickly returns an error. + if (at->supportsAsyncSockets && sock_connected) { + DBG("### Closing socket asynchronously! Socket might remain open " + "until arrival of +UUSOCL:", + mux); // faster asynchronous close // NOT supported on SARA-R404M / SARA-R410M-01B at->sendAT(GF("+USOCL="), mux, GF(",1")); // NOTE: can take up to 120s to get a response at->waitResponse((maxWaitMs - (millis() - startMillis))); - // We set the sock as disconnected right away because it can no longer be used + // We set the sock as disconnected right away because it can no longer + // be used sock_connected = false; } else { // synchronous close @@ -370,21 +380,30 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID() } RegStatus getRegistrationStatus() { - if (has2GFallback) { + // Check first for EPS registration + sendAT(GF("+CEREG?")); + if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); /* Skip format (0) */ + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + + // If we're connected on EPS, great! + if ((RegStatus)status == REG_OK_HOME || + (RegStatus)status == REG_OK_ROAMING) { + return (RegStatus)status; + } else { + // Otherwise, check generic network status sendAT(GF("+CREG?")); if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { return REG_UNKNOWN; } - } else { - sendAT(GF("+CEREG?")); - if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { - return REG_UNKNOWN; - } + streamSkipUntil(','); /* Skip format (0) */ + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; } - streamSkipUntil(','); /* Skip format (0) */ - int status = stream.readStringUntil('\n').toInt(); - waitResponse(); - return (RegStatus)status; } TINY_GSM_MODEM_GET_OPERATOR_COPS() @@ -459,6 +478,15 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } bool gprsDisconnect() { + // Mark all the sockets as closed + // This ensures that asynchronously closed sockets are marked closed + for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { + GsmClient* sock = sockets[mux]; + if (sock && sock->sock_connected) { + sock->sock_connected = false; + } + } + // sendAT(GF("+CGACT=0,1")); // Deactivate PDP context 1 sendAT(GF("+CGACT=0")); // Deactivate all contexts if (waitResponse(40000L) != 1) { @@ -642,9 +670,15 @@ protected: DBG("### Opening socket asynchronously! Socket cannot be used until " "the URC '+UUSOCO' appears."); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); - while (millis() - startMillis < timeout_ms && - sockets[*mux]->sock_connected == false) {} - return sockets[*mux]->sock_connected == true; + if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO:")) == 1) { + stream.readStringUntil(',').toInt(); // skip repeated mux + int connection_status = stream.readStringUntil('\n').toInt(); + DBG("### Waited", millis() - startMillis, "ms for socket to open"); + return (0 == connection_status); + } else { + DBG("### Waited", millis() - startMillis, "but never got socket open notice"); + return false; + } } else { // use synchronous open sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); From 6a60e3be7620cb3fa0d093298b8140f6d78e5916 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Thu, 23 Jan 2020 11:07:13 -0500 Subject: [PATCH 16/88] Some tweaks to Sequans Signed-off-by: Sara Damiano --- src/TinyGsmClientSequansMonarch.h | 123 ++++++++++++++++++------------ 1 file changed, 74 insertions(+), 49 deletions(-) diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index 6b44fbc..53ac2a5 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -66,7 +66,7 @@ public: init(&modem, mux); } - virtual ~GsmClient(){} + virtual ~GsmClient() {} bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) { this->at = modem; @@ -84,7 +84,7 @@ public: } public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { if (sock_connected) stop(); TINY_GSM_YIELD(); rx.clear(); @@ -127,9 +127,7 @@ private: RxFifo rx; }; - -class GsmClientSecure : public GsmClient -{ + class GsmClientSecure : public GsmClient { public: GsmClientSecure() {} @@ -137,13 +135,13 @@ public: : GsmClient(modem, mux) {} - virtual ~GsmClientSecure(){} + virtual ~GsmClientSecure() {} protected: - bool strictSSL = false; + bool strictSSL = false; public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); @@ -152,7 +150,8 @@ public: if (strictSSL) { // require minimum of TLS 1.2 (3) // only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256 - // verify server certificate against imported CA certs 0 and enforce validity period (3) + // verify server certificate against imported CA certs 0 and enforce + // validity period (3) at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\"")); } else { // use TLS 1.0 or higher (1) @@ -176,10 +175,7 @@ public: }; public: - - TinyGsmSequansMonarch(Stream& stream) - : stream(stream) - { + TinyGsmSequansMonarch(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } @@ -200,11 +196,18 @@ public: return false; } - sendAT(GF("E0")); // Echo Off + sendAT(GF("E0")); // Echo Off if (waitResponse() != 1) { return false; } +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); + DBG(GF("### Modem:"), getModemName()); int ret = getSimStatus(); @@ -221,7 +224,25 @@ public: } String getModemName() { - return "Sequans Monarch"; + // return "Sequans Monarch"; + sendAT(GF("+CGMI")); + String res1; + if (waitResponse(1000L, res1) != 1) { + return "u-blox Cellular Modem"; + } + res1.replace(GSM_NL "OK" GSM_NL, ""); + res1.trim(); + + sendAT(GF("+CGMM")); + String res2; + if (waitResponse(1000L, res2) != 1) { + return "u-blox Cellular Modem"; + } + res2.replace(GSM_NL "OK" GSM_NL, ""); + res2.trim(); + + String name = res1 + String(' ') + res2; + return name; } TINY_GSM_MODEM_SET_BAUD_IPR() @@ -280,7 +301,7 @@ TINY_GSM_MODEM_GET_INFO_ATI() } sendAT(GF("+CFUN=1,1")); - res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)) ; + res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)); if (res != 1 && res != 3) { return false; } @@ -461,7 +482,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() bool sendSMS(const String& number, const String& text) { sendAT(GF("+CMGF=1")); waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) + // Set GSM 7 bit default alphabet (3GPP TS 23.038) sendAT(GF("+CSCS=\"GSM\"")); waitResponse(); sendAT(GF("+CMGS=\""), number, GF("\"")); @@ -490,7 +511,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() 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; + bool getBattStats(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; float getTemperature() { sendAT(GF("+SMDTH")); @@ -501,24 +523,22 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() if (waitResponse(1000L, res) != 1) { return (float)-9999; } - if (res.indexOf("ERROR") >=0) { + if (res.indexOf("ERROR") >= 0) { return (float)-9999; } return res.toFloat(); } protected: - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) - { + bool ssl = false, int timeout_s = 75) { int rsp; unsigned long startMillis = millis(); - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; if (ssl) { // enable SSl and use security profile 1 - //AT+SQNSSCFG=,, + // AT+SQNSSCFG=,, sendAT(GF("+SQNSSCFG="), mux, GF(",1,1")); if (waitResponse() != 1) { DBG("### WARNING: failed to configure secure socket"); @@ -549,7 +569,7 @@ protected: waitResponse(5000L); // Socket dial - //AT+SQNSD=,,,[,[,[,[,acceptAnyRemote]]]] + // AT+SQNSD=,,,[,[,[,[,acceptAnyRemote]]]] // = Connection ID = mux // = Transmission protocol = 0 - TCP (1 for UDP) // = Remote host port to contact @@ -572,7 +592,7 @@ protected: bool connected = false; while (!connected && ((millis() - startMillis) < timeout_ms)) { connected = modemGetConnected(mux); - delay(100); // socket may be in opening state + delay(100); // socket may be in opening state } return connected; } @@ -623,12 +643,16 @@ protected: if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; } - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip mux int len = stream.readStringUntil('\n').toInt(); - for (int i=0; i_timeout)) { TINY_GSM_YIELD(); } \ - char c = stream.read(); \ + for (int i = 0; i < len; i++) { + uint32_t startMillis = millis(); + while (!stream.available() && + ((millis() - startMillis) < + sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) { + TINY_GSM_YIELD(); + } + char c = stream.read(); sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c); } DBG("### Read:", len, "from", mux); @@ -663,7 +687,7 @@ protected: // if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no // DBG("### Warning: misaligned mux numbers!"); // } - streamSkipUntil(','); // skip mux [use muxNo] + streamSkipUntil(','); // skip mux [use muxNo] status = stream.parseInt(); // Read the status // if mux is in use, will have comma then other info after the status // if not, there will be new line immediately after status @@ -692,9 +716,9 @@ 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) - { + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -709,7 +733,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case + if (a <= 0) continue; // Skip 0x00 bytes, just in case data += (char)a; if (r1 && data.endsWith(r1)) { index = 1; @@ -729,7 +753,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) { int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); - if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && + sockets[mux % TINY_GSM_MUX_COUNT]) { sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true; sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len; } @@ -737,7 +762,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES() DBG("### URC Data Received:", len, "on", mux); } else if (data.endsWith(GF("SQNSH: "))) { int mux = stream.readStringUntil('\n').toInt(); - if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && + sockets[mux % TINY_GSM_MUX_COUNT]) { sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false; } data = ""; @@ -753,30 +779,29 @@ finish: } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + 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_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) - { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } public: - Stream& stream; + Stream& stream; protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + GsmClient* sockets[TINY_GSM_MUX_COUNT]; }; #endif From 033092f8fe467e5de9bbab931fff630bde2ba39d Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 24 Jan 2020 11:41:24 -0500 Subject: [PATCH 17/88] Set CFUN in Sequans init - else fails Signed-off-by: Sara Damiano --- src/TinyGsmClientSequansMonarch.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index 53ac2a5..7065f9b 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -210,6 +210,13 @@ public: DBG(GF("### Modem:"), getModemName()); + // Make sure the module is enabled. Unlike others, the VZN20Q powers on + // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full functionality + // The module cannot even detect the sim card if the cellular functionality is disabled so + // unless we explicitly enable the functionality the init will fail. + sendAT(GF("+CFUN=1")); // turn off error codes + waitResponse(); + int ret = getSimStatus(); // 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) { From d85e83f04932cbb18c3972c21883dc2af20926b7 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 31 Jan 2020 17:03:10 -0500 Subject: [PATCH 18/88] Fixes to BG96 Signed-off-by: Sara Damiano --- src/TinyGsmClientBG96.h | 11 +++++++---- src/TinyGsmClientSequansMonarch.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index 2a0bfa1..bc40c6e 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -231,7 +231,7 @@ TINY_GSM_MODEM_GET_INFO_ATI() if (waitResponse(60000L, GF("POWERED DOWN")) != 1) { return false; } - delay(3000); + waitResponse(5000L, GF("RDY")); return init(); } @@ -348,8 +348,11 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() */ String getLocalIP() { - sendAT(GF("+QILOCIP")); - stream.readStringUntil('\n'); + sendAT(GF("+CGPADDR=1")); + if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) { + return ""; + } + streamSkipUntil(','); // Skip context id String res = stream.readStringUntil('\n'); if (waitResponse() != 1) { return ""; @@ -590,7 +593,7 @@ protected: sendAT(GF("+QISTATE=1,"), mux); //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" - if (waitResponse(GF("+QISTATE:"))) + if (waitResponse(GF("+QISTATE:")) != 1) return false; streamSkipUntil(','); // Skip mux diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index 7065f9b..8e65d93 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -214,7 +214,7 @@ public: // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full functionality // The module cannot even detect the sim card if the cellular functionality is disabled so // unless we explicitly enable the functionality the init will fail. - sendAT(GF("+CFUN=1")); // turn off error codes + sendAT(GF("+CFUN=1")); waitResponse(); int ret = getSimStatus(); From 4ad29b59c43a6735b36c0798b8c1e7a7c03819be Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 31 Jan 2020 17:15:22 -0500 Subject: [PATCH 19/88] check ip in connection with correct local ip fxn Signed-off-by: Sara Damiano --- src/TinyGsmClientBG96.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index 365b67d..a689e3d 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -341,21 +341,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return true; } - // TINY_GSM_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 true; - } + TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() /* * IP Address functions From d3d1083d8f2f12864eec71f1fa36516161c4dd8e Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Thu, 6 Feb 2020 15:20:44 -0500 Subject: [PATCH 20/88] CRTP!!!! Totally untested Signed-off-by: Sara Damiano --- .clang-format | 110 ++ .gitignore | 1 + cpplint.cfg | 3 + examples/AllFunctions/AllFunctions.ino | 6 +- examples/BlynkClient/BlynkClient.ino | 2 +- examples/FileDownload/FileDownload.ino | 12 +- examples/HttpClient/HttpClient.ino | 6 +- examples/HttpsClient/HttpsClient.ino | 6 +- examples/MqttClient/MqttClient.ino | 8 +- examples/WebClient/WebClient.ino | 8 +- examples/more/Hologram_Dash/Hologram_Dash.ino | 8 +- examples/more/Industruino/Industruino.ino | 6 +- .../SIM800_SslSetCert/SIM800_SslSetCert.ino | 2 +- src/TinyGsmClient.h | 175 +- src/TinyGsmClientA6.h | 588 +++--- src/TinyGsmClientBG96.h | 653 +++---- src/TinyGsmClientESP8266.h | 489 +++-- src/TinyGsmClientM590.h | 515 ++--- src/TinyGsmClientM95.h | 679 +++---- src/TinyGsmClientMC60.h | 703 +++---- src/TinyGsmClientSIM5360.h | 671 +++---- src/TinyGsmClientSIM7000.h | 835 +++----- src/TinyGsmClientSIM7600.h | 689 +++---- src/TinyGsmClientSIM800.h | 850 +++----- src/TinyGsmClientSIM808.h | 95 +- src/TinyGsmClientSaraR4.h | 689 +++---- src/TinyGsmClientSequansMonarch.h | 665 +++---- src/TinyGsmClientUBLOX.h | 603 +++--- src/TinyGsmClientXBee.h | 1075 ++++++----- src/TinyGsmCommon.h | 1708 +++++++++++------ tools/test_build/test_build.ino | 27 +- 31 files changed, 5226 insertions(+), 6661 deletions(-) create mode 100644 .clang-format create mode 100644 cpplint.cfg diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..110d35d --- /dev/null +++ b/.clang-format @@ -0,0 +1,110 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +# ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 60 +PenaltyReturnTypeOnItsOwnLine: 5 +PointerAlignment: Left +PointerBindsToType: true +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never +--- diff --git a/.gitignore b/.gitignore index 051117d..b5e30af 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ .clang_complete .gcc-flags.json platformio.ini +extra_envs.ini lib/readme.txt include/readme.txt .atomrc.cson diff --git a/cpplint.cfg b/cpplint.cfg new file mode 100644 index 0000000..6485487 --- /dev/null +++ b/cpplint.cfg @@ -0,0 +1,3 @@ +# Allow references to be used to change values +filter=-runtime/references +filter=-build/namespaces diff --git a/examples/AllFunctions/AllFunctions.ino b/examples/AllFunctions/AllFunctions.ino index 7164086..7313a6d 100644 --- a/examples/AllFunctions/AllFunctions.ino +++ b/examples/AllFunctions/AllFunctions.ino @@ -42,7 +42,7 @@ //SoftwareSerial SerialAT(2, 3); // RX, TX // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon @@ -68,8 +68,8 @@ #define GSM_PIN "" // Set phone numbers, if you want to test SMS and Calls -//#define SMS_TARGET "+380xxxxxxxxx" -//#define CALL_TARGET "+380xxxxxxxxx" +// #define SMS_TARGET "+380xxxxxxxxx" +// #define CALL_TARGET "+380xxxxxxxxx" // Your GPRS credentials, if any const char apn[] = "YourAPN"; diff --git a/examples/BlynkClient/BlynkClient.ino b/examples/BlynkClient/BlynkClient.ino index 0ae92ee..20f98c0 100644 --- a/examples/BlynkClient/BlynkClient.ino +++ b/examples/BlynkClient/BlynkClient.ino @@ -26,7 +26,7 @@ // Default heartbeat interval for GSM is 60 // If you want override this value, uncomment and set this option: -//#define BLYNK_HEARTBEAT 30 +// #define BLYNK_HEARTBEAT 30 // Select your modem: #define TINY_GSM_MODEM_SIM800 diff --git a/examples/FileDownload/FileDownload.ino b/examples/FileDownload/FileDownload.ino index cfab6a7..f20e187 100644 --- a/examples/FileDownload/FileDownload.ino +++ b/examples/FileDownload/FileDownload.ino @@ -52,14 +52,14 @@ #define TINY_GSM_RX_BUFFER 1024 // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon -//#define LOGGING // <- Logging is for the HTTP library +// #define LOGGING // <- Logging is for the HTTP library // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Define how you're planning to connect to the internet #define TINY_GSM_USE_GPRS true @@ -217,7 +217,7 @@ void loop() { client.print("Connection: close\r\n\r\n"); // Let's see what the entire elapsed time is, from after we send the request. - unsigned long timeElapsed = millis(); + uint32_t timeElapsed = millis(); SerialMon.println(F("Waiting for response header")); @@ -246,7 +246,7 @@ void loop() { // SerialMon.print(c, HEX); // SerialMon.print(' '); // if (isprint(c)) - // SerialMon.print((char) c); + // SerialMon.print(reinterpret_cast c); // else // SerialMon.print('*'); // SerialMon.print(' '); @@ -301,7 +301,7 @@ void loop() { while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) { while (client.available()) { uint8_t c = client.read(); - //SerialMon.print((char)c); // Uncomment this to show data + //SerialMon.print(reinterpret_castc); // Uncomment this to show data crc.update(c); readLength++; if (readLength % (contentLength / 13) == 0) { diff --git a/examples/HttpClient/HttpClient.ino b/examples/HttpClient/HttpClient.ino index d77f1de..1bff394 100644 --- a/examples/HttpClient/HttpClient.ino +++ b/examples/HttpClient/HttpClient.ino @@ -57,18 +57,18 @@ #define TINY_GSM_RX_BUFFER 650 // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon -//#define LOGGING // <- Logging is for the HTTP library +// #define LOGGING // <- Logging is for the HTTP library // Range to attempt to autobaud #define GSM_AUTOBAUD_MIN 9600 #define GSM_AUTOBAUD_MAX 115200 // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Define how you're planning to connect to the internet #define TINY_GSM_USE_GPRS true diff --git a/examples/HttpsClient/HttpsClient.ino b/examples/HttpsClient/HttpsClient.ino index 6330ea9..fbbd02a 100644 --- a/examples/HttpsClient/HttpsClient.ino +++ b/examples/HttpsClient/HttpsClient.ino @@ -49,18 +49,18 @@ #define TINY_GSM_RX_BUFFER 650 // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon -//#define LOGGING // <- Logging is for the HTTP library +// #define LOGGING // <- Logging is for the HTTP library // Range to attempt to autobaud #define GSM_AUTOBAUD_MIN 9600 #define GSM_AUTOBAUD_MAX 115200 // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Define how you're planning to connect to the internet #define TINY_GSM_USE_GPRS true diff --git a/examples/MqttClient/MqttClient.ino b/examples/MqttClient/MqttClient.ino index 1e269d8..aa0876c 100644 --- a/examples/MqttClient/MqttClient.ino +++ b/examples/MqttClient/MqttClient.ino @@ -60,7 +60,7 @@ //SoftwareSerial SerialAT(2, 3); // RX, TX // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon @@ -70,7 +70,7 @@ #define GSM_AUTOBAUD_MAX 115200 // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Define how you're planning to connect to the internet #define TINY_GSM_USE_GPRS true @@ -125,7 +125,7 @@ PubSubClient mqtt(client); #define LED_PIN 13 int ledStatus = LOW; -long lastReconnectAttempt = 0; +uint32_t lastReconnectAttempt = 0; void mqttCallback(char* topic, byte* payload, unsigned int len) { SerialMon.print("Message arrived ["); @@ -252,7 +252,7 @@ void loop() { if (!mqtt.connected()) { SerialMon.println("=== MQTT NOT CONNECTED ==="); // Reconnect every 10 seconds - unsigned long t = millis(); + uint32_t t = millis(); if (t - lastReconnectAttempt > 10000L) { lastReconnectAttempt = t; if (mqttConnect()) { diff --git a/examples/WebClient/WebClient.ino b/examples/WebClient/WebClient.ino index 8207c06..1e80494 100644 --- a/examples/WebClient/WebClient.ino +++ b/examples/WebClient/WebClient.ino @@ -47,7 +47,7 @@ #define TINY_GSM_RX_BUFFER 650 // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon @@ -57,10 +57,10 @@ #define GSM_AUTOBAUD_MAX 115200 // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Uncomment this if you want to use SSL -//#define USE_SSL +// #define USE_SSL // Define how you're planning to connect to the internet #define TINY_GSM_USE_GPRS true @@ -210,7 +210,7 @@ void loop() { client.print("Connection: close\r\n\r\n"); client.println(); - unsigned long timeout = millis(); + uint32_t timeout = millis(); while (client.connected() && millis() - timeout < 10000L) { // Print available data while (client.available()) { diff --git a/examples/more/Hologram_Dash/Hologram_Dash.ino b/examples/more/Hologram_Dash/Hologram_Dash.ino index 331fbd1..ae4543a 100644 --- a/examples/more/Hologram_Dash/Hologram_Dash.ino +++ b/examples/more/Hologram_Dash/Hologram_Dash.ino @@ -12,15 +12,15 @@ #define TINY_GSM_MODEM_UBLOX // Increase RX buffer if needed -//#define TINY_GSM_RX_BUFFER 512 +// #define TINY_GSM_RX_BUFFER 512 #include // Uncomment this if you want to see all AT commands -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Uncomment this if you want to use SSL -//#define USE_SSL +// #define USE_SSL // Set serial for debug console (to the Serial Monitor, speed 115200) #define SerialMon Serial @@ -108,7 +108,7 @@ void loop() { client.print(String("Host: ") + server + "\r\n"); client.print("Connection: close\r\n\r\n"); - unsigned long timeout = millis(); + uint32_t timeout = millis(); while (client.connected() && millis() - timeout < 10000L) { // Print available data while (client.available()) { diff --git a/examples/more/Industruino/Industruino.ino b/examples/more/Industruino/Industruino.ino index b51acc6..6b8b48e 100644 --- a/examples/more/Industruino/Industruino.ino +++ b/examples/more/Industruino/Industruino.ino @@ -18,16 +18,16 @@ #define TINY_GSM_MODEM_SIM800 // Increase RX buffer if needed -//#define TINY_GSM_RX_BUFFER 512 +// #define TINY_GSM_RX_BUFFER 512 #include #include // Uncomment this if you want to see all AT commands -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Uncomment this if you want to use SSL -//#define USE_SSL +// #define USE_SSL // Set serial for debug console (to the Serial Monitor, speed 115200) #define SerialMon SerialUSB diff --git a/examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino b/examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino index e2a679d..8aadb3c 100644 --- a/examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino +++ b/examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino @@ -28,7 +28,7 @@ #define SerialAT Serial1 // Uncomment this if you want to see all AT commands -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS #ifdef DUMP_AT_COMMANDS diff --git a/src/TinyGsmClient.h b/src/TinyGsmClient.h index 0b25d28..fd23b11 100644 --- a/src/TinyGsmClient.h +++ b/src/TinyGsmClient.h @@ -6,129 +6,128 @@ * @date Nov 2016 */ -#ifndef TinyGsmClient_h -#define TinyGsmClient_h +#ifndef SRC_TINYGSMCLIENT_h +#define SRC_TINYGSMCLIENT_h #if defined(TINY_GSM_MODEM_SIM800) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmSim800 TinyGsm; - typedef TinyGsmSim800::GsmClient TinyGsmClient; - typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientSIM800.h" +typedef TinyGsmSim800 TinyGsm; +typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient; +typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_SSL - #define TINY_GSM_MODEM_HAS_GPS - #include - typedef TinyGsmSim808 TinyGsm; - typedef TinyGsmSim808::GsmClient TinyGsmClient; - typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_SSL +#define TINY_GSM_MODEM_HAS_GPS +#include "TinyGsmClientSIM808.h" +typedef TinyGsmSim808 TinyGsm; +typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient; +typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SIM900) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmSim800 TinyGsm; - typedef TinyGsmSim800::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientSIM800.h" +typedef TinyGsmSim800 TinyGsm; +typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient; #elif defined(TINY_GSM_MODEM_SIM7000) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_GPS - #include - typedef TinyGsmSim7000 TinyGsm; - typedef TinyGsmSim7000::GsmClient TinyGsmClient; - // typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO! +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_GPS +#include "TinyGsmClientSIM7000.h" +typedef TinyGsmSim7000 TinyGsm; +typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient; +// typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO! #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ - defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmSim5360 TinyGsm; - typedef TinyGsmSim5360::GsmClient TinyGsmClient; + defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientSIM5360.h" +typedef TinyGsmSim5360 TinyGsm; +typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient; #elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \ defined(TINY_GSM_MODEM_SIM7500) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmSim7600 TinyGsm; - typedef TinyGsmSim7600::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientSIM7600.h" +typedef TinyGsmSim7600 TinyGsm; +typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient; #elif defined(TINY_GSM_MODEM_UBLOX) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmUBLOX TinyGsm; - typedef TinyGsmUBLOX::GsmClient TinyGsmClient; - typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientUBLOX.h" +typedef TinyGsmUBLOX TinyGsm; +typedef TinyGsmUBLOX::GsmClientUBLOX TinyGsmClient; +typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SARAR4) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmSaraR4 TinyGsm; - typedef TinyGsmSaraR4::GsmClient TinyGsmClient; - typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientSaraR4.h" +typedef TinyGsmSaraR4 TinyGsm; +typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient; +typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_M95) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmM95 TinyGsm; - typedef TinyGsmM95::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientM95.h" +typedef TinyGsmM95 TinyGsm; +typedef TinyGsmM95::GsmClientM95 TinyGsmClient; #elif defined(TINY_GSM_MODEM_BG96) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmBG96 TinyGsm; - typedef TinyGsmBG96::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientBG96.h" +typedef TinyGsmBG96 TinyGsm; +typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient; #elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmA6 TinyGsm; - typedef TinyGsmA6::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientA6.h" +typedef TinyGsmA6 TinyGsm; +typedef TinyGsmA6::GsmClientA6 TinyGsmClient; #elif defined(TINY_GSM_MODEM_M590) - #define TINY_GSM_MODEM_HAS_GPRS - #include - typedef TinyGsmM590 TinyGsm; - typedef TinyGsmM590::GsmClient TinyGsmClient; +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientM590.h" +typedef TinyGsmM590 TinyGsm; +typedef TinyGsmM590::GsmClientM590 TinyGsmClient; #elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E) - #include - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_GPS - typedef TinyGsmMC60 TinyGsm; - typedef TinyGsmMC60::GsmClient TinyGsmClient; +#include "TinyGsmClientMC60.h" +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_GPS +typedef TinyGsmMC60 TinyGsm; +typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient; #elif defined(TINY_GSM_MODEM_ESP8266) - #define TINY_GSM_MODEM_HAS_WIFI - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmESP8266 TinyGsm; - typedef TinyGsmESP8266::GsmClient TinyGsmClient; - typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_WIFI +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientESP8266.h" +typedef TinyGsmESP8266 TinyGsm; +typedef TinyGsmESP8266::GsmClientESP8266 TinyGsmClient; +typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_XBEE) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_WIFI - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmXBee TinyGsm; - typedef TinyGsmXBee::GsmClient TinyGsmClient; - typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure; +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_WIFI +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientXBee.h" +typedef TinyGsmXBee TinyGsm; +typedef TinyGsmXBee::GsmClientXBee TinyGsmClient; +typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH) - #define TINY_GSM_MODEM_HAS_GPRS - #define TINY_GSM_MODEM_HAS_SSL - #include - typedef TinyGsmSequansMonarch TinyGsm; - typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient; - typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure; - +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_SSL +#include "TinyGsmClientSequansMonarch.h" +typedef TinyGsmSequansMonarch TinyGsm; +typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient; +typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch TinyGsmClientSecure; #else - #error "Please define GSM modem model" +#error "Please define GSM modem model" #endif #endif diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 14dc15a..fc89369 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -6,31 +6,23 @@ * @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 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,112 +31,101 @@ enum RegStatus { REG_UNKNOWN = 4, }; - class TinyGsmA6 -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmA6; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} - - GsmClient(TinyGsmA6& modem) { - init(&modem); - } + : public TinyGsmModem { + friend class TinyGsmModem; - 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) { + 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) { + 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; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -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; + // Doesn't support SSL -private: - TinyGsmA6* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; -}; - - -public: - - TinyGsmA6(Stream& stream) - : stream(stream) - { + /* + * Constructor + */ + public: + explicit TinyGsmA6(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } // sendAT(GF("&FZ")); // Factory + Reset // waitResponse(); sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -152,7 +133,8 @@ public: sendAT(GF("+CMEE=0")); // turn off error codes #endif 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(); DBG(GF("### Modem:"), getModemName()); @@ -162,272 +144,184 @@ public: if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { simUnlock(pin); 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); } } - 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 waitResponse(); - sendAT(GF("&W")); // Write configuration + sendAT(GF("&W")); // Write configuration return waitResponse() == 1; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { + bool thisHasSSL() { return false; } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+RST=1")); delay(3000); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPOF")); + // +CPOF: MS OFF OK return waitResponse() == 1; } - bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - - String getSimCCID() { + protected: + String getSimCCIDImpl() { sendAT(GF("+CCID")); - if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { - return ""; - } + 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; - } - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); 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, '"'); waitResponse(); if (!user) user = ""; - if (!pwd) pwd = ""; + if (!pwd) pwd = ""; 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")); waitResponse(60000L); sendAT(GF("+CIPMUX=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { // Shut the TCP/IP connection 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")); - if (waitResponse(5000L) == 1) - return true; + if (waitResponse(5000L) == 1) { return true; } } 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(); - return (res == 1); + return res; } /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+CIFSR")); String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * 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 - bool callNumber(const String& number) { + bool callNumberImpl(const String& number) { if (number == GF("last")) { sendAT(GF("DLST")); } else { 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; } - int rsp = waitResponse(60000L, - GF(GSM_NL "+CIEV: \"SOUNDER\",0"), - GF(GSM_NL "+CIEV: \"CALL\",0")); + int 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)); + int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), + GF(GSM_NL "NO ANSWER" GSM_NL)); return rsp == 1 && rsp2 == 0; } - bool callHangup() { - sendAT(GF("H")); - return waitResponse() == 1; - } - // 0-9,*,#,A,B,C,D - bool dtmfSend(char cmd, unsigned duration_ms = 100) { + bool dtmfSendImpl(char cmd, unsigned duration_ms = 100) { duration_ms = constrain(duration_ms, 100, 1000); // 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); if (waitResponse(10000L) == 1) { @@ -440,7 +334,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Audio functions */ - + public: bool audioSetHeadphones() { sendAT(GF("+SNFS=0")); return waitResponse() == 1; @@ -459,19 +353,15 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Messaging functions */ - - String sendUSSD(const String& code) { + protected: + String sendUSSDImpl(const String& code) { sendAT(GF("+CMGF=1")); waitResponse(); sendAT(GF("+CSCS=\"HEX\"")); waitResponse(); sendAT(GF("+CUSD=1,\""), code, GF("\",15")); - if (waitResponse(10000L) != 1) { - return ""; - } - if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } + if (waitResponse(10000L) != 1) { return ""; } + if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; } stream.readStringUntil('"'); String hex = stream.readStringUntil('"'); stream.readStringUntil(','); @@ -486,38 +376,35 @@ 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 */ + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * GPS location functions + */ + public: + // No functions of this type supported /* - * Battery & temperature functions + * Time functions */ + protected: + // Can follow the standard CCLK function in the template + // Note - the clock probably has to be set manaually first - uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Battery & temperature functions + */ + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - int8_t getBattPercent() { + int8_t getBattPercentImpl() { 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 int res = stream.readStringUntil('\n').toInt(); // Wait for final OK @@ -525,57 +412,37 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return res; } - uint8_t getBattChargeState() { + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - // Read battery charge status - int res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil('\n').toInt(); - milliVolts = 0; + percent = stream.readStringUntil('\n').toInt(); + milliVolts = 0; // Wait for final OK waitResponse(); return true; } - - float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * 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; - } + 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; } int newMux = stream.readStringUntil('\n').toInt(); - int rsp = waitResponse((timeout_ms- (millis() - startMillis)), - GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), + 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; - } + if (waitResponse() != 1) { return false; } *mux = newMux; return (1 == rsp); @@ -583,37 +450,38 @@ protected: int16_t modemSend(const void* buff, size_t len, uint8_t mux) { 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(buff), len); 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; } + size_t modemRead(size_t, uint8_t) { + return 0; + } + size_t modemGetAvailable(uint8_t) { + return 0; + } + 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? + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), + GF(",\"CLOSING\""), GF(",\"INITIAL\"")); waitResponse(); 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -621,15 +489,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -646,19 +514,19 @@ TINY_GSM_MODEM_STREAM_UTILITIES() index = 5; goto finish; } else if (data.endsWith(GF("+CIPRCV:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(',').toInt(); + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(',').toInt(); int len_orig = len; if (len > sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); } else { 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 = ""; } else if (data.endsWith(GF("+TCPCLOSED:"))) { @@ -671,38 +539,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { 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_ diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index cd738d7..dad31cb 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -6,31 +6,23 @@ * @date Apr 2018 */ -#ifndef TinyGsmClientBG96_h -#define TinyGsmClientBG96_h -//#pragma message("TinyGSM: TinyGsmClientBG96") +#ifndef SRC_TINYGSMCLIENTBG96_H_ +#define SRC_TINYGSMCLIENTBG96_H_ +// #pragma message("TinyGSM: TinyGsmClientBG96") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 12 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,474 +31,303 @@ enum RegStatus { REG_UNKNOWN = 4, }; +class TinyGsmBG96 + : public TinyGsmModem { + friend class TinyGsmModem; -class TinyGsmBG96: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmBG96; - typedef TinyGsmFifo RxFifo; + /* + * Inner Client + */ + public: + class GsmClientBG96 : public GsmClient { + friend class TinyGsmBG96; -public: - GsmClient() {} + public: + GsmClientBG96() {} - GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) { - init(&modem, mux); - } + explicit GsmClientBG96(TinyGsmBG96& modem, uint8_t mux = 1) { + init(&modem, mux); + } - virtual ~GsmClient(){} + bool init(TinyGsmBG96* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - bool init(TinyGsmBG96* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + at->sockets[mux] = this; - at->sockets[mux] = this; + return true; + } - return true; - } + public: + virtual int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+QICLOSE="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + /* + * Extended API + */ - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+QICLOSE="), mux); - sock_connected = false; - at->waitResponse(); - } + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; - virtual void stop() { stop(15000L); } + /* + * Inner Secure Client + */ -TINY_GSM_CLIENT_WRITE() + /* + class GsmClientSecureBG96 : public GsmClientBG96 + { + public: + GsmClientSecure() {} -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1) + : public GsmClient(modem, mux) + {} -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + public: + virtual int connect(const char *host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; + */ /* - * Extended API + * Constructor */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmBG96* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -// class GsmClientSecure : public GsmClient -// { -// public: -// GsmClientSecure() {} -// -// GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1) -// : GsmClient(modem, mux) -// {} -// -// virtual ~GsmClientSecure(){} -// -// public: -// virtual int connect(const char *host, uint16_t port, int timeout_s) { -// stop(); -// TINY_GSM_YIELD(); -// rx.clear(); -// sock_connected = at->modemConnect(host, port, mux, true, timeout_s); -// return sock_connected; -// } -// }; - - -public: - - TinyGsmBG96(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmBG96(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } - - // sendAT(GF("&FZ")); // Factory + Reset - // waitResponse(); + if (!testAT()) { return false; } sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable automatic time zone update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - return "Quectel BG96"; - } - -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { - sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - waitResponse(); - sendAT(GF("+IPR=0")); // Auto-baud - waitResponse(); - sendAT(GF("&W")); // Write configuration - return waitResponse() == 1; - } - -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { - return false; // TODO: For now + bool thisHasSSL() { + return false; // TODO(?): Add SSL support } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=1,1")); - if (waitResponse(60000L, GF("POWERED DOWN")) != 1) { - return false; - } + if (waitResponse(60000L, GF("POWERED DOWN")) != 1) { return false; } waitResponse(5000L, GF("RDY")); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+QPOWD=1")); waitResponse(300); // returns OK first return waitResponse(300, GF("POWERED DOWN")) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; + // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN + // is pulled up, the module can directly enter into sleep mode.If entering + // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled + // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first, + // and then the module can enter into sleep mode. + bool sleepEnableImpl(bool enable = true) { + sendAT(GF("+QSCLK="), enable); + return waitResponse() == 1; } /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - - String getSimCCID() { + protected: + String getSimCCIDImpl() { sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+QCCID:")) != 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"), GF("NOT INSERTED")); - 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) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); - //Configure the TCPIP Context - sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse() != 1) { - return false; - } + // Configure the TCPIP Context + sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, + GF("\"")); + if (waitResponse() != 1) { return false; } - //Activate GPRS/CSD Context + // Activate GPRS/CSD Context sendAT(GF("+QIACT=1")); - if (waitResponse(150000L) != 1) { - return false; - } + if (waitResponse(150000L) != 1) { return false; } - //Attach to Packet Domain service - is this necessary? + // Attach to Packet Domain service - is this necessary? sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { sendAT(GF("+QIDEACT=1")); // Deactivate the bearer context - if (waitResponse(40000L) != 1) - return false; + if (waitResponse(40000L) != 1) { return false; } return true; } - TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() - /* * IP Address functions */ - - String getLocalIP() { - sendAT(GF("+CGPADDR=1")); - if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) { - return ""; - } - streamSkipUntil(','); // Skip context id - String res = stream.readStringUntil('\n'); - if (waitResponse() != 1) { - return ""; - } - return res; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + protected: + // Can follow all of the IP functions from the template /* * Phone Call functions */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() { - sendAT(GF("A")); - return waitResponse() == 1; - } - - // Returns true on pick-up, false on error/busy - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callHangup() { - sendAT(GF("H")); - return waitResponse() == 1; - } - - // 0-9,*,#,A,B,C,D - bool dtmfSend(char cmd, int duration_ms = 100) { // TODO: check - duration_ms = constrain(duration_ms, 100, 1000); - - sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second - waitResponse(); - - sendAT(GF("+VTS="), cmd); - return waitResponse(10000L) == 1; - } + protected: + // Can follow all of the phone call functions from the template /* * Messaging functions */ - - String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } - + protected: + // Follows all messaging functions per template /* * Location functions */ - - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* - * Battery & temperature functions + * GPS location functions */ + public: + // No functions of this type supported - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); - milliVolts = stream.readStringUntil('\n').toInt(); - // Wait for final OK - waitResponse(); - return true; - } + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template - float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Battery & temperature functions + */ + protected: + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * Client related functions */ + protected: + bool modemConnect(const char* host, uint16_t port, uint8_t mux, + bool ssl = false, int timeout_s = 20) { + if (ssl) { DBG("SSL not yet supported on this module!"); } + int rsp; + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + + // (1-16), (0-11), + // "TCP/UDP/TCP LISTENER/UDPSERVICE", "/", + // ,,(0-2; 0=buffer) + sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host, + GF("\","), port, GF(",0,0")); + waitResponse(); -protected: - - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 20) { - if (ssl) { - DBG("SSL not yet supported on this module!"); - } - int rsp; - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - - // (1-16), (0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE", - // "/",,,(0-2 0=buffer) - sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0")); - rsp = waitResponse(); - - if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { - return false; - } + if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; } - if (stream.readStringUntil(',').toInt() != mux) { - return false; - } + if (stream.readStringUntil(',').toInt() != mux) { return false; } // Read status rsp = stream.readStringUntil('\n').toInt(); @@ -515,28 +336,20 @@ protected: int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { - return 0; - } - // TODO: Wait for ACK? AT+QISEND=id,0 + if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } + // TODO(?): Wait for ACK? AT+QISEND=id,0 return len; } size_t modemRead(size_t size, uint8_t mux) { sendAT(GF("+QIRD="), mux, ',', (uint16_t)size); - if (waitResponse(GF("+QIRD:")) != 1) { - return 0; - } + if (waitResponse(GF("+QIRD:")) != 1) { return 0; } int len = stream.readStringUntil('\n').toInt(); - for (int i=0; isock_available = modemGetAvailable(mux); @@ -547,33 +360,28 @@ protected: sendAT(GF("+QIRD="), mux, GF(",0")); size_t result = 0; if (waitResponse(GF("+QIRD:")) == 1) { - streamSkipUntil(','); // Skip total received - streamSkipUntil(','); // Skip have read + streamSkipUntil(','); // Skip total received + streamSkipUntil(','); // Skip have read result = stream.readStringUntil('\n').toInt(); - if (result) { - DBG("### DATA AVAILABLE:", result, "on", mux); - } + if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); } waitResponse(); } - if (!result) { - sockets[mux]->sock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } return result; } bool modemGetConnected(uint8_t mux) { sendAT(GF("+QISTATE=1,"), mux); - //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" + // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" - if (waitResponse(GF("+QISTATE:")) != 1) - return false; + if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = stream.readStringUntil(',').toInt(); // socket state waitResponse(); @@ -581,19 +389,16 @@ protected: return 2 == 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -601,15 +406,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -648,38 +453,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientBG96* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTBG96_H_ diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 3ea8e98..aac5e98 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -6,24 +6,21 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientESP8266_h -#define TinyGsmClientESP8266_h -//#pragma message("TinyGSM: TinyGsmClientESP8266") +#ifndef SRC_TINYGSMCLIENTESP8266_H_ +#define SRC_TINYGSMCLIENTESP8266_H_ +// #pragma message("TinyGSM: TinyGsmClientESP8266") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 512 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 5 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; -static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; +static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; // status of ESP8266 station interface // 2 : ESP8266 station connected to an AP and has obtained IP @@ -38,214 +35,187 @@ enum RegStatus { REG_UNKNOWN = 6, }; - class TinyGsmESP8266 -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmESP8266; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} - - GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) { - init(&modem, mux); - } + : public TinyGsmModem { + friend class TinyGsmModem; - virtual ~GsmClient(){} - - bool init(TinyGsmESP8266* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_connected = false; + /* + * Inner Client + */ + public: + class GsmClientESP8266 : public GsmClient { + friend class TinyGsmESP8266; - at->sockets[mux] = this; + public: + GsmClientESP8266() {} - return true; - } - -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) { + init(&modem, mux); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + bool init(TinyGsmESP8266* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_connected = false; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_YIELD(); - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(maxWaitMs); - rx.clear(); - } + at->sockets[mux] = this; - virtual void stop() { stop(5000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -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(5000L); + } -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 */ + public: + class GsmClientSecureESP8266 : public GsmClientESP8266 { + public: + GsmClientSecureESP8266() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) + : GsmClientESP8266(modem, mux) {} -private: - TinyGsmESP8266* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; -}; - - -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} - - virtual ~GsmClientSecure() {} - -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } -}; - - -public: + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; - TinyGsmESP8266(Stream& stream) - : stream(stream) - { + /* + * Constructor + */ + public: + explicit TinyGsmESP8266(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + + if (!testAT()) { return false; } if (pin && strlen(pin) > 0) { DBG("ESP8266 modules do not use an unlock pin!"); } - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } DBG(GF("### Modem:"), getModemName()); return true; } - String getModemName() { + String getModemNameImpl() { return "ESP8266"; } - void setBaud(unsigned long baud) { + void setBaudImpl(uint32_t baud) { sendAT(GF("+UART_CUR="), baud, "8,1,0,0"); } -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_LISTEN() - - bool factoryDefault() { + bool factoryDefaultImpl() { sendAT(GF("+RESTORE")); return waitResponse() == 1; } - String getModemInfo() { + String getModemInfoImpl() { sendAT(GF("+GMR")); String res; - if (waitResponse(1000L, res) != 1) { - return ""; - } + if (waitResponse(1000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, " "); res.trim(); return res; } - bool hasSSL() { + bool thisHasSSL() { return true; } - bool hasWifi() { + bool thisHasWifi() { return true; } - bool hasGPRS() { + bool thisHasGPRS() { return false; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+RST")); - if (waitResponse(10000L) != 1) { - return false; - } - if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } + if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; } delay(500); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset! return waitResponse() == 1; } - bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; /* * SIM card functions */ + protected: + // SIM card functions don't apply + /* + * Generic network functions + */ + public: RegStatus getRegistrationStatus() { sendAT(GF("+CIPSTATUS")); if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN; @@ -255,52 +225,44 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() return (RegStatus)status; } - /* - * Generic network functions - */ - - int16_t getSignalQuality() { + protected: + int16_t getSignalQualityImpl() { sendAT(GF("+CWJAP_CUR?")); int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); if (res1 != 2) { waitResponse(); return 0; } - streamSkipUntil(','); // Skip SSID - streamSkipUntil(','); // Skip BSSID/MAC address - streamSkipUntil(','); // Skip Chanel number + streamSkipUntil(','); // Skip SSID + streamSkipUntil(','); // Skip BSSID/MAC address + streamSkipUntil(','); // Skip Chanel number int res2 = stream.parseInt(); // Read RSSI - waitResponse(); // Returns an OK after the value + waitResponse(); // Returns an OK after the value return res2; } - bool isNetworkConnected() { + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); if (s == REG_OK_IP || s == REG_OK_TCP) { // with these, we're definitely connected return true; - } - else if (s == REG_OK_NO_TCP) { + } else if (s == REG_OK_NO_TCP) { // with this, we may or may not be connected if (getLocalIP() == "") { return false; - } - else { + } else { return true; } - } - else { + } else { return false; } } - TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * WiFi functions */ - - bool networkConnect(const char* ssid, const char* pwd) { + protected: + bool networkConnectImpl(const char* ssid, const char* pwd) { sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\"")); if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) { return false; @@ -309,7 +271,7 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() return true; } - bool networkDisconnect() { + bool networkDisconnectImpl() { sendAT(GF("+CWQAP")); bool retVal = waitResponse(10000L) == 1; waitResponse(GF("WIFI DISCONNECT")); @@ -319,74 +281,107 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() /* * IP Address functions */ - - String getLocalIP() { - sendAT(GF("+CIPSTA_CUR??")); + protected: + String getLocalIPImpl() { + sendAT(GF("+CIPSTA_CUR?")); int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); - if (res1 != 2) { - return ""; - } + if (res1 != 2) { return ""; } String res2 = stream.readStringUntil('"'); waitResponse(); return res2; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + /* + * Phone Call functions + */ + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; + bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; /* - * Battery & temperature functions + * Messaging functions */ + protected: + String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE; + bool sendSMSImpl(const String& number, + const String& text) TINY_GSM_ATTR_NOT_AVAILABLE; + bool sendSMS_UTF16Impl(const char* const number, const void* text, + size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; - // 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() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Location functions + */ + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* - * Client related functions + * GPS location functions */ + public: + // No functions of this type supported -protected: + /* + * Time functions + */ + protected: + String + getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Battery & temperature functions + */ + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Client related functions + */ + protected: bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) - { - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; + bool ssl = false, int timeout_s = 75) { + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; if (ssl) { sendAT(GF("+CIPSSLSIZE=4096")); waitResponse(); } sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), - GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE); - // TODO: Check mux - int rsp = waitResponse(timeout_ms, - GFP(GSM_OK), - GFP(GSM_ERROR), + GF("\",\""), host, GF("\","), port, GF(","), + TINY_GSM_TCP_KEEP_ALIVE); + // TODO(?): Check mux + int rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR), GF("ALREADY CONNECT")); - // if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT" + // if (rsp == 3) waitResponse(); + // May return "ERROR" after the "ALREADY CONNECT" return (1 == rsp); } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { - return 0; - } + if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; } return len; } + size_t modemRead(size_t, uint8_t) { + return 0; + } + size_t modemGetAvailable(uint8_t) { + return 0; + } + bool modemGetConnected(uint8_t mux) { sendAT(GF("+CIPSTATUS")); - if (waitResponse(3000, GF("STATUS:")) != 1) return false; + if (waitResponse(3000, GF("STATUS:")) != 1) { return false; } int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); if (status != 3) { @@ -399,14 +394,15 @@ protected: } bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0}; for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { - uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); + uint8_t has_status = + waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); if (has_status == 1) { int returned_mux = stream.readStringUntil(',').toInt(); - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip type - streamSkipUntil(','); // Skip remote IP - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip type + streamSkipUntil(','); // Skip remote IP + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port streamSkipUntil('\n'); // Skip client/server type verified_connections[returned_mux] = 1; } @@ -418,19 +414,16 @@ protected: return verified_connections[mux]; } -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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -438,15 +431,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -463,25 +456,27 @@ TINY_GSM_MODEM_STREAM_UTILITIES() index = 5; goto finish; } else if (data.endsWith(GF("+IPD,"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(':').toInt(); + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(':').toInt(); int len_orig = len; if (len > sockets[mux]->rx.free()) { - DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available"); + DBG("### Buffer overflow: ", len, "received vs", + sockets[mux]->rx.free(), "available"); } else { DBG("### Got Data: ", len, "on", mux); } - 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(SRGDamia1): deal with buffer overflow/missed characters + if (len_orig > sockets[mux]->available()) { + DBG("### Fewer characters received than expected: ", + sockets[mux]->available(), " vs ", len_orig); } data = ""; } else if (data.endsWith(GF("CLOSED"))) { - int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8)); + int muxStart = + TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8)); int coma = data.indexOf(',', muxStart); - int mux = data.substring(muxStart, coma).toInt(); + int mux = data.substring(muxStart, coma).toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } @@ -490,38 +485,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTESP8266_H_ diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index ba6851c..3cc3edd 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -6,31 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientM590_h -#define TinyGsmClientM590_h -//#pragma message("TinyGSM: TinyGsmClientM590") +#ifndef SRC_TINYGSMCLIENTM590_H_ +#define SRC_TINYGSMCLIENTM590_H_ +// #pragma message("TinyGSM: TinyGsmClientM590") -//#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 2 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 3, REG_DENIED = 2, @@ -39,110 +31,89 @@ enum RegStatus { REG_UNKNOWN = 4, }; - class TinyGsmM590 -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmM590; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} + : public TinyGsmModem { + friend class TinyGsmModem; - GsmClient(TinyGsmM590& modem, uint8_t mux = 1) { - init(&modem, mux); - } - - virtual ~GsmClient(){} - - bool init(TinyGsmM590* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_connected = false; - - at->sockets[mux] = this; - - return true; - } + /* + * Inner Client + */ + public: + class GsmClientM590 : public GsmClient { + friend class TinyGsmM590; -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, timeout_s); + public: + GsmClientM590() {} - return sock_connected; - } + explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 1) { + init(&modem, mux); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + bool init(TinyGsmM590* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_connected = false; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_YIELD(); - at->sendAT(GF("+TCPCLOSE="), mux); - sock_connected = false; - at->waitResponse(maxWaitMs); - rx.clear(); - } + at->sockets[mux] = this; - 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(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() + void stop(uint32_t maxWaitMs) { + TINY_GSM_YIELD(); + at->sendAT(GF("+TCPCLOSE="), 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 + * Constructor */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmM590* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; -}; - - -public: - - TinyGsmM590(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmM590(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } - - // sendAT(GF("&FZ")); // Factory + Reset - // waitResponse(); + if (!testAT()) { return false; } sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -158,76 +129,63 @@ public: if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { simUnlock(pin); 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); } } - String getModemName() { + // Doesn't support CGMI + String getModemNameImpl() { return "Neoway M590"; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_LISTEN() - - bool factoryDefault() { + // Extra stuff here - pwr save, internal stack + bool factoryDefaultImpl() { sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write waitResponse(); - sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop + sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop waitResponse(); - sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save + sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save waitResponse(); sendAT(GF("+XISP=0")); // Use internal stack waitResponse(); - sendAT(GF("&W")); // Write configuration + sendAT(GF("&W")); // Write configuration return waitResponse() == 1; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { + bool thisHasSSL() { return false; } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=15")); - if (waitResponse(10000L) != 1) { - return false; - } - //MODEM:STARTUP + if (waitResponse(10000L) != 1) { return false; } + // MODEM:STARTUP waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL)); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPWROFF")); return waitResponse(3000L) == 1; } - bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sleepEnable(bool enable = true) { + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+ENPWRSAVE="), enable); return waitResponse() == 1; } @@ -235,54 +193,29 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - -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) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() + protected: + // Able to follow all SIM card functions as inherited from the template /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); sendAT(GF("+XISP=0")); @@ -292,44 +225,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(); if (!user) user = ""; - if (!pwd) pwd = ""; + if (!pwd) pwd = ""; sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\"")); waitResponse(); sendAT(GF("+XIIC=1")); waitResponse(); - const unsigned long timeout_ms = 60000L; - for (unsigned long start = millis(); millis() - start < timeout_ms; ) { + const uint32_t timeout_ms = 60000L; + for (uint32_t start = millis(); millis() - start < timeout_ms;) { if (isGprsConnected()) { - //goto set_dns; // TODO + // goto set_dns; // TODO return true; } delay(500); } return false; -// set_dns: // TODO -// sendAT(GF("+DNSSERVER=1,8.8.8.8")); -// waitResponse(); -// -// sendAT(GF("+DNSSERVER=2,8.8.4.4")); -// waitResponse(); + // set_dns: // TODO + // sendAT(GF("+DNSSERVER=1,8.8.8.8")); + // waitResponse(); + // + // sendAT(GF("+DNSSERVER=2,8.8.4.4")); + // waitResponse(); return true; } - bool gprsDisconnect() { - // TODO: There is no command in AT command set + bool gprsDisconnectImpl() { + // TODO(?): There is no command in AT command set // XIIC=0 does not work return true; } - bool isGprsConnected() { + bool isGprsConnectedImpl() { sendAT(GF("+XIIC?")); - if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; } int res = stream.readStringUntil(',').toInt(); waitResponse(); return res == 1; @@ -338,12 +269,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+XIIC?")); - if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; } stream.readStringUntil(','); String res = stream.readStringUntil('\n'); waitResponse(); @@ -351,103 +280,64 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; + bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; /* * Messaging functions */ - - String sendUSSD(const String& code) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("D"), code); - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (waitResponse() != 1) { - return ""; - } - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CSCS=\"GSM\"")); - waitResponse(); - 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; - } - - bool sendSMS_UTF16(const String& number, const void* text, size_t len) - TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + bool sendSMS_UTF16Impl(const String& number, const void* text, + size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; /* * Location functions */ + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * GPS location functions + */ + public: + // No functions of this type available + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - - 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() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * Client related functions */ - -protected: - - bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) { - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; - for (int i=0; i<3; i++) { // TODO: no need for loop? + protected: + bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool, + int timeout_s = 75) { + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + for (int i = 0; i < 3; i++) { // TODO(?): no need for loop? String ip = dnsIpQuery(host); sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port); - int rsp = waitResponse(timeout_ms, - GF(",OK" GSM_NL), - GF(",FAIL" GSM_NL), - GF("+TCPSETUP:Error" GSM_NL)); + int rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL), GF(",FAIL" GSM_NL), + GF("+TCPSETUP:Error" GSM_NL)); if (1 == rsp) { return true; } else if (3 == rsp) { @@ -461,50 +351,49 @@ protected: int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); - stream.write((char)0x0D); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); + stream.write(static_cast(0x0D)); stream.flush(); - if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { - return 0; - } + if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; } stream.readStringUntil('\n'); return len; } + size_t modemRead(size_t, uint8_t) { + return 0; + } + size_t modemGetAvailable(uint8_t) { + return 0; + } + bool modemGetConnected(uint8_t mux) { sendAT(GF("+CIPSTATUS="), mux); - int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), + GF(",\"CLOSING\""), GF(",\"INITIAL\"")); waitResponse(); return 1 == res; } String dnsIpQuery(const char* host) { sendAT(GF("+DNS=\""), host, GF("\"")); - if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { - return ""; - } + if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(GF("+DNS:OK" GSM_NL)); res.trim(); return 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -512,15 +401,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -537,19 +426,19 @@ TINY_GSM_MODEM_STREAM_UTILITIES() index = 5; goto finish; } else if (data.endsWith(GF("+TCPRECV:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(',').toInt(); + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(',').toInt(); int len_orig = len; if (len > sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); } else { 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(?): Handle lost characters + if (len_orig > sockets[mux]->available()) { + DBG("### Fewer characters received than expected: ", + sockets[mux]->available(), " vs ", len_orig); } data = ""; } else if (data.endsWith(GF("+TCPCLOSE:"))) { @@ -563,38 +452,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientM590* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTM590_H_ diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 752d8e2..d983775 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -2,35 +2,28 @@ * @file TinyGsmClientM95.h * @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd. * @license LGPL-3.0 - * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. + * * @date Nov 2016 */ -#ifndef TinyGsmClientM95_h -#define TinyGsmClientM95_h -//#pragma message("TinyGSM: TinyGsmClientM95") +#ifndef SRC_TINYGSMCLIENTM95_H_ +#define SRC_TINYGSMCLIENTM95_H_ +// #pragma message("TinyGSM: TinyGsmClientM95") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 6 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,132 +32,120 @@ enum RegStatus { REG_UNKNOWN = 4, }; +class TinyGsmM95 + : public TinyGsmModem { + friend class TinyGsmModem; -class TinyGsmM95: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmM95; - typedef TinyGsmFifo RxFifo; + /* + * Inner Client + */ + public: + class GsmClientM95 : public GsmClient { + friend class TinyGsmM95; -public: - GsmClient() {} + public: + GsmClientM95() {} - GsmClient(TinyGsmM95& modem, uint8_t mux = 1) { - init(&modem, mux); - } + explicit GsmClientM95(TinyGsmM95& modem, uint8_t mux = 1) { + init(&modem, mux); + } - virtual ~GsmClient(){} + bool init(TinyGsmM95* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + sock_connected = false; - bool init(TinyGsmM95* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - sock_connected = false; + at->sockets[mux] = this; - at->sockets[mux] = this; + return true; + } - return true; - } + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + void stop(uint32_t maxWaitMs) { + uint32_t startMillis = millis(); + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+QICLOSE="), mux); + sock_connected = false; + at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), + GF("CLOSE OK"), GF("ERROR")); + } + void stop() override { + stop(75000L); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + /* + * Extended API + */ - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+QICLOSE="), mux); - sock_connected = false; - at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR")); - } + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; - virtual void stop() { stop(75000L); } + /* + * Inner Secure Client + */ -TINY_GSM_CLIENT_WRITE() + /* + class GsmClientSecureM95 : public GsmClientM95 + { + public: + GsmClientSecure() {} -TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() + GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} -TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + public: + virtual int connect(const char *host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; + */ /* - * Extended API + * Constructor */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmM95* at; - uint8_t mux; - uint16_t sock_available; - bool sock_connected; - RxFifo rx; -}; - - -// class GsmClientSecure : public GsmClient -// { -// public: -// GsmClientSecure() {} -// -// GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1) -// : GsmClient(modem, mux) -// {} -// -// virtual ~GsmClientSecure() {} -// -// public: -// virtual int connect(const char *host, uint16_t port, int timeout_s) { -// stop(); -// TINY_GSM_YIELD(); -// rx.clear(); -// sock_connected = at->modemConnect(host, port, mux, true, timeout_s); -// return sock_connected; -// } -// }; - - -public: - - TinyGsmM95(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmM95(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } // sendAT(GF("&FZ")); // Factory + Reset // waitResponse(); sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -175,62 +156,43 @@ public: DBG(GF("### Modem:"), getModemName()); + // Enable network time synchronization + sendAT(GF("+QNITZ=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - return "Quectel M95"; + bool thisHasSSL() { + return false; // TODO(?): Add SSL support } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_LISTEN() - - bool factoryDefault() { - sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - waitResponse(); - sendAT(GF("+IPR=0")); // Auto-baud - waitResponse(); - sendAT(GF("&W")); // Write configuration - return waitResponse() == 1; - } - -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { - return false; // TODO: For now - } - - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=0")); - if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) { + if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == + 3) { return false; } sendAT(GF("+CFUN=1")); @@ -240,77 +202,51 @@ TINY_GSM_MODEM_GET_INFO_ATI() return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+QPOWD=1")); return waitResponse(300, GF("NORMAL POWER DOWN")) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; + // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN + // is pulled up, the module can directly enter into sleep mode.If entering + // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled + // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first, + // and then the module can enter into sleep mode. + bool sleepEnableImpl(bool enable = true) { + sendAT(GF("+QSCLK="), enable); + return waitResponse() == 1; } - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; - /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - - String getSimCCID() { + protected: + String getSimCCIDImpl() { sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+QCCID:")) != 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) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - void setHostFormat( bool useDottedQuad ) { - if ( useDottedQuad ) { + public: + void setHostFormat(bool useDottedQuad) { + if (useDottedQuad) { sendAT(GF("+QIDNSIP=0")); } else { sendAT(GF("+QIDNSIP=1")); @@ -318,63 +254,47 @@ TINY_GSM_MODEM_GET_CSQ() waitResponse(); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); // select foreground context 0 = VIRTUAL_UART_1 sendAT(GF("+QIFGCNT=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } - //Select GPRS (=1) as the Bearer - sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse() != 1) { - return false; - } + // Select GPRS (=1) as the Bearer + sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, + GF("\"")); + if (waitResponse() != 1) { return false; } // Select TCP/IP transfer mode - NOT transparent mode sendAT(GF("+QIMODE=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Enable multiple TCP/IP connections sendAT(GF("+QIMUX=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } - //Start TCPIP Task and Set APN, User Name and Password - sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" ); - if (waitResponse() != 1) { - return false; - } + // Start TCPIP Task and Set APN, User Name and Password + sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\""); + if (waitResponse() != 1) { return false; } - //Activate GPRS/CSD Context + // Activate GPRS/CSD Context sendAT(GF("+QIACT")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Check that we have a local IP address - if (localIP() == IPAddress(0,0,0,0)) { - return false; - } + if (localIP() == IPAddress(0, 0, 0, 0)) { return false; } // Set Method to Handle Received TCP/IP Data // Mode = 1 - Output a notification when data is received // “+QIRDI: ,,” sendAT(GF("+QINDI=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // // Request an IP header for received data // // "IPD(data length):" @@ -390,7 +310,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // return false; // } // - // // Do NOT show the protocol type at the end of the header for received data + // // Do NOT show the protocol type at the end of the header for received + // data // // IPD(data length)(TCP/UDP): // sendAT(GF("+QISHOWPT=0")); // if (waitResponse() != 1) { @@ -407,18 +328,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return true; } - bool gprsDisconnect() { - sendAT(GF("+QIDEACT")); + bool gprsDisconnectImpl() { + sendAT(GF("+QIDEACT")); // Deactivate the bearer context return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1; } -TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() - /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+QILOCIP")); stream.readStringUntil('\n'); String res = stream.readStringUntil('\n'); @@ -426,147 +345,59 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + /* + * Phone Call functions + */ + protected: + // Can follow all of the phone call functions from the template /* * Messaging functions */ + protected: + // Can follow all template functions - String sendUSSD(const String& code) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (waitResponse() != 1) { - return ""; - } - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } - + public: /** Delete all SMS */ bool deleteAllSMS() { sendAT(GF("+QMGDA=6")); - if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) { + if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) { return true; } return false; } /* - * Phone Call functions + * Location functions */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE; - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; - bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* - * Location functions + * GPS location functions */ + public: + // No functions of this type supported - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); - milliVolts = stream.readStringUntil('\n').toInt(); - // Wait for final OK - waitResponse(); - return true; - } - - float getTemperature() { + protected: + float getTemperatureImpl() { sendAT(GF("+QTEMP")); if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) { - return (float)-9999; + return static_cast(-9999); } - streamSkipUntil(','); // Skip mode + streamSkipUntil(','); // Skip mode // Read charge of thermistor // milliVolts = stream.readStringUntil(',').toInt(); - streamSkipUntil(','); // Skip thermistor charge + streamSkipUntil(','); // Skip thermistor charge float temp = stream.readStringUntil('\n').toFloat(); // Wait for final OK waitResponse(); @@ -576,33 +407,25 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() /* * Client related functions */ - -protected: - - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) { - if (ssl) { - DBG("SSL not yet supported on this module!"); - } - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); - int rsp = waitResponse(timeout_ms, - GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), - GF("ALREADY CONNECT" GSM_NL)); - return (1 == rsp); + protected: + bool modemConnect(const char* host, uint16_t port, uint8_t mux, + bool ssl = false, int timeout_s = 75) { + if (ssl) { DBG("SSL not yet supported on this module!"); } + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, + GF("\","), port); + int rsp = + waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); + return (1 == rsp); } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } // bool allAcknowledged = false; // // bool failed = false; @@ -621,11 +444,11 @@ protected: // } // waitResponse(5000L); - return len; // TODO + return len; // TODO(?): get len/ack properly } size_t modemRead(size_t size, uint8_t mux) { - // TODO: Does this work???? + // TODO(?): Does this work???? // AT+QIRD=,,, // id = GPRS context number = 0, set in GPRS connect // sc = role in connection = 1, client of connection @@ -641,40 +464,43 @@ protected: streamSkipUntil(','); // skip connection type (TCP/UDP) // read the real length of the retrieved data uint16_t len = stream.readStringUntil('\n').toInt(); - // We have no way of knowing in advance how much data will be in the buffer - // so when data is received we always assume the buffer is completely full. - // Chances are, this is not true and there's really not that much there. - // In that case, make sure we make sure we re-set the amount of data available. - if (len < size) { - sockets[mux]->sock_available = len; - } - for (uint16_t i=0; isock_available = len; } + for (uint16_t i = 0; i < len; i++) { + moveCharFromStreamToFifo(mux); sockets[mux]->sock_available--; - // ^^ One less character available after moving from modem's FIFO to our FIFO + // ^^ One less character available after moving from modem's FIFO to our + // FIFO } waitResponse(); // ends with an OK DBG("### READ:", len, "from", mux); return len; } else { - sockets[mux]->sock_available = 0; - return 0; + sockets[mux]->sock_available = 0; + return 0; } } + size_t modemGetAvailable(uint8_t) { + return 0; + } + bool modemGetConnected(uint8_t mux) { sendAT(GF("+QISTATE=1,"), mux); - //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" + // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" - if (waitResponse(GF("+QISTATE:"))) - return false; + if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = stream.readStringUntil(',').toInt(); // socket state waitResponse(); @@ -682,19 +508,16 @@ protected: return 2 == 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -702,15 +525,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -738,9 +561,9 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } data = ""; } else if (data.endsWith(GF("CLOSED" GSM_NL))) { - int nl = data.lastIndexOf(GSM_NL, data.length()-8); - int coma = data.indexOf(',', nl+2); - int mux = data.substring(nl+2, coma).toInt(); + int nl = data.lastIndexOf(GSM_NL, data.length() - 8); + int coma = data.indexOf(',', nl + 2); + int mux = data.substring(nl + 2, coma).toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } @@ -749,38 +572,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: + protected: Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + GsmClientM95* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTM95_H_ diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 740ea06..9681153 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -9,32 +9,23 @@ * */ -#ifndef TinyGsmClientMC60_h -#define TinyGsmClientMC60_h -//#pragma message("TinyGSM: TinyGsmClientMC60") +#ifndef SRC_TINYGSMCLIENTMC60_H_ +#define SRC_TINYGSMCLIENTMC60_H_ +// #pragma message("TinyGSM: TinyGsmClientMC60") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 6 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, - SIM_ANTITHEFT_LOCKED = 3, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -43,178 +34,150 @@ enum RegStatus { REG_UNKNOWN = 4, }; +class TinyGsmMC60 + : public TinyGsmModem { + friend class TinyGsmModem; -class TinyGsmMC60: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmMC60; - typedef TinyGsmFifo RxFifo; + /* + * Inner Client + */ + public: + class GsmClientMC60 : public GsmClient { + friend class TinyGsmMC60; -public: - GsmClient() {} + public: + GsmClientMC60() {} - GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) { - init(&modem, mux); - } + explicit GsmClientMC60(TinyGsmMC60& modem, uint8_t mux = 1) { + init(&modem, mux); + } - virtual ~GsmClient(){} + bool init(TinyGsmMC60* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + sock_connected = false; - bool init(TinyGsmMC60* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - sock_connected = false; + at->sockets[mux] = this; - at->sockets[mux] = this; + return true; + } - return true; - } + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + void stop(uint32_t maxWaitMs) { + uint32_t startMillis = millis(); + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+QICLOSE="), mux); + sock_connected = false; + at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), + GF("CLOSE OK"), GF("ERROR")); + } + void stop() override { + stop(75000L); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + /* + * Extended API + */ - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+QICLOSE="), mux); - sock_connected = false; - at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR")); - } + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; - virtual void stop() { stop(75000L); } + /* + * Inner Secure Client + */ -TINY_GSM_CLIENT_WRITE() + /* + class GsmClientSecureMC60 : public GsmClientMC60 + { + public: + GsmClientSecure() {} -TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() + GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} -TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + public: + virtual int connect(const char *host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; + */ /* - * Extended API + * Constructor */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmMC60* at; - uint8_t mux; - uint16_t sock_available; - bool sock_connected; - RxFifo rx; -}; - - -// class GsmClientSecure : public GsmClient -// { -// public: -// GsmClientSecure() {} -// -// GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1) -// : GsmClient(modem, mux) -// {} -// -// virtual ~GsmClientSecure(){} -// -// public: -// virtual int connect(const char *host, uint16_t port, int timeout_s) { -// stop(); -// TINY_GSM_YIELD(); -// rx.clear(); -// sock_connected = at->modemConnect(host, port, mux, true, timeout_s); -// return sock_connected; -// } -// }; - - -public: - - TinyGsmMC60(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmMC60(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } // sendAT(GF("&FZ")); // Factory + Reset // waitResponse(); - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable network time synchronization + sendAT(GF("+QNITZ=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - #if defined(TINY_GSM_MODEM_MC60) - return "Quectel MC60"; - #elif defined(TINY_GSM_MODEM_MC60E) - return "Quectel MC60E"; - #endif - return "Quectel MC60"; - } - -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_LISTEN() - - bool factoryDefault() { - sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - waitResponse(); - sendAT(GF("+IPR=0")); // Auto-baud - waitResponse(); - sendAT(GF("&W")); // Write configuration - return waitResponse() == 1; - } - -TINY_GSM_MODEM_GET_INFO_ATI() - /* - * under development - */ - // bool hasSSL() { + * under development + */ + // bool thisHasSSL() { // sendAT(GF("+QIPSSL=?")); // if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { // return false; @@ -222,125 +185,106 @@ TINY_GSM_MODEM_GET_INFO_ATI() // return waitResponse() == 1; // } - bool hasSSL() { - return false; // TODO: For now + bool thisHasSSL() { + return false; // TODO(?): Add SSL support } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } sendAT(GF("+CFUN=1,1")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } delay(3000); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+QPOWD=1")); return waitResponse(GF("NORMAL POWER DOWN")) == 1; } - bool radioOff() { - if (!testAT()) { - return false; - } - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; + // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN + // is pulled up, the module can directly enter into sleep mode.If entering + // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled + // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first, + // and then the module can enter into sleep mode. + bool sleepEnableImpl(bool enable = true) { + sendAT(GF("+QSCLK="), enable); + return waitResponse() == 1; } - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; - /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - -TINY_GSM_MODEM_GET_IMEI_GSN() - - SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { - for (unsigned long start = millis(); millis() - start < timeout_ms; ) { + protected: + SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t 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"), GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); + int status = + waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), + GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); waitResponse(); switch (status) { case 2: - case 3: return SIM_LOCKED; + case 3: return SIM_LOCKED; case 5: - case 6: return SIM_ANTITHEFT_LOCKED; - case 1: return SIM_READY; + case 6: return SIM_ANTITHEFT_LOCKED; + case 1: return SIM_READY; default: return SIM_ERROR; } } return SIM_ERROR; } -TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); // select foreground context 0 = VIRTUAL_UART_1 sendAT(GF("+QIFGCNT=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } - //Select GPRS (=1) as the Bearer - sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse() != 1) { - return false; - } + // Select GPRS (=1) as the Bearer + sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, + GF("\"")); + if (waitResponse() != 1) { return false; } - //Define PDP context - is this necessary? + // Define PDP context - is this necessary? sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); waitResponse(); @@ -350,56 +294,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // Select TCP/IP transfer mode - NOT transparent mode sendAT(GF("+QIMODE=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Enable multiple TCP/IP connections sendAT(GF("+QIMUX=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } - //Start TCPIP Task and Set APN, User Name and Password - sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" ); - if (waitResponse() != 1) { - return false; - } + // Start TCPIP Task and Set APN, User Name and Password + sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\""); + if (waitResponse() != 1) { return false; } - //Activate GPRS/CSD Context + // Activate GPRS/CSD Context sendAT(GF("+QIACT")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Check that we have a local IP address - if (localIP() == IPAddress(0,0,0,0)) { - return false; - } + if (localIP() == IPAddress(0, 0, 0, 0)) { return false; } - //Set Method to Handle Received TCP/IP Data + // Set Method to Handle Received TCP/IP Data // Mode=2 - Output a notification statement: // “+QIRDI: ,,,,,< tlen>” sendAT(GF("+QINDI=2")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } - bool gprsDisconnect() { - sendAT(GF("+QIDEACT")); + bool gprsDisconnectImpl() { + sendAT(GF("+QIDEACT")); // Deactivate the bearer context return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1; } -TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() - /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+QILOCIP")); stream.readStringUntil('\n'); String res = stream.readStringUntil('\n'); @@ -407,61 +337,23 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + /* + * Phone Call functions + */ + protected: + // Can follow all of the phone call functions from the template /* * Messaging functions */ + protected: + // Can follow all template functions - String sendUSSD(const String& code) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (waitResponse() != 1) { - return ""; - } - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } - + public: /** Delete all SMS */ bool deleteAllSMS() { sendAT(GF("+QMGDA=6")); - if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) { + if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) { return true; } return false; @@ -470,118 +362,60 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() /* * Location functions */ - - String getGsmLocation() { - sendAT(GF("+CIPGSMLOC=1,1")); - if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } + protected: + // Can use CIPGSMLOC as inherited from the template /* - * Battery & temperature functions + * GPS location functions */ + public: + // No functions of this type supported - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); - milliVolts = stream.readStringUntil('\n').toInt(); - // Wait for final OK - waitResponse(); - return true; - } + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template - float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Battery & temperature functions + */ + protected: + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * Client related functions */ - -protected: - + protected: bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) { - if (ssl) { - DBG("SSL not yet supported on this module!"); - } - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); - int rsp = waitResponse(timeout_ms, - GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), - GF("ALREADY CONNECT" GSM_NL)); + bool ssl = false, int timeout_s = 75) { + if (ssl) { DBG("SSL not yet supported on this module!"); } + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, + GF("\","), port); + int rsp = + waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); return (1 == rsp); } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } bool allAcknowledged = false; // bool failed = false; - while ( !allAcknowledged ) { - sendAT( GF("+QISACK")); + while (!allAcknowledged) { + sendAT(GF("+QISACK")); if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) { return -1; } else { streamSkipUntil(','); /** Skip total */ streamSkipUntil(','); /** Skip acknowledged data size */ - if ( stream.readStringUntil('\n').toInt() == 0 ) { + if (stream.readStringUntil('\n').toInt() == 0) { allAcknowledged = true; } } @@ -591,16 +425,16 @@ protected: // streamSkipUntil(','); // Skip mux // return stream.readStringUntil('\n').toInt(); - return len; // TODO + return len; // TODO(?): verify len/ack } size_t modemRead(size_t size, uint8_t mux) { - // TODO: Does this work???? + // TODO(?): Does this work???? // AT+QIRD=,,, - // id = GPRS context number - 0, set in GPRS connect - // sc = roll in connection - 1, client of connection - // sid = index of connection - mux - // len = maximum length of data to send + // id = GPRS context number = 0, set in GPRS connect + // sc = role in connection = 1, client of connection + // sid = index of connection = mux + // len = maximum length of data to retrieve sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size); // If it replies only OK for the write command, it means there is no // received data in the buffer of the connection. @@ -615,36 +449,38 @@ protected: // This is quite likely if the buffer is broken into packets - which may // be different sizes. // If so, make sure we make sure we re-set the amount of data available. - if (len < size) { - sockets[mux]->sock_available = len; - } - for (uint16_t i=0; isock_available = len; } + for (uint16_t i = 0; i < len; i++) { + moveCharFromStreamToFifo(mux); sockets[mux]->sock_available--; - // ^^ One less character available after moving from modem's FIFO to our FIFO + // ^^ One less character available after moving from modem's FIFO to our + // FIFO } - waitResponse(); + waitResponse(); // ends with an OK DBG("### READ:", len, "from", mux); return len; } else { - sockets[mux]->sock_available = 0; - return 0; + sockets[mux]->sock_available = 0; + return 0; } } + size_t modemGetAvailable(uint8_t) { + return 0; + } + bool modemGetConnected(uint8_t mux) { sendAT(GF("+QISTATE=1,"), mux); - //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" + // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" - if (waitResponse(GF("+QISTATE:"))) - return false; + if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = stream.readStringUntil(',').toInt(); // socket state waitResponse(); @@ -652,19 +488,16 @@ protected: return 2 == 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, GsmConstStr r6=NULL) - { + public: + // TODO(vshymanskyy): Optimize this! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -673,15 +506,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r6s(r6); r6s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -700,7 +533,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } else if (r6 && data.endsWith(r6)) { index = 6; goto finish; - } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) { // TODO: QIRD? or QIRDI? + } else if (data.endsWith( + GF(GSM_NL "+QIRD:"))) { // TODO(?): QIRD? or QIRDI? // +QIRDI: ,,,,,< tlen> streamSkipUntil(','); // Skip the context streamSkipUntil(','); // Skip the role @@ -711,14 +545,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() // read the length of the current packet int len_packet = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->sock_available = len_packet*num_packets; + sockets[mux]->sock_available = len_packet * num_packets; } data = ""; - DBG("### Got Data:", len, "on", mux); + DBG("### Got Data:", len_packet * num_packets, "on", mux); } else if (data.endsWith(GF("CLOSED" GSM_NL))) { - int nl = data.lastIndexOf(GSM_NL, data.length()-8); - int coma = data.indexOf(',', nl+2); - int mux = data.substring(nl+2, coma).toInt(); + int nl = data.lastIndexOf(GSM_NL, data.length() - 8); + int coma = data.indexOf(',', nl + 2); + int mux = data.substring(nl + 2, coma).toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } @@ -727,38 +561,37 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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, GsmConstStr r6=NULL) - { + uint8_t + waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { String data; return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6); } - uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), - GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5, r6); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientMC60* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTMC60_H_ diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index e306a2e..e598dfc 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -6,31 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSIM5360_h -#define TinyGsmClientSIM5360_h +#ifndef SRC_TINYGSMCLIENTSIM5360_H_ +#define SRC_TINYGSMCLIENTSIM5360_H_ // #define TINY_GSM_DEBUG Serial -//#define TINY_GSM_USE_HEX - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_USE_HEX #define TINY_GSM_MUX_COUNT 10 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,140 +31,148 @@ enum RegStatus { REG_UNKNOWN = 4, }; -enum TinyGSMDateTimeFormat { - DATE_FULL = 0, - DATE_TIME = 1, - DATE_DATE = 2 -}; - -class TinyGsmSim5360: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSim5360; - typedef TinyGsmFifo RxFifo; +class TinyGsmSim5360 : public TinyGsmModem { + friend class TinyGsmModem; -public: - GsmClient() {} - - GsmClient(TinyGsmSim5360& modem, uint8_t mux = 0) { - init(&modem, mux); - } - - virtual ~GsmClient(){} - - bool init(TinyGsmSim5360* modem, uint8_t mux = 0) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + /* + * Inner Client + */ + public: + class GsmClientSim5360 : public GsmClient { + friend class TinyGsmSim5360; - at->sockets[mux] = this; + public: + GsmClientSim5360() {} - return true; - } + explicit GsmClientSim5360(TinyGsmSim5360& modem, uint8_t mux = 0) { + init(&modem, mux); + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + bool init(TinyGsmSim5360* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + at->sockets[mux] = this; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(); - } - - virtual void stop() { stop(15000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * 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: - TinyGsmSim5360* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; + // TODO(?): Add SSL support + /* + class GsmClientSecureSim5360 : public GsmClientSim5360 { + public: + GsmClientSecureSim5360() {} + explicit GsmClientSecureSim5360(TinyGsmSim5360& modem, uint8_t mux = 1) + : GsmClientSim5360(modem, mux) {} -public: + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; + */ - TinyGsmSim5360(Stream& stream) - : stream(stream) - { + /* + * Constructor + */ + public: + explicit TinyGsmSim5360(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable automatic time zome update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - String name = "SIMCom SIM5360"; + String getModemNameImpl() { + String name = "SIMCom SIM5360"; sendAT(GF("+CGMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return name; - } + if (waitResponse(1000L, res2) != 1) { return name; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.replace("_", " "); res2.trim(); @@ -182,61 +182,47 @@ public: return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { // these commands aren't supported + bool factoryDefaultImpl() { // these commands aren't supported return false; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { - return false; // TODO: Module supports SSL, but not yet implemented + bool thisHasSSL() { + return false; // TODO(>): Module supports SSL, but not yet implemented } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+REBOOT")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000L); // TODO: Test this delay! + if (waitResponse(10000L) != 1) { return false; } + delay(3000L); // TODO(?): Test this delay! return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPOF")); return waitResponse() == 1; } - bool radioOff() { + bool radioOffImpl() { sendAT(GF("+CFUN=4")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } delay(3000); return true; } - bool sleepEnable(bool enable = true) { + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+CSCLK="), enable); return waitResponse() == 1; } @@ -244,85 +230,54 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -// Gets the CCID of a sim card via AT+CCID - String getSimCCID() { + protected: + // Gets the CCID of a sim card via AT+CCID + String getSimCCIDImpl() { sendAT(GF("+CICCID")); - if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+ICCID:")) != 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(CGREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CGREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + public: String getNetworkModes() { sendAT(GF("+CNMP=?")); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - String setNetworkMode(uint8_t mode) { - sendAT(GF("+CNMP="), mode); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return "OK"; - } + sendAT(GF("+CNMP="), mode); + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } - /* * 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(); // Make sure we're not connected first // Define the PDP context @@ -336,7 +291,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } // Define external PDP context 1 - sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"',",\"0.0.0.0\",0,0"); + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"', ",\"0.0.0.0\",0,0"); waitResponse(); // The CGSOCKCONT commands define the "embedded" PDP context for TCP/IP @@ -367,21 +322,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(); // Configure socket parameters - //AT+CIPCCFG= [][,[][,[][,[][,]][,[[][,[]]]]]]]] - // NmRetry = number of retransmission to be made for an IP packet = 10 (default) - // DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default) + // AT+CIPCCFG= , , , , , + // , + // NmRetry = number of retransmission to be made for an IP packet + // = 10 (default) + // DelayTm = number of milliseconds to delay before outputting received data + // = 0 (default) // Ack = sets whether reporting a string “Send ok” = 0 (don't report) // errMode = mode of reporting error result code = 0 (numberic values) - // HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,,”) - // AsyncMode = sets mode of executing commands = 0 (synchronous command executing) + // HeaderType = which data header of receiving data in multi-client mode + // = 1 (“+RECEIVE,,”) + // AsyncMode = sets mode of executing commands + // = 0 (synchronous command executing) // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Configure timeouts for opening and closing sockets - // AT+CIPTIMEOUT=[][, [][, []]] + // AT+CIPTIMEOUT=, , sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); waitResponse(); @@ -393,45 +351,36 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // We to ignore any immediate response and wait for the // URC to show it's really connected. sendAT(GF("+NETOPEN")); - if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { - return false; - } + if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { // Close any open sockets for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { - GsmClient *sock = sockets[mux]; - if (sock) { - sock->stop(); - } + GsmClientSim5360* sock = sockets[mux]; + if (sock) { sock->stop(); } } // Stop the socket service - // Note: all sockets should be closed first - on 3G/4G models the sockets must be closed manually + // Note: all sockets should be closed first - on 3G/4G models the sockets + // must be closed manually sendAT(GF("+NETCLOSE")); - if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { - return false; - } + if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; } return true; } - bool isGprsConnected() { + bool isGprsConnectedImpl() { sendAT(GF("+NETOPEN?")); // May return +NETOPEN: 1, 0. We just confirm that the first number is 1 - if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; } waitResponse(); - sendAT(GF("+IPADDR")); // Inquire Socket PDP address + sendAT(GF("+IPADDR")); // Inquire Socket PDP address // sendAT(GF("+CGPADDR=1")); // Show PDP address - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } @@ -439,175 +388,92 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+IPADDR")); // Inquire Socket PDP address // sendAT(GF("+CGPADDR=1")); // Show PDP address String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - - bool setGsmBusy() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * Messaging functions */ - - String sendUSSD(const String& code) { - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - // Select TE character set - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse() != 1) { - return ""; - } - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - // Get SMS service centre address - sendAT(GF("+AT+CSCA?")); - waitResponse(); - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - waitResponse(); - // Send the message! - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - stream.print(text); - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - + protected: + // Follows all messaging functions per template /* * Location functions */ - - String getGsmLocation() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * GPS location functions */ + public: + // No functions of this type supported /* * Time functions */ + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { + protected: + uint16_t getBattVoltageImpl() { sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; } + streamSkipUntil(','); // Skip battery charge status + streamSkipUntil(','); // Skip battery charge level // get voltage in VOLTS float voltage = stream.readStringUntil('\n').toFloat(); // Wait for final OK waitResponse(); // Return millivolts - uint16_t res = voltage*1000; + uint16_t res = voltage * 1000; return res; } - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); + percent = stream.readStringUntil(',').toInt(); // get voltage in VOLTS float voltage = stream.readStringUntil('\n').toFloat(); - milliVolts = voltage*1000; + milliVolts = voltage * 1000; // Wait for final OK waitResponse(); return true; } // get temperature in degree celsius - float getTemperature() { + float getTemperatureImpl() { // Enable Temparature Reading sendAT(GF("+CMTE=1")); - if (waitResponse() != 1) { - return 0; - } + if (waitResponse() != 1) { return 0; } // Get Temparature Value sendAT(GF("+CMTE?")); - if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { return false; } float res = stream.readStringUntil('\n').toFloat(); // Wait for final OK waitResponse(); @@ -617,75 +483,67 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Client related functions */ - -protected: - + protected: bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false, int timeout_s = 15) { + if (ssl) { DBG("SSL not yet supported on this module!"); } // Make sure we'll be getting data manually on this connection sendAT(GF("+CIPRXGET=1")); - if (waitResponse() != 1) { - return false; - } - - if (ssl) { - DBG("SSL not yet supported on this module!"); - } + if (waitResponse() != 1) { return false; } // Establish a connection in multi-socket mode uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port); + sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), + port); // The reply is +CIPOPEN: ## of socket created - if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { - return false; - } + if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; } return true; } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip requested bytes to send - // TODO: make sure requested and confirmed bytes match + if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip requested bytes to send + // TODO(?): make sure requested and confirmed bytes match return stream.readStringUntil('\n').toInt(); } size_t modemRead(size_t size, uint8_t mux) { #ifdef TINY_GSM_USE_HEX sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #else sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #endif - streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX - streamSkipUntil(','); // Skip mux/cid (connecion id) + streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX + streamSkipUntil(','); // Skip mux/cid (connecion id) int len_requested = stream.readStringUntil(',').toInt(); // ^^ Requested number of data bytes (1-1460 bytes)to be read int len_confirmed = stream.readStringUntil('\n').toInt(); // ^^ The data length which not read in the buffer - for (int i=0; i_timeout)) { TINY_GSM_YIELD(); } - char buf[4] = { 0, }; + while (stream.available() < 2 && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char buf[4] = { + 0, + }; buf[0] = stream.read(); buf[1] = stream.read(); char c = strtol(buf, NULL, 16); #else - while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } + while (!stream.available() && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } char c = stream.read(); #endif sockets[mux]->rx.put(c); @@ -701,25 +559,21 @@ protected: sendAT(GF("+CIPRXGET=4,"), mux); size_t result = 0; if (waitResponse(GF("+CIPRXGET:")) == 1) { - streamSkipUntil(','); // Skip mode 4 - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux result = stream.readStringUntil('\n').toInt(); waitResponse(); } DBG("### Available:", result, "on", mux); - if (!result) { - sockets[mux]->sock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } return result; } bool modemGetConnected(uint8_t mux) { // Read the status of all sockets at once sendAT(GF("+CIPCLOSE?")); - if (waitResponse(GF("+CIPCLOSE:")) != 1) { - return false; - } - for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { + if (waitResponse(GF("+CIPCLOSE:")) != 1) { return false; } + for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { // +CIPCLOSE:,,..., sockets[muxNo]->sock_connected = stream.parseInt(); } @@ -727,19 +581,16 @@ protected: return sockets[mux]->sock_connected; } -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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -747,15 +598,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -787,7 +638,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; @@ -804,45 +655,41 @@ TINY_GSM_MODEM_STREAM_UTILITIES() // Need to close all open sockets and release the network library. // User will then need to reconnect. DBG("### Network error!"); - if (!isGprsConnected()) { - gprsDisconnect(); - } + if (!isGprsConnected()) { gprsDisconnect(); } data = ""; } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientSim5360* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTSIM5360_H_ diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 5f56091..a9390d7 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -6,31 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSIM7000_h -#define TinyGsmClientSIM7000_h +#ifndef SRC_TINYGSMCLIENTSIM7000_H_ +#define SRC_TINYGSMCLIENTSIM7000_H_ // #define TINY_GSM_DEBUG Serial -//#define TINY_GSM_USE_HEX - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_USE_HEX #define TINY_GSM_MUX_COUNT 8 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,164 +31,146 @@ enum RegStatus { REG_UNKNOWN = 4, }; -enum TinyGSMDateTimeFormat { - DATE_FULL = 0, - DATE_TIME = 1, - DATE_DATE = 2 -}; - -class TinyGsmSim7000: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSim7000; - typedef TinyGsmFifo RxFifo; +class TinyGsmSim7000 : public TinyGsmModem { + friend class TinyGsmModem; -public: - GsmClient() {} - - GsmClient(TinyGsmSim7000& modem, uint8_t mux = 1) { - init(&modem, mux); - } - - virtual ~GsmClient(){} - - bool init(TinyGsmSim7000* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + /* + * Inner Client + */ + public: + class GsmClientSim7000 : public GsmClient { + friend class TinyGsmSim7000; - at->sockets[mux] = this; + public: + GsmClientSim7000() {} - return true; - } + explicit GsmClientSim7000(TinyGsmSim7000& modem, uint8_t mux = 1) { + init(&modem, mux); + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + bool init(TinyGsmSim7000* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + at->sockets[mux] = this; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(); - } - - virtual void stop() { stop(15000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * 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: - TinyGsmSim7000* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -/*TODO! -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmSim7000& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} - - virtual ~GsmClientSecure(){} - -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } -}; -*/ + /*TODO(?)) + class GsmClientSecureSIM7000 : public GsmClientSim7000 + { + public: + GsmClientSecure() {} + GsmClientSecure(TinyGsmSim7000& modem, uint8_t mux = 1) + : public GsmClient(modem, mux) + {} -public: + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; + */ - TinyGsmSim7000(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmSim7000(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable Local Time Stamp for getting network time + sendAT(GF("+CLTS=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - String name = "SIMCom SIM7000"; + String getModemNameImpl() { + String name = "SIMCom SIM7000"; sendAT(GF("+GMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return name; - } + if (waitResponse(1000L, res2) != 1) { return name; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.replace("_", " "); res2.trim(); @@ -206,77 +180,45 @@ public: return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { // these commands aren't supported + bool factoryDefaultImpl() { // these commands aren't supported return false; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { - return false; // TODO: Module supports SSL, but not yet implemented + bool thisHasSSL() { + return false; // TODO(?): Module supports SSL, but not yet implemented } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } - //Enable Local Time Stamp for getting network time - // TODO: Find a better place for this - sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { - return false; - } + protected: + bool restartImpl() { sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } sendAT(GF("+CFUN=1,1")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); //TODO: Test this delay + if (waitResponse(10000L) != 1) { return false; } + delay(3000); // TODO(SRGDamia1): Test this delay return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPOWD=1")); return waitResponse(GF("NORMAL POWER DOWN")) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; - } - - /* - During sleep, the SIM7000 module has its serial communication disabled. - In order to reestablish communication pull the DRT-pin of the SIM7000 module - LOW for at least 50ms. Then use this function to disable sleep mode. - The DTR-pin can then be released again. - */ - bool sleepEnable(bool enable = true) { + // During sleep, the SIM7000 module has its serial communication disabled. + // In order to reestablish communication pull the DRT-pin of the SIM7000 + // module LOW for at least 50ms. Then use this function to disable sleep mode. + // The DTR-pin can then be released again. + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+CSCLK="), enable); return waitResponse() == 1; } @@ -284,64 +226,35 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - -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(CGREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() + protected: + // Able to follow all SIM card functions as inherited from the template /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CGREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + public: String getNetworkModes() { sendAT(GF("+CNMP=?")); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - String setNetworkMode(uint8_t mode) { - sendAT(GF("+CNMP="), mode); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return "OK"; - } + sendAT(GF("+CNMP="), mode); + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; } String res = stream.readStringUntil('\n'); waitResponse(); return res; @@ -349,9 +262,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() String getPreferredModes() { sendAT(GF("+CMNB=?")); - if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); return res; @@ -359,24 +270,23 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() String setPreferredMode(uint8_t mode) { sendAT(GF("+CMNB="), mode); - if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { - return "OK"; - } + if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return "OK"; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } - /* * 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(); // Set the Bearer for the IP - sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS + sendAT(GF( + "+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS waitResponse(); sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN @@ -404,81 +314,49 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(85000L); // Query the GPRS bearer context status sendAT(GF("+SAPBR=2,1")); - if (waitResponse(30000L) != 1) - return false; + if (waitResponse(30000L) != 1) { return false; } // Attach to GPRS sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } - // TODO: wait AT+CGATT? + // TODO(?): wait AT+CGATT? // Set to multi-IP sendAT(GF("+CIPMUX=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Put in "quick send" mode (thus no extra "Send OK") sendAT(GF("+CIPQSEND=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Set to get data manually sendAT(GF("+CIPRXGET=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Start Task and Set APN, USER NAME, PASSWORD sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Bring Up Wireless Connection with GPRS or CSD sendAT(GF("+CIICR")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Get Local IP Address, only assigned after connection sendAT(GF("+CIFSR;E0")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { // Shut the TCP/IP connection + // CIPSHUT will close *all* open connections sendAT(GF("+CIPSHUT")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } sendAT(GF("+CGATT=0")); // Deactivate the bearer context - if (waitResponse(60000L) != 1) - return false; - - return true; - } - - 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; - - sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1 - if (waitResponse() != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } return true; } @@ -486,126 +364,60 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+CIFSR;E0")); String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - - bool setGsmBusy() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * Messaging functions */ - - String sendUSSD(const String& code) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse() != 1) { - return ""; - } - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - - sendAT(GF("+AT+CSCA?")); - waitResponse(); - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } - + protected: + // Follows all messaging functions per template /* * Location functions */ - - String getGsmLocation() { - sendAT(GF("+CIPGSMLOC=1,1")); - if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - + protected: + // Can return a location from CIPGSMLOC as per the template /* * GPS location functions */ - + public: // enable GPS bool enableGPS() { sendAT(GF("+CGNSPWR=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } bool disableGPS() { sendAT(GF("+CGNSPWR=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } // get the RAW GPS output String getGPSraw() { sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -613,22 +425,21 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } // get GPS informations - bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) { - //String buffer = ""; + bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0, + int* vsat = 0, int* usat = 0) { + // String buffer = ""; bool fix = false; sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return false; - } - - stream.readStringUntil(','); // mode - if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; - stream.readStringUntil(','); //utctime - *lat = stream.readStringUntil(',').toFloat(); //lat - *lon = stream.readStringUntil(',').toFloat(); //lon - if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon - if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } + + stream.readStringUntil(','); // mode + if (stream.readStringUntil(',').toInt() == 1) fix = true; + stream.readStringUntil(','); // utctime + *lat = stream.readStringUntil(',').toFloat(); // lat + *lon = stream.readStringUntil(',').toFloat(); // lon + if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // lon + if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed stream.readStringUntil(','); stream.readStringUntil(','); stream.readStringUntil(','); @@ -636,8 +447,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() stream.readStringUntil(','); stream.readStringUntil(','); stream.readStringUntil(','); - if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites - if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites + if (vsat != NULL) + *vsat = stream.readStringUntil(',').toInt(); // viewed satelites + if (usat != NULL) + *usat = stream.readStringUntil(',').toInt(); // used satelites stream.readStringUntil('\n'); waitResponse(); @@ -648,59 +461,33 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Time functions */ - - String getGSMDateTime(TinyGSMDateTimeFormat format) { - sendAT(GF("+CCLK?")); - if (waitResponse(2000L, GF(GSM_NL "+CCLK: \"")) != 1) { - return ""; - } - - String res; - - switch(format) { - case DATE_FULL: - res = stream.readStringUntil('"'); - break; - case DATE_TIME: - streamSkipUntil(','); - res = stream.readStringUntil('"'); - break; - case DATE_DATE: - res = stream.readStringUntil(','); - break; - } - return res; - } - + public: // get GPS time - bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) { + bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute, + int* second) { bool fix = false; char chr_buffer[12]; sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } for (int i = 0; i < 3; i++) { String buffer = stream.readStringUntil(','); buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); switch (i) { case 0: - //mode + // mode break; case 1: - //fixstatus - if ( buffer.toInt() == 1 ) { - fix = buffer.toInt(); - } + // fixstatus + if (buffer.toInt() == 1) { fix = buffer.toInt(); } break; case 2: - *year = buffer.substring(0,4).toInt(); - *month = buffer.substring(4,6).toInt(); - *day = buffer.substring(6,8).toInt(); - *hour = buffer.substring(8,10).toInt(); - *minute = buffer.substring(10,12).toInt(); - *second = buffer.substring(12,14).toInt(); + *year = buffer.substring(0, 4).toInt(); + *month = buffer.substring(4, 6).toInt(); + *day = buffer.substring(6, 8).toInt(); + *hour = buffer.substring(8, 10).toInt(); + *minute = buffer.substring(10, 12).toInt(); + *second = buffer.substring(12, 14).toInt(); break; default: @@ -709,7 +496,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() break; } } - String res = stream.readStringUntil('\n'); + stream.readStringUntil('\n'); waitResponse(); if (fix) { @@ -722,130 +509,72 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Battery & temperature functions */ - - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); - milliVolts = stream.readStringUntil('\n').toInt(); - // Wait for final OK - waitResponse(); - return true; - } - - float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * Client related functions */ - -protected: - - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) { - if (ssl) { - DBG("SSL not yet supported on this module!"); - } - - int rsp; - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), - port); - rsp = waitResponse( - timeout_ms, GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL), - GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL), - GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails - ); - return (1 == rsp); + protected: + bool modemConnect(const char* host, uint16_t port, uint8_t mux, + bool ssl = false, int timeout_s = 75) { + if (ssl) { DBG("SSL not yet supported on this module!"); } + + int rsp; + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, + GF("\","), port); + rsp = waitResponse( + timeout_ms, GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL), + GF("CLOSE OK" GSM_NL)); // Happens when HTTPS handshake fails + return (1 == rsp); } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux + if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux return stream.readStringUntil('\n').toInt(); } size_t modemRead(size_t size, uint8_t mux) { #ifdef TINY_GSM_USE_HEX sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #else sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #endif - streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX + streamSkipUntil(','); // Skip mux int len_requested = stream.readStringUntil(',').toInt(); // ^^ Requested number of data bytes (1-1460 bytes)to be read int len_confirmed = stream.readStringUntil('\n').toInt(); - // ^^ Confirmed number of data bytes to be read, which may be less than requested. - // 0 indicates that no data can be read. - // This is actually be the number of bytes that will be remaining after the read - for (int i=0; i_timeout)) { TINY_GSM_YIELD(); } - char buf[4] = { 0, }; + while (stream.available() < 2 && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char buf[4] = { + 0, + }; buf[0] = stream.read(); buf[1] = stream.read(); char c = strtol(buf, NULL, 16); #else - while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } + while (!stream.available() && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } char c = stream.read(); #endif sockets[mux]->rx.put(c); @@ -861,38 +590,34 @@ protected: sendAT(GF("+CIPRXGET=4,"), mux); size_t result = 0; if (waitResponse(GF("+CIPRXGET:")) == 1) { - streamSkipUntil(','); // Skip mode 4 - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux result = stream.readStringUntil('\n').toInt(); waitResponse(); } DBG("### Available:", result, "on", mux); - if (!result) { - sockets[mux]->sock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } return result; } bool modemGetConnected(uint8_t mux) { sendAT(GF("+CIPSTATUS="), mux); - int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), + GF(",\"CLOSING\""), GF(",\"INITIAL\"")); waitResponse(); 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -900,15 +625,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -940,15 +665,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; DBG("### Got Data:", len, "on", mux); } else if (data.endsWith(GF("CLOSED" GSM_NL))) { - int nl = data.lastIndexOf(GSM_NL, data.length()-8); - int coma = data.indexOf(',', nl+2); - int mux = data.substring(nl+2, coma).toInt(); + int nl = data.lastIndexOf(GSM_NL, data.length() - 8); + int coma = data.indexOf(',', nl + 2); + int mux = data.substring(nl + 2, coma).toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } @@ -957,38 +682,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientSim7000* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTSIM7000_H_ diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index c1ec12f..e747268 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -6,31 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSIM7600_h -#define TinyGsmClientSIM7600_h +#ifndef SRC_TINYGSMCLIENTSIM7600_H_ +#define SRC_TINYGSMCLIENTSIM7600_H_ // #define TINY_GSM_DEBUG Serial -//#define TINY_GSM_USE_HEX - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_USE_HEX #define TINY_GSM_MUX_COUNT 10 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,140 +31,124 @@ enum RegStatus { REG_UNKNOWN = 4, }; -enum TinyGSMDateTimeFormat { - DATE_FULL = 0, - DATE_TIME = 1, - DATE_DATE = 2 -}; - -class TinyGsmSim7600: public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSim7600; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} +class TinyGsmSim7600 : public TinyGsmModem { + friend class TinyGsmModem; - GsmClient(TinyGsmSim7600& modem, uint8_t mux = 0) { - init(&modem, mux); - } - - virtual ~GsmClient(){} - - bool init(TinyGsmSim7600* modem, uint8_t mux = 0) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; - - at->sockets[mux] = this; + /* + * Inner Client + */ + public: + class GsmClientSim7600 : public GsmClient { + friend class TinyGsmSim7600; - return true; - } + public: + GsmClientSim7600() {} -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) { + init(&modem, mux); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + bool init(TinyGsmSim7600* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+CIPCLOSE="), mux); - sock_connected = false; - at->waitResponse(); - } + at->sockets[mux] = this; - virtual void stop() { stop(15000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * Extended API + */ -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* - * Extended API + * Constructor */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmSim7600* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -public: - - TinyGsmSim7600(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmSim7600(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable automatic time zome update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - String name = "SIMCom SIM7600"; + String getModemNameImpl() { + String name = "SIMCom SIM7600"; sendAT(GF("+CGMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return name; - } + if (waitResponse(1000L, res2) != 1) { return name; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.replace("_", " "); res2.trim(); @@ -182,61 +158,47 @@ public: return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { // these commands aren't supported + bool factoryDefaultImpl() { // these commands aren't supported return false; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { - return false; // TODO: Module supports SSL, but not yet implemented + bool thisHasSSL() { + return false; // TODO(?): Module supports SSL, but not yet implemented } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CRESET")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(5000L); // TODO: Test this delay! + if (waitResponse(10000L) != 1) { return false; } + delay(5000L); // TODO(?): Test this delay! return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPOF")); return waitResponse() == 1; } - bool radioOff() { + bool radioOffImpl() { sendAT(GF("+CFUN=4")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } delay(3000); return true; } - bool sleepEnable(bool enable = true) { + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+CSCLK="), enable); return waitResponse() == 1; } @@ -244,85 +206,54 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -// Gets the CCID of a sim card via AT+CCID - String getSimCCID() { + protected: + // Gets the CCID of a sim card via AT+CCID + String getSimCCIDImpl() { sendAT(GF("+CICCID")); - if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+ICCID:")) != 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(CGREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CGREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + public: String getNetworkModes() { sendAT(GF("+CNMP=?")); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - String setNetworkMode(uint8_t mode) { - sendAT(GF("+CNMP="), mode); - if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { - return "OK"; - } + sendAT(GF("+CNMP="), mode); + if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; } String res = stream.readStringUntil('\n'); waitResponse(); return res; } - /* * 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(); // Make sure we're not connected first // Define the PDP context @@ -336,7 +267,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } // Define external PDP context 1 - sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"',",\"0.0.0.0\",0,0"); + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"', ",\"0.0.0.0\",0,0"); waitResponse(); // Configure TCP parameters @@ -350,21 +281,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(); // Configure socket parameters - //AT+CIPCCFG= [][,[][,[][,[][,]][,[[][,[]]]]]]]] - // NmRetry = number of retransmission to be made for an IP packet = 10 (default) - // DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default) + // AT+CIPCCFG= , , , , , + // , + // NmRetry = number of retransmission to be made for an IP packet + // = 10 (default) + // DelayTm = number of milliseconds to delay before outputting received data + // = 0 (default) // Ack = sets whether reporting a string “Send ok” = 0 (don't report) // errMode = mode of reporting error result code = 0 (numberic values) - // HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,,”) - // AsyncMode = sets mode of executing commands = 0 (synchronous command executing) + // HeaderType = which data header of receiving data in multi-client mode + // = 1 (“+RECEIVE,,”) + // AsyncMode = sets mode of executing commands + // = 0 (synchronous command executing) // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Configure timeouts for opening and closing sockets - // AT+CIPTIMEOUT=[][, [][, []]] + // AT+CIPTIMEOUT= , sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); waitResponse(); @@ -376,38 +310,30 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // We to ignore any immediate response and wait for the // URC to show it's really connected. sendAT(GF("+NETOPEN")); - if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { - return false; - } + if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; } return true; } - bool gprsDisconnect() { - + bool gprsDisconnectImpl() { // Close all sockets and stop the socket service - // Note: On the LTE models, this single command closes all sockets and the service + // Note: On the LTE models, this single command closes all sockets and the + // service sendAT(GF("+NETCLOSE")); - if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { - return false; - } + if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; } return true; } - bool isGprsConnected() { + bool isGprsConnectedImpl() { sendAT(GF("+NETOPEN?")); // May return +NETOPEN: 1, 0. We just confirm that the first number is 1 - if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; } waitResponse(); - sendAT(GF("+IPADDR")); // Inquire Socket PDP address + sendAT(GF("+IPADDR")); // Inquire Socket PDP address // sendAT(GF("+CGPADDR=1")); // Show PDP address - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } @@ -415,120 +341,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+IPADDR")); // Inquire Socket PDP address // sendAT(GF("+CGPADDR=1")); // Show PDP address String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - - bool setGsmBusy() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; - bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * Messaging functions */ - - String sendUSSD(const String& code) { - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - // Select TE character set - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse() != 1) { - return ""; - } - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - // Get SMS service centre address - sendAT(GF("+AT+CSCA?")); - waitResponse(); - // Select message format (1=text) - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - waitResponse(); - // Send the message! - sendAT(GF("+CMGS=\""), number, GF("\"")); - if (waitResponse(GF(">")) != 1) { - return false; - } - stream.print(text); - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - + protected: + // Follows all messaging functions per template /* * Location functions */ - - String getGsmLocation() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * GPS location functions */ + public: // enable GPS bool enableGPS() { sendAT(GF("+CGPS=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } bool disableGPS() { sendAT(GF("+CGPS=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } // get the RAW GPS output String getGPSraw() { sendAT(GF("+CGNSSINFO=32")); - if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -536,81 +403,78 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } // get GPS informations - bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0) { - //String buffer = ""; + bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0) { + // String buffer = ""; bool fix = false; sendAT(GF("+CGNSSINFO")); - if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { - return false; - } - - //stream.readStringUntil(','); // mode - if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; - stream.readStringUntil(','); //gps - stream.readStringUntil(','); // glonass - stream.readStringUntil(','); // beidu - *lat = stream.readStringUntil(',').toFloat(); //lat - stream.readStringUntil(','); // N/S - *lon = stream.readStringUntil(',').toFloat(); //lon - stream.readStringUntil(','); // E/W - stream.readStringUntil(','); // date - stream.readStringUntil(','); // UTC time - if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //alt - if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed - stream.readStringUntil(','); //course - stream.readStringUntil(','); //time - stream.readStringUntil(',');//PDOP - stream.readStringUntil(',');//HDOP - stream.readStringUntil(',');//VDOP + if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; } + + // stream.readStringUntil(','); // mode + if (stream.readStringUntil(',').toInt() == 1) fix = true; + stream.readStringUntil(','); // gps + stream.readStringUntil(','); // glonass + stream.readStringUntil(','); // beidu + *lat = stream.readStringUntil(',').toFloat(); // lat + stream.readStringUntil(','); // N/S + *lon = stream.readStringUntil(',').toFloat(); // lon + stream.readStringUntil(','); // E/W + stream.readStringUntil(','); // date + stream.readStringUntil(','); // UTC time + if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // alt + if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed + stream.readStringUntil(','); // course + stream.readStringUntil(','); // time + stream.readStringUntil(','); // PDOP + stream.readStringUntil(','); // HDOP + stream.readStringUntil(','); // VDOP stream.readStringUntil('\n'); waitResponse(); return fix; } + /* * Time functions */ + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - + protected: // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { + uint16_t getBattVoltageImpl() { sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; } // get voltage in VOLTS float voltage = stream.readStringUntil('\n').toFloat(); // Wait for final OK waitResponse(); // Return millivolts - uint16_t res = voltage*1000; + uint16_t res = voltage * 1000; return res; } - int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; + int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStats(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) { + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { chargeState = 0; - percent = 0; - milliVolts = getBattVoltage(); + percent = 0; + milliVolts = getBattVoltage(); return true; } // get temperature in degree celsius - uint16_t getTemperature() { + uint16_t getTemperatureImpl() { sendAT(GF("+CPMUTEMP")); - if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { return 0; } // return temperature in C uint16_t res = stream.readStringUntil('\n').toInt(); // Wait for final OK @@ -621,75 +485,67 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Client related functions */ - -protected: - - bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 15) { - if (ssl) { - DBG("SSL not yet supported on this module!"); - } - // Make sure we'll be getting data manually on this connection - sendAT(GF("+CIPRXGET=1")); - if (waitResponse() != 1) { - return false; - } - - // Establish a connection in multi-socket mode - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), - port); - // The reply is +CIPOPEN: ## of socket created - if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { - return false; - } - return true; + protected: + bool modemConnect(const char* host, uint16_t port, uint8_t mux, + bool ssl = false, int timeout_s = 15) { + if (ssl) { DBG("SSL not yet supported on this module!"); } + // Make sure we'll be getting data manually on this connection + sendAT(GF("+CIPRXGET=1")); + if (waitResponse() != 1) { return false; } + + // Establish a connection in multi-socket mode + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), + port); + // The reply is +CIPOPEN: ## of socket created + if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; } + return true; } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip requested bytes to send - // TODO: make sure requested and confirmed bytes match + if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip requested bytes to send + // TODO(?): make sure requested and confirmed bytes match return stream.readStringUntil('\n').toInt(); } size_t modemRead(size_t size, uint8_t mux) { #ifdef TINY_GSM_USE_HEX sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #else sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #endif - streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX - streamSkipUntil(','); // Skip mux/cid (connecion id) + streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX + streamSkipUntil(','); // Skip mux/cid (connecion id) int len_requested = stream.readStringUntil(',').toInt(); // ^^ Requested number of data bytes (1-1460 bytes)to be read int len_confirmed = stream.readStringUntil('\n').toInt(); // ^^ The data length which not read in the buffer - for (int i=0; i_timeout)) { TINY_GSM_YIELD(); } - char buf[4] = { 0, }; + while (stream.available() < 2 && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char buf[4] = { + 0, + }; buf[0] = stream.read(); buf[1] = stream.read(); char c = strtol(buf, NULL, 16); #else - while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } + while (!stream.available() && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } char c = stream.read(); #endif sockets[mux]->rx.put(c); @@ -705,15 +561,13 @@ protected: sendAT(GF("+CIPRXGET=4,"), mux); size_t result = 0; if (waitResponse(GF("+CIPRXGET:")) == 1) { - streamSkipUntil(','); // Skip mode 4 - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux result = stream.readStringUntil('\n').toInt(); waitResponse(); } DBG("### Available:", result, "on", mux); - if (!result) { - sockets[mux]->sock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } return result; } @@ -723,7 +577,7 @@ protected: if (waitResponse(GF("+CIPCLOSE:")) != 1) { // return false; // TODO: Why does this not read correctly? } - for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { + for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { // +CIPCLOSE:,,..., sockets[muxNo]->sock_connected = stream.parseInt(); } @@ -731,19 +585,16 @@ protected: return sockets[mux]->sock_connected; } -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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -751,15 +602,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -791,7 +642,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; @@ -808,45 +659,41 @@ TINY_GSM_MODEM_STREAM_UTILITIES() // Need to close all open sockets and release the network library. // User will then need to reconnect. DBG("### Network error!"); - if (!isGprsConnected()) { - gprsDisconnect(); - } + if (!isGprsConnected()) { gprsDisconnect(); } data = ""; } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientSim7600* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTSIM7600_H_ diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index 5b0fa3d..c10fd54 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -6,32 +6,24 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSIM800_h -#define TinyGsmClientSIM800_h -//#pragma message("TinyGSM: TinyGsmClientSIM800") +#ifndef SRC_TINYGSMCLIENTSIM800_H_ +#define SRC_TINYGSMCLIENTSIM800_H_ +// #pragma message("TinyGSM: TinyGsmClientSIM800") -//#define TINY_GSM_DEBUG Serial -//#define TINY_GSM_USE_HEX - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial +// #define TINY_GSM_USE_HEX #define TINY_GSM_MUX_COUNT 5 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -39,174 +31,154 @@ enum RegStatus { REG_OK_ROAMING = 5, REG_UNKNOWN = 4, }; +class TinyGsmSim800 : public TinyGsmModem { + friend class TinyGsmModem; -enum TinyGSMDateTimeFormat { - DATE_FULL = 0, - DATE_TIME = 1, - DATE_DATE = 2 -}; - -class TinyGsmSim800 : public TinyGsmUTFSMS -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSim800; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} - - GsmClient(TinyGsmSim800& modem, uint8_t mux = 1) { - init(&modem, mux); - } - - virtual ~GsmClient(){} - - bool init(TinyGsmSim800* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; - - at->sockets[mux] = this; + /* + * Inner Client + */ + public: + class GsmClientSim800 : public GsmClient { + friend class TinyGsmSim800; - return true; - } + public: + GsmClientSim800() {} -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + explicit GsmClientSim800(TinyGsmSim800& modem, uint8_t mux = 1) { + init(&modem, mux); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + bool init(TinyGsmSim800* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+CIPCLOSE="), mux, GF(",1")); // Quick close - sock_connected = false; - at->waitResponse(); - } + at->sockets[mux] = this; - virtual void stop() { stop(15000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+CIPCLOSE="), mux, GF(",1")); // Quick close + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * Extended API + */ -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* - * Extended API + * Inner Secure Client */ + public: + class GsmClientSecureSim800 : public GsmClientSim800 { + public: + GsmClientSecureSim800() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmSim800* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmSim800& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} - - virtual ~GsmClientSecure(){} + explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 1) + : GsmClientSim800(modem, mux) {} -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } -}; - - -public: + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + }; - TinyGsmSim800(Stream& stream) - : stream(stream) - { + public: + explicit TinyGsmSim800(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } // sendAT(GF("&FZ")); // Factory + Reset // waitResponse(); - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } + +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); // turn on verbose error codes +#else + sendAT(GF("+CMEE=0")); // turn off error codes +#endif + waitResponse(); DBG(GF("### Modem:"), getModemName()); + // Enable Local Time Stamp for getting network time + sendAT(GF("+CLTS=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { + String getModemNameImpl() { String name = ""; - #if defined(TINY_GSM_MODEM_SIM800) - name = "SIMCom SIM800"; - #elif defined(TINY_GSM_MODEM_SIM808) - name = "SIMCom SIM808"; - #elif defined(TINY_GSM_MODEM_SIM868) - name = "SIMCom SIM868"; - #elif defined(TINY_GSM_MODEM_SIM900) - name = "SIMCom SIM900"; - #endif +#if defined(TINY_GSM_MODEM_SIM800) + name = "SIMCom SIM800"; +#elif defined(TINY_GSM_MODEM_SIM808) + name = "SIMCom SIM808"; +#elif defined(TINY_GSM_MODEM_SIM868) + name = "SIMCom SIM868"; +#elif defined(TINY_GSM_MODEM_SIM900) + name = "SIMCom SIM900"; +#endif sendAT(GF("+GMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return name; - } + if (waitResponse(1000L, res2) != 1) { return name; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.replace("_", " "); res2.trim(); @@ -216,97 +188,65 @@ public: return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { + bool factoryDefaultImpl() { sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write waitResponse(); - sendAT(GF("+IPR=0")); // Auto-baud + sendAT(GF("+IPR=0")); // Auto-baud waitResponse(); - sendAT(GF("+IFC=0,0")); // No Flow Control + sendAT(GF("+IFC=0,0")); // No Flow Control waitResponse(); - sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop + sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop waitResponse(); - sendAT(GF("+CSCLK=0")); // Disable Slow Clock + sendAT(GF("+CSCLK=0")); // Disable Slow Clock waitResponse(); - sendAT(GF("&W")); // Write configuration + sendAT(GF("&W")); // Write configuration return waitResponse() == 1; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { + bool thisHasSSL() { #if defined(TINY_GSM_MODEM_SIM900) return false; #else sendAT(GF("+CIPSSL=?")); - if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { return false; } return waitResponse() == 1; #endif } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } - //Enable Local Time Stamp for getting network time - // TODO: Find a better place for this - sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("&W")); waitResponse(); sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } sendAT(GF("+CFUN=1,1")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } delay(3000); return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPOWD=1")); return waitResponse(10000L, GF("NORMAL POWER DOWN")) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; - } - - /* - During sleep, the SIM800 module has its serial communication disabled. In order to reestablish communication - pull the DRT-pin of the SIM800 module LOW for at least 50ms. Then use this function to disable sleep mode. - The DTR-pin can then be released again. - */ - bool sleepEnable(bool enable = true) { + // During sleep, the SIM800 module has its serial communication disabled. In + // order to reestablish communication pull the DRT-pin of the SIM800 module + // LOW for at least 50ms. Then use this function to disable sleep mode. The + // DTR-pin can then be released again. + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+CSCLK="), enable); return waitResponse() == 1; } @@ -314,58 +254,34 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - -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"), GF("NOT INSERTED"), GF("NOT READY")); - 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) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() + protected: + // Able to follow all SIM card functions as inherited from the template /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); // Set the Bearer for the IP - sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS + sendAT(GF( + "+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS waitResponse(); sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN @@ -393,88 +309,53 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(85000L); // Query the GPRS bearer context status sendAT(GF("+SAPBR=2,1")); - if (waitResponse(30000L) != 1) - return false; + if (waitResponse(30000L) != 1) { return false; } // Attach to GPRS sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } - // TODO: wait AT+CGATT? + // TODO(?): wait AT+CGATT? // Set to multi-IP sendAT(GF("+CIPMUX=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Put in "quick send" mode (thus no extra "Send OK") sendAT(GF("+CIPQSEND=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Set to get data manually sendAT(GF("+CIPRXGET=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } // Start Task and Set APN, USER NAME, PASSWORD sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Bring Up Wireless Connection with GPRS or CSD sendAT(GF("+CIICR")); - if (waitResponse(60000L) != 1) { - return false; - } + if (waitResponse(60000L) != 1) { return false; } // Get Local IP Address, only assigned after connection sendAT(GF("+CIFSR;E0")); - if (waitResponse(10000L) != 1) { - return false; - } + if (waitResponse(10000L) != 1) { return false; } // Configure Domain Name Server (DNS) sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\"")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { // Shut the TCP/IP connection // CIPSHUT will close *all* open connections sendAT(GF("+CIPSHUT")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } sendAT(GF("+CGATT=0")); // Deactivate the bearer context - if (waitResponse(60000L) != 1) - return false; - - return true; - } - - 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; - - sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1 - if (waitResponse() != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } return true; } @@ -482,273 +363,96 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+CIFSR;E0")); String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - + public: bool setGsmBusy(bool busy = true) { sendAT(GF("+GSMBUSY="), busy ? 1 : 0); return waitResponse() == 1; } - bool callAnswer() { - sendAT(GF("A")); - return waitResponse() == 1; - } - - // Returns true on pick-up, false on error/busy - bool callNumber(const String& number) { - if (number == GF("last")) { - sendAT(GF("DL")); - } else { - sendAT(GF("D"), number, ";"); - } - int status = waitResponse(60000L, - GFP(GSM_OK), - GF("BUSY" GSM_NL), - GF("NO ANSWER" GSM_NL), - GF("NO CARRIER" GSM_NL)); - switch (status) { - case 1: return true; - case 2: - case 3: return false; - default: return false; - } - } - - bool callHangup() { - sendAT(GF("H")); - return waitResponse() == 1; - } - - // 0-9,*,#,A,B,C,D - bool dtmfSend(char cmd, int duration_ms = 100) { - duration_ms = constrain(duration_ms, 100, 1000); - - sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second - waitResponse(); - - sendAT(GF("+VTS="), cmd); - return waitResponse(10000L) == 1; - } - /* * Messaging functions */ - - String sendUSSD(const String& code) { - sendAT(GF("+CMGF=1")); - waitResponse(); - sendAT(GF("+CSCS=\"HEX\"")); - waitResponse(); - sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (waitResponse() != 1) { - return ""; - } - if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { - return ""; - } - stream.readStringUntil('"'); - String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CMGF=1")); - waitResponse(); - //Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } + protected: + // Follows all messaging functions per template /* * Location functions */ + protected: + // Can return a location from CIPGSMLOC as per the template - String getGsmLocation() { - sendAT(GF("+CIPGSMLOC=1,1")); - if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } + /* + * GPS location functions + */ + public: + // No functions of this type supported /* * Time functions */ - - String getGSMDateTime(TinyGSMDateTimeFormat format) { - sendAT(GF("+CCLK?")); - if (waitResponse(2000L, GF(GSM_NL "+CCLK: \"")) != 1) { - return ""; - } - - String res; - - switch(format) { - case DATE_FULL: - res = stream.readStringUntil('"'); - break; - case DATE_TIME: - streamSkipUntil(','); - res = stream.readStringUntil('"'); - break; - case DATE_DATE: - res = stream.readStringUntil(','); - break; - } - return res; - } + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip battery charge status - streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = stream.readStringUntil(',').toInt(); - // Wait for final OK - waitResponse(); - return res; - } - - int8_t getBattPercent() { - sendAT(GF("+CBC")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = stream.readStringUntil(',').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(); - // Wait for final OK - waitResponse(); - return res; - } - - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - sendAT(GF("+CBC?")); - if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { - return false; - } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil(',').toInt(); - milliVolts = stream.readStringUntil('\n').toInt(); - // Wait for final OK - waitResponse(); - return true; - } - - float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; + protected: + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * NTP server functions */ - + public: boolean isValidNumber(String str) { - if(!(str.charAt(0) == '+' || str.charAt(0) == '-' || isDigit(str.charAt(0)))) return false; + if (!(str.charAt(0) == '+' || str.charAt(0) == '-' || + isDigit(str.charAt(0)))) + return false; - for(byte i=1;i < str.length(); i++) { - if(!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) return false; + for (byte i = 1; i < str.length(); i++) { + if (!(isDigit(str.charAt(i)) || str.charAt(i) == '.')) { return false; } } return true; } String ShowNTPError(byte error) { switch (error) { - case 1: - return "Network time synchronization is successful"; - case 61: - return "Network error"; - case 62: - return "DNS resolution error"; - case 63: - return "Connection error"; - case 64: - return "Service response error"; - case 65: - return "Service response timeout"; - default: - return "Unknown error: " + String(error); + case 1: return "Network time synchronization is successful"; + case 61: return "Network error"; + case 62: return "DNS resolution error"; + case 63: return "Connection error"; + case 64: return "Service response error"; + case 65: return "Service response timeout"; + default: return "Unknown error: " + String(error); } } byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) { sendAT(GF("+CNTPCID=1")); - if (waitResponse(10000L) != 1) { - return -1; - } + if (waitResponse(10000L) != 1) { return -1; } sendAT(GF("+CNTP="), server, ',', String(TimeZone)); - if (waitResponse(10000L) != 1) { - return -1; - } + if (waitResponse(10000L) != 1) { return -1; } sendAT(GF("+CNTP")); if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) { - String result = stream.readStringUntil('\n'); - result.trim(); - if (isValidNumber(result)) - { - return result.toInt(); - } - } - else { + String result = stream.readStringUntil('\n'); + result.trim(); + if (isValidNumber(result)) { return result.toInt(); } + } else { return -1; } return -1; @@ -757,76 +461,69 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() /* * Client related functions */ - -protected: - + protected: bool modemConnect(const char* host, uint16_t port, uint8_t mux, - bool ssl = false, int timeout_s = 75) - { - int rsp; - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; + bool ssl = false, int timeout_s = 75) { + int rsp; + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; #if !defined(TINY_GSM_MODEM_SIM900) sendAT(GF("+CIPSSL="), ssl); rsp = waitResponse(); - if (ssl && rsp != 1) { - return false; - } + if (ssl && rsp != 1) { return false; } #endif - sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port); - rsp = waitResponse(timeout_ms, - GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), - GF("ALREADY CONNECT" GSM_NL), - GF("ERROR" GSM_NL), - GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails - ); + sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, + GF("\","), port); + rsp = waitResponse( + timeout_ms, GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL), GF("ERROR" GSM_NL), + GF("CLOSE OK" GSM_NL)); // Happens when HTTPS handshake fails return (1 == rsp); } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); - if (waitResponse(GF(">")) != 1) { - return 0; - } - stream.write((uint8_t*)buff, len); + if (waitResponse(GF(">")) != 1) { return 0; } + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux + if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux return stream.readStringUntil('\n').toInt(); } size_t modemRead(size_t size, uint8_t mux) { #ifdef TINY_GSM_USE_HEX sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #else sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); - if (waitResponse(GF("+CIPRXGET:")) != 1) { - return 0; - } + if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } #endif - streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX + streamSkipUntil(','); // Skip mux int len_requested = stream.readStringUntil(',').toInt(); // ^^ Requested number of data bytes (1-1460 bytes)to be read int len_confirmed = stream.readStringUntil('\n').toInt(); - // ^^ Confirmed number of data bytes to be read, which may be less than requested. - // 0 indicates that no data can be read. - // This is actually be the number of bytes that will be remaining after the read - for (int i=0; i_timeout)) { TINY_GSM_YIELD(); } - char buf[4] = { 0, }; + while (stream.available() < 2 && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char buf[4] = { + 0, + }; buf[0] = stream.read(); buf[1] = stream.read(); char c = strtol(buf, NULL, 16); #else - while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } + while (!stream.available() && + (millis() - startMillis < sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } char c = stream.read(); #endif sockets[mux]->rx.put(c); @@ -842,40 +539,36 @@ protected: sendAT(GF("+CIPRXGET=4,"), mux); size_t result = 0; if (waitResponse(GF("+CIPRXGET:")) == 1) { - streamSkipUntil(','); // Skip mode 4 - streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux result = stream.readStringUntil('\n').toInt(); waitResponse(); } DBG("### Available:", result, "on", mux); - if (!result) { - sockets[mux]->sock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } return result; } bool modemGetConnected(uint8_t mux) { sendAT(GF("+CIPSTATUS="), mux); waitResponse(GF("+CIPSTATUS")); - int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), - GF(",\"REMOTE CLOSING\""), GF(",\"INITIAL\"")); + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), + GF(",\"CLOSING\""), GF(",\"REMOTE CLOSING\""), + GF(",\"INITIAL\"")); waitResponse(); 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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -883,14 +576,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { + TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -922,15 +616,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; DBG("### Got Data:", len, "on", mux); } else if (data.endsWith(GF("CLOSED" GSM_NL))) { - int nl = data.lastIndexOf(GSM_NL, data.length()-8); - int coma = data.indexOf(',', nl+2); - int mux = data.substring(nl+2, coma).toInt(); + int nl = data.lastIndexOf(GSM_NL, data.length() - 8); + int coma = data.indexOf(',', nl + 2); + int mux = data.substring(nl + 2, coma).toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } @@ -939,38 +633,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientSim800* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTSIM800_H_ diff --git a/src/TinyGsmClientSIM808.h b/src/TinyGsmClientSIM808.h index 35754a0..9df90a7 100644 --- a/src/TinyGsmClientSIM808.h +++ b/src/TinyGsmClientSIM808.h @@ -6,34 +6,26 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSIM808_h -#define TinyGsmClientSIM808_h -//#pragma message("TinyGSM: TinyGsmClientSIM808") +#ifndef SRC_TINYGSMCLIENTSIM808_H_ +#define SRC_TINYGSMCLIENTSIM808_H_ +// #pragma message("TinyGSM: TinyGsmClientSIM808") #include - -class TinyGsmSim808: public TinyGsmSim800 -{ - -public: - - TinyGsmSim808(Stream& stream) - : TinyGsmSim800(stream) - {} +class TinyGsmSim808 : public TinyGsmSim800 { + public: + explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {} /* * GPS location functions */ - + public: // enable GPS bool enableGPS() { // uint16_t state; sendAT(GF("+CGNSPWR=1")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } @@ -42,9 +34,7 @@ public: // uint16_t state; sendAT(GF("+CGNSPWR=0")); - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return true; } @@ -53,9 +43,7 @@ public: // works only with ans SIM808 V2 String getGPSraw() { sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -64,23 +52,22 @@ public: // get GPS informations // works only with ans SIM808 V2 - bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) { - //String buffer = ""; + bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0, + int* vsat = 0, int* usat = 0) { + // String buffer = ""; // char chr_buffer[12]; bool fix = false; sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return false; - } - - stream.readStringUntil(','); // mode - if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; - stream.readStringUntil(','); //utctime - *lat = stream.readStringUntil(',').toFloat(); //lat - *lon = stream.readStringUntil(',').toFloat(); //lon - if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon - if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } + + stream.readStringUntil(','); // mode + if (stream.readStringUntil(',').toInt() == 1) fix = true; + stream.readStringUntil(','); // utctime + *lat = stream.readStringUntil(',').toFloat(); // lat + *lon = stream.readStringUntil(',').toFloat(); // lon + if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // lon + if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed stream.readStringUntil(','); stream.readStringUntil(','); stream.readStringUntil(','); @@ -88,8 +75,10 @@ public: stream.readStringUntil(','); stream.readStringUntil(','); stream.readStringUntil(','); - if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites - if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites + if (vsat != NULL) + *vsat = stream.readStringUntil(',').toInt(); // viewed satelites + if (usat != NULL) + *usat = stream.readStringUntil(',').toInt(); // used satelites stream.readStringUntil('\n'); waitResponse(); @@ -99,34 +88,31 @@ public: // get GPS time // works only with SIM808 V2 - bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) { + bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute, + int* second) { bool fix = false; char chr_buffer[12]; sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } for (int i = 0; i < 3; i++) { String buffer = stream.readStringUntil(','); buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); switch (i) { case 0: - //mode + // mode break; case 1: - //fixstatus - if ( buffer.toInt() == 1 ) { - fix = buffer.toInt(); - } + // fixstatus + if (buffer.toInt() == 1) { fix = buffer.toInt(); } break; case 2: - *year = buffer.substring(0,4).toInt(); - *month = buffer.substring(4,6).toInt(); - *day = buffer.substring(6,8).toInt(); - *hour = buffer.substring(8,10).toInt(); - *minute = buffer.substring(10,12).toInt(); - *second = buffer.substring(12,14).toInt(); + *year = buffer.substring(0, 4).toInt(); + *month = buffer.substring(4, 6).toInt(); + *day = buffer.substring(6, 8).toInt(); + *hour = buffer.substring(8, 10).toInt(); + *minute = buffer.substring(10, 12).toInt(); + *second = buffer.substring(12, 14).toInt(); break; default: @@ -135,7 +121,7 @@ public: break; } } - String res = stream.readStringUntil('\n'); + stream.readStringUntil('\n'); waitResponse(); if (fix) { @@ -144,7 +130,6 @@ public: return false; } } - }; -#endif +#endif // SRC_TINYGSMCLIENTSIM808_H_ diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index afb35ba..7a130f9 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -6,32 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientSaraR4_h -#define TinyGsmClientSaraR4_h -//#pragma message("TinyGSM: TinyGsmClientSaraR4") +#ifndef SRC_TINYGSMCLIENTSARAR4_H_ +#define SRC_TINYGSMCLIENTSARAR4_H_ +// #pragma message("TinyGSM: TinyGsmClientSaraR4") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 7 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -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_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; - enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -40,185 +31,157 @@ enum RegStatus { REG_UNKNOWN = 4, }; +class TinyGsmSaraR4 : public TinyGsmModem { + friend class TinyGsmModem; -class TinyGsmSaraR4 -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSaraR4; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} + /* + * Inner Client + */ + public: + class GsmClientSaraR4 : public GsmClient { + friend class TinyGsmSaraR4; - GsmClient(TinyGsmSaraR4& modem, uint8_t mux = 0) { init(&modem, mux); } + public: + GsmClientSaraR4() {} - virtual ~GsmClient(){} + explicit GsmClientSaraR4(TinyGsmSaraR4& modem, uint8_t mux = 0) { + init(&modem, mux); + } - bool init(TinyGsmSaraR4* modem, uint8_t mux = 0) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + bool init(TinyGsmSaraR4* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - at->sockets[mux] = this; + at->sockets[mux] = this; - return true; - } + return true; + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); - uint8_t oldMux = mux; - sock_connected = at->modemConnect(host, port, &mux, false, timeout_s); - if (mux != oldMux) { + uint8_t oldMux = mux; + sock_connected = at->modemConnect(host, port, &mux, false, timeout_s); + if (mux != oldMux) { DBG("WARNING: Mux number changed from", oldMux, "to", mux); at->sockets[oldMux] = NULL; + } + at->sockets[mux] = this; + at->maintain(); + + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 120); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 120); + } + + void stop(uint32_t maxWaitMs) { + uint32_t startMillis = millis(); + dumpModemBuffer(maxWaitMs); + // We want to use an async socket close because the syncrhonous close of + // an open socket is INCREDIBLY SLOW and the modem can freeze up. But we + // only attempt the async close if we already KNOW the socket is open + // because calling the async close on a closed socket and then attempting + // opening a new socket causes the board to lock up for 2-3 minutes and + // then finally return with a "new" socket that is immediately closed. + // Attempting to close a socket that is already closed with a synchronous + // close quickly returns an error. + if (at->supportsAsyncSockets && sock_connected) { + DBG("### Closing socket asynchronously! Socket might remain open " + "until arrival of +UUSOCL:", + mux); + // faster asynchronous close + // NOT supported on SARA-R404M / SARA-R410M-01B + at->sendAT(GF("+USOCL="), mux, GF(",1")); + // NOTE: can take up to 120s to get a response + at->waitResponse((maxWaitMs - (millis() - startMillis))); + // We set the sock as disconnected right away because it can no longer + // be used + sock_connected = false; + } else { + // synchronous close + at->sendAT(GF("+USOCL="), mux); + // NOTE: can take up to 120s to get a response + at->waitResponse((maxWaitMs - (millis() - startMillis))); + sock_connected = false; + } } - at->sockets[mux] = this; - at->maintain(); - - return sock_connected; - } - virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { - String host; - host.reserve(16); - host += ip[0]; - host += "."; - host += ip[1]; - host += "."; - host += ip[2]; - host += "."; - host += ip[3]; - return connect(host.c_str(), port, timeout_s); - } - virtual int connect(const char* host, uint16_t port) { - return connect(host, port, 120); - } - virtual int connect(IPAddress ip, uint16_t port) { - return connect(ip, port, 120); - } - - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - // We want to use an async socket close because the syncrhonous close of an - // open socket is INCREDIBLY SLOW and the modem can freeze up. But we only - // attempt the async close if we already KNOW the socket is open because - // calling the async close on a closed socket and then attempting opening a - // new socket causes the board to lock up for 2-3 minutes and then finally - // return with a "new" socket that is immediately closed. - // Attempting to close a socket that is already closed with a synchronous - // close quickly returns an error. - if (at->supportsAsyncSockets && sock_connected) { - DBG("### Closing socket asynchronously! Socket might remain open " - "until arrival of +UUSOCL:", - mux); - // faster asynchronous close - // NOT supported on SARA-R404M / SARA-R410M-01B - at->sendAT(GF("+USOCL="), mux, GF(",1")); - // NOTE: can take up to 120s to get a response - at->waitResponse((maxWaitMs - (millis() - startMillis))); - // We set the sock as disconnected right away because it can no longer - // be used - sock_connected = false; - } else { - // synchronous close - at->sendAT(GF("+USOCL="), mux); - // NOTE: can take up to 120s to get a response - at->waitResponse((maxWaitMs - (millis() - startMillis))); - sock_connected = false; + void stop() override { + stop(135000L); } - } - virtual void stop() { stop(135000L); } + /* + * Extended API + */ -TINY_GSM_CLIENT_WRITE() - -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() - -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() - -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* - * Extended API + * Inner Secure Client */ + public: + class GsmClientSecureR4 : public GsmClientSaraR4 { + public: + GsmClientSecureR4() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmSaraR4* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmSaraR4& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} - - virtual ~GsmClientSecure(){} + explicit GsmClientSecureR4(TinyGsmSaraR4& modem, uint8_t mux = 1) + : GsmClientSaraR4(modem, mux) {} -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - uint8_t oldMux = mux; - sock_connected = at->modemConnect(host, port, &mux, true, timeout_s); - if (mux != oldMux) { + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + uint8_t oldMux = mux; + sock_connected = at->modemConnect(host, port, &mux, true, timeout_s); + if (mux != oldMux) { DBG("WARNING: Mux number changed from", oldMux, "to", mux); at->sockets[oldMux] = NULL; + } + at->sockets[mux] = this; + at->maintain(); + return sock_connected; } - at->sockets[mux] = this; - at->maintain(); - return sock_connected; - } -}; - + }; -public: - - TinyGsmSaraR4(Stream& stream) - : stream(stream) - { + /* + * Constructor + */ + public: + explicit TinyGsmSaraR4(Stream& stream) + : stream(stream), + has2GFallback(false), + supportsAsyncSockets(false) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -241,33 +204,33 @@ public: supportsAsyncSockets = true; } + // Enable automatic time zome update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); return (getSimStatus() == SIM_READY); - } - // if the sim is ready, or it's locked but no pin has been provided,return - // 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); } } - String getModemName() { + // only difference in implementation is the warning on the wrong type + String getModemNameImpl() { sendAT(GF("+CGMI")); String res1; - if (waitResponse(1000L, res1) != 1) { - return "u-blox Cellular Modem"; - } + if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; } res1.replace(GSM_NL "OK" GSM_NL, ""); res1.trim(); sendAT(GF("+GMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return "u-blox Cellular Modem"; - } + if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.trim(); @@ -281,108 +244,65 @@ public: return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { + bool factoryDefaultImpl() { sendAT(GF("&F")); // Resets the current profile, other NVM not affected return waitResponse() == 1; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { + bool thisHasSSL() { return true; } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + // using +CFUN=15 instead of the more common CFUN=1,1 + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=15")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); // TODO: Verify delay timing here + if (waitResponse(10000L) != 1) { return false; } + delay(3000); // TODO(?): Verify delay timing here return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPWROFF")); return waitResponse(40000L) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; - } - - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - - String getIMEI() { + protected: + // This uses "CGSN" instead of "GSN" + String getIMEIImpl() { sendAT(GF("+CGSN")); - if (waitResponse(GF(GSM_NL)) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL)) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); return res; } - 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"), - GF("NOT INSERTED")); - waitResponse(); - switch (status) { - case 2: - case 3: return SIM_LOCKED; - case 1: return SIM_READY; - default: return SIM_ERROR; - } - } - return SIM_ERROR; - } - + /* + * Generic network functions + */ + public: RegStatus getRegistrationStatus() { // Check first for EPS registration sendAT(GF("+CEREG?")); - if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { - return REG_UNKNOWN; - } + if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { return REG_UNKNOWN; } streamSkipUntil(','); /* Skip format (0) */ int status = stream.readStringUntil('\n').toInt(); waitResponse(); @@ -394,64 +314,43 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID() } else { // Otherwise, check generic network status sendAT(GF("+CREG?")); - if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { - return REG_UNKNOWN; - } + if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { return REG_UNKNOWN; } streamSkipUntil(','); /* Skip format (0) */ - int status = stream.readStringUntil('\n').toInt(); + status = stream.readStringUntil('\n').toInt(); waitResponse(); return (RegStatus)status; } } - TINY_GSM_MODEM_GET_OPERATOR_COPS() - - /* - * Generic network functions - */ - -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); - if (s == REG_OK_HOME || s == REG_OK_ROAMING) - return true; - // else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown.. - // return isGprsConnected(); - else return false; + return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - + public: bool setURAT(uint8_t urat) { // AT+URAT=[,[,<2ndPreferredAct>]] sendAT(GF("+COPS=2")); // Deregister from network - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } sendAT(GF("+URAT="), urat); // Radio Access Technology (RAT) selection - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } sendAT(GF("+COPS=0")); // Auto-register to the network - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } return restart(); } /* * 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(); sendAT(GF("+CGATT=1")); // attach to GPRS - if (waitResponse(360000L) != 1) { - return false; - } + if (waitResponse(360000L) != 1) { return false; } // Using CGDCONT sets up an "external" PCP context, i.e. a data connection // using the external IP stack (e.g. Windows dial up) and PPP link over the @@ -468,21 +367,17 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(); sendAT(GF("+CGACT=1,1")); // activate PDP profile/context 1 - if (waitResponse(150000L) != 1) { - return false; - } + if (waitResponse(150000L) != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { // Mark all the sockets as closed // This ensures that asynchronously closed sockets are marked closed for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { - GsmClient* sock = sockets[mux]; - if (sock && sock->sock_connected) { - sock->sock_connected = false; - } + GsmClientSaraR4* sock = sockets[mux]; + if (sock && sock->sock_connected) { sock->sock_connected = false; } } // sendAT(GF("+CGACT=0,1")); // Deactivate PDP context 1 @@ -492,81 +387,44 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() } sendAT(GF("+CGATT=0")); // detach from GPRS - if (waitResponse(360000L) != 1) { - return false; - } + if (waitResponse(360000L) != 1) { return false; } return true; } -TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() - /* * IP Address functions */ - - String getLocalIP() { - sendAT(GF("+CGPADDR")); - if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) { - return ""; - } - streamSkipUntil(','); // Skip context id - String res = stream.readStringUntil('\r'); - if (waitResponse() != 1) { - return ""; - } - return res; - } - - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } + protected: + // Can follow the template in all function /* * Phone Call functions */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + // While the AT commands for call answer and hang-up are nominally supported, + // no voice calls are supported rendering them meaningless + bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; + bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; /* * Messaging functions */ - - String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CSCS=\"GSM\"")); // Set GSM default alphabet - waitResponse(); - sendAT(GF("+CMGF=1")); // Set preferred message format to text mode - waitResponse(); - sendAT(GF("+CMGS=\""), number, GF("\"")); // set the phone number - if (waitResponse(GF(">")) != 1) { - return false; - } - stream.print(text); // Actually send the message - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - - bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; - + protected: + String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sendSMS_UTF16Impl(const String& number, const void* text, + size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * Location functions */ - - String getGsmLocation() { + protected: + String getGsmLocationImpl() { sendAT(GF("+ULOC=2,3,0,120,1")); - if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { - return ""; - } + if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -574,68 +432,71 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() } /* - * Battery & temperature functions + * GPS location functions */ + public: + // No functions of this type supported - uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template - int8_t getBattPercent() { + /* + * Battery & temperature functions + */ + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + + int8_t getBattPercentImpl() { sendAT(GF("+CIND?")); - if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; } - int res = stream.readStringUntil(',').toInt(); - int8_t percent = res*20; // return is 0-5 + int res = stream.readStringUntil(',').toInt(); + int8_t percent = res * 20; // return is 0-5 // Wait for final OK waitResponse(); return percent; } - uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { - percent = getBattPercent(); + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { chargeState = 0; - milliVolts = 0; + percent = getBattPercent(); + milliVolts = 0; return true; } - float getTemperature() { + float getTemperatureImpl() { // First make sure the temperature is set to be in celsius sendAT(GF("+UTEMP=0")); // Would use 1 for Fahrenheit - if (waitResponse() != 1) { - return (float)-9999; - } + if (waitResponse() != 1) { return static_cast(-9999); } sendAT(GF("+UTEMP?")); if (waitResponse(GF(GSM_NL "+UTEMP:")) != 1) { - return (float)-9999; - } - int16_t res = stream.readStringUntil('\n').toInt(); - float temp = -9999; - if (res != -1) { - temp = ((float)res)/10; + return static_cast(-9999); } + int16_t res = stream.readStringUntil('\n').toInt(); + float temp = -9999; + if (res != -1) { temp = (static_cast(res)) / 10; } return temp; } /* * Client related functions */ - -protected: - + protected: bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false, int timeout_s = 120) { - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; - unsigned long startMillis = millis(); + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + uint32_t startMillis = millis(); // create a socket sendAT(GF("+USOCR=6")); // reply is +USOCR: ## of socket created - if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { - return false; - } + if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { return false; } *mux = stream.readStringUntil('\n').toInt(); waitResponse(); @@ -668,35 +529,33 @@ protected: DBG("### Opening socket asynchronously! Socket cannot be used until " "the URC '+UUSOCO' appears."); sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); - if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO:")) == 1) { + if (waitResponse(timeout_ms - (millis() - startMillis), + GF(GSM_NL "+UUSOCO:")) == 1) { stream.readStringUntil(',').toInt(); // skip repeated mux int connection_status = stream.readStringUntil('\n').toInt(); DBG("### Waited", millis() - startMillis, "ms for socket to open"); return (0 == connection_status); } else { - DBG("### Waited", millis() - startMillis, "but never got socket open notice"); + DBG("### Waited", millis() - startMillis, + "but never got socket open notice"); return false; } } else { // use synchronous open sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); - int rsp = waitResponse(timeout_ms); + int rsp = waitResponse(timeout_ms - (millis() - startMillis)); return (1 == rsp); } } int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+USOWR="), mux, ',', (uint16_t)len); - if (waitResponse(GF("@")) != 1) { - return 0; - } + if (waitResponse(GF("@")) != 1) { return 0; } // 50ms delay, see AT manual section 25.10.4 delay(50); - stream.write((uint8_t*)buff, len); + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; } streamSkipUntil(','); // Skip mux int sent = stream.readStringUntil('\n').toInt(); waitResponse(); // sends back OK after the confirmation of number sent @@ -705,16 +564,12 @@ protected: size_t modemRead(size_t size, uint8_t mux) { sendAT(GF("+USORD="), mux, ',', (uint16_t)size); - if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; } streamSkipUntil(','); // Skip mux int len = stream.readStringUntil(',').toInt(); streamSkipUntil('\"'); - for (int i=0; isock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } DBG("### AVAILABLE:", result, "on", mux); return result; } @@ -746,7 +599,7 @@ protected: // NOTE: Querying a closed socket gives an error "operation not allowed" sendAT(GF("+USOCTL="), mux, ",10"); uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:")); - if (res != 1) return false; + if (res != 1) { return false; } streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip type @@ -767,20 +620,16 @@ protected: return (result != 0); } -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 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { + public: + // TODO(vshymanskyy): Optimize this! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -788,15 +637,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -819,7 +668,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; @@ -832,7 +681,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() data = ""; DBG("### URC Sock Closed: ", mux); } else if (data.endsWith(GF("+UUSOCO:"))) { - int mux = stream.readStringUntil('\n').toInt(); + int mux = stream.readStringUntil('\n').toInt(); int socket_error = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] && socket_error == 0) { @@ -843,12 +692,10 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } // data.replace(GSM_NL, "/"); @@ -856,8 +703,7 @@ finish: return index; } - uint8_t waitResponse(uint32_t timeout_ms, - GsmConstStr r1 = GFP(GSM_OK), + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { @@ -865,20 +711,19 @@ finish: 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 = GFP(GSM_CME_ERROR), - GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; - bool has2GFallback; - bool supportsAsyncSockets; + protected: + Stream& stream; + GsmClientSaraR4* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; + bool has2GFallback; + bool supportsAsyncSockets; }; -#endif +#endif // SRC_TINYGSMCLIENTSARAR4_H_ diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index c333ed1..31dfcae 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -6,30 +6,22 @@ * @date Jan 2019 */ -#ifndef TinyGsmClientSequansMonarch_h -#define TinyGsmClientSequansMonarch_h +#ifndef SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ +#define SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 6 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; -static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; +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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -48,156 +40,144 @@ enum SocketStatus { SOCK_OPENING = 6, }; - class TinyGsmSequansMonarch -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmSequansMonarch; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} - - GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) { - init(&modem, mux); - } + : public TinyGsmModem { + friend class TinyGsmModem; - virtual ~GsmClient() {} - - bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + /* + * Inner Client + */ + public: + class GsmClientSequansMonarch : public GsmClient { + friend class TinyGsmSequansMonarch; - // adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers - // using modulus will force 6 back to 0 - at->sockets[mux % TINY_GSM_MUX_COUNT] = this; + public: + GsmClientSequansMonarch() {} - return true; - } - -public: - virtual int connect(const char* host, uint16_t port, int timeout_s) { - if (sock_connected) stop(); - TINY_GSM_YIELD(); - rx.clear(); - sock_connected = at->modemConnect(host, port, mux, false, timeout_s); - return sock_connected; - } + explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem, + uint8_t mux = 1) { + init(&modem, mux); + } -TINY_GSM_CLIENT_CONNECT_OVERLOADS() + bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+SQNSH="), mux); - sock_connected = false; - at->waitResponse(); - } + // adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers + // using modulus will force 6 back to 0 + at->sockets[mux % TINY_GSM_MUX_COUNT] = this; - virtual void stop() { stop(15000L); } + return true; + } -TINY_GSM_CLIENT_WRITE() + public: + int connect(const char* host, uint16_t port, int timeout_s) { + if (sock_connected) stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+SQNSH="), mux); + sock_connected = false; + at->waitResponse(); + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * Extended API + */ -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* - * Extended API + * Inner Secure Client */ + public: + class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch { + public: + GsmClientSecureSequansMonarch() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem, + uint8_t mux = 1) + : GsmClientSequansMonarch(modem, mux) {} -private: - TinyGsmSequansMonarch* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - class GsmClientSecure : public GsmClient { -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} - - virtual ~GsmClientSecure() {} - -protected: + protected: bool strictSSL = false; -public: - virtual int connect(const char* host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - - // configure security profile 1 with parameters: - if (strictSSL) { - // require minimum of TLS 1.2 (3) - // only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256 - // verify server certificate against imported CA certs 0 and enforce - // validity period (3) - at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\"")); - } else { - // use TLS 1.0 or higher (1) - // support wider variety of cipher suites - // do not verify server certificate (0) - at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\"")); - } - if (at->waitResponse() != 1) { - DBG("failed to configure security profile"); - return false; - } - - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + + // configure security profile 1 with parameters: + if (strictSSL) { + // require minimum of TLS 1.2 (3) + // only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256 + // verify server certificate against imported CA certs 0 and enforce + // validity period (3) + at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\"")); + } else { + // use TLS 1.0 or higher (1) + // support wider variety of cipher suites + // do not verify server certificate (0) + at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\"")); + } + if (at->waitResponse() != 1) { + DBG("failed to configure security profile"); + return false; + } - void setStrictSSL(bool strict) { - strictSSL = strict; - } + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } -}; + void setStrictSSL(bool strict) { + strictSSL = strict; + } + }; -public: - TinyGsmSequansMonarch(Stream& stream) : stream(stream) { + /* + * Constructor + */ + public: + explicit TinyGsmSequansMonarch(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } /* * 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); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -209,133 +189,87 @@ public: DBG(GF("### Modem:"), getModemName()); // Make sure the module is enabled. Unlike others, the VZN20Q powers on - // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full functionality - // The module cannot even detect the sim card if the cellular functionality is disabled so - // unless we explicitly enable the functionality the init will fail. + // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full + // functionality The module cannot even detect the sim card if the cellular + // functionality is disabled so unless we explicitly enable the + // functionality the init will fail. sendAT(GF("+CFUN=1")); waitResponse(); + // Enable automatic time zome update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { - // return "Sequans Monarch"; - sendAT(GF("+CGMI")); - String res1; - if (waitResponse(1000L, res1) != 1) { - return "u-blox Cellular Modem"; - } - res1.replace(GSM_NL "OK" GSM_NL, ""); - res1.trim(); - - sendAT(GF("+CGMM")); - String res2; - if (waitResponse(1000L, res2) != 1) { - return "u-blox Cellular Modem"; - } - res2.replace(GSM_NL "OK" GSM_NL, ""); - res2.trim(); - - String name = res1 + String(' ') + res2; - return name; - } - -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - - void maintain() { + void maintainImpl() { for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) { - GsmClient* sock = sockets[mux % TINY_GSM_MUX_COUNT]; + GsmClientSequansMonarch* sock = sockets[mux % TINY_GSM_MUX_COUNT]; if (sock && sock->got_data) { - sock->got_data = false; + sock->got_data = false; sock->sock_available = modemGetAvailable(mux); // modemGetConnected() always checks the state of ALL socks modemGetConnected(); } } - while (stream.available()) { - waitResponse(15, NULL, NULL); - } + while (stream.available()) { waitResponse(15, NULL, NULL); } } - bool factoryDefault() { - sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - waitResponse(); - sendAT(GF("+IPR=0")); // Auto-baud - waitResponse(); - sendAT(GF("+IFC=0,0")); // No Flow Control - waitResponse(); - sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop - waitResponse(); - sendAT(GF("+CSCLK=0")); // Disable Slow Clock - waitResponse(); - sendAT(GF("&W")); // Write configuration - return waitResponse() == 1; + bool thisHasGPRS() { + return true; } -TINY_GSM_MODEM_GET_INFO_ATI() + bool thisHasWifi() { + return false; + } - bool hasSSL() { + bool thisHasSSL() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=0")); - int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ; - if (res != 1 && res != 3) { - return false; - } + int res = + waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")); + if (res != 1 && res != 3) { return false; } sendAT(GF("+CFUN=1,1")); res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)); - if (res != 1 && res != 3) { - return false; - } + if (res != 1 && res != 3) { return false; } delay(1000); return init(); } - bool poweroff() { + bool powerOffImpl() { + // NOTE: The only way to turn the modem back on after this shutdown is with + // a hard reset sendAT(GF("+SQNSSHDN")); return waitResponse(); } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; - } - - /* - When power saving is enabled, UART0 interface is activated with sleep mode support. - Module power state is controlled by RTS0 line. When no activity on UART, CTS line - will be set to OFF state (driven high level) milliseconds (100ms to 10s, - default 5s) after the last sent character, then module will go to sleep mode as soon - as DTE set RTS line to OFF state (driver high level). - */ - bool sleepEnable(bool enable = true) { + // When power saving is enabled, UART0 interface is activated with sleep mode + // support. Module power state is controlled by RTS0 line. When no activity + // on UART, CTS line will be set to OFF state (driven high level) + // milliseconds (100ms to 10s, default 5s) after the last sent character, + // then module will go to sleep mode as soon as DTE set RTS line to OFF state + // (driver high level). + bool sleepEnableImpl(bool enable = true) { sendAT(GF("+SQNIPSCFG="), enable); return waitResponse() == 1; } @@ -343,68 +277,36 @@ TINY_GSM_MODEM_GET_INFO_ATI() /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - - String getSimCCID() { + protected: + String getSimCCIDImpl() { sendAT(GF("+SQNCCID")); - if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 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"), GF("NOT INSERTED")); - 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(CEREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CEREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); - if (s == REG_OK_HOME || s == REG_OK_ROAMING) { - // DBG(F("connected with status:"), s); - return true; - } else { - return false; - } + return (s == REG_OK_HOME || s == REG_OK_ROAMING); } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); // Define the PDP context (This uses context #3!) @@ -423,123 +325,89 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // Attach to GPRS sendAT(GF("+CGATT=1")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } return true; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { sendAT(GF("+CGATT=0")); - if (waitResponse(60000L) != 1) - return false; + if (waitResponse(60000L) != 1) { return false; } return true; } - 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 true; - } - - /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+CGPADDR=3")); - if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { - return ""; - } + if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; } String res = stream.readStringUntil('\"'); waitResponse(); return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - - /* * Phone Call functions */ + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CMGF=1")); - waitResponse(); - // Set GSM 7 bit default alphabet (3GPP TS 23.038) - sendAT(GF("+CSCS=\"GSM\"")); - 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; - } - - bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; + /* + * Messaging functions + */ + protected: + // Follows all messaging functions per template /* * Location functions */ + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * GPS location functions + */ + public: + // No functions of this type supported + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template /* * Battery & temperature functions */ - - 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() { + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; + + float getTemperatureImpl() { sendAT(GF("+SMDTH")); if (waitResponse(10000L, GF("+SMDTH: ")) != 1) { - return (float)-9999; + return static_cast(-9999); } String res; - if (waitResponse(1000L, res) != 1) { - return (float)-9999; - } - if (res.indexOf("ERROR") >= 0) { - return (float)-9999; - } + if (waitResponse(1000L, res) != 1) { return static_cast(-9999); } + if (res.indexOf("ERROR") >= 0) { return static_cast(-9999); } return res.toFloat(); } -protected: + protected: bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false, int timeout_s = 75) { - int rsp; - unsigned long startMillis = millis(); - uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; + int rsp; + uint32_t startMillis = millis(); + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; if (ssl) { // enable SSl and use security profile 1 @@ -552,24 +420,28 @@ protected: } // Socket configuration - //AT+SQNSCFG:, , , , , + // AT+SQNSCFG:, , , , , // = Connection ID = mux - // = PDP context ID = 3 - this is number set up above in the GprsConnect function + // = PDP context ID = 3 - this is number set up above in the + // GprsConnect function // = Packet Size, used for online data mode only = 300 (default) // = Max timeout in seconds = 90 (default) - // = Connection timeout in hundreds of milliseconds = 600 (default) - // = Data sending timeout in hundreds of milliseconds, used for online data mode only = 50 (default) + // = Connection timeout in hundreds of milliseconds + // = 600 (default) + // = Data sending timeout in hundreds of milliseconds, + // used for online data mode only = 50 (default) sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50")); waitResponse(5000L); // Socket configuration extended - //AT+SQNSCFGEXT:, , , , , + // AT+SQNSCFGEXT:, , , , + // , // = Connection ID = mux // = Send/Receive URC model = 1 - data amount mode - // = Receive data mode = 0 - data as text (1 would be as hex) + // = Receive data mode = 0 - data as text (1 for hex) // = unused = 0 // = Listen auto-response mode = 0 - deactivated - // = Send data mode = 0 - data as text (1 would be as hex) + // = Send data mode = 0 - data as text (1 for hex) sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0")); waitResponse(5000L); @@ -578,20 +450,20 @@ protected: // = Connection ID = mux // = Transmission protocol = 0 - TCP (1 for UDP) // = Remote host port to contact - // = Any valid IP address in the format “xxx.xxx.xxx.xxx” or any host name solved with a DNS query - // = Socket closure behaviour for TCP, has no effect for UDP = 0 - local port closes when remote does (default) + // = Any valid IP address in the format “xxx.xxx.xxx.xxx” or any + // host name solved with a DNS query + // = Socket closure behaviour for TCP, has no effect for UDP + // = 0 - local port closes when remote does (default) // = UDP connection local port, has no effect for TCP connections. // = Connection mode = 1 - command mode connection // = Applies to UDP only - sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), ",0,0,1"); - rsp = waitResponse((timeout_ms - (millis() - startMillis)), - GFP(GSM_OK), - GFP(GSM_ERROR), - GF("NO CARRIER" GSM_NL) - ); + sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), + ",0,0,1"); + rsp = waitResponse((timeout_ms - (millis() - startMillis)), GFP(GSM_OK), + GFP(GSM_ERROR), GF("NO CARRIER" GSM_NL)); // creation of socket failed immediately. - if (rsp != 1) return false; + if (rsp != 1) { return false; } // wait until we get a good status bool connected = false; @@ -602,7 +474,6 @@ protected: return connected; } - int modemSend(const void* buff, size_t len, uint8_t mux) { if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) { DBG("### Sock closed, cannot send data!"); @@ -611,7 +482,7 @@ protected: sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len); waitResponse(10000L, GF(GSM_NL "> ")); - stream.write((uint8_t*)buff, len); + stream.write(reinterpret_cast(buff), len); stream.flush(); if (waitResponse() != 1) { DBG("### no OK after send"); @@ -630,8 +501,8 @@ protected: // delay(50); // } // if (gotPrompt) { - // stream.write((uint8_t*)buff, len); - // stream.write((char)0x1A); + // stream.write(reinterpret_cast(buff), len); + // stream.write(reinterpret_cast0x1A); // stream.flush(); // if (waitResponse() != 1) { // DBG("### no OK after send"); @@ -642,12 +513,9 @@ protected: // return 0; } - size_t modemRead(size_t size, uint8_t mux) { sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size); - if (waitResponse(GF("+SQNSRECV: ")) != 1) { - return 0; - } + if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; } streamSkipUntil(','); // Skip mux int len = stream.readStringUntil('\n').toInt(); for (int i = 0; i < len; i++) { @@ -670,9 +538,9 @@ protected: sendAT(GF("+SQNSI="), mux); size_t result = 0; if (waitResponse(GF("+SQNSI:")) == 1) { - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip total sent - streamSkipUntil(','); // Skip total received + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip total sent + streamSkipUntil(','); // Skip total received result = stream.readStringUntil(',').toInt(); // keep data not yet read waitResponse(); } @@ -685,9 +553,7 @@ protected: // six possible sockets. sendAT(GF("+SQNSS")); for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { - if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { - break; - }; + if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; } uint8_t status = 0; // if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no // DBG("### Warning: misaligned mux numbers!"); @@ -704,26 +570,24 @@ protected: // SOCK_LISTENING = 4, // SOCK_INCOMING = 5, // SOCK_OPENING = 6, - sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \ - ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING)); + sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = + ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && + (status != SOCK_OPENING)); } waitResponse(); // Should be an OK at the end return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected; } -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! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -731,15 +595,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -760,7 +624,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { - sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true; + sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true; sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len; } data = ""; @@ -776,12 +640,10 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } // data.replace(GSM_NL, "/"); @@ -790,23 +652,24 @@ finish: } uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ diff --git a/src/TinyGsmClientUBLOX.h b/src/TinyGsmClientUBLOX.h index c35f10f..de27737 100644 --- a/src/TinyGsmClientUBLOX.h +++ b/src/TinyGsmClientUBLOX.h @@ -6,32 +6,23 @@ * @date Nov 2016 */ -#ifndef TinyGsmClientUBLOX_h -#define TinyGsmClientUBLOX_h -//#pragma message("TinyGSM: TinyGsmClientUBLOX") +#ifndef SRC_TINYGSMCLIENTUBLOX_H_ +#define SRC_TINYGSMCLIENTUBLOX_H_ +// #pragma message("TinyGSM: TinyGsmClientUBLOX") -//#define TINY_GSM_DEBUG Serial - -#if !defined(TINY_GSM_RX_BUFFER) - #define TINY_GSM_RX_BUFFER 64 -#endif +// #define TINY_GSM_DEBUG Serial #define TINY_GSM_MUX_COUNT 7 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r\n" -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_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, -}; - enum RegStatus { + REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, @@ -40,127 +31,115 @@ enum RegStatus { REG_UNKNOWN = 4, }; - class TinyGsmUBLOX -{ + : public TinyGsmModem { + friend class TinyGsmModem; -public: - -class GsmClient : public Client -{ - friend class TinyGsmUBLOX; - typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} + /* + * Inner Client + */ + public: + class GsmClientUBLOX : public GsmClient { + friend class TinyGsmUBLOX; - GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) { - init(&modem, mux); - } + public: + GsmClientUBLOX() {} - virtual ~GsmClient(){} + explicit GsmClientUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0) { + init(&modem, mux); + } - bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) { - this->at = modem; - this->mux = mux; - sock_available = 0; - prev_check = 0; - sock_connected = false; - got_data = false; + bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; - at->sockets[mux] = this; + at->sockets[mux] = this; - return true; - } + return true; + } -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); - uint8_t oldMux = mux; - sock_connected = at->modemConnect(host, port, &mux, false, timeout_s); - if (mux != oldMux) { + uint8_t oldMux = mux; + sock_connected = at->modemConnect(host, port, &mux, false, timeout_s); + if (mux != oldMux) { DBG("WARNING: Mux number changed from", oldMux, "to", mux); at->sockets[oldMux] = NULL; - } - at->sockets[mux] = this; - at->maintain(); - - return sock_connected; - } - -TINY_GSM_CLIENT_CONNECT_OVERLOADS() - - virtual void stop(uint32_t maxWaitMs) { - TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() - at->sendAT(GF("+USOCL="), mux); - at->waitResponse(); // should return within 1s - sock_connected = false; - } - - virtual void stop() { stop(15000L); } + } + at->sockets[mux] = this; + at->maintain(); -TINY_GSM_CLIENT_WRITE() + return sock_connected; + } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 75); + } -TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() + void stop(uint32_t maxWaitMs) { + dumpModemBuffer(maxWaitMs); + at->sendAT(GF("+USOCL="), mux); + at->waitResponse(); // should return within 1s + sock_connected = false; + } + void stop() override { + stop(15000L); + } -TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() + /* + * Extended API + */ -TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; /* - * Extended API + * Inner Secure Client */ + public: + class GsmClientSecureUBLOX : public GsmClientUBLOX { + public: + GsmClientSecureUBLOX() {} - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmUBLOX* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; -}; - - -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} - - GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1) - : GsmClient(modem, mux) - {} + explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 1) + : GsmClientUBLOX(modem, mux) {} - virtual ~GsmClientSecure(){} - -public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { - stop(); - TINY_GSM_YIELD(); - rx.clear(); - uint8_t oldMux = mux; - sock_connected = at->modemConnect(host, port, &mux, true, timeout_s); - if (mux != oldMux) { + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + uint8_t oldMux = mux; + sock_connected = at->modemConnect(host, port, &mux, true, timeout_s); + if (mux != oldMux) { DBG("WARNING: Mux number changed from", oldMux, "to", mux); at->sockets[oldMux] = NULL; + } + at->sockets[mux] = this; + at->maintain(); + return sock_connected; } - at->sockets[mux] = this; - at->maintain(); - return sock_connected; - } -}; + }; - -public: - - TinyGsmUBLOX(Stream& stream) - : stream(stream) - { + /* + * Constructor + */ + public: + explicit TinyGsmUBLOX(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); } @@ -168,21 +147,13 @@ public: * Basic functions */ - bool begin(const char* pin = NULL) { - return init(pin); - } - - bool init(const char* pin = NULL) { + bool initImpl(const char* pin = NULL) { DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); - if (!testAT()) { - return false; - } + if (!testAT()) { return false; } - sendAT(GF("E0")); // Echo Off - if (waitResponse() != 1) { - return false; - } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { return false; } #ifdef TINY_GSM_DEBUG sendAT(GF("+CMEE=2")); // turn on verbose error codes @@ -193,176 +164,127 @@ public: getModemName(); + // Enable automatic time zome update + sendAT(GF("+CTZU=1")); + if (waitResponse(10000L) != 1) { return false; } + int ret = getSimStatus(); // 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) { simUnlock(pin); 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); } } - String getModemName() { + String getModemNameImpl() { sendAT(GF("+CGMI")); String res1; - if (waitResponse(1000L, res1) != 1) { - return "u-blox Cellular Modem"; - } + if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; } res1.replace(GSM_NL "OK" GSM_NL, ""); res1.trim(); sendAT(GF("+GMM")); String res2; - if (waitResponse(1000L, res2) != 1) { - return "u-blox Cellular Modem"; - } + if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; } res2.replace(GSM_NL "OK" GSM_NL, ""); res2.trim(); String name = res1 + String(' ') + res2; DBG("### Modem:", name); - if (name.startsWith("u-blox SARA-R4") || name.startsWith("u-blox SARA-N4")) { + if (name.startsWith("u-blox SARA-R4") || + name.startsWith("u-blox SARA-N4")) { DBG("### WARNING: You are using the wrong TinyGSM modem!"); - } - else if (name.startsWith("u-blox SARA-N2")) { + } else if (name.startsWith("u-blox SARA-N2")) { DBG("### SARA N2 NB-IoT modems not supported!"); } return name; } -TINY_GSM_MODEM_SET_BAUD_IPR() - -TINY_GSM_MODEM_TEST_AT() - -TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() - - bool factoryDefault() { + bool factoryDefaultImpl() { sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM waitResponse(); - sendAT(GF("+CFUN=16")); // Reset + sendAT(GF("+CFUN=16")); // Reset return waitResponse() == 1; } -TINY_GSM_MODEM_GET_INFO_ATI() - - bool hasSSL() { + bool thisHasSSL() { return true; } - bool hasWifi() { + bool thisHasWifi() { return false; } - bool hasGPRS() { + bool thisHasGPRS() { return true; } /* * Power functions */ - - bool restart() { - if (!testAT()) { - return false; - } + protected: + bool restartImpl() { + if (!testAT()) { return false; } sendAT(GF("+CFUN=16")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); // TODO: Verify delay timing here + if (waitResponse(10000L) != 1) { return false; } + delay(3000); // TODO(?): Verify delay timing here return init(); } - bool poweroff() { + bool powerOffImpl() { sendAT(GF("+CPWROFF")); return waitResponse(40000L) == 1; } - bool radioOff() { - sendAT(GF("+CFUN=0")); - if (waitResponse(10000L) != 1) { - return false; - } - delay(3000); - return true; - } - - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * SIM card functions */ - -TINY_GSM_MODEM_SIM_UNLOCK_CPIN() - -TINY_GSM_MODEM_GET_SIMCCID_CCID() - - String getIMEI() { + protected: + String getIMEIImpl() { sendAT(GF("+CGSN")); - if (waitResponse(GF(GSM_NL)) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL)) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); return res; } - 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"), GF("NOT INSERTED")); - 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(CGREG) - -TINY_GSM_MODEM_GET_OPERATOR_COPS() - /* * Generic network functions */ + public: + RegStatus getRegistrationStatus() { + return (RegStatus)getRegistrationStatusXREG("CGREG"); + } -TINY_GSM_MODEM_GET_CSQ() - - bool isNetworkConnected() { + protected: + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); if (s == REG_OK_HOME || s == REG_OK_ROAMING) return true; else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown.. return isGprsConnected(); - else return false; + else + return false; } -TINY_GSM_MODEM_WAIT_FOR_NETWORK() - /* * 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(); sendAT(GF("+CGATT=1")); // attach to GPRS - if (waitResponse(360000L) != 1) { - return false; - } + if (waitResponse(360000L) != 1) { return false; } // Setting up the PSD profile/PDP context with the UPSD commands sets up an // "internal" PDP context, i.e. a data connection using the internal IP @@ -388,15 +310,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() waitResponse(); } - sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP on PSD profile 0 + sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP on PSD profile 0 waitResponse(); // Packet switched data action // AT+UPSDA=, // profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context) - // action = 3: activate; it activates a PDP context with the specified profile, - // using the current parameters - sendAT(GF("+UPSDA=0,3")); // Activate the PDP context associated with profile 0 + // action = 3: activate; it activates a PDP context with the specified + // profile, using the current parameters + sendAT(GF( + "+UPSDA=0,3")); // Activate the PDP context associated with profile 0 if (waitResponse(360000L) != 1) { // Should return ok return false; } @@ -406,12 +329,13 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() // for the active PDP context associated with the specified PSD profile. // AT+UPSND=, // profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context) - // param_tag = 8: PSD profile status: if the profile is active the return value is 1, 0 otherwise - sendAT(GF("+UPSND=0,8")); // Check if PSD profile 0 is now active + // param_tag = 8: PSD profile status: if the profile is active the return + // value is 1, 0 otherwise + sendAT(GF("+UPSND=0,8")); // Check if PSD profile 0 is now active int res = waitResponse(GF(",8,1"), GF(",8,0")); waitResponse(); // Should return another OK if (res == 1) { - return true; // It's now active + return true; // It's now active } else if (res == 2) { // If it's not active yet, wait for the +UUPSDA URC if (waitResponse(180000L, GF("+UUPSDA: 0")) != 1) { // 0=successful return false; @@ -424,89 +348,50 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() return true; } - bool gprsDisconnect() { - sendAT(GF("+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0 - if (waitResponse(360000L) != 1) { - return false; - } + bool gprsDisconnectImpl() { + sendAT(GF( + "+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0 + if (waitResponse(360000L) != 1) { return false; } sendAT(GF("+CGATT=0")); // detach from GPRS - if (waitResponse(360000L) != 1) { - return false; - } + if (waitResponse(360000L) != 1) { return false; } return true; } -TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() - /* * IP Address functions */ - - String getLocalIP() { + protected: + String getLocalIPImpl() { sendAT(GF("+UPSND=0,0")); - if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { - return ""; - } - streamSkipUntil(','); // Skip PSD profile - streamSkipUntil('\"'); // Skip request type + if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; } + streamSkipUntil(','); // Skip PSD profile + streamSkipUntil('\"'); // Skip request type String res = stream.readStringUntil('\"'); - if (waitResponse() != 1) { - return ""; - } + if (waitResponse() != 1) { return ""; } return res; } - IPAddress localIP() { - return TinyGsmIpFromString(getLocalIP()); - } - /* * Phone Call functions */ - - bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; - - bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; + protected: + // Can follow all of the phone call functions from the template /* * Messaging functions */ - - String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - bool sendSMS(const String& number, const String& text) { - sendAT(GF("+CSCS=\"GSM\"")); // Set GSM default alphabet - waitResponse(); - sendAT(GF("+CMGF=1")); // Set preferred message format to text mode - waitResponse(); - sendAT(GF("+CMGS=\""), number, GF("\"")); // set the phone number - if (waitResponse(GF(">")) != 1) { - return false; - } - stream.print(text); // Actually send the message - stream.write((char)0x1A); - stream.flush(); - return waitResponse(60000L) == 1; - } - - bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; - + protected: + // Can follow all template functions /* * Location functions */ - - String getGsmLocation() { + protected: + String getGsmLocationImpl() { sendAT(GF("+ULOC=2,3,0,120,1")); - if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { - return ""; - } + if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -514,48 +399,58 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() } /* - * Battery & temperature functions + * GPS location functions */ + public: + // No functions of this type supported - uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * Time functions + */ + protected: + // Can follow the standard CCLK function in the template + + /* + * Battery & temperature functions + */ + protected: + uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - int8_t getBattPercent() { + int8_t getBattPercentImpl() { sendAT(GF("+CIND?")); - if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { - return 0; - } + if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; } - int res = stream.readStringUntil(',').toInt(); - int8_t percent = res*20; // return is 0-5 + int res = stream.readStringUntil(',').toInt(); + int8_t percent = res * 20; // return is 0-5 // Wait for final OK waitResponse(); return percent; } - uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { chargeState = 0; - percent = getBattPercent(); - milliVolts = 0; + percent = getBattPercent(); + milliVolts = 0; return true; } - // This would only available for a small number of modules in this group (TOBY-L) - float getTemperature() TINY_GSM_ATTR_NOT_IMPLEMENTED; + // This would only available for a small number of modules in this group + // (TOBY-L) + float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * Client related functions */ - -protected: - + protected: bool modemConnect(const char* host, uint16_t port, uint8_t* mux, - bool ssl = false, int timeout_s = 120) - { - uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; + bool ssl = false, int timeout_s = 120) { + uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; sendAT(GF("+USOCR=6")); // create a socket - if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { // reply is +USOCR: ## of socket created + if (waitResponse(GF(GSM_NL "+USOCR:")) != + 1) { // reply is +USOCR: ## of socket created return false; } *mux = stream.readStringUntil('\n').toInt(); @@ -571,8 +466,8 @@ protected: waitResponse(); // Enable KEEPALIVE, 30 sec - //sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); - //waitResponse(); + // sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); + // waitResponse(); // connect on the allocated socket sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); @@ -582,17 +477,13 @@ protected: int16_t modemSend(const void* buff, size_t len, uint8_t mux) { sendAT(GF("+USOWR="), mux, ',', (uint16_t)len); - if (waitResponse(GF("@")) != 1) { - return 0; - } + if (waitResponse(GF("@")) != 1) { return 0; } // 50ms delay, see AT manual section 25.10.4 delay(50); - stream.write((uint8_t*)buff, len); + stream.write(reinterpret_cast(buff), len); stream.flush(); - if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux + if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux int sent = stream.readStringUntil('\n').toInt(); waitResponse(); // sends back OK after the confirmation of number sent return sent; @@ -600,16 +491,12 @@ protected: size_t modemRead(size_t size, uint8_t mux) { sendAT(GF("+USORD="), mux, ',', (uint16_t)size); - if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { - return 0; - } - streamSkipUntil(','); // Skip mux + if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; } + streamSkipUntil(','); // Skip mux int len = stream.readStringUntil(',').toInt(); streamSkipUntil('\"'); - for (int i=0; isock_connected = modemGetConnected(mux); - } + if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } DBG("### AVAILABLE:", result, "on", mux); return result; } @@ -641,11 +526,10 @@ protected: // NOTE: Querying a closed socket gives an error "operation not allowed" sendAT(GF("+USOCTL="), mux, ",10"); uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:")); - if (res != 1) - return false; + if (res != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip type + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip type int result = stream.readStringUntil('\n').toInt(); // 0: the socket is in INACTIVE status (it corresponds to CLOSED status // defined in RFC793 "TCP Protocol Specification" [112]) @@ -663,19 +547,16 @@ protected: return (result != 0); } -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=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) - { + public: + // TODO(vshymanskyy): Optimize this! + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -683,15 +564,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; - unsigned long startMillis = millis(); + int index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -714,7 +595,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() int mux = stream.readStringUntil(',').toInt(); int len = stream.readStringUntil('\n').toInt(); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { - sockets[mux]->got_data = true; + sockets[mux]->got_data = true; sockets[mux]->sock_available = len; } data = ""; @@ -729,38 +610,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); - if (data.length()) { - DBG("### Unhandled:", data); - } + if (data.length()) { DBG("### Unhandled:", data); } data = ""; } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); return index; } - uint8_t waitResponse(uint32_t timeout_ms, - GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), - GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } -public: - Stream& stream; - -protected: - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; }; -#endif +#endif // SRC_TINYGSMCLIENTUBLOX_H_ diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 79e743e..fa2eb4f 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -2,48 +2,45 @@ * @file TinyGsmClientXBee.h * @author Volodymyr Shymanskyy * @license LGPL-3.0 - * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, XBee module by Sara Damiano + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, XBee module by Sara + * Damiano * @date Nov 2016 */ -#ifndef TinyGsmClientXBee_h -#define TinyGsmClientXBee_h -//#pragma message("TinyGSM: TinyGsmClientXBee") +#ifndef SRC_TINYGSMCLIENTXBEE_H_ +#define SRC_TINYGSMCLIENTXBEE_H_ +// #pragma message("TinyGSM: TinyGsmClientXBee") -//#define TINY_GSM_DEBUG Serial +// #define TINY_GSM_DEBUG Serial // XBee's do not support multi-plexing in transparent/command mode // The much more complicated API mode is needed for multi-plexing #define TINY_GSM_MUX_COUNT 1 -// XBee's have a default guard time of 1 second (1000ms, 10 extra for safety here) +// XBee's have a default guard time of 1 second (1000ms, 10 extra for safety +// here) #define TINY_GSM_XBEE_GUARD_TIME 1010 -#include +#include "TinyGsmCommon.h" #define GSM_NL "\r" -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_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; +static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; // 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_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(); \ +#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, - SIM_LOCKED = 2, -}; - enum RegStatus { REG_OK = 0, REG_UNREGISTERED = 1, @@ -54,7 +51,7 @@ enum RegStatus { // These are responses to the HS command to get "hardware series" enum XBeeType { - XBEE_UNKNOWN = 0, + XBEE_UNKNOWN = 0, XBEE_S6B_WIFI = 0x601, // Digi XBee® Wi-Fi XBEE_LTE1_VZN = 0xB01, // Digi XBee® Cellular LTE Cat 1 XBEE_3G = 0xB02, // Digi XBee® Cellular 3G @@ -62,240 +59,242 @@ enum XBeeType { XBEE3_LTEM_ATT = 0xB08, // Digi XBee3™ Cellular LTE-M }; - class TinyGsmXBee -{ - -public: - -class GsmClient : public Client -{ - friend class TinyGsmXBee; - // typedef TinyGsmFifo RxFifo; - -public: - GsmClient() {} + : public TinyGsmModem { + friend class TinyGsmModem; - GsmClient(TinyGsmXBee& modem, uint8_t mux = 0) { - init(&modem, mux); - } + /* + * Inner Client + */ + public: + class GsmClientXBee : public GsmClient { + friend class TinyGsmXBee; - virtual ~GsmClient(){} + public: + GsmClientXBee() {} - bool init(TinyGsmXBee* modem, uint8_t mux = 0) { - this->at = modem; - this->mux = mux; - sock_connected = false; + explicit GsmClientXBee(TinyGsmXBee& modem, uint8_t mux = 0) { + init(&modem, mux); + } - at->sockets[mux] = this; + bool init(TinyGsmXBee* modem, uint8_t mux = 0) { + this->at = modem; + this->mux = mux; + sock_connected = false; - return true; - } + at->sockets[mux] = this; -public: - // 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 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 - 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, int timeout_s) { - if (timeout_s != 0) { - DBG("Timeout [", timeout_s, "] doesn't apply here."); + return true; } - // NOTE: Not caling stop() or yeild() here - at->streamClear(); // Empty anything in the buffer before starting - sock_connected = at->modemConnect(ip, port, mux, false); - return sock_connected; - } - virtual int connect(IPAddress ip, uint16_t port) { - return connect(ip, port, 0); - } - virtual void stop(uint32_t maxWaitMs) { - at->streamClear(); // Empty anything in the buffer - // empty the saved currently-in-use destination address - at->modemStop(maxWaitMs); - at->streamClear(); // Empty anything in the buffer - sock_connected = false; - - // Note: because settings are saved in flash, the XBEE will attempt to - // reconnect to the previous socket if it receives any outgoing data. - // Setting sock_connected to false after the stop ensures that connected() - // will return false after a stop has been ordered. This makes it play - // much more nicely with libraries like PubSubClient. - } + public: + // 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 data + // even if you haven't "made" any connection. + 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 + sock_connected = at->modemConnect(host, port, mux, false, timeout_s); + return sock_connected; + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } - virtual void stop() { stop(5000L); } + int connect(IPAddress ip, uint16_t port, int timeout_s) { + if (timeout_s != 0) { + DBG("Timeout [", timeout_s, "] doesn't apply here."); + } + // NOTE: Not caling stop() or yeild() here + at->streamClear(); // Empty anything in the buffer before starting + sock_connected = at->modemConnect(ip, port, mux, false); + return sock_connected; + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 0); + } - virtual size_t write(const uint8_t *buf, size_t size) { - TINY_GSM_YIELD(); - return at->modemSend(buf, size, mux); - } + void stop(uint32_t maxWaitMs) { + at->streamClear(); // Empty anything in the buffer + // empty the saved currently-in-use destination address + at->modemStop(maxWaitMs); + at->streamClear(); // Empty anything in the buffer + sock_connected = false; + + // Note: because settings are saved in flash, the XBEE will attempt to + // reconnect to the previous socket if it receives any outgoing data. + // Setting sock_connected to false after the stop ensures that connected() + // will return false after a stop has been ordered. This makes it play + // much more nicely with libraries like PubSubClient. + } + void stop() override { + stop(5000L); + } - virtual size_t write(uint8_t c) { - return write(&c, 1); - } + size_t write(const uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + return at->modemSend(buf, size, mux); + } - virtual size_t write(const char *str) { - if (str == NULL) return 0; - return write((const uint8_t *)str, strlen(str)); - } + size_t write(uint8_t c) override { + return write(&c, 1); + } - virtual int available() { - TINY_GSM_YIELD(); - return at->stream.available(); - /* - if (!rx.size() || at->stream.available()) { - at->maintain(); + size_t write(const char* str) { + if (str == NULL) return 0; + return write((const uint8_t*)str, strlen(str)); } - return at->stream.available() + rx.size(); - */ - } - virtual int read(uint8_t *buf, size_t size) { - TINY_GSM_YIELD(); - return at->stream.readBytes((char *)buf, size); - /* - size_t cnt = 0; - uint32_t _startMillis = millis(); - while (cnt < size && millis() - _startMillis < _timeout) { - size_t chunk = TinyGsmMin(size-cnt, rx.size()); - if (chunk > 0) { - rx.get(buf, chunk); - buf += chunk; - cnt += chunk; - continue; - } - // TODO: Read directly into user buffer? + int available() override { + TINY_GSM_YIELD(); + return at->stream.available(); + /* if (!rx.size() || at->stream.available()) { at->maintain(); } + return at->stream.available() + rx.size(); + */ } - return cnt; - */ - } - virtual int read() { - TINY_GSM_YIELD(); - return at->stream.read(); - /* - uint8_t c; - if (read(&c, 1) == 1) { - return c; + int read(uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + return at->stream.readBytes(reinterpret_cast(buf), size); + /* + size_t cnt = 0; + uint32_t _startMillis = millis(); + while (cnt < size && millis() - _startMillis < _timeout) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO(vshymanskyy): Read directly into user buffer? + if (!rx.size() || at->stream.available()) { + at->maintain(); + } + } + return cnt; + */ } - return -1; - */ - } - - virtual int peek() { return at->stream.peek(); } - virtual void flush() { at->stream.flush(); } - virtual uint8_t connected() { - if (available()) { - return true; - // if we never got an IP, it can't be connected - } else if (at->savedIP == IPAddress(0, 0, 0, 0)){ - return false; + int read() override { + TINY_GSM_YIELD(); + return at->stream.read(); + /* + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + */ } - return sock_connected; - // NOTE: We don't check or return - // modemGetConnected() because we don't - // want to go into command mode. - // return at->modemGetConnected(); - } - virtual operator bool() { return connected(); } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - -private: - TinyGsmXBee* at; - uint8_t mux; - bool sock_connected; - // RxFifo rx; -}; - -class GsmClientSecure : public GsmClient -{ -public: - GsmClientSecure() {} + int peek() override { + return at->stream.peek(); + } + void flush() override { + at->stream.flush(); + } - GsmClientSecure(TinyGsmXBee& modem, uint8_t mux = 0) - : GsmClient(modem, mux) - {} + uint8_t connected() override { + if (available()) { + return true; + // if we never got an IP, it can't be connected + } else if (at->savedIP == IPAddress(0, 0, 0, 0)) { + return false; + } + return sock_connected; + // NOTE: We don't check or return + // modemGetConnected() because we don't + // want to go into command mode. + // return at->modemGetConnected(); + } + operator bool() override { + return connected(); + } - virtual ~GsmClientSecure(){} + /* + * Extended API + */ -public: - 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 - sock_connected = at->modemConnect(host, port, mux, true, timeout_s); - return sock_connected; - } + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + }; - virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { - if (timeout_s != 0) { - DBG("Timeout [", timeout_s, "] doesn't apply here."); + /* + * Inner Secure Client + */ + public: + class GsmClientSecureXBee : public GsmClientXBee { + public: + GsmClientSecureXBee() {} + + explicit GsmClientSecureXBee(TinyGsmXBee& modem, uint8_t mux = 0) + : GsmClientXBee(modem, mux) {} + + public: + 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 + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; } - // NOTE: Not caling stop() or yeild() here - at->streamClear(); // Empty anything in the buffer before starting - sock_connected = at->modemConnect(ip, port, mux, true); - return sock_connected; - } -}; - -public: + int connect(IPAddress ip, uint16_t port, int timeout_s) { + if (timeout_s != 0) { + DBG("Timeout [", timeout_s, "] doesn't apply here."); + } + // NOTE: Not caling stop() or yeild() here + at->streamClear(); // Empty anything in the buffer before starting + sock_connected = at->modemConnect(ip, port, mux, true); + return sock_connected; + } + }; - TinyGsmXBee(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 = ""; - savedHostIP = IPAddress(0,0,0,0); - inCommandMode = false; - memset(sockets, 0, sizeof(sockets)); + /* + * Constructor + */ + public: + explicit TinyGsmXBee(Stream& stream) + : stream(stream), + guardTime(TINY_GSM_XBEE_GUARD_TIME), + beeType(XBEE_UNKNOWN), + resetPin(-1), + savedIP(IPAddress(0, 0, 0, 0)), + savedHost(""), + savedHostIP(IPAddress(0, 0, 0, 0)), + savedOperatingIP(IPAddress(0, 0, 0, 0)), + inCommandMode(false), + lastCommandModeMillis(0) { + // Start not knowing what kind of bee it is + // Start with the default guard time of 1 second + memset(sockets, 0, sizeof(sockets)); } TinyGsmXBee(Stream& stream, int8_t resetPin) - : 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 = ""; - savedHostIP = IPAddress(0,0,0,0); - inCommandMode = false; - memset(sockets, 0, sizeof(sockets)); + : stream(stream), + guardTime(TINY_GSM_XBEE_GUARD_TIME), + beeType(XBEE_UNKNOWN), + resetPin(resetPin), + savedIP(IPAddress(0, 0, 0, 0)), + savedHost(""), + savedHostIP(IPAddress(0, 0, 0, 0)), + savedOperatingIP(IPAddress(0, 0, 0, 0)), + inCommandMode(false), + lastCommandModeMillis(0) { + // Start not knowing what kind of bee it is + // Start with the default guard time of 1 second + memset(sockets, 0, sizeof(sockets)); } /* * Basic functions */ - bool begin(const char* pin = NULL) { - return init(pin); - } - - bool init(const char* pin = NULL) { + bool initImpl(const char* pin = NULL) { DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); if (resetPin >= 0) { @@ -312,13 +311,13 @@ public: sendAT(GF("AP0")); // Put in transparent mode bool ret_val = waitResponse() == 1; - sendAT(GF("GT64")); // shorten the guard time to 100ms + sendAT(GF("GT64")); // shorten the guard time to 100ms 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 100ms (10 seconds) + // 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(); @@ -330,14 +329,13 @@ public: return ret_val; } - String getModemName() { + String getModemNameImpl() { return getBeeName(); } - void setBaud(unsigned long baud) { + void setBaudImpl(uint32_t baud) { XBEE_COMMAND_START_DECORATOR(5, ) - switch(baud) - { + switch (baud) { case 2400: sendAT(GF("BD1")); break; case 4800: sendAT(GF("BD2")); break; case 9600: sendAT(GF("BD3")); break; @@ -349,9 +347,9 @@ public: case 460800: sendAT(GF("BD9")); break; case 921600: sendAT(GF("BDA")); break; default: { - DBG(GF("Specified baud rate is unsupported! Setting to 9600 baud.")); - sendAT(GF("BD3")); // Set to default of 9600 - break; + DBG(GF("Specified baud rate is unsupported! Setting to 9600 baud.")); + sendAT(GF("BD3")); // Set to default of 9600 + break; } } waitResponse(); @@ -359,28 +357,28 @@ public: XBEE_COMMAND_END_DECORATOR } - bool testAT(unsigned long timeout_ms = 10000L) { - unsigned long start = millis(); - bool success = false; + bool testATImpl(uint32_t timeout_ms = 10000L) { + uint32_t start = millis(); + bool success = false; while (!success && millis() - start < timeout_ms) { if (!inCommandMode) { success = commandMode(); if (success) exitCommand(); - } - else { - sendAT(); - if (waitResponse(200) == 1) { - success = true; - } + } else { + sendAT(); + if (waitResponse(200) == 1) { + success = true; + } else { // if we didn't respond to the AT, assume we're not in command mode - else inCommandMode = false; + inCommandMode = false; + } } delay(250); } return success; } - void maintain() { + void maintainImpl() { // this only happens OUTSIDE command mode, so if we're getting characters // they should be data received from the TCP connection // TINY_GSM_YIELD(); @@ -392,7 +390,7 @@ public: // } } - bool factoryDefault() { + bool factoryDefaultImpl() { XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("RE")); bool ret_val = waitResponse() == 1; @@ -404,44 +402,51 @@ public: return ret_val; } - String getModemInfo() { + String getModemInfoImpl() { return sendATGetString(GF("HS")); } - bool hasSSL() { - if (beeType == XBEE_S6B_WIFI) return false; - else return true; + bool thisHasSSL() { + if (beeType == XBEE_S6B_WIFI) + return false; + else + return true; } - bool hasWifi() { - if (beeType == XBEE_S6B_WIFI) return true; - else return false; + bool thisHasWifi() { + if (beeType == XBEE_S6B_WIFI) + return true; + else + return false; } - bool hasGPRS() { - if (beeType == XBEE_S6B_WIFI) return false; - else return true; + bool thisHasGPRS() { + if (beeType == XBEE_S6B_WIFI) + return false; + else + return true; } + public: XBeeType getBeeType() { return beeType; } String getBeeName() { - switch (beeType){ + switch (beeType) { case XBEE_S6B_WIFI: return "Digi XBee Wi-Fi"; case XBEE_LTE1_VZN: return "Digi XBee Cellular LTE Cat 1"; case XBEE_3G: return "Digi XBee Cellular 3G"; case XBEE3_LTE1_ATT: return "Digi XBee3 Cellular LTE CAT 1"; case XBEE3_LTEM_ATT: return "Digi XBee3 Cellular LTE-M"; - default: return "Digi XBee"; + default: return "Digi XBee"; } } /* * Power functions */ - + protected: // The XBee's have a bad habit of getting into an unresponsive funk // This uses the board's hardware reset pin to force it to reset void pinReset() { @@ -453,28 +458,32 @@ public: } } - bool restart() { - - if (!commandMode()) return false; // Return immediately + bool restartImpl() { + if (!commandMode()) { return false; } // Return immediately if (beeType == XBEE_UNKNOWN) getSeries(); // how we restart depends on this if (beeType != XBEE_S6B_WIFI) { - sendAT(GF("AM1")); // Digi suggests putting cellular modules into airplane mode before restarting - // This allows the sockets and connections to close cleanly + sendAT(GF("AM1")); // Digi suggests putting cellular modules into + // airplane mode before restarting This allows the + // sockets and connections to close cleanly if (waitResponse() != 1) return exitAndFail(); if (!writeChanges()) return exitAndFail(); } 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 100ms before reset happens - - // Wait until reboot complete and responds to command mode call again - for (unsigned long start = millis(); millis() - start < 60000L; ) { + 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 100ms before reset happens + + // Wait until reboot completes and XBee responds to command mode call again + for (uint32_t start = millis(); millis() - start < 60000L;) { if (commandMode(1)) break; delay(250); // wait a litle before trying again } @@ -495,102 +504,117 @@ public: if (beeType == XBEE_UNKNOWN) getSeries(); // Command depends on series - sendAT(GF("SM"),1); // Pin sleep + sendAT(GF("SM"), 1); // Pin sleep waitResponse(); if (beeType == XBEE_S6B_WIFI && !maintainAssociation) { - sendAT(GF("SO"),200); // For lowest power, dissassociated deep sleep - waitResponse(); - } - - else if (!maintainAssociation){ - sendAT(GF("SO"),1); // For supported cellular modules, maintain association - // Not supported by all modules, will return "ERROR" - waitResponse(); + sendAT(GF("SO"), 200); // For lowest power, dissassociated deep sleep + waitResponse(); + } else if (!maintainAssociation) { + sendAT(GF("SO"), + 1); // For supported cellular modules, maintain association + // Not supported by all modules, will return "ERROR" + waitResponse(); } writeChanges(); XBEE_COMMAND_END_DECORATOR } - bool poweroff() { // NOTE: Not supported for WiFi or older cellular firmware + bool + powerOffImpl() { // NOTE: Not supported for WiFi or older cellular firmware XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("SD")); bool ret_val = waitResponse(120000L) == 1; - if (ret_val) { - ret_val &= (sendATGetString(GF("AI")) == "2D"); - } + if (ret_val) { ret_val &= (sendATGetString(GF("AI")) == "2D"); } XBEE_COMMAND_END_DECORATOR return ret_val; } - bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + // Enable airplane mode + bool radioOffImpl() { + XBEE_COMMAND_START_DECORATOR(5, false) + sendAT(GF("AM1")); + int8_t res = (1 == waitResponse(5000)); + writeChanges(); + XBEE_COMMAND_END_DECORATOR + return res; + } - bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; /* * SIM card functions */ - - bool simUnlock(const char *pin) { // Not supported + protected: + bool simUnlockImpl(const char* pin) { // Not supported if (pin && strlen(pin) > 0) { DBG("XBee's do not support SIMs that require an unlock pin!"); } return false; } - String getSimCCID() { + String getSimCCIDImpl() { return sendATGetString(GF("S#")); } - String getIMEI() { + String getIMEIImpl() { return sendATGetString(GF("IM")); } - SimStatus getSimStatus() { + SimStatus getSimStatusImpl(uint32_t) { return SIM_READY; // unsupported } + /* + * Generic network functions + */ + public: RegStatus getRegistrationStatus() { - 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 + if (beeType == XBEE_UNKNOWN) + getSeries(); // Need to know the bee type to interpret response sendAT(GF("AI")); - int16_t intRes = readResponseInt(10000L); - RegStatus stat = REG_UNKNOWN; + int16_t intRes = readResponseInt(10000L); + RegStatus stat = REG_UNKNOWN; - switch (beeType){ + switch (beeType) { case XBEE_S6B_WIFI: { switch (intRes) { - case 0x00: // 0x00 Successfully joined an access point, established IP addresses and IP listening sockets + case 0x00: // 0x00 Successfully joined an access point, established + // IP addresses and IP listening sockets stat = REG_OK; break; case 0x01: // 0x01 Wi-Fi transceiver initialization in progress. - case 0x02: // 0x02 Wi-Fi transceiver initialized, but not yet scanning for access point. + case 0x02: // 0x02 Wi-Fi transceiver initialized, but not yet + // scanning for access point. case 0x40: // 0x40 Waiting for WPA or WPA2 Authentication. - case 0x41: // 0x41 Device joined a network and is waiting for IP configuration to complete - case 0x42: // 0x42 Device is joined, IP is configured, and listening sockets are being set up. - case 0xFF: // 0xFF Device is currently scanning for the configured SSID. + case 0x41: // 0x41 Device joined a network and is waiting for IP + // configuration to complete + case 0x42: // 0x42 Device is joined, IP is configured, and listening + // sockets are being set up. + case 0xFF: // 0xFF Device is currently scanning for the configured + // SSID. stat = REG_SEARCHING; break; - case 0x13: // 0x13 Disconnecting from access point. - restart(); // Restart the device; the S6B tends to get stuck "disconnecting" + case 0x13: // 0x13 Disconnecting from access point. + restart(); // Restart the device; the S6B tends to get stuck + // "disconnecting" stat = REG_UNREGISTERED; break; case 0x23: // 0x23 SSID not configured. stat = REG_UNREGISTERED; break; - case 0x24: // 0x24 Encryption key invalid (either NULL or invalid length for WEP). + case 0x24: // 0x24 Encryption key invalid (either NULL or invalid + // length for WEP). case 0x27: // 0x27 SSID was found, but join failed. stat = REG_DENIED; break; - default: - stat = REG_UNKNOWN; - break; + default: stat = REG_UNKNOWN; break; } break; } @@ -603,8 +627,9 @@ public: case 0x23: // 0x23 Connecting to the Internet. case 0xFF: // 0xFF Initializing. stat = REG_SEARCHING; - break; - case 0x24: // 0x24 The cellular component is missing, corrupt, or otherwise in error. + break; + case 0x24: // 0x24 The cellular component is missing, corrupt, or + // otherwise in error. case 0x2B: // 0x2B USB Direct active. case 0x2C: // 0x2C Cellular component is in PSM (power save mode). stat = REG_UNKNOWN; @@ -612,21 +637,19 @@ public: case 0x25: // 0x25 Cellular network registration denied. stat = REG_DENIED; break; - case 0x2A: // 0x2A Airplane mode. + case 0x2A: // 0x2A Airplane mode. sendAT(GF("AM0")); // Turn off airplane mode waitResponse(); writeChanges(); stat = REG_UNKNOWN; break; - case 0x2F: // 0x2F Bypass mode active. + case 0x2F: // 0x2F Bypass mode active. sendAT(GF("AP0")); // Set back to transparent mode waitResponse(); writeChanges(); stat = REG_UNKNOWN; break; - default: - stat = REG_UNKNOWN; - break; + default: stat = REG_UNKNOWN; break; } break; } @@ -636,40 +659,36 @@ public: return stat; } - String getOperator() { - return sendATGetString(GF("MN")); - } - - /* - * Generic network functions - */ - - int16_t getSignalQuality() { - + protected: + int16_t getSignalQualityImpl() { 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 - else sendAT(GF("DB")); // ask for the cell strength in dBm + 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(); 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) { if (intRes == 0xFF) { - return 0; // 0xFF returned for unknown + return 0; // 0xFF returned for unknown } else { return -93 + intRes; // the maximum sensitivity is -93dBm } } else { - return -1*intRes; // need to convert to negative number + return -1 * intRes; // need to convert to negative number } } - bool isNetworkConnected() { + bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); if (s == REG_OK) { IPAddress ip = localIP(); @@ -683,10 +702,10 @@ public: } } - bool waitForNetwork(unsigned long timeout_ms = 60000L) { + bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) { bool retVal = false; XBEE_COMMAND_START_DECORATOR(5, false) - for (unsigned long start = millis(); millis() - start < timeout_ms; ) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { if (isNetworkConnected()) { retVal = true; break; @@ -700,17 +719,15 @@ public: /* * WiFi functions */ - - bool networkConnect(const char* ssid, const char* pwd) { - + protected: + bool networkConnectImpl(const char* ssid, const char* pwd) { bool retVal = true; XBEE_COMMAND_START_DECORATOR(5, false) - //nh For no pwd don't set setscurity or pwd - if (ssid == NULL) retVal = false;; + // nh For no pwd don't set set security or pwd + if (ssid == NULL) retVal = false; - if (pwd && strlen(pwd) > 0) - { + if (pwd && strlen(pwd) > 0) { sendAT(GF("EE"), 2); // Set security to WPA2 if (waitResponse() != 1) retVal = false; sendAT(GF("PK"), pwd); @@ -729,7 +746,7 @@ public: return retVal; } - bool networkDisconnect() { + bool networkDisconnectImpl() { XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("NR0")); // Do a network reset in order to disconnect // WARNING: On wifi modules, using a network reset will not @@ -740,31 +757,12 @@ public: return res; } - /* - * IP Address functions - */ - - String getLocalIP() { - 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); - 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) { + protected: + bool gprsConnectImpl(const char* apn, const char* user = NULL, + const char* pwd = NULL) { if (user && strlen(user) > 0) { DBG("XBee's do not support SIMs that a user name/password!"); } @@ -781,9 +779,10 @@ public: return success; } - bool gprsDisconnect() { + bool gprsDisconnectImpl() { 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)); writeChanges(); // sendAT(GF("AM0")); // Airplane mode off @@ -793,32 +792,64 @@ public: return res; } - bool isGprsConnected() { + bool isGprsConnectedImpl() { return isNetworkConnected(); } + String getOperatorImpl() { + return sendATGetString(GF("MN")); + } + /* - * Messaging functions + * IP Address functions + */ + protected: + String getLocalIPImpl() { + 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); + XBEE_COMMAND_END_DECORATOR + IPaddr.trim(); + return IPaddr; + } + + /* + * Phone Call functions */ + protected: + bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; + bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + bool + dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; - String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; + /* + * Messaging functions + */ + protected: + String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE; - bool sendSMS(const String& number, const String& text) { - if (!commandMode()) return false; // Return immediately + bool sendSMSImpl(const String& number, const String& text) { + if (!commandMode()) { return false; } // Return immediately sendAT(GF("IP"), 2); // Put in text messaging mode - if (waitResponse() !=1) return exitAndFail(); + if (waitResponse() != 1) return exitAndFail(); sendAT(GF("PH"), number); // Set the phone number - if (waitResponse() !=1) return exitAndFail(); - sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage return) - if (waitResponse() !=1) return exitAndFail(); + 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(); // Get out of command mode to actually send the text exitCommand(); streamWrite(text); - stream.write((char)0x0D); // close off with the carriage return + stream.write( + static_cast(0x0D)); // close off with the carriage return return true; } @@ -826,15 +857,28 @@ public: /* * Location functions */ + protected: + String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + /* + * GPS location functions + */ + public: + // No functions of this type supported /* - * Battery & temperature functions + * Time functions */ + protected: + String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) + TINY_GSM_ATTR_NOT_IMPLEMENTED; + /* + * Battery & temperature functions + */ + protected: // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltage() { + uint16_t getBattVoltageImpl() { int16_t intRes = 0; XBEE_COMMAND_START_DECORATOR(5, false) if (beeType == XBEE_UNKNOWN) getSeries(); @@ -846,35 +890,36 @@ public: return intRes; } - int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; - uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; + int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { chargeState = 0; - percent = 0; - milliVolts = getBattVoltage(); + percent = 0; + milliVolts = getBattVoltage(); return true; } - float getTemperature() { - XBEE_COMMAND_START_DECORATOR(5, (float)-9999) + float getTemperatureImpl() { + XBEE_COMMAND_START_DECORATOR(5, static_cast(-9999)) String res = sendATGetString(GF("TP")); - if (res == "") { - return (float)-9999; - } - char buf[5] = {0,}; + if (res == "") { return static_cast(-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. + int8_t intRes = (int8_t)strtol( + buf, 0, + 16); // degrees Celsius displayed in 8-bit two's complement format. XBEE_COMMAND_END_DECORATOR - return (float)intRes; + return static_cast(intRes); } /* * Client related functions */ - protected: - int16_t getConnectionIndicator() { XBEE_COMMAND_START_DECORATOR(5, false) sendAT(GF("CI")); @@ -895,23 +940,27 @@ public: if (strIP != "" && strIP != GF("ERROR")) { return TinyGsmIpFromString(strIP); - } else + } else { return IPAddress(0, 0, 0, 0); + } } IPAddress lookupHostIP(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)) + uint32_t 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) < timeout_ms) // the lookup can take a while - { + // functionality to look up the IP address from a fully qualified domain + // name + // NOTE: the lookup can take a while + while ((millis() - startMillis) < timeout_ms) { sendAT(GF("LA"), host); - while (stream.available() < 4 && (millis() - startMillis < timeout_ms)) {TINY_GSM_YIELD()}; + while (stream.available() < 4 && (millis() - startMillis < timeout_ms)) { + TINY_GSM_YIELD() + } strIP = stream.readStringUntil('\r'); // read result strIP.trim(); if (strIP != "" && strIP != GF("ERROR")) { @@ -925,29 +974,32 @@ public: if (gotIP) { 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, int timeout_s = 75) - { + bool ssl = false, int timeout_s = 75) { bool retVal = false; XBEE_COMMAND_START_DECORATOR(5, false) - // If this is a new host name, replace the saved host and wipe out the saved host IP + // If this is a new host name, replace the saved host and wipe out the saved + // host IP if (this->savedHost != String(host)) { this->savedHost = String(host); - savedHostIP = IPAddress(0,0,0,0); + savedHostIP = IPAddress(0, 0, 0, 0); } // If we don't have a good IP for the host, we need to do a DNS search - if (savedHostIP == IPAddress(0,0,0,0)) { - savedHostIP = lookupHostIP(host, timeout_s); // This will return 0.0.0.0 if lookup fails + if (savedHostIP == IPAddress(0, 0, 0, 0)) { + // This will return 0.0.0.0 if lookup fails + savedHostIP = lookupHostIP(host, timeout_s); } // If we now have a valid IP address, use it to connect - if (savedHostIP != IPAddress(0,0,0,0)) { // Only re-set connection information if we have an IP address + if (savedHostIP != IPAddress(0, 0, 0, 0)) { + // Only re-set connection information if we have an IP address retVal = modemConnect(savedHostIP, port, mux, ssl); } @@ -956,8 +1008,8 @@ public: 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) { bool success = true; if (mux != 0) { @@ -971,8 +1023,9 @@ public: if (ip != savedIP) { // Can skip almost everything if there's no // change in the IP address - savedIP = ip; // Set the newly requested IP address - String host; host.reserve(16); + savedIP = ip; // Set the newly requested IP address + String host; + host.reserve(16); host += ip[0]; host += "."; host += ip[1]; @@ -1003,9 +1056,7 @@ public: success &= (ci == 0x00 || ci == 0xFF || ci == 0x28); } - if (success) { - sockets[mux]->sock_connected = true; - } + if (success) { sockets[mux]->sock_connected = true; } XBEE_COMMAND_END_DECORATOR @@ -1026,7 +1077,7 @@ public: // For WiFi models, there's no direct way to close the socket. This is a // hack to shut the socket by setting the timeout to zero. if (beeType == XBEE_S6B_WIFI) { - sendAT(GF("TM0")); // Set socket timeout to 0 + sendAT(GF("TM0")); // Set socket timeout to 0 waitResponse(maxWaitMs); // This response can be slow writeChanges(); } @@ -1035,7 +1086,7 @@ public: // timeout) value while in Transparent Mode, the current connection is // immediately closed - this works even if the TM values is unchanged sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout - waitResponse(maxWaitMs); // This response can be slow + waitResponse(maxWaitMs); // This response can be slow writeChanges(); XBEE_COMMAND_END_DECORATOR @@ -1046,17 +1097,16 @@ public: if (mux != 0) { DBG("XBee only supports 1 IP channel in transparent mode!"); } - stream.write((uint8_t*)buff, len); + stream.write(reinterpret_cast(buff), len); stream.flush(); if (beeType != XBEE_S6B_WIFI) { // After a send, verify the outgoing ip if it isn't set if (savedOperatingIP == IPAddress(0, 0, 0, 0)) { modemGetConnected(); - } - // After sending several characters, also re-check - // NOTE: I'm intentionally not checking after every single character! - else if (len > 5) { + } else if (len > 5) { + // After sending several characters, also re-check + // NOTE: I'm intentionally not checking after every single character! modemGetConnected(); } } @@ -1064,20 +1114,27 @@ public: return len; } + size_t modemRead(size_t, uint8_t) { + return 0; + } + size_t modemGetAvailable(uint8_t) { + return 0; + } + // NOTE: The CI command returns the status of the TCP connection as open only // after data has been sent on the socket. If it returns 0xFF the socket may - // 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. + // 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 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) + if (savedIP == IPAddress(0, 0, 0, 0)) { return false; } - if (beeType == XBEE_UNKNOWN) getSeries(); // Need to know the bee type to interpret response + XBEE_COMMAND_START_DECORATOR(5, false) - switch (beeType){ + 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(); @@ -1095,8 +1152,7 @@ public: IPAddress od = getOperatingIP(); XBEE_COMMAND_END_DECORATOR - switch(ci) { - + switch (ci) { // 0x00 = The socket is definitely open case 0x00: { savedOperatingIP = od; @@ -1112,28 +1168,26 @@ public: // 0xFF = No known status - always returned prior to sending data case 0x28: case 0xFF: { - // If we previously had an operating destination and we no longer do, - // the socket must have closed - if (od == IPAddress(0, 0, 0, 0) && savedOperatingIP != IPAddress(0, 0, 0, 0)) { - savedOperatingIP = od; + // If we previously had an operating destination and we no longer + // do, the socket must have closed + if (od == IPAddress(0, 0, 0, 0) && + savedOperatingIP != IPAddress(0, 0, 0, 0)) { + savedOperatingIP = od; sockets[0]->sock_connected = false; return false; - } - // else if the operating destination exists, but is wrong - // we need to close and re-open - else if (od != IPAddress(0, 0, 0, 0) && od != savedIP) { + } else if (od != IPAddress(0, 0, 0, 0) && od != savedIP) { + // else if the operating destination exists, but is wrong + // we need to close and re-open sockets[0]->stop(); return false; - } - // else if the operating destination exists and matches, we're - // good to go - else if (od != IPAddress(0, 0, 0, 0) && od == savedIP) { + } else if (od != IPAddress(0, 0, 0, 0) && od == savedIP) { + // else if the operating destination exists and matches, we're + // good to go savedOperatingIP = od; return true; - } - // If we never had an operating destination, then sock may be open - // but data never sent - this is the dreaded "we don't know" - else { + } else { + // If we never had an operating destination, then sock may be open + // but data never sent - this is the dreaded "we don't know" savedOperatingIP = od; return true; } @@ -1167,12 +1221,12 @@ public: // 0x27 = Connection lost // If the connection is lost or timed out on our side, // we force close so it can reopen - case 0x21 : - case 0x27 : { + case 0x21: + case 0x27: { sendAT(GF("TM")); // Get socket timeout String timeoutUsed = readResponseString(5000L); sendAT(GF("TM"), timeoutUsed); // Re-set socket timeout - waitResponse(5000L); // This response can be slow + waitResponse(5000L); // This response can be slow } // 0x02 = Invalid parameters (bad IP/host) @@ -1190,7 +1244,7 @@ public: // fall through default: { sockets[0]->sock_connected = false; - savedOperatingIP = od; + savedOperatingIP = od; return false; } } @@ -1198,12 +1252,10 @@ public: } } -public: - /* - Utilities + * Utilities */ - + public: void streamClear(void) { while (stream.available()) { stream.read(); @@ -1211,16 +1263,15 @@ public: } } -TINY_GSM_MODEM_STREAM_UTILITIES() - - // TODO: Optimize this! + // TODO(vshymanskyy): 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_ms, String& data, - GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), - GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) - { + uint8_t + waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -1228,15 +1279,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(16); // Should never be getting much here for the XBee - int8_t index = 0; - unsigned long startMillis = millis(); + int8_t index = 0; + uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); while (stream.available() > 0) { TINY_GSM_YIELD(); int a = stream.read(); - if (a <= 0) continue; // Skip 0x00 bytes, just in case - data += (char)a; + if (a <= 0) continue; // Skip 0x00 bytes, just in case + data += static_cast(a); if (r1 && data.endsWith(r1)) { index = 1; goto finish; @@ -1255,7 +1306,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES() } } } while (millis() - startMillis < timeout_ms); -finish: + finish: if (!index) { data.trim(); data.replace(GSM_NL GSM_NL, GSM_NL); @@ -1269,44 +1320,43 @@ finish: data.trim(); data.replace(GSM_NL GSM_NL, GSM_NL); data.replace(GSM_NL, "\r\n "); - if (data.length()) { - } } - //data.replace(GSM_NL, "/"); - //DBG('<', index, '>', data); + // data.replace(GSM_NL, "/"); + // DBG('<', index, '>', data); 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) - { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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) - { + uint8_t + waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, + GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } bool commandMode(uint8_t retries = 5) { - // If we're already in command mode, move on - if (inCommandMode && (millis() - lastCommandModeMillis) < 10000L) return true; + if (inCommandMode && (millis() - lastCommandModeMillis) < 10000L) + return true; - uint8_t triesMade = 0; + uint8_t triesMade = 0; uint8_t triesUntilReset = 4; // only reset after 4 failures - bool success = false; + bool success = false; streamClear(); // Empty everything in the buffer before starting - while (!success and triesMade < retries) { + while (!success && triesMade < retries) { // 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 delay(guardTime + 10); streamWrite(GF("+++")); // enter command mode - int res = waitResponse(guardTime*2); + int res = waitResponse(guardTime * 2); success = (1 == res); if (0 == res) { triesUntilReset--; @@ -1314,14 +1364,14 @@ finish: triesUntilReset = 4; pinReset(); // if it's unresponsive, reset delay(250); // a short delay to allow it to come back up - // TODO-optimize this + // TODO(SRGDamia1) optimize this } } - triesMade ++; + triesMade++; } if (success) { - inCommandMode = true; + inCommandMode = true; lastCommandModeMillis = millis(); } return success; @@ -1329,9 +1379,9 @@ finish: bool writeChanges(void) { sendAT(GF("WR")); // Write changes to flash - if (1 != waitResponse()) return false; + if (1 != waitResponse()) { return false; } sendAT(GF("AC")); // Apply changes - if (1 != waitResponse()) return false; + if (1 != waitResponse()) { return false; } return true; } @@ -1351,23 +1401,27 @@ finish: void getSeries(void) { sendAT(GF("HS")); // Get the "Hardware Series"; int16_t intRes = readResponseInt(); - beeType = (XBeeType)intRes; + beeType = (XBeeType)intRes; DBG(GF("### Modem: "), getModemName()); } String readResponseString(uint32_t timeout_ms = 1000) { TINY_GSM_YIELD(); - unsigned long startMillis = millis(); - while (!stream.available() && millis() - startMillis < timeout_ms) {}; - String res = stream.readStringUntil('\r'); // lines end with carriage returns + uint32_t startMillis = millis(); + 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_ms = 1000) { - String res = readResponseString(timeout_ms); // it just works better reading a string first + String res = readResponseString( + timeout_ms); // it just works better reading a string first if (res == "") res = "FF"; - char buf[5] = {0,}; + char buf[5] = { + 0, + }; res.toCharArray(buf, 5); int16_t intRes = strtol(buf, 0, 16); return intRes; @@ -1382,24 +1436,25 @@ finish: } bool gotIPforSavedHost() { - if (savedHost != "" && savedHostIP != IPAddress(0,0,0,0)) return true; - else return false; + if (savedHost != "" && savedHostIP != IPAddress(0, 0, 0, 0)) + return true; + else + return false; } -public: - Stream& stream; - -protected: - int16_t guardTime; - int8_t resetPin; - XBeeType beeType; - IPAddress savedIP; - String savedHost; - IPAddress savedHostIP; - IPAddress savedOperatingIP; - bool inCommandMode; - uint32_t lastCommandModeMillis; - GsmClient* sockets[TINY_GSM_MUX_COUNT]; + protected: + Stream& stream; + GsmClientXBee* sockets[TINY_GSM_MUX_COUNT]; + const char* gsmNL = GSM_NL; + int16_t guardTime; + XBeeType beeType; + int8_t resetPin; + IPAddress savedIP; + String savedHost; + IPAddress savedHostIP; + IPAddress savedOperatingIP; + bool inCommandMode; + uint32_t lastCommandModeMillis; }; -#endif +#endif // SRC_TINYGSMCLIENTXBEE_H_ diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index f3a2ea3..0f97f33 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -6,105 +6,110 @@ * @date Nov 2016 */ -#ifndef TinyGsmCommon_h -#define TinyGsmCommon_h +#ifndef SRC_TINYGSMCOMMON_H_ +#define SRC_TINYGSMCOMMON_H_ // The current library version number #define TINYGSM_VERSION "0.9.19" #if defined(SPARK) || defined(PARTICLE) - #include "Particle.h" +#include "Particle.h" #elif defined(ARDUINO) - #if ARDUINO >= 100 - #include "Arduino.h" - #else - #include "WProgram.h" - #endif +#if ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif #endif #if defined(ARDUINO_DASH) - #include +#include #else - #include +#include #endif -#include +#include "TinyGsmFifo.h" #ifndef TINY_GSM_YIELD_MS - #define TINY_GSM_YIELD_MS 0 +#define TINY_GSM_YIELD_MS 0 #endif #ifndef TINY_GSM_YIELD - #define TINY_GSM_YIELD() { delay(TINY_GSM_YIELD_MS); } +#define TINY_GSM_YIELD() \ + { delay(TINY_GSM_YIELD_MS); } +#endif + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 64 #endif -#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type"))) +#define TINY_GSM_ATTR_NOT_AVAILABLE \ + __attribute__((error("Not available on this modem type"))) #define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented"))) #if defined(__AVR__) - #define TINY_GSM_PROGMEM PROGMEM - typedef const __FlashStringHelper* GsmConstStr; - #define GFP(x) (reinterpret_cast(x)) - #define GF(x) F(x) +#define TINY_GSM_PROGMEM PROGMEM +typedef const __FlashStringHelper* GsmConstStr; +#define GFP(x) (reinterpret_cast(x)) +#define GF(x) F(x) #else - #define TINY_GSM_PROGMEM - typedef const char* GsmConstStr; - #define GFP(x) x - #define GF(x) x +#define TINY_GSM_PROGMEM +typedef const char* GsmConstStr; +#define GFP(x) x +#define GF(x) x #endif #ifdef TINY_GSM_DEBUG namespace { - template - static void DBG_PLAIN(T last) { - TINY_GSM_DEBUG.println(last); - } +template +static void DBG_PLAIN(T last) { + TINY_GSM_DEBUG.println(last); +} - template - static void DBG_PLAIN(T head, Args... tail) { - TINY_GSM_DEBUG.print(head); - TINY_GSM_DEBUG.print(' '); - DBG_PLAIN(tail...); - } +template +static void DBG_PLAIN(T head, Args... tail) { + TINY_GSM_DEBUG.print(head); + TINY_GSM_DEBUG.print(' '); + DBG_PLAIN(tail...); +} - template - static void DBG(Args... args) { - TINY_GSM_DEBUG.print(GF("[")); - TINY_GSM_DEBUG.print(millis()); - TINY_GSM_DEBUG.print(GF("] ")); - DBG_PLAIN(args...); - } +template +static void DBG(Args... args) { + TINY_GSM_DEBUG.print(GF("[")); + TINY_GSM_DEBUG.print(millis()); + TINY_GSM_DEBUG.print(GF("] ")); + DBG_PLAIN(args...); } +} // namespace #else - #define DBG_PLAIN(...) - #define DBG(...) +#define DBG_PLAIN(...) +#define DBG(...) #endif -template -const T& TinyGsmMin(const T& a, const T& b) -{ - return (b < a) ? b : a; +template +const T& TinyGsmMin(const T& a, const T& b) { + return (b < a) ? b : a; } -template -const T& TinyGsmMax(const T& a, const T& b) -{ - return (b < a) ? a : b; +template +const T& TinyGsmMax(const T& a, const T& b) { + return (b < a) ? a : b; } -template -uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200) -{ - static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 }; +template +uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, + uint32_t maximum = 115200) { + static uint32_t rates[] = {115200, 57600, 38400, 19200, 9600, 74400, 74880, + 230400, 460800, 2400, 4800, 14400, 28800}; - for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) { + for (unsigned i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) { uint32_t rate = rates[i]; if (rate < minimum || rate > maximum) continue; DBG("Trying baud rate", rate, "..."); SerialAT.begin(rate); delay(10); - for (int i=0; i<10; i++) { + for (int j = 0; j < 10; j++) { SerialAT.print("AT\r\n"); String input = SerialAT.readString(); if (input.indexOf("OK") >= 0) { @@ -116,560 +121,908 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum return 0; } -static inline -IPAddress TinyGsmIpFromString(const String& strIP) { - int Parts[4] = {0, }; - int Part = 0; - for (uint8_t i=0; i 3) { - return IPAddress(0,0,0,0); +enum modemInternalBuffferType { + NO_MODEM_BUFFER = + 0, // For modules that do not store incoming data in any sort of buffer + READ_NO_CHECK = 1, // Data is stored in a buffer, but we can only read from + // the buffer, not check how much data is stored in it + READ_AND_CHECK_SIZE = 2, // Data is stored in a buffer and we can both read + // and check the size of the buffer +}; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, + SIM_ANTITHEFT_LOCKED = 3, +}; + +enum TinyGSMDateTimeFormat { DATE_FULL = 0, DATE_TIME = 1, DATE_DATE = 2 }; + +template +class TinyGsmModem { + public: + /* + * Basic functions + */ + bool begin(const char* pin = NULL) { + return thisModem().initImpl(pin); + } + bool init(const char* pin = NULL) { + return thisModem().initImpl(pin); + } + template + void sendAT(Args... cmd) { + thisModem().streamWrite("AT", cmd..., thisModem().gsmNL); + thisModem().stream.flush(); + TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */ + } + void setBaud(uint32_t baud) { + thisModem().setBaudImpl(baud); + } + // Test response to AT commands + bool testAT(uint32_t timeout_ms = 10000L) { + return thisModem().testATImpl(timeout_ms); + } + + // Asks for modem information via the V.25TER standard ATI command + // NOTE: The actual value and style of the response is quite varied + String getModemInfo() { + return thisModem().getModemInfoImpl(); + } + // Gets the modem name (as it calls itself) + String getModemName() { + return thisModem().getModemNameImpl(); + } + void maintain() { + return thisModem().maintainImpl(); + } + bool factoryDefault() { + return thisModem().factoryDefaultImpl(); + } + bool hasSSL() { + return thisModem().thisHasSSL(); + } + bool hasWifi() { + return thisModem().thisHasWifi(); + } + bool hasGPRS() { + return thisModem().thisHasGPRS(); + } + + /* + * Power functions + */ + bool restart() { + return thisModem().restartImpl(); + } + bool poweroff() { + return thisModem().powerOffImpl(); + } + bool radioOff() { + return thisModem().radioOffImpl(); + } + bool sleepEnable(bool enable = true) { + return thisModem().sleepEnableImpl(enable); + } + + /* + * SIM card functions + */ + // Unlocks the SIM + bool simUnlock(const char* pin) { + return thisModem().simUnlockImpl(pin); + } + // Gets the CCID of a sim card via AT+CCID + String getSimCCID() { + return thisModem().getSimCCIDImpl(); + } + // Asks for TA Serial Number Identification (IMEI) + String getIMEI() { + return thisModem().getIMEIImpl(); + } + SimStatus getSimStatus(uint32_t timeout_ms = 10000L) { + return thisModem().getSimStatusImpl(timeout_ms); + } + + /* + * Generic network functions + */ + // RegStatus getRegistrationStatus() {} + bool isNetworkConnected() { + return thisModem().isNetworkConnectedImpl(); + } + // Waits for network attachment + bool waitForNetwork(uint32_t timeout_ms = 60000L) { + return thisModem().waitForNetworkImpl(timeout_ms); + } + // Gets signal quality report + int16_t getSignalQuality() { + return thisModem().getSignalQualityImpl(); + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, + const char* pwd = NULL) { + return thisModem().gprsConnectImpl(apn, user, pwd); + } + bool gprsDisconnect() { + return thisModem().gprsDisconnectImpl(); + } + // Checks if current attached to GPRS/EPS service + bool isGprsConnected() { + return thisModem().isGprsConnectedImpl(); + } + // Gets the current network operator + String getOperator() { + return thisModem().getOperatorImpl(); + } + + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + return thisModem().networkConnectImpl(ssid, pwd); + } + bool networkDisconnect() { + return thisModem().networkDisconnectImpl(); + } + + /* + * GPRS functions + */ + String getLocalIP() { + return thisModem().getLocalIPImpl(); + } + IPAddress localIP() { + return thisModem().TinyGsmIpFromString(thisModem().getLocalIP()); + } + + /* + * Phone Call functions + */ + bool callAnswer() { + return thisModem().callAnswerImpl(); + } + bool callNumber(const String& number) { + return thisModem().callNumberImpl(number); + } + bool callHangup() { + return thisModem().callHangupImpl(); + } + bool dtmfSend(char cmd, int duration_ms = 100) { + return thisModem().dtmfSendImpl(cmd, duration_ms); + } + + /* + * Messaging functions + */ + String sendUSSD(const String& code) { + return thisModem().sendUSSDImpl(code); + } + bool sendSMS(const String& number, const String& text) { + return thisModem().sendSMSImpl(number, text); + } + bool sendSMS_UTF16(const char* const number, const void* text, size_t len) { + return thisModem().sendSMS_UTF16Impl(number, text, len); + } + + /* + * Location functions + */ + String getGsmLocation() { + return thisModem().getGsmLocationImpl(); + } + + /* + * GPS location functions + */ + // No template interface or implementation of these functions + + /* + * Time functions + */ + String getGSMDateTime(TinyGSMDateTimeFormat format) { + return thisModem().getGSMDateTimeImpl(format); + } + + /* + * Battery & temperature functions + */ + uint16_t getBattVoltage() { + return thisModem().getBattVoltageImpl(); + } + int8_t getBattPercent() { + return thisModem().getBattPercentImpl(); + } + uint8_t getBattChargeState() { + return thisModem().getBattChargeStateImpl(); + } + bool + getBattStats(uint8_t& chargeState, int8_t& percent, uint16_t& milliVolts) { + return thisModem().getBattStatsImpl(chargeState, percent, milliVolts); + } + float getTemperature() { + return thisModem().getTemperatureImpl(); + } + + /* + * CRTP Helper + */ + protected: + const modemType& thisModem() const { + return static_cast(*this); + } + modemType& thisModem() { + return static_cast(*this); + } + + /* + * Inner Client + */ + public: + class GsmClient : public Client { + // Make all classes created from the modem template friends + friend class TinyGsmModem; + typedef TinyGsmFifo RxFifo; + + public: + // bool init(modemType* modem, uint8_t); + // int connect(const char* host, uint16_t port, int timeout_s); + + // Connect to a IP address given as an IPAddress object by + // converting said IP address to text + // int connect(IPAddress ip, uint16_t port, int timeout_s) { + // return connect(TinyGsmStringFromIp(ip).c_str(), port, + // timeout_s); + // } + // int connect(const char* host, uint16_t port) override { + // return connect(host, port, 75); + // } + // int connect(IPAddress ip, uint16_t port) override { + // return connect(ip, port, 75); + // } + + static String TinyGsmStringFromIp(IPAddress ip) { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return host; + } + + // void stop(uint32_t maxWaitMs); + // void stop() override { + // stop(15000L); + // } + + // Writes data out on the client using the modem send functionality + size_t write(const uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + size_t write(uint8_t c) override { + return write(&c, 1); + } + + size_t write(const char* str) { + if (str == NULL) return 0; + return write((const uint8_t*)str, strlen(str)); + } + + int available() override { + TINY_GSM_YIELD(); + switch (bufType) { + // Returns the number of characters available in the TinyGSM fifo + case NO_MODEM_BUFFER: + if (!rx.size() && sock_connected) { at->maintain(); } + return rx.size(); + + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo. + case READ_NO_CHECK: + if (!rx.size()) { at->maintain(); } + return rx.size() + sock_available; + + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo, doing an extra check-in + // with the modem to see if anything has arrived without a UURC. + case READ_AND_CHECK_SIZE: + if (!rx.size()) { + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + at->maintain(); + } + return rx.size() + sock_available; + } + } + + int read(uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + size_t cnt = 0; + uint32_t _startMillis = millis(); + + switch (bufType) { + // Reads characters out of the TinyGSM fifo, waiting for any URC's + // from the modem for new data if there's nothing in the fifo. + case NO_MODEM_BUFFER: + while (cnt < size && millis() - _startMillis < _timeout) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } /* TODO: Read directly into user buffer? */ + if (!rx.size() && sock_connected) { at->maintain(); } + } + return cnt; + + // Reads characters out of the TinyGSM fifo, and from the modem chip's + // internal fifo if avaiable. + case READ_NO_CHECK: + at->maintain(); + while (cnt < size) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } /* TODO: Read directly into user buffer? */ + at->maintain(); + if (sock_available > 0) { + int n = at->modemRead( + TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + if (n == 0) break; + } else { + break; + } + } + return cnt; + + // Reads characters out of the TinyGSM fifo, and from the modem chips + // internal fifo if avaiable, also double checking with the modem if + // data has arrived without issuing a UURC. + case READ_AND_CHECK_SIZE: + at->maintain(); + while (cnt < size) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // Workaround: Some modules "forget" to notify about data arrival + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + // TODO(vshymanskyy): Read directly into user buffer? + at->maintain(); + if (sock_available > 0) { + int n = at->modemRead( + TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + if (n == 0) break; + } else { + break; + } + } + return cnt; + } + } + + int read() override { + uint8_t c; + if (read(&c, 1) == 1) { return c; } + return -1; + } + + // TODO(SRGDamia1): Implement peek + int peek() override { + return -1; + } + + void flush() override { + at->stream.flush(); + } + + uint8_t connected() override { + if (available()) { return true; } + return sock_connected; + } + operator bool() override { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + protected: + // Read and dump anything remaining in the modem's internal buffer. + // Using this in the client stop() function. + // The socket will appear open in response to connected() even after it + // closes until all data is read from the buffer. + // Doing it this way allows the external mcu to find and get all of the + // data that it wants from the socket even if it was closed externally. + void dumpModemBuffer(uint32_t maxWaitMs) { + TINY_GSM_YIELD(); + rx.clear(); + at->maintain(); + uint32_t startMillis = millis(); + while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { + at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + rx.clear(); + at->maintain(); + } + } + + modemType* at; + uint8_t mux; + uint16_t sock_available; + uint32_t prev_check; + bool sock_connected; + bool got_data; + RxFifo rx; + }; + + /* + * Inner Secure Client + */ + + /* + * Constructor + */ + + protected: + /* + * Basic functions + */ + + void setBaudImpl(uint32_t baud) { + thisModem().sendAT(GF("+IPR="), baud); + thisModem().waitResponse(); + } + + bool testATImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + thisModem().sendAT(GF("")); + if (thisModem().waitResponse(200) == 1) { return true; } + delay(100); + } + return false; + } + + String getModemInfoImpl() { + thisModem().sendAT(GF("I")); + String res; + if (thisModem().waitResponse(1000L, res) != 1) { return ""; } + // Do the replaces twice so we cover both \r and \r\n type endings + res.replace("\r\nOK\r\n", ""); + res.replace("\rOK\r", ""); + res.replace("\r\n", " "); + res.replace("\r", " "); + res.trim(); + return res; + } + + String getModemNameImpl() { + thisModem().sendAT(GF("+CGMI")); + String res1; + if (thisModem().waitResponse(1000L, res1) != 1) { return "unknown"; } + res1.replace("\r\nOK\r\n", ""); + res1.replace("\rOK\r", ""); + res1.trim(); + + thisModem().sendAT(GF("+GMM")); + String res2; + if (thisModem().waitResponse(1000L, res2) != 1) { return "unknown"; } + res1.replace("\r\nOK\r\n", ""); + res1.replace("\rOK\r", ""); + res2.trim(); + + String name = res1 + String(' ') + res2; + DBG("### Modem:", name); + return name; + } + + void maintainImpl() { + switch (bufType) { + case READ_AND_CHECK_SIZE: + // Keep listening for modem URC's and proactively iterate through + // sockets asking if any data is avaiable + for (int mux = 0; mux < muxCount; mux++) { + GsmClient* sock = thisModem().sockets[mux]; + if (sock && sock->got_data) { + sock->got_data = false; + sock->sock_available = thisModem().modemGetAvailable(mux); + } + } + while (thisModem().stream.available()) { + thisModem().waitResponse(15, NULL, NULL); + } + break; + default: + // Just listen for any URC's + thisModem().waitResponse(100, NULL, NULL); + break; + } + } + + bool factoryDefaultImpl() { + thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write + thisModem().waitResponse(); + thisModem().sendAT(GF("+IPR=0")); // Auto-baud + thisModem().waitResponse(); + thisModem().sendAT(GF("&W")); // Write configuration + return thisModem().waitResponse() == 1; + } + + /* + * Power functions + */ + protected: + bool radioOffImpl() { + thisModem().sendAT(GF("+CFUN=0")); + if (thisModem().waitResponse(10000L) != 1) { return false; } + delay(3000); + return true; + } + + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + /* + * SIM card functions + */ + protected: + // Unlocks a sim via the 3GPP TS command AT+CPIN + bool simUnlockImpl(const char* pin) { + if (pin && strlen(pin) > 0) { + thisModem().sendAT(GF("+CPIN=\""), pin, GF("\"")); + return thisModem().waitResponse() == 1; + } + return true; + } + + // Gets the CCID of a sim card via AT+CCID + String getSimCCIDImpl() { + thisModem().sendAT(GF("+CCID")); + if (thisModem().waitResponse(GF("+CCID:")) != 1) { return ""; } + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + + // Asks for TA Serial Number Identification (IMEI) via the V.25TER standard + // AT+GSN command + String getIMEIImpl() { + thisModem().sendAT(GF("+GSN")); + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + thisModem().sendAT(GF("+CPIN?")); + if (thisModem().waitResponse(GF("+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = + thisModem().waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), + GF("NOT INSERTED"), GF("NOT READY")); + thisModem().waitResponse(); + switch (status) { + case 2: + case 3: return SIM_LOCKED; + case 1: return SIM_READY; + default: return SIM_ERROR; + } + } + return SIM_ERROR; + } + + /* + * Generic network functions + */ + protected: + // Gets the modem's registration status via CREG/CGREG/CEREG + // CREG = Generic network registration + // CGREG = GPRS service registration + // CEREG = EPS registration for LTE modules + int getRegistrationStatusXREG(const char* regCommand) { + thisModem().sendAT('+', regCommand, '?'); + // check for any of the three for simplicity + int resp = + thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"), GF("+CEREG:")); + if (resp != 1 && resp != 2 && resp != 3) { return -1; } + thisModem().streamSkipUntil(','); /* Skip format (0) */ + int status = thisModem().stream.readStringUntil('\n').toInt(); + thisModem().waitResponse(); + return status; + } + + bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + if (thisModem().isNetworkConnected()) { return true; } + delay(250); + } + return false; + } + + // Gets signal quality report according to 3GPP TS command AT+CSQ + int16_t getSignalQualityImpl() { + thisModem().sendAT(GF("+CSQ")); + if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; } + int res = thisModem().stream.readStringUntil(',').toInt(); + thisModem().waitResponse(); + return res; + } + + /* + * GPRS functions + */ + protected: + // Checks if current attached to GPRS/EPS service + bool isGprsConnectedImpl() { + thisModem().sendAT(GF("+CGATT?")); + if (thisModem().waitResponse(GF("+CGATT:")) != 1) { return false; } + int res = thisModem().stream.readStringUntil('\n').toInt(); + thisModem().waitResponse(); + if (res != 1) { return false; } + + return thisModem().localIP() != IPAddress(0, 0, 0, 0); + } + + // Gets the current network operator via the 3GPP TS command AT+COPS + String getOperatorImpl() { + thisModem().sendAT(GF("+COPS?")); + if (thisModem().waitResponse(GF("+COPS:")) != 1) { return ""; } + thisModem().streamSkipUntil('"'); /* Skip mode and format */ + String res = thisModem().stream.readStringUntil('"'); + thisModem().waitResponse(); + return res; + } + + /* + * WiFi functions + */ + + bool networkConnectImpl(const char* ssid, const char* pwd) { + return false; + } + bool networkDisconnectImpl() { + return thisModem().gprsConnectImpl(); + } + + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + thisModem().sendAT(GF("+CGPADDR=1")); + if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; } + thisModem().streamSkipUntil(','); // Skip context id + String res = thisModem().stream.readStringUntil('\r'); + if (thisModem().waitResponse() != 1) { return ""; } + return res; + } + + static IPAddress TinyGsmIpFromString(const String& strIP) { + int Parts[4] = { + 0, + }; + int Part = 0; + for (uint8_t i = 0; i < strIP.length(); i++) { + char c = strIP[i]; + if (c == '.') { + Part++; + if (Part > 3) { return IPAddress(0, 0, 0, 0); } + continue; + } else if (c >= '0' && c <= '9') { + Parts[Part] *= 10; + Parts[Part] += c - '0'; + } else { + if (Part == 3) break; } - continue; - } else if (c >= '0' && c <= '9') { - Parts[Part] *= 10; - Parts[Part] += c - '0'; + } + return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]); + } + + /* + * Phone Call functions + */ + protected: + bool callAnswerImpl() { + thisModem().sendAT(GF("A")); + return thisModem().waitResponse() == 1; + } + + // Returns true on pick-up, false on error/busy + bool callNumberImpl(const String& number) { + if (number == GF("last")) { + thisModem().sendAT(GF("DL")); } else { - if (Part == 3) break; + thisModem().sendAT(GF("D"), number, ";"); + } + int status = thisModem().waitResponse(60000L, GF("OK"), GF("BUSY"), + GF("NO ANSWER"), GF("NO CARRIER")); + switch (status) { + case 1: return true; + case 2: + case 3: return false; + default: return false; } } - return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]); -} -static inline -String TinyGsmDecodeHex7bit(String &instr) { - String result; - byte reminder = 0; - int bitstate = 7; - for (unsigned i=0; i> bitstate; - bitstate--; - if (bitstate == 0) { - char c = reminder; + bool callHangupImpl() { + thisModem().sendAT(GF("H")); + return thisModem().waitResponse() == 1; + } + + // 0-9,*,#,A,B,C,D + bool dtmfSendImpl(char cmd, int duration_ms = 100) { + duration_ms = constrain(duration_ms, 100, 1000); + + thisModem().sendAT(GF("+VTD="), + duration_ms / 100); // VTD accepts in 1/10 of a second + thisModem().waitResponse(); + + thisModem().sendAT(GF("+VTS="), cmd); + return thisModem().waitResponse(10000L) == 1; + } + + /* + * Messaging functions + */ + protected: + static inline String TinyGsmDecodeHex7bit(String& instr) { + String result; + byte reminder = 0; + int bitstate = 7; + for (unsigned i = 0; i < instr.length(); i += 2) { + char buf[4] = { + 0, + }; + buf[0] = instr[i]; + buf[1] = instr[i + 1]; + byte b = strtol(buf, NULL, 16); + + byte bb = b << (7 - bitstate); + char c = (bb + reminder) & 0x7F; result += c; - reminder = 0; - bitstate = 7; + reminder = b >> bitstate; + bitstate--; + if (bitstate == 0) { + char cc = reminder; + result += cc; + reminder = 0; + bitstate = 7; + } } + return result; } - return result; -} -static inline -String TinyGsmDecodeHex8bit(String &instr) { - String result; - for (unsigned i=0; imaintain(); \ - return at->modemSend(buf, size, mux); \ - } \ - \ - virtual size_t write(uint8_t c) {\ - return write(&c, 1); \ - }\ - \ - virtual size_t write(const char *str) { \ - if (str == NULL) return 0; \ - return write((const uint8_t *)str, strlen(str)); \ - } - - -// Returns the combined number of characters available in the TinyGSM fifo -// and the modem chips internal fifo, doing an extra check-in with the -// modem to see if anything has arrived without a UURC. -#define TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() \ - virtual int available() { \ - TINY_GSM_YIELD(); \ - if (!rx.size()) { \ - /* Workaround: sometimes module forgets to notify about data arrival. - TODO: Currently we ping the module periodically, - but maybe there's a better indicator that we need to poll */ \ - if (millis() - prev_check > 500) { \ - got_data = true; \ - prev_check = millis(); \ - } \ - at->maintain(); \ - } \ - return rx.size() + sock_available; \ - } - - -// Returns the combined number of characters available in the TinyGSM fifo and -// the modem chips internal fifo. Use this if you don't expect to miss any URC's. -#define TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() \ - virtual int available() { \ - TINY_GSM_YIELD(); \ - if (!rx.size()) { \ - at->maintain(); \ - } \ - return rx.size() + sock_available; \ - } - - -// Returns the number of characters available in the TinyGSM fifo -// Assumes the modem chip has no internal fifo -#define TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() \ - virtual int available() { \ - TINY_GSM_YIELD(); \ - if (!rx.size() && sock_connected) { \ - at->maintain(); \ - } \ - return rx.size(); \ - } - - -#define TINY_GSM_CLIENT_READ_OVERLOAD() \ - virtual int read() { \ - uint8_t c; \ - if (read(&c, 1) == 1) { \ - return c; \ - } \ - return -1; \ - } - -// Reads characters out of the TinyGSM fifo, and from the modem chips internal -// fifo if avaiable, also double checking with the modem if data has arrived -// without issuing a UURC. -#define TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() \ - virtual int read(uint8_t *buf, size_t size) { \ - TINY_GSM_YIELD(); \ - at->maintain(); \ - size_t cnt = 0; \ - while (cnt < size) { \ - size_t chunk = TinyGsmMin(size-cnt, rx.size()); \ - if (chunk > 0) { \ - rx.get(buf, chunk); \ - buf += chunk; \ - cnt += chunk; \ - continue; \ - } \ - /* Workaround: sometimes module forgets to notify about data arrival. - TODO: Currently we ping the module periodically, - but maybe there's a better indicator that we need to poll */ \ - if (millis() - prev_check > 500) { \ - got_data = true; \ - prev_check = millis(); \ - } \ - /* TODO: Read directly into user buffer? */ \ - at->maintain(); \ - if (sock_available > 0) { \ - int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \ - if (n == 0) break; \ - } else { \ - break; \ - } \ - } \ - return cnt; \ - } \ - TINY_GSM_CLIENT_READ_OVERLOAD() - - -// Reads characters out of the TinyGSM fifo, and from the modem chips internal -// fifo if avaiable. Use this if you don't expect to miss any URC's. -#define TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() \ - virtual int read(uint8_t *buf, size_t size) { \ - TINY_GSM_YIELD(); \ - at->maintain(); \ - size_t cnt = 0; \ - while (cnt < size) { \ - size_t chunk = TinyGsmMin(size-cnt, rx.size()); \ - if (chunk > 0) { \ - rx.get(buf, chunk); \ - buf += chunk; \ - cnt += chunk; \ - continue; \ - } \ - /* TODO: Read directly into user buffer? */ \ - at->maintain(); \ - if (sock_available > 0) { \ - int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \ - if (n == 0) break; \ - } else { \ - break; \ - } \ - } \ - return cnt; \ - } \ - TINY_GSM_CLIENT_READ_OVERLOAD() - - -// Reads characters out of the TinyGSM fifo, waiting for any URC's from the -// modem for new data if there's nothing in the fifo. This assumes the -//modem chip itself has no fifo. -#define TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() \ - virtual int read(uint8_t *buf, size_t size) { \ - TINY_GSM_YIELD(); \ - size_t cnt = 0; \ - uint32_t _startMillis = millis(); \ - while (cnt < size && millis() - _startMillis < _timeout) { \ - size_t chunk = TinyGsmMin(size-cnt, rx.size()); \ - if (chunk > 0) { \ - rx.get(buf, chunk); \ - buf += chunk; \ - cnt += chunk; \ - continue; \ - } \ - /* TODO: Read directly into user buffer? */ \ - if (!rx.size() && sock_connected) { \ - at->maintain(); \ - } \ - } \ - return cnt; \ - } \ - \ - virtual int read() { \ - uint8_t c; \ - if (read(&c, 1) == 1) { \ - return c; \ - } \ - return -1; \ - } - - -// Read and dump anything remaining in the modem's internal buffer. -// Using this in the client stop() function. -// The socket will appear open in response to connected() even after it -// closes until all data is read from the buffer. -// Doing it this way allows the external mcu to find and get all of the data -// that it wants from the socket even if it was closed externally. -#define TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() \ - TINY_GSM_YIELD(); \ - rx.clear(); \ - at->maintain(); \ - unsigned long startMillis = millis(); \ - while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { \ - at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \ - rx.clear(); \ - at->maintain(); \ + String sendUSSDImpl(const String& code) { + // Set preferred message format to text mode + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + // Set 8-bit hexadecimal alphabet (3GPP TS 23.038) + thisModem().sendAT(GF("+CSCS=\"HEX\"")); + thisModem().waitResponse(); + // Send the message + thisModem().sendAT(GF("+CUSD=1,\""), code, GF("\"")); + if (thisModem().waitResponse() != 1) { return ""; } + if (thisModem().waitResponse(10000L, GF("+CUSD:")) != 1) { return ""; } + thisModem().stream.readStringUntil('"'); + String hex = thisModem().stream.readStringUntil('"'); + thisModem().stream.readStringUntil(','); + int dcs = thisModem().stream.readStringUntil('\n').toInt(); + + if (dcs == 15) { + return TinyGsmDecodeHex8bit(hex); + } else if (dcs == 72) { + return TinyGsmDecodeHex16bit(hex); + } else { + return hex; } + } + bool sendSMSImpl(const String& number, const String& text) { + // Set preferred message format to text mode + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + // Set GSM 7 bit default alphabet (3GPP TS 23.038) + thisModem().sendAT(GF("+CSCS=\"GSM\"")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); + if (thisModem().waitResponse(GF(">")) != 1) { return false; } + thisModem().stream.print(text); // Actually send the message + thisModem().stream.write(static_cast(0x1A)); // Terminate the message + thisModem().stream.flush(); + return thisModem().waitResponse(60000L) == 1; + } -// The peek, flush, and connected functions -#define TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() \ - virtual int peek() { return -1; } /* TODO */ \ - \ - virtual void flush() { at->stream.flush(); } \ - \ - virtual uint8_t connected() { \ - if (available()) { \ - return true; \ - } \ - return sock_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_ms = 10000L) { \ - for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \ - 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(100, 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) { \ - if (pin && strlen(pin) > 0) { \ - sendAT(GF("+CPIN=\""), pin, GF("\"")); \ - return waitResponse() == 1; \ - } \ - return true; \ - } - - -// 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_ms = 60000L) { \ - for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \ - if (isNetworkConnected()) { \ - return true; \ - } \ - delay(250); \ - } \ - return false; \ - } - - -// Checks if current attached to GPRS/EPS service -#define TINY_GSM_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_GSM_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; \ - } - - -// Yields up to a time-out period and then reads a character from the stream into the mux FIFO -// TODO: Do we need to wait two _timeout periods for no character return? Will wait once in the first -// "while !stream.available()" and then will wait again in the stream.read() function. -#define TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT \ - uint32_t startMillis = millis(); \ - while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } \ - char c = stream.read(); \ - sockets[mux]->rx.put(c); - - -// Utility templates for writing/skipping characters on a stream -#define TINY_GSM_MODEM_STREAM_UTILITIES() \ - template \ - void streamWrite(T last) { \ - stream.print(last); \ - } \ - \ - template \ - void streamWrite(T head, Args... tail) { \ - stream.print(head); \ - streamWrite(tail...); \ - } \ - \ - template \ - 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_ms = 1000L) { \ - unsigned long startMillis = millis(); \ - while (millis() - startMillis < timeout_ms) { \ - while (millis() - startMillis < timeout_ms && !stream.available()) { \ - TINY_GSM_YIELD(); \ - } \ - if (stream.read() == c) { \ - return true; \ - } \ - } \ - return false; \ - } - - -//Common methods for UTF8/UTF16 SMS. -//Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800 -template -class TinyGsmUTFSMS { -public: - + // Common methods for UTF8/UTF16 SMS. + // Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800 class UTF8Print : public Print { - public: - UTF8Print(Print& p) : p(p) {} - virtual size_t write(const uint8_t c) override { - if(prv < 0xC0) { - if(c < 0xC0) printHex(c); + public: + explicit UTF8Print(Print& p) : p(p) {} + size_t write(const uint8_t c) override { + if (prv < 0xC0) { + if (c < 0xC0) printHex(c); prv = c; } else { - uint16_t v = uint16_t(prv)<<8 | c; - v -= (v>>8 == 0xD0)? 0xCC80 : 0xCD40; + uint16_t v = uint16_t(prv) << 8 | c; + v -= (v >> 8 == 0xD0) ? 0xCC80 : 0xCD40; printHex(v); prv = 0; } return 1; } - private: - Print& p; + + private: + Print& p; uint8_t prv = 0; - void printHex(const uint16_t v) { + void printHex(const uint16_t v) { uint8_t c = v >> 8; if (c < 0x10) p.print('0'); p.print(c, HEX); @@ -680,42 +1033,185 @@ public: }; bool sendSMS_UTF8_begin(const char* const number) { - static_cast(this)->sendAT(GF("+CMGF=1")); - static_cast(this)->waitResponse(); - static_cast(this)->sendAT(GF("+CSCS=\"HEX\"")); - static_cast(this)->waitResponse(); - static_cast(this)->sendAT(GF("+CSMP=17,167,0,8")); - static_cast(this)->waitResponse(); - - static_cast(this)->sendAT(GF("+CMGS=\""), number, GF("\"")); - return static_cast(this)->waitResponse(GF(">")) == 1; + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CSCS=\"HEX\"")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CSMP=17,167,0,8")); + thisModem().waitResponse(); + + thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); + return thisModem().waitResponse(GF(">")) == 1; } bool sendSMS_UTF8_end() { - static_cast(this)->stream.write((char)0x1A); - static_cast(this)->stream.flush(); - return static_cast(this)->waitResponse(60000L) == 1; + thisModem().stream.write(static_cast(0x1A)); + thisModem().stream.flush(); + return thisModem().waitResponse(60000L) == 1; } UTF8Print sendSMS_UTF8_stream() { - return UTF8Print(static_cast(this)->stream); + return UTF8Print(thisModem().stream); } - bool sendSMS_UTF16(const char* const number, const void* text, size_t len) { - if (!sendSMS_UTF8_begin(number)) { - return false; - } + bool + sendSMS_UTF16Impl(const char* const number, const void* text, size_t len) { + if (!sendSMS_UTF8_begin(number)) { return false; } - uint16_t* t = (uint16_t*)text; - for (size_t i=0; i(text); + for (size_t i = 0; i < len; i++) { uint8_t c = t[i] >> 8; - if (c < 0x10) { static_cast(this)->stream.print('0'); } - static_cast(this)->stream.print(c, HEX); + if (c < 0x10) { thisModem().stream.print('0'); } + thisModem().stream.print(c, HEX); c = t[i] & 0xFF; - if (c < 0x10) { static_cast(this)->stream.print('0'); } - static_cast(this)->stream.print(c, HEX); + if (c < 0x10) { thisModem().stream.print('0'); } + thisModem().stream.print(c, HEX); } - + return sendSMS_UTF8_end(); } + + /* + * Location functions + */ + protected: + String getGsmLocationImpl() { + thisModem().sendAT(GF("+CIPGSMLOC=1,1")); + if (thisModem().waitResponse(10000L, GF("+CIPGSMLOC:")) != 1) { return ""; } + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + + /* + * GPS location functions + */ + public: + /* + * Time functions + */ + protected: + String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) { + thisModem().sendAT(GF("+CCLK?")); + if (thisModem().waitResponse(2000L, GF("+CCLK: \"")) != 1) { return ""; } + + String res; + + switch (format) { + case DATE_FULL: res = thisModem().stream.readStringUntil('"'); break; + case DATE_TIME: + thisModem().streamSkipUntil(','); + res = thisModem().stream.readStringUntil('"'); + break; + case DATE_DATE: res = thisModem().stream.readStringUntil(','); break; + } + return res; + } + + /* + * Battery & temperature functions + */ + protected: + // Use: float vBatt = modem.getBattVoltage() / 1000.0; + uint16_t getBattVoltageImpl() { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return 0; } + thisModem().streamSkipUntil(','); // Skip battery charge status + thisModem().streamSkipUntil(','); // Skip battery charge level + // return voltage in mV + uint16_t res = thisModem().stream.readStringUntil(',').toInt(); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + int8_t getBattPercentImpl() { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + thisModem().streamSkipUntil(','); // Skip battery charge status + // Read battery charge level + int res = thisModem().stream.readStringUntil(',').toInt(); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + uint8_t getBattChargeStateImpl() { + thisModem().sendAT(GF("+CBC?")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + // Read battery charge status + int res = thisModem().stream.readStringUntil(',').toInt(); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { + thisModem().sendAT(GF("+CBC?")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + chargeState = thisModem().stream.readStringUntil(',').toInt(); + percent = thisModem().stream.readStringUntil(',').toInt(); + milliVolts = thisModem().stream.readStringUntil('\n').toInt(); + // Wait for final OK + thisModem().waitResponse(); + return true; + } + + float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Client related functions + */ + protected: + /* + Utilities + */ + + // Utility templates for writing/skipping characters on a stream + template + void streamWrite(T last) { + thisModem().stream.print(last); + } + + template + void streamWrite(T head, Args... tail) { + thisModem().stream.print(head); + thisModem().streamWrite(tail...); + } + + // template void sendAT(Args... cmd) { + // thisModem().streamWrite("AT", cmd..., thisModem().gsmNL); + // thisModem().stream.flush(); + // TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */ + // } + + bool streamSkipUntil(const char c, const uint32_t timeout_ms = 1000L) { + uint32_t startMillis = millis(); + while (millis() - startMillis < timeout_ms) { + while (millis() - startMillis < timeout_ms && + !thisModem().stream.available()) { + TINY_GSM_YIELD(); + } + if (thisModem().stream.read() == c) { return true; } + } + return false; + } + + // Yields up to a time-out period and then reads a character from the stream + // into the mux FIFO + // TODO(SRGDamia1): Do we need to wait two _timeout periods for no + // character return? Will wait once in the first "while + // !stream.available()" and then will wait again in the stream.read() + // function. + void moveCharFromStreamToFifo(uint8_t mux) { + uint32_t startMillis = millis(); + while (!thisModem().stream.available() && + (millis() - startMillis < thisModem().sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char c = thisModem().stream.read(); + thisModem().sockets[mux]->rx.put(c); + } }; -#endif +#endif // SRC_TINYGSMCOMMON_H_ diff --git a/tools/test_build/test_build.ino b/tools/test_build/test_build.ino index 296f623..1f8d80b 100644 --- a/tools/test_build/test_build.ino +++ b/tools/test_build/test_build.ino @@ -25,23 +25,35 @@ void setup() { void loop() { - // Test the start/restart functions - modem.restart(); + // Test the basic functions + modem.init(); modem.begin(); + modem.setBaud(115200); modem.testAT(); modem.factoryDefault(); + modem.getModemInfo(); + modem.getModemName(); + modem.maintain(); + modem.hasSSL(); + modem.hasWifi(); + modem.hasGPRS(); + + // Test Power functions + modem.restart(); + // modem.sleepEnable(); + modem.radioOff(); + modem.poweroff(); // Test the SIM card functions #if defined(TINY_GSM_MODEM_HAS_GPRS) modem.getSimCCID(); modem.getIMEI(); modem.getSimStatus(); - modem.getRegistrationStatus(); modem.getOperator(); #endif - // Test the Networking functions + modem.getRegistrationStatus(); modem.getSignalQuality(); modem.localIP(); @@ -61,7 +73,7 @@ void loop() { client.print(String("Host: ") + server + "\r\n"); client.print("Connection: close\r\n\r\n"); - unsigned long timeout = millis(); + uint32_t timeout = millis(); while (client.connected() && millis() - timeout < 10000L) { while (client.available()) { client.read(); @@ -77,4 +89,9 @@ void loop() { #if defined(TINY_GSM_MODEM_HAS_WIFI) modem.networkDisconnect(); #endif + + // Test battery and temperature functions + // modem.getBattVoltage(); + // modem.getBattPercent(); + // modem.getTemperature(); } From 5daa3efa828e4ad16d89fde16d85b60c37f14b48 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Thu, 6 Feb 2020 18:24:22 -0500 Subject: [PATCH 21/88] Version bump Signed-off-by: Sara Damiano --- .github/ISSUE_TEMPLATE.md | 2 +- README.md | 29 ++++++++++++++++------------- library.json | 2 +- library.properties | 2 +- src/TinyGsmClientBG96.h | 2 +- src/TinyGsmClientM95.h | 2 +- src/TinyGsmClientMC60.h | 2 +- src/TinyGsmCommon.h | 3 ++- tools/Diagnostics/Diagnostics.ino | 10 +++++----- tools/test_build/test_build.ino | 7 +++---- 10 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 72063f1..ef24062 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,7 +22,7 @@ with your board before submitting any issues. Main processor board: Modem: -TinyGSM version: +TinyGSM version: Code: ### Scenario, steps to reproduce diff --git a/README.md b/README.md index 4ab951a..59bc900 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope - Neoway M590 - u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx) - u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_) -- Sequans Monarch LTE Cat M1/NB1 +- Sequans Monarch LTE Cat M1/NB1 (VZM20Q) - Quectel BG96 - Quectel M95 - Quectel MC60 ***(alpha)*** @@ -83,26 +83,29 @@ Watch this repo for new updates! And of course, contributions are welcome ;) - SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch - Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.) - Not yet supported on: - - Quectel modems, SIM7000, SIM5360/5320/7100/7500/7600 + - Quectel modems, SIM7000, SIM5360/5320, SIM7100/7500/7600 - Not possible on: - - SIM900, A6/A7, M560, XBee _WiFi_ + - SIM900, A6/A7, Neoway M590, XBee _WiFi_ **USSD** - Sending USSD requests and decoding 7,8,16-bit responses - Supported on: - - SIM800/SIM900, SIM7000 - - Not yet supported on: - - Quectel modems, SIM5360/5320/7100/7500/7600, XBee + - All SIMCom modems, Quectel modems, most u-blox + - Not possible on: + - XBee, u-blox SARA R4/N4, ESP8266 (obviously) **SMS** - Only _sending_ SMS is supported, not receiving - - Supported on: - - SIM800/SIM900, SIM7000, XBee - - Not yet supported on: - - Quectel modems, SIM5360/5320/7100/7500/7600 + - Supported on all cellular modules **Voice Calls** -- Only Supported on SIM800 and A6/A7/A20 +- Supported on: + - SIM800/SIM900, A6/A7, Quectel modems, u-blox +- Not yet supported on: + - SIM7000, SIM5360/5320/7100, SIM7500/7600/7800, VZM20Q (Monarch) +- Not possible on: + - XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously) +- Functions: - Dial, hangup - Receiving calls - Incoming event (RING) @@ -111,9 +114,9 @@ Watch this repo for new updates! And of course, contributions are welcome ;) **Location** - GPS/GNSS - - SIM808 and SIM7000 only + - SIM808, SIM7000, SIM7500/7600/7800 only - GSM location service - - SIM800, SIM and SIM7000 only + - SIM800, SIM7000, Quectel, u-blox **Credits** - Primary Authors/Contributors: diff --git a/library.json b/library.json index d16cda6..b529261 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "TinyGSM", - "version": "0.9.19", + "version": "0.10.0", "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.", "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M", "authors": diff --git a/library.properties b/library.properties index aa8f193..fcfd3fb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TinyGSM -version=0.9.19 +version=0.10.0 author=Volodymyr Shymanskyy maintainer=Volodymyr Shymanskyy sentence=A small Arduino library for GPRS modules, that just works. diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index dad31cb..a255037 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -113,7 +113,7 @@ class TinyGsmBG96 public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index d983775..5954a31 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -114,7 +114,7 @@ class TinyGsmM95 public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 9681153..ecb1fd3 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -116,7 +116,7 @@ class TinyGsmMC60 public: - virtual int connect(const char *host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index 0f97f33..99a3edf 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -10,7 +10,7 @@ #define SRC_TINYGSMCOMMON_H_ // The current library version number -#define TINYGSM_VERSION "0.9.19" +#define TINYGSM_VERSION "0.10.0" #if defined(SPARK) || defined(PARTICLE) #include "Particle.h" @@ -118,6 +118,7 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, } } } + SerialAT.begin(minimum); return 0; } diff --git a/tools/Diagnostics/Diagnostics.ino b/tools/Diagnostics/Diagnostics.ino index 962043c..c44aa48 100644 --- a/tools/Diagnostics/Diagnostics.ino +++ b/tools/Diagnostics/Diagnostics.ino @@ -48,7 +48,7 @@ #define TINY_GSM_RX_BUFFER 1024 // See all AT commands, if wanted -//#define DUMP_AT_COMMANDS +// #define DUMP_AT_COMMANDS // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon @@ -58,10 +58,10 @@ #define GSM_AUTOBAUD_MAX 115200 // Add a reception delay - may be needed for a fast processor at a slow baud rate -//#define TINY_GSM_YIELD() { delay(2); } +// #define TINY_GSM_YIELD() { delay(2); } // Uncomment this if you want to use SSL -//#define USE_SSL +// #define USE_SSL #define TINY_GSM_USE_GPRS true #define TINY_GSM_USE_WIFI false @@ -236,8 +236,8 @@ void loop() { client.find("\r\n\r\n"); // Read data - unsigned long timeout = millis(); - unsigned long bytesReceived = 0; + uint32_t timeout = millis(); + uint32_t bytesReceived = 0; while (client.connected() && millis() - timeout < 10000L) { while (client.available()) { char c = client.read(); diff --git a/tools/test_build/test_build.ino b/tools/test_build/test_build.ino index 1f8d80b..e5b0db7 100644 --- a/tools/test_build/test_build.ino +++ b/tools/test_build/test_build.ino @@ -3,7 +3,7 @@ * DO NOT USE THIS - this is just a compilation test! * **************************************************************/ -// #define TINY_GSM_MODEM_SIM800 +#define TINY_GSM_MODEM_SIM800 #include @@ -20,13 +20,12 @@ char resource[] = "something"; void setup() { Serial.begin(115200); delay(3000); - modem.restart(); } void loop() { // Test the basic functions - modem.init(); + // modem.init(); modem.begin(); modem.setBaud(115200); modem.testAT(); @@ -62,7 +61,7 @@ void loop() { modem.gprsConnect("YourAPN", "", ""); #endif #if defined(TINY_GSM_MODEM_HAS_WIFI) - modem.networkConnect("YourSSID", "YourPWD"); + modem.networkConnect("YourSSID", "YourWiFiPass"); modem.waitForNetwork(); #endif From 944f651865be7f9d9ca9ea6e69fa34bc75f1c706 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 7 Feb 2020 13:18:36 -0500 Subject: [PATCH 22/88] Changed some format penalties Signed-off-by: Sara Damiano --- .clang-format | 4 +-- src/TinyGsmClientA6.h | 20 +++++++------- src/TinyGsmClientBG96.h | 20 +++++++------- src/TinyGsmClientESP8266.h | 36 ++++++++++++------------- src/TinyGsmClientM590.h | 24 ++++++++--------- src/TinyGsmClientM95.h | 26 +++++++++--------- src/TinyGsmClientMC60.h | 44 ++++++++++++++++--------------- src/TinyGsmClientSIM5360.h | 24 ++++++++--------- src/TinyGsmClientSIM7000.h | 27 ++++++++++--------- src/TinyGsmClientSIM7600.h | 24 ++++++++--------- src/TinyGsmClientSIM800.h | 23 +++++++++------- src/TinyGsmClientSaraR4.h | 24 ++++++++--------- src/TinyGsmClientSequansMonarch.h | 28 ++++++++++---------- src/TinyGsmClientUBLOX.h | 22 ++++++++-------- src/TinyGsmClientXBee.h | 26 +++++++++--------- src/TinyGsmCommon.h | 27 +++++++++++-------- 16 files changed, 206 insertions(+), 193 deletions(-) diff --git a/.clang-format b/.clang-format index 110d35d..60ffff7 100644 --- a/.clang-format +++ b/.clang-format @@ -74,14 +74,14 @@ NamespaceIndentation: None ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 +PenaltyBreakAssignment: 25 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 60 -PenaltyReturnTypeOnItsOwnLine: 5 +PenaltyReturnTypeOnItsOwnLine: 50 PointerAlignment: Left PointerBindsToType: true ReflowComments: true diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index fc89369..3b28a94 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -477,11 +477,11 @@ class TinyGsmA6 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -489,7 +489,7 @@ class TinyGsmA6 String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -558,10 +558,10 @@ class TinyGsmA6 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 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index a255037..0347055 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -394,11 +394,11 @@ class TinyGsmBG96 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -406,7 +406,7 @@ class TinyGsmBG96 String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -472,10 +472,10 @@ class TinyGsmBG96 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 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index aac5e98..4466e38 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -219,8 +219,8 @@ class TinyGsmESP8266 RegStatus getRegistrationStatus() { sendAT(GF("+CIPSTATUS")); if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN; - int status = - waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), + GF("5")); waitResponse(); // Returns an OK after the status return (RegStatus)status; } @@ -298,8 +298,8 @@ class TinyGsmESP8266 bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool - dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; + bool dtmfSendImpl(char cmd, + int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; /* * Messaging functions @@ -382,8 +382,8 @@ class TinyGsmESP8266 bool modemGetConnected(uint8_t mux) { sendAT(GF("+CIPSTATUS")); if (waitResponse(3000, GF("STATUS:")) != 1) { return false; } - int status = - waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), + GF("5")); if (status != 3) { // if the status is anything but 3, there are no connections open waitResponse(); // Returns an OK after the status @@ -394,8 +394,8 @@ class TinyGsmESP8266 } bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0}; for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { - uint8_t has_status = - waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); + uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), + GFP(GSM_ERROR)); if (has_status == 1) { int returned_mux = stream.readStringUntil(',').toInt(); streamSkipUntil(','); // Skip mux @@ -419,11 +419,11 @@ class TinyGsmESP8266 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -431,7 +431,7 @@ class TinyGsmESP8266 String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -504,10 +504,10 @@ class TinyGsmESP8266 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 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index 3cc3edd..8fada7b 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -287,8 +287,8 @@ class TinyGsmM590 bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool - dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; + bool dtmfSendImpl(char cmd, + int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; /* * Messaging functions @@ -389,11 +389,11 @@ class TinyGsmM590 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -401,7 +401,7 @@ class TinyGsmM590 String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -471,10 +471,10 @@ class TinyGsmM590 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 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 5954a31..1b6031a 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -414,9 +414,9 @@ class TinyGsmM95 uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); - int rsp = - waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); + int rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL)); return (1 == rsp); } @@ -513,11 +513,11 @@ class TinyGsmM95 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -525,7 +525,7 @@ class TinyGsmM95 String r5s(r5); r5s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -591,10 +591,10 @@ class TinyGsmM95 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 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index ecb1fd3..4c51552 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -237,9 +237,9 @@ class TinyGsmMC60 delay(1000); continue; } - int status = - waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), - GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), + GF("NOT INSERTED"), GF("PH_SIM PIN"), + GF("PH_SIM PUK")); waitResponse(); switch (status) { case 2: @@ -393,9 +393,9 @@ class TinyGsmMC60 uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); - int rsp = - waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), - GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); + int rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL)); return (1 == rsp); } @@ -493,11 +493,12 @@ class TinyGsmMC60 */ public: // TODO(vshymanskyy): Optimize this! - uint8_t - waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, String& data, + GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL, + GsmConstStr r6 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); String r3s(r3); r3s.trim(); @@ -506,7 +507,7 @@ class TinyGsmMC60 String r6s(r6); r6s.trim(); DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/ data.reserve(64); - int index = 0; + uint8_t index = 0; uint32_t startMillis = millis(); do { TINY_GSM_YIELD(); @@ -572,19 +573,20 @@ class TinyGsmMC60 return index; } - uint8_t - waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { + uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL, + GsmConstStr r6 = NULL) { String data; return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6); } - uint8_t - waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, - GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { + uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), + GsmConstStr r2 = GFP(GSM_ERROR), + GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r4 = NULL, GsmConstStr r5 = NULL, + GsmConstStr r6 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5, r6); } diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index e598dfc..47d6c49 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -407,8 +407,8 @@ class TinyGsmSim5360 : public TinyGsmModem(text); @@ -1198,6 +1197,12 @@ class TinyGsmModem { return false; } + void streamClear() { + while (thisModem().stream.available()) { + thisModem().waitResponse(50, NULL, NULL); + } + } + // Yields up to a time-out period and then reads a character from the stream // into the mux FIFO // TODO(SRGDamia1): Do we need to wait two _timeout periods for no From efb6450045ade3dc3087797998150f21f39da3c8 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 7 Feb 2020 13:42:26 -0500 Subject: [PATCH 23/88] Refixed the CBC error found by @VinceKezel Signed-off-by: Sara Damiano --- src/TinyGsmClientA6.h | 2 ++ src/TinyGsmClientSIM5360.h | 4 +++- src/TinyGsmClientSIM7600.h | 2 +- src/TinyGsmCommon.h | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 3b28a94..4a5b086 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -401,6 +401,7 @@ class TinyGsmA6 protected: uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + // Needs a '?' after CBC, unlike most int8_t getBattPercentImpl() { sendAT(GF("+CBC?")); if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } @@ -412,6 +413,7 @@ class TinyGsmA6 return res; } + // Needs a '?' after CBC, unlike most bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, uint16_t& milliVolts) { sendAT(GF("+CBC?")); diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 47d6c49..49179a7 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -438,6 +438,7 @@ class TinyGsmSim5360 : public TinyGsmModem Date: Fri, 7 Feb 2020 14:12:25 -0500 Subject: [PATCH 24/88] Fixes around cmee Signed-off-by: Sara Damiano --- src/TinyGsmClientA6.h | 3 +++ src/TinyGsmClientBG96.h | 3 +++ src/TinyGsmClientESP8266.h | 16 ++++++---------- src/TinyGsmClientM590.h | 3 +++ src/TinyGsmClientM95.h | 3 +++ src/TinyGsmClientMC60.h | 3 +++ src/TinyGsmClientSIM5360.h | 3 +++ src/TinyGsmClientSIM7000.h | 3 +++ src/TinyGsmClientSIM7600.h | 3 +++ src/TinyGsmClientSIM800.h | 3 +++ src/TinyGsmClientSaraR4.h | 2 +- src/TinyGsmClientSequansMonarch.h | 3 +++ src/TinyGsmClientUBLOX.h | 2 +- src/TinyGsmClientXBee.h | 14 +++++--------- 14 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 4a5b086..6343d89 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -507,6 +507,9 @@ class TinyGsmA6 index = 2; goto finish; } else if (r3 && data.endsWith(r3)) { + if (r3 == GFP(GSM_CME_ERROR)) { + streamSkipUntil('\n'); // Read out the error + } index = 3; goto finish; } else if (r4 && data.endsWith(r4)) { diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index 0347055..d517655 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -422,6 +422,9 @@ class TinyGsmBG96 index = 2; goto finish; } else if (r3 && data.endsWith(r3)) { + if (r3 == GFP(GSM_CME_ERROR)) { + streamSkipUntil('\n'); // Read out the error + } index = 3; goto finish; } else if (r4 && data.endsWith(r4)) { diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 4466e38..a0cf2a5 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -17,10 +17,9 @@ #include "TinyGsmCommon.h" #define GSM_NL "\r\n" -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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; -static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; +static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; // status of ESP8266 station interface // 2 : ESP8266 station connected to an AP and has obtained IP @@ -421,8 +420,7 @@ class TinyGsmESP8266 // TODO(vshymanskyy): Optimize this! uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { /*String r1s(r1); r1s.trim(); String r2s(r2); r2s.trim(); @@ -497,16 +495,14 @@ class TinyGsmESP8266 } uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), - GsmConstStr r2 = GFP(GSM_ERROR), - GsmConstStr r3 = GFP(GSM_CME_ERROR), + GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { String data; 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 = GFP(GSM_CME_ERROR), + GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { return waitResponse(1000, r1, r2, r3, r4, r5); } diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index 8fada7b..522c3e8 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -417,6 +417,9 @@ class TinyGsmM590 index = 2; goto finish; } else if (r3 && data.endsWith(r3)) { + if (r3 == GFP(GSM_CME_ERROR)) { + streamSkipUntil('\n'); // Read out the error + } index = 3; goto finish; } else if (r4 && data.endsWith(r4)) { diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 1b6031a..7f259d5 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -541,6 +541,9 @@ class TinyGsmM95 index = 2; goto finish; } else if (r3 && data.endsWith(r3)) { + if (r3 == GFP(GSM_CME_ERROR)) { + streamSkipUntil('\n'); // Read out the error + } index = 3; goto finish; } else if (r4 && data.endsWith(r4)) { diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 4c51552..0416ded 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -523,6 +523,9 @@ class TinyGsmMC60 index = 2; goto finish; } else if (r3 && data.endsWith(r3)) { + if (r3 == GFP(GSM_CME_ERROR)) { + streamSkipUntil('\n'); // Read out the error + } index = 3; goto finish; } else if (r4 && data.endsWith(r4)) { diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 49179a7..58bce88 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -616,6 +616,9 @@ class TinyGsmSim5360 : public TinyGsmModem Date: Fri, 7 Feb 2020 16:58:44 -0500 Subject: [PATCH 25/88] Adjust ublox gsm location Signed-off-by: Sara Damiano --- examples/AllFunctions/AllFunctions.ino | 4 ++-- src/TinyGsmClientUBLOX.h | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/AllFunctions/AllFunctions.ino b/examples/AllFunctions/AllFunctions.ino index 7313a6d..7ba2045 100644 --- a/examples/AllFunctions/AllFunctions.ino +++ b/examples/AllFunctions/AllFunctions.ino @@ -126,7 +126,7 @@ void setup() { // Set GSM module baud rate TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); - //SerialAT.begin(9600); + //SerialAT.begin(115200); delay(3000); } @@ -174,7 +174,7 @@ void loop() { #endif DBG("Waiting for network..."); - if (!modem.waitForNetwork()) { + if (!modem.waitForNetwork(600000L)) { delay(10000); return; } diff --git a/src/TinyGsmClientUBLOX.h b/src/TinyGsmClientUBLOX.h index 29d634f..4a8a375 100644 --- a/src/TinyGsmClientUBLOX.h +++ b/src/TinyGsmClientUBLOX.h @@ -390,8 +390,19 @@ class TinyGsmUBLOX */ protected: String getGsmLocationImpl() { - sendAT(GF("+ULOC=2,3,0,120,1")); - if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } + // AT+ULOC=,,,, + // - 2: single shot position + // - 2: use cellular CellLocate® location information + // - 0: standard (single-hypothesis) response + // - Timeout period in seconds + // - Target accuracy in meters (1 - 999999) + sendAT(GF("+ULOC=2,2,0,120,1")); + // wait for first "OK" + if (waitResponse(10000L) != 1) { + return ""; + } + // wait for the final result - wait full timeout time + if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); From 06c31aa856c24f35d841ac84f1566527bdb1e43a Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Fri, 7 Feb 2020 17:42:02 -0500 Subject: [PATCH 26/88] Replace *most* toInt and toFloat's Signed-off-by: Sara Damiano --- src/TinyGsmClientA6.h | 20 +++++----- src/TinyGsmClientBG96.h | 30 +++++++------- src/TinyGsmClientESP8266.h | 6 +-- src/TinyGsmClientM590.h | 14 +++---- src/TinyGsmClientM95.h | 24 ++++++------ src/TinyGsmClientMC60.h | 28 +++++++------ src/TinyGsmClientSIM5360.h | 30 +++++++------- src/TinyGsmClientSIM7000.h | 60 ++++++++++++++-------------- src/TinyGsmClientSIM7600.h | 65 ++++++++++++++++--------------- src/TinyGsmClientSIM800.h | 18 ++++----- src/TinyGsmClientSIM808.h | 42 ++++++++++---------- src/TinyGsmClientSaraR4.h | 32 +++++++-------- src/TinyGsmClientSequansMonarch.h | 18 ++++----- src/TinyGsmClientUBLOX.h | 22 +++++------ src/TinyGsmClientXBee.h | 2 +- src/TinyGsmCommon.h | 48 ++++++++++++++++------- 16 files changed, 240 insertions(+), 219 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 6343d89..f0d62af 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -362,10 +362,10 @@ class TinyGsmA6 sendAT(GF("+CUSD=1,\""), code, GF("\",15")); if (waitResponse(10000L) != 1) { return ""; } if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; } - stream.readStringUntil('"'); + streamSkipUntil('"'); String hex = stream.readStringUntil('"'); - stream.readStringUntil(','); - int dcs = stream.readStringUntil('\n').toInt(); + streamSkipUntil(','); + int dcs = streamGetInt('\n'); if (dcs == 15) { return TinyGsmDecodeHex7bit(hex); @@ -407,7 +407,7 @@ class TinyGsmA6 if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } streamSkipUntil(','); // Skip battery charge status // Read battery charge level - int res = stream.readStringUntil('\n').toInt(); + int res = streamGetInt('\n'); // Wait for final OK waitResponse(); return res; @@ -418,8 +418,8 @@ class TinyGsmA6 uint16_t& milliVolts) { sendAT(GF("+CBC?")); if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } - chargeState = stream.readStringUntil(',').toInt(); - percent = stream.readStringUntil('\n').toInt(); + chargeState = streamGetInt(','); + percent = streamGetInt('\n'); milliVolts = 0; // Wait for final OK waitResponse(); @@ -439,7 +439,7 @@ class TinyGsmA6 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 newMux = streamGetInt('\n'); int rsp = waitResponse((timeout_ms - (millis() - startMillis)), GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL), @@ -519,8 +519,8 @@ class TinyGsmA6 index = 5; goto finish; } else if (data.endsWith(GF("+CIPRCV:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(',').toInt(); + int mux = streamGetInt(','); + int len = streamGetInt(','); int len_orig = len; if (len > sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); @@ -535,7 +535,7 @@ class TinyGsmA6 } data = ""; } else if (data.endsWith(GF("+TCPCLOSED:"))) { - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { sockets[mux]->sock_connected = false; } diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index d517655..e47c623 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -327,9 +327,9 @@ class TinyGsmBG96 if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; } - if (stream.readStringUntil(',').toInt() != mux) { return false; } + if (streamGetInt(',') != mux) { return false; } // Read status - rsp = stream.readStringUntil('\n').toInt(); + rsp = streamGetInt('\n'); return (0 == rsp); } @@ -347,7 +347,7 @@ class TinyGsmBG96 size_t modemRead(size_t size, uint8_t mux) { sendAT(GF("+QIRD="), mux, ',', (uint16_t)size); if (waitResponse(GF("+QIRD:")) != 1) { return 0; } - int len = stream.readStringUntil('\n').toInt(); + int len = streamGetInt('\n'); for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } waitResponse(); @@ -362,7 +362,7 @@ class TinyGsmBG96 if (waitResponse(GF("+QIRD:")) == 1) { streamSkipUntil(','); // Skip total received streamSkipUntil(','); // Skip have read - result = stream.readStringUntil('\n').toInt(); + result = streamGetInt('\n'); if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); } waitResponse(); } @@ -376,12 +376,12 @@ class TinyGsmBG96 if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = streamGetInt(','); // socket state waitResponse(); @@ -434,23 +434,23 @@ class TinyGsmBG96 index = 5; goto finish; } else if (data.endsWith(GF(GSM_NL "+QIURC:"))) { - stream.readStringUntil('\"'); + streamSkipUntil('\"'); String urc = stream.readStringUntil('\"'); - stream.readStringUntil(','); + streamSkipUntil(','); if (urc == "recv") { - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); DBG("### URC RECV:", mux); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; } } else if (urc == "closed") { - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); DBG("### URC CLOSE:", mux); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } } else { - stream.readStringUntil('\n'); + streamSkipUntil('\n'); } data = ""; } diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index a0cf2a5..7433b8f 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -396,7 +396,7 @@ class TinyGsmESP8266 uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); if (has_status == 1) { - int returned_mux = stream.readStringUntil(',').toInt(); + int returned_mux = streamGetInt(','); streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip type streamSkipUntil(','); // Skip remote IP @@ -454,8 +454,8 @@ class TinyGsmESP8266 index = 5; goto finish; } else if (data.endsWith(GF("+IPD,"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(':').toInt(); + int mux = streamGetInt(','); + int len = streamGetInt(':'); int len_orig = len; if (len > sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "received vs", diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index 522c3e8..a508273 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -261,7 +261,7 @@ class TinyGsmM590 bool isGprsConnectedImpl() { sendAT(GF("+XIIC?")); if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; } - int res = stream.readStringUntil(',').toInt(); + int res = streamGetInt(','); waitResponse(); return res == 1; } @@ -273,7 +273,7 @@ class TinyGsmM590 String getLocalIPImpl() { sendAT(GF("+XIIC?")); if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; } - stream.readStringUntil(','); + streamSkipUntil(','); String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -356,7 +356,7 @@ class TinyGsmM590 stream.write(static_cast(0x0D)); stream.flush(); if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; } - stream.readStringUntil('\n'); + streamSkipUntil('\n'); return len; } @@ -429,8 +429,8 @@ class TinyGsmM590 index = 5; goto finish; } else if (data.endsWith(GF("+TCPRECV:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil(',').toInt(); + int mux = streamGetInt(','); + int len = streamGetInt(','); int len_orig = len; if (len > sockets[mux]->rx.free()) { DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); @@ -445,8 +445,8 @@ class TinyGsmM590 } data = ""; } else if (data.endsWith(GF("+TCPCLOSE:"))) { - int mux = stream.readStringUntil(',').toInt(); - stream.readStringUntil('\n'); + int mux = streamGetInt(','); + streamSkipUntil('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { sockets[mux]->sock_connected = false; } diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 7f259d5..223bcc5 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -339,7 +339,7 @@ class TinyGsmM95 protected: String getLocalIPImpl() { sendAT(GF("+QILOCIP")); - stream.readStringUntil('\n'); + streamSkipUntil('\n'); String res = stream.readStringUntil('\n'); res.trim(); return res; @@ -396,9 +396,9 @@ class TinyGsmM95 } streamSkipUntil(','); // Skip mode // Read charge of thermistor - // milliVolts = stream.readStringUntil(',').toInt(); + // milliVolts = streamGetInt(','); streamSkipUntil(','); // Skip thermistor charge - float temp = stream.readStringUntil('\n').toFloat(); + float temp = streamGetFloat('\n'); // Wait for final OK waitResponse(); return temp; @@ -437,7 +437,7 @@ class TinyGsmM95 // streamSkipUntil(','); // Skip total length sent on connection // streamSkipUntil(','); // Skip length already acknowledged by remote // // Make sure the total length un-acknowledged is 0 - // if ( stream.readStringUntil('\n').toInt() == 0 ) { + // if ( streamGetInt('\n') == 0 ) { // allAcknowledged = true; // } // } @@ -463,7 +463,7 @@ class TinyGsmM95 streamSkipUntil(','); // skip port streamSkipUntil(','); // skip connection type (TCP/UDP) // read the real length of the retrieved data - uint16_t len = stream.readStringUntil('\n').toInt(); + uint16_t len = streamGetInt('\n'); // We have no way of knowing in advance how much data will be in the // buffer so when data is received we always assume the buffer is // completely full. Chances are, this is not true and there's really not @@ -495,12 +495,12 @@ class TinyGsmM95 if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = streamGetInt(','); // socket state waitResponse(); @@ -555,7 +555,7 @@ class TinyGsmM95 } else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) { streamSkipUntil(','); // Skip the context streamSkipUntil(','); // Skip the role - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); DBG("### Got Data:", mux); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { // We have no way of knowing how much data actually came in, so diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 0416ded..0ee5496 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -331,7 +331,7 @@ class TinyGsmMC60 protected: String getLocalIPImpl() { sendAT(GF("+QILOCIP")); - stream.readStringUntil('\n'); + streamSkipUntil('\n'); String res = stream.readStringUntil('\n'); res.trim(); return res; @@ -415,15 +415,13 @@ class TinyGsmMC60 } else { streamSkipUntil(','); /** Skip total */ streamSkipUntil(','); /** Skip acknowledged data size */ - if (stream.readStringUntil('\n').toInt() == 0) { - allAcknowledged = true; - } + if (streamGetInt('\n') == 0) { allAcknowledged = true; } } } waitResponse(5000L); // streamSkipUntil(','); // Skip mux - // return stream.readStringUntil('\n').toInt(); + // return streamGetInt('\n'); return len; // TODO(?): verify len/ack } @@ -444,7 +442,7 @@ class TinyGsmMC60 streamSkipUntil(','); // skip port streamSkipUntil(','); // skip connection type (TCP/UDP) // read the real length of the retrieved data - uint16_t len = stream.readStringUntil('\n').toInt(); + uint16_t len = streamGetInt('\n'); // It's possible that the real length available is less than expected // This is quite likely if the buffer is broken into packets - which may // be different sizes. @@ -475,12 +473,12 @@ class TinyGsmMC60 if (waitResponse(GF("+QISTATE:")) != 1) { return false; } - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip socket type - streamSkipUntil(','); // Skip remote ip - streamSkipUntil(','); // Skip remote port - streamSkipUntil(','); // Skip local port - int res = stream.readStringUntil(',').toInt(); // socket state + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip socket type + streamSkipUntil(','); // Skip remote ip + streamSkipUntil(','); // Skip remote port + streamSkipUntil(','); // Skip local port + int res = streamGetInt(','); // socket state waitResponse(); @@ -543,11 +541,11 @@ class TinyGsmMC60 streamSkipUntil(','); // Skip the context streamSkipUntil(','); // Skip the role // read the connection id - int mux = stream.readStringUntil(',').toInt(); + int mux = streamGetInt(','); // read the number of packets in the buffer - int num_packets = stream.readStringUntil(',').toInt(); + int num_packets = streamGetInt(','); // read the length of the current packet - int len_packet = stream.readStringUntil('\n').toInt(); + int len_packet = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_available = len_packet * num_packets; } diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 58bce88..3588a3e 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -445,7 +445,7 @@ class TinyGsmSim5360 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; } @@ -640,8 +640,8 @@ class TinyGsmSim5360 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; @@ -649,7 +649,7 @@ class TinyGsmSim5360 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 5654437..7726f09 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -436,25 +436,27 @@ class TinyGsmSim7000 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; } @@ -668,8 +670,8 @@ class TinyGsmSim7000 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index a1beb50..b9244d3 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -410,25 +410,28 @@ class TinyGsmSim7600 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; } @@ -642,8 +645,8 @@ class TinyGsmSim7600 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; @@ -651,7 +654,7 @@ class TinyGsmSim7600 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index cff7973..ad5393f 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -490,7 +490,7 @@ class TinyGsmSim800 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; } @@ -619,8 +619,8 @@ class TinyGsmSim800 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; diff --git a/src/TinyGsmClientSIM808.h b/src/TinyGsmClientSIM808.h index 9df90a7..7dfdaa8 100644 --- a/src/TinyGsmClientSIM808.h +++ b/src/TinyGsmClientSIM808.h @@ -61,25 +61,27 @@ class TinyGsmSim808 : public TinyGsmSim800 { sendAT(GF("+CGNSINF")); if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } - stream.readStringUntil(','); // mode - if (stream.readStringUntil(',').toInt() == 1) fix = true; - stream.readStringUntil(','); // utctime - *lat = stream.readStringUntil(',').toFloat(); // lat - *lon = stream.readStringUntil(',').toFloat(); // lon - if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // lon - if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed - stream.readStringUntil(','); - stream.readStringUntil(','); - stream.readStringUntil(','); - stream.readStringUntil(','); - stream.readStringUntil(','); - stream.readStringUntil(','); - stream.readStringUntil(','); - if (vsat != NULL) - *vsat = stream.readStringUntil(',').toInt(); // viewed satelites - if (usat != NULL) - *usat = stream.readStringUntil(',').toInt(); // used satelites - stream.readStringUntil('\n'); + streamSkipUntil(','); // GNSS run status + if (streamGetInt(',') == 1) fix = true; // fix status + streamSkipUntil(','); // UTC date & Time + *lat = streamGetFloat(','); // Latitude + *lon = streamGetFloat(','); // Longitude + if (alt != NULL) *alt = streamGetFloat(','); // MSL Altitude + if (speed != NULL) *speed = streamGetFloat(','); // Speed Over Ground + streamSkipUntil(','); // Course Over Ground + streamSkipUntil(','); // Fix Mode + streamSkipUntil(','); // Reserved1 + streamSkipUntil(','); // Horizontal Dilution Of Precision + streamSkipUntil(','); // Position Dilution Of Precision + streamSkipUntil(','); // Vertical Dilution Of Precision + streamSkipUntil(','); // Reserved2 + if (vsat != NULL) *vsat = streamGetInt(','); // GNSS Satellites in View + if (usat != NULL) *usat = streamGetInt(','); // GNSS Satellites Used + streamSkipUntil(','); // GLONASS Satellites Used + streamSkipUntil(','); // Reserved3 + streamSkipUntil(','); // C/N0 max + streamSkipUntil(','); // HPA + streamSkipUntil('\n'); // VPA waitResponse(); @@ -121,7 +123,7 @@ class TinyGsmSim808 : public TinyGsmSim800 { break; } } - stream.readStringUntil('\n'); + streamSkipUntil('\n'); waitResponse(); if (fix) { diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 0b143e4..44e3aeb 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -304,7 +304,7 @@ class TinyGsmSaraR4 : public TinyGsmModem(-9999); } - int16_t res = stream.readStringUntil('\n').toInt(); + int16_t res = streamGetInt('\n'); float temp = -9999; if (res != -1) { temp = (static_cast(res)) / 10; } return temp; @@ -497,7 +497,7 @@ class TinyGsmSaraR4 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; @@ -674,15 +674,15 @@ class TinyGsmSaraR4 : public TinyGsmModem= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } data = ""; DBG("### URC Sock Closed: ", mux); } else if (data.endsWith(GF("+UUSOCO:"))) { - int mux = stream.readStringUntil('\n').toInt(); - int socket_error = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); + int socket_error = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux] && socket_error == 0) { sockets[mux]->sock_connected = true; diff --git a/src/TinyGsmClientSequansMonarch.h b/src/TinyGsmClientSequansMonarch.h index b10c6ed..d1241d7 100644 --- a/src/TinyGsmClientSequansMonarch.h +++ b/src/TinyGsmClientSequansMonarch.h @@ -517,7 +517,7 @@ class TinyGsmSequansMonarch sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size); if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; } streamSkipUntil(','); // Skip mux - int len = stream.readStringUntil('\n').toInt(); + int len = streamGetInt('\n'); for (int i = 0; i < len; i++) { uint32_t startMillis = millis(); while (!stream.available() && @@ -538,10 +538,10 @@ class TinyGsmSequansMonarch sendAT(GF("+SQNSI="), mux); size_t result = 0; if (waitResponse(GF("+SQNSI:")) == 1) { - streamSkipUntil(','); // Skip mux - streamSkipUntil(','); // Skip total sent - streamSkipUntil(','); // Skip total received - result = stream.readStringUntil(',').toInt(); // keep data not yet read + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip total sent + streamSkipUntil(','); // Skip total received + result = streamGetInt(','); // keep data not yet read waitResponse(); } DBG("### Available:", result, "on", mux); @@ -555,7 +555,7 @@ class TinyGsmSequansMonarch for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; } uint8_t status = 0; - // if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no + // if (streamGetInt(',') != muxNo) { // check the mux no // DBG("### Warning: misaligned mux numbers!"); // } streamSkipUntil(','); // skip mux [use muxNo] @@ -623,8 +623,8 @@ class TinyGsmSequansMonarch index = 5; goto finish; } else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt(','); + int len = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true; @@ -633,7 +633,7 @@ class TinyGsmSequansMonarch data = ""; DBG("### URC Data Received:", len, "on", mux); } else if (data.endsWith(GF("SQNSH: "))) { - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false; diff --git a/src/TinyGsmClientUBLOX.h b/src/TinyGsmClientUBLOX.h index 4a8a375..d7e91f0 100644 --- a/src/TinyGsmClientUBLOX.h +++ b/src/TinyGsmClientUBLOX.h @@ -398,9 +398,7 @@ class TinyGsmUBLOX // - Target accuracy in meters (1 - 999999) sendAT(GF("+ULOC=2,2,0,120,1")); // wait for first "OK" - if (waitResponse(10000L) != 1) { - return ""; - } + if (waitResponse(10000L) != 1) { return ""; } // wait for the final result - wait full timeout time if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); @@ -431,7 +429,7 @@ class TinyGsmUBLOX sendAT(GF("+CIND?")); if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; } - int res = stream.readStringUntil(',').toInt(); + int res = streamGetInt(','); int8_t percent = res * 20; // return is 0-5 // Wait for final OK waitResponse(); @@ -464,7 +462,7 @@ class TinyGsmUBLOX 1) { // reply is +USOCR: ## of socket created return false; } - *mux = stream.readStringUntil('\n').toInt(); + *mux = streamGetInt('\n'); waitResponse(); if (ssl) { @@ -495,7 +493,7 @@ class TinyGsmUBLOX stream.flush(); if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; } streamSkipUntil(','); // Skip mux - int sent = stream.readStringUntil('\n').toInt(); + int sent = streamGetInt('\n'); waitResponse(); // sends back OK after the confirmation of number sent return sent; } @@ -504,7 +502,7 @@ class TinyGsmUBLOX sendAT(GF("+USORD="), mux, ',', (uint16_t)size); if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; } streamSkipUntil(','); // Skip mux - int len = stream.readStringUntil(',').toInt(); + int len = streamGetInt(','); streamSkipUntil('\"'); for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } @@ -524,7 +522,7 @@ class TinyGsmUBLOX // that you have already told to close if (res == 1) { streamSkipUntil(','); // Skip mux - result = stream.readStringUntil('\n').toInt(); + result = streamGetInt('\n'); // if (result) DBG("### DATA AVAILABLE:", result, "on", mux); waitResponse(); } @@ -541,7 +539,7 @@ class TinyGsmUBLOX streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip type - int result = stream.readStringUntil('\n').toInt(); + int result = streamGetInt('\n'); // 0: the socket is in INACTIVE status (it corresponds to CLOSED status // defined in RFC793 "TCP Protocol Specification" [112]) // 1: the socket is in LISTEN status @@ -603,8 +601,8 @@ class TinyGsmUBLOX index = 5; goto finish; } else if (data.endsWith(GF("+UUSORD:"))) { - int mux = stream.readStringUntil(',').toInt(); - int len = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt(','); + int len = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->got_data = true; sockets[mux]->sock_available = len; @@ -612,7 +610,7 @@ class TinyGsmUBLOX data = ""; DBG("### URC Data Received:", len, "on", mux); } else if (data.endsWith(GF("+UUSOCL:"))) { - int mux = stream.readStringUntil('\n').toInt(); + int mux = streamGetInt('\n'); if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { sockets[mux]->sock_connected = false; } diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 10664ce..876bb7d 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -1212,7 +1212,7 @@ class TinyGsmXBee // // read remote ip address // String remoted_address = // stream.readStringUntil('\r'); // read result - // stream.readStringUntil('\r'); // final carriage return + // streamSkipUntil('\r'); // final carriage return // } } diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index 5d4e97d..bae5447 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -755,7 +755,7 @@ class TinyGsmModem { GF("+CEREG:")); if (resp != 1 && resp != 2 && resp != 3) { return -1; } thisModem().streamSkipUntil(','); /* Skip format (0) */ - int status = thisModem().stream.readStringUntil('\n').toInt(); + int status = thisModem().streamGetInt('\n'); thisModem().waitResponse(); return status; } @@ -772,7 +772,7 @@ class TinyGsmModem { int16_t getSignalQualityImpl() { thisModem().sendAT(GF("+CSQ")); if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; } - int res = thisModem().stream.readStringUntil(',').toInt(); + int res = thisModem().streamGetInt(','); thisModem().waitResponse(); return res; } @@ -785,7 +785,7 @@ class TinyGsmModem { bool isGprsConnectedImpl() { thisModem().sendAT(GF("+CGATT?")); if (thisModem().waitResponse(GF("+CGATT:")) != 1) { return false; } - int res = thisModem().stream.readStringUntil('\n').toInt(); + int res = thisModem().streamGetInt('\n'); thisModem().waitResponse(); if (res != 1) { return false; } @@ -975,7 +975,7 @@ class TinyGsmModem { thisModem().stream.readStringUntil('"'); String hex = thisModem().stream.readStringUntil('"'); thisModem().stream.readStringUntil(','); - int dcs = thisModem().stream.readStringUntil('\n').toInt(); + int dcs = thisModem().streamGetInt('\n'); if (dcs == 15) { return TinyGsmDecodeHex8bit(hex); @@ -1118,7 +1118,7 @@ class TinyGsmModem { thisModem().streamSkipUntil(','); // Skip battery charge status thisModem().streamSkipUntil(','); // Skip battery charge level // return voltage in mV - uint16_t res = thisModem().stream.readStringUntil(',').toInt(); + uint16_t res = thisModem().streamGetInt(','); // Wait for final OK thisModem().waitResponse(); return res; @@ -1129,7 +1129,7 @@ class TinyGsmModem { if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } thisModem().streamSkipUntil(','); // Skip battery charge status // Read battery charge level - int res = thisModem().stream.readStringUntil(',').toInt(); + int res = thisModem().streamGetInt(','); // Wait for final OK thisModem().waitResponse(); return res; @@ -1139,7 +1139,7 @@ class TinyGsmModem { thisModem().sendAT(GF("+CBC")); if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } // Read battery charge status - int res = thisModem().stream.readStringUntil(',').toInt(); + int res = thisModem().streamGetInt(','); // Wait for final OK thisModem().waitResponse(); return res; @@ -1149,9 +1149,9 @@ class TinyGsmModem { uint16_t& milliVolts) { thisModem().sendAT(GF("+CBC")); if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } - chargeState = thisModem().stream.readStringUntil(',').toInt(); - percent = thisModem().stream.readStringUntil(',').toInt(); - milliVolts = thisModem().stream.readStringUntil('\n').toInt(); + chargeState = thisModem().streamGetInt(','); + percent = thisModem().streamGetInt(','); + milliVolts = thisModem().streamGetInt('\n'); // Wait for final OK thisModem().waitResponse(); return true; @@ -1179,11 +1179,29 @@ class TinyGsmModem { thisModem().streamWrite(tail...); } - // template void sendAT(Args... cmd) { - // thisModem().streamWrite("AT", cmd..., thisModem().gsmNL); - // thisModem().stream.flush(); - // TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */ - // } + int16_t streamGetInt(char lastChar) { + char buf[6]; + size_t bytesRead = thisModem().stream.readBytesUntil( + lastChar, buf, static_cast(6)); + if (bytesRead) { + int16_t res = atoi(buf); + return res; + } else { + return -9999; + } + } + + float streamGetFloat(char lastChar) { + char buf[12]; + size_t bytesRead = thisModem().stream.readBytesUntil( + lastChar, buf, static_cast(12)); + if (bytesRead) { + float res = atof(buf); + return res; + } else { + return static_cast(-9999); + } + } bool streamSkipUntil(const char c, const uint32_t timeout_ms = 1000L) { uint32_t startMillis = millis(); From 49c2653dcaefdd9c41e74c8463080b74ea22975f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Cervera=20And=C3=A9s?= Date: Tue, 11 Feb 2020 10:12:59 +0100 Subject: [PATCH 27/88] Added support for IMSI information on SIM800 and SIM808 modules --- src/TinyGsmClientSIM800.h | 2 ++ src/TinyGsmCommon.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index be225d5..51347ab 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -321,6 +321,8 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID() TINY_GSM_MODEM_GET_IMEI_GSN() +TINY_GSM_MODEM_GET_IMSI_CIMI() + SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { for (unsigned long start = millis(); millis() - start < timeout_ms; ) { sendAT(GF("+CPIN?")); diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index bb2e541..d176554 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -527,6 +527,20 @@ String TinyGsmDecodeHex16bit(String &instr) { } +// Asks for International Mobile Subscriber Identity IMSI via the AT+CIMI command +#define TINY_GSM_MODEM_GET_IMSI_CIMI() \ + String getIMSI() { \ + sendAT(GF("+CIMI")); \ + 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 From 41531c339bf0408f433ff674ae5e47fc0b109444 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 11:08:03 -0500 Subject: [PATCH 28/88] Reorder some functions --- src/TinyGsmClientA6.h | 44 ++++++++++--------- src/TinyGsmClientBG96.h | 32 +++++++------- src/TinyGsmClientESP8266.h | 28 ++++++------ src/TinyGsmClientM590.h | 34 ++++++++------- src/TinyGsmClientM95.h | 36 ++++++++-------- src/TinyGsmClientMC60.h | 72 ++++++++++++++++--------------- src/TinyGsmClientSIM5360.h | 48 +++++++++++---------- src/TinyGsmClientSIM7000.h | 34 ++++++++------- src/TinyGsmClientSIM7600.h | 48 +++++++++++---------- src/TinyGsmClientSIM800.h | 34 ++++++++------- src/TinyGsmClientSaraR4.h | 34 ++++++++------- src/TinyGsmClientSequansMonarch.h | 40 +++++++++-------- src/TinyGsmClientUBLOX.h | 48 ++++++++++++--------- src/TinyGsmClientXBee.h | 68 +++++++++++++---------------- 14 files changed, 317 insertions(+), 283 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index f0d62af..4d14984 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -189,19 +189,6 @@ class TinyGsmA6 bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; - /* - * SIM card functions - */ - 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(); - return res; - } - /* * Generic network functions */ @@ -216,6 +203,22 @@ class TinyGsmA6 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + /* + * IP Address functions + */ + protected: + 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 */ @@ -272,15 +275,16 @@ class TinyGsmA6 } /* - * IP Address functions + * SIM card functions */ protected: - String getLocalIPImpl() { - sendAT(GF("+CIFSR")); - String res; - if (waitResponse(10000L, res) != 1) { return ""; } - res.replace(GSM_NL "OK" GSM_NL, ""); - res.replace(GSM_NL, ""); + String getSimCCIDImpl() { + sendAT(GF("+CCID")); + if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); res.trim(); return res; } diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index e47c623..b7b7706 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -208,19 +208,6 @@ class TinyGsmBG96 return waitResponse() == 1; } - /* - * SIM card functions - */ - protected: - String getSimCCIDImpl() { - sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - /* * Generic network functions */ @@ -235,6 +222,12 @@ class TinyGsmBG96 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + /* + * IP Address functions + */ + protected: + // Can follow all of the IP functions from the template + /* * GPRS functions */ @@ -267,10 +260,19 @@ class TinyGsmBG96 } /* - * IP Address functions + * SIM card functions */ protected: - // Can follow all of the IP functions from the template + String getSimCCIDImpl() { + sendAT(GF("+QCCID")); + if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } /* * Phone Call functions diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 7433b8f..156cb1f 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -257,6 +257,21 @@ class TinyGsmESP8266 } } + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + sendAT(GF("+CIPSTA_CUR?")); + int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + return ""; + } + String res2 = stream.readStringUntil('"'); + waitResponse(); + return res2; + } + /* * WiFi functions */ @@ -277,19 +292,6 @@ class TinyGsmESP8266 return retVal; } - /* - * IP Address functions - */ - protected: - String getLocalIPImpl() { - sendAT(GF("+CIPSTA_CUR?")); - int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); - if (res1 != 2) { return ""; } - String res2 = stream.readStringUntil('"'); - waitResponse(); - return res2; - } - /* * Phone Call functions */ diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index a508273..a54357a 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -190,12 +190,6 @@ class TinyGsmM590 return waitResponse() == 1; } - /* - * SIM card functions - */ - protected: - // Able to follow all SIM card functions as inherited from the template - /* * Generic network functions */ @@ -210,6 +204,22 @@ class TinyGsmM590 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + sendAT(GF("+XIIC?")); + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { + return ""; + } + streamSkipUntil(','); + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + /* * GPRS functions */ @@ -267,18 +277,10 @@ class TinyGsmM590 } /* - * IP Address functions + * SIM card functions */ protected: - String getLocalIPImpl() { - sendAT(GF("+XIIC?")); - if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; } - streamSkipUntil(','); - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } + // Able to follow all SIM card functions as inherited from the template /* * Phone Call functions diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index 223bcc5..af63f01 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -217,19 +217,6 @@ class TinyGsmM95 return waitResponse() == 1; } - /* - * SIM card functions - */ - protected: - String getSimCCIDImpl() { - sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - /* * Generic network functions */ @@ -254,6 +241,18 @@ class TinyGsmM95 waitResponse(); } + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + sendAT(GF("+QILOCIP")); + streamSkipUntil('\n'); + String res = stream.readStringUntil('\n'); + res.trim(); + return res; + } + /* * GPRS functions */ @@ -334,13 +333,16 @@ class TinyGsmM95 } /* - * IP Address functions + * SIM card functions */ protected: - String getLocalIPImpl() { - sendAT(GF("+QILOCIP")); - streamSkipUntil('\n'); + String getSimCCIDImpl() { + sendAT(GF("+QCCID")); + if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { + return ""; + } String res = stream.readStringUntil('\n'); + waitResponse(); res.trim(); return res; } diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index 0ee5496..bb4b3e5 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -226,33 +226,6 @@ class TinyGsmMC60 return waitResponse() == 1; } - /* - * SIM card functions - */ - protected: - SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { - for (uint32_t 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"), - GF("NOT INSERTED"), GF("PH_SIM PIN"), - GF("PH_SIM PUK")); - waitResponse(); - switch (status) { - case 2: - case 3: return SIM_LOCKED; - case 5: - case 6: return SIM_ANTITHEFT_LOCKED; - case 1: return SIM_READY; - default: return SIM_ERROR; - } - } - return SIM_ERROR; - } - /* * Generic network functions */ @@ -267,6 +240,18 @@ class TinyGsmMC60 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + sendAT(GF("+QILOCIP")); + streamSkipUntil('\n'); + String res = stream.readStringUntil('\n'); + res.trim(); + return res; + } + /* * GPRS functions */ @@ -326,15 +311,34 @@ class TinyGsmMC60 } /* - * IP Address functions + * SIM card functions */ protected: - String getLocalIPImpl() { - sendAT(GF("+QILOCIP")); - streamSkipUntil('\n'); - String res = stream.readStringUntil('\n'); - res.trim(); - return res; + SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t 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"), + GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); + waitResponse(); + switch (status) { + case 2: + case 3: + return SIM_LOCKED; + case 5: + case 6: + return SIM_ANTITHEFT_LOCKED; + case 1: + return SIM_READY; + default: + return SIM_ERROR; + } + } + return SIM_ERROR; } /* diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 3588a3e..8740cd1 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -227,20 +227,6 @@ class TinyGsmSim5360 : public TinyGsmModem 0) { - DBG("XBee's do not support SIMs that require an unlock pin!"); - } - return false; - } - - String getSimCCIDImpl() { - return sendATGetString(GF("S#")); - } - - String getIMEIImpl() { - return sendATGetString(GF("IM")); - } - - SimStatus getSimStatusImpl(uint32_t) { - return SIM_READY; // unsupported - } - /* * Generic network functions */ @@ -715,6 +692,22 @@ class TinyGsmXBee return retVal; } + /* + * IP Address functions + */ + protected: + String getLocalIPImpl() { + 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); + XBEE_COMMAND_END_DECORATOR + IPaddr.trim(); + return IPaddr; + } + /* * WiFi functions */ @@ -795,24 +788,25 @@ class TinyGsmXBee return isNetworkConnected(); } - String getOperatorImpl() { - return sendATGetString(GF("MN")); - } + String getOperatorImpl() { return sendATGetString(GF("MN")); } /* - * IP Address functions + * SIM card functions */ protected: - String getLocalIPImpl() { - 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); - XBEE_COMMAND_END_DECORATOR - IPaddr.trim(); - return IPaddr; + bool simUnlockImpl(const char* pin) { // Not supported + if (pin && strlen(pin) > 0) { + DBG("XBee's do not support SIMs that require an unlock pin!"); + } + return false; + } + + String getSimCCIDImpl() { return sendATGetString(GF("S#")); } + + String getIMEIImpl() { return sendATGetString(GF("IM")); } + + SimStatus getSimStatusImpl(uint32_t) { + return SIM_READY; // unsupported } /* From 915660ceafa38c3c9f764bdc4a6ce0d182fa6070 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 11:11:05 -0500 Subject: [PATCH 29/88] Specify int sizes --- src/TinyGsmClientA6.h | 2 +- src/TinyGsmClientESP8266.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 4d14984..790b363 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -318,7 +318,7 @@ class TinyGsmA6 } // 0-9,*,#,A,B,C,D - bool dtmfSendImpl(char cmd, unsigned duration_ms = 100) { + bool dtmfSendImpl(char cmd, uint8_t duration_ms = 100) { duration_ms = constrain(duration_ms, 100, 1000); // The duration parameter is not working, so we simulate it using delay.. diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 156cb1f..2e5c37e 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -19,7 +19,7 @@ #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; -static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; +static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120; // status of ESP8266 station interface // 2 : ESP8266 station connected to an AP and has obtained IP From 9ec9111f32163162a91ac41a3749f0bd49f34c25 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 12:35:21 -0500 Subject: [PATCH 30/88] Failed partial specialization Signed-off-by: Sara Damiano --- src/TinyGsmTCP.tpp | 549 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 src/TinyGsmTCP.tpp diff --git a/src/TinyGsmTCP.tpp b/src/TinyGsmTCP.tpp new file mode 100644 index 0000000..1044159 --- /dev/null +++ b/src/TinyGsmTCP.tpp @@ -0,0 +1,549 @@ +/** + * @file TinyGsmTCP.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMTCP_H_ +#define SRC_TINYGSMTCP_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_HAS_TCP + +enum modemInternalBuffferType { + NO_MODEM_BUFFER = + 0, // For modules that do not store incoming data in any sort of buffer + READ_NO_CHECK = 1, // Data is stored in a buffer, but we can only read from + // the buffer, not check how much data is stored in it + READ_AND_CHECK_SIZE = 2, // Data is stored in a buffer and we can both read + // and check the size of the buffer +}; + +// The fully generic template is empty +template +class TinyGsmTCP {}; + +// Partially specialized templates + +/* =========================================================================== +* Specialized template for modems no internal buffer +=========================================================================== */ +template +class TinyGsmTCP { + public: + /* + * Basic functions + */ + void maintain() { + return thisModem().maintainImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Inner Client + */ + public: + class GsmClient : public Client { + // Make all classes created from the modem template friends + friend class TinyGsmModem; + typedef TinyGsmFifo RxFifo; + + public: + static inline String TinyGsmStringFromIp(IPAddress ip) { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return host; + } + + // Writes data out on the client using the modem send functionality + size_t write(const uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + size_t write(uint8_t c) override { + return write(&c, 1); + } + + size_t write(const char* str) { + if (str == NULL) return 0; + return write((const uint8_t*)str, strlen(str)); + } + + int available() override { + TINY_GSM_YIELD(); + // Returns the number of characters available in the TinyGSM fifo + if (!rx.size() && sock_connected) { at->maintain(); } + return rx.size(); + } + + int read(uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + size_t cnt = 0; + uint32_t _startMillis = millis(); + // Reads characters out of the TinyGSM fifo, waiting for any URC's + // from the modem for new data if there's nothing in the fifo. + while (cnt < size && millis() - _startMillis < _timeout) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } /* TODO: Read directly into user buffer? */ + if (!rx.size() && sock_connected) { at->maintain(); } + } + return cnt; + } + + int read() override { + uint8_t c; + if (read(&c, 1) == 1) { return c; } + return -1; + } + + // TODO(SRGDamia1): Implement peek + int peek() override { + return -1; + } + + void flush() override { + at->stream.flush(); + } + + uint8_t connected() override { + if (available()) { return true; } + return sock_connected; + } + operator bool() override { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + protected: + modemType* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; + }; + + /* + * Basic functions + */ + protected: + void maintainImpl() { + // Just listen for any URC's + thisModem().waitResponse(100, NULL, NULL); + } +}; + +/* =========================================================================== +* Specialized template for modems with an internal buffer that can be read +* but NOT queried for current size. +=========================================================================== */ +template +class TinyGsmTCP { + public: + /* + * Basic functions + */ + void maintain() { + return thisModem().maintainImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Inner Client + */ + public: + class GsmClient : public Client { + // Make all classes created from the modem template friends + friend class TinyGsmModem; + typedef TinyGsmFifo RxFifo; + + public: + static inline String TinyGsmStringFromIp(IPAddress ip) { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return host; + } + + // Writes data out on the client using the modem send functionality + size_t write(const uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + size_t write(uint8_t c) override { + return write(&c, 1); + } + + size_t write(const char* str) { + if (str == NULL) return 0; + return write((const uint8_t*)str, strlen(str)); + } + + int available() override { + TINY_GSM_YIELD(); + + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo. + if (!rx.size()) { at->maintain(); } + return rx.size() + sock_available; + } + + int read(uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + size_t cnt = 0; + uint32_t _startMillis = millis(); + + // Reads characters out of the TinyGSM fifo, and from the modem chip's + // internal fifo if avaiable. + at->maintain(); + while (cnt < size) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } /* TODO: Read directly into user buffer? */ + at->maintain(); + if (sock_available > 0) { + int n = at->modemRead( + TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + if (n == 0) break; + } else { + break; + } + } + return cnt; + } + + int read() override { + uint8_t c; + if (read(&c, 1) == 1) { return c; } + return -1; + } + + // TODO(SRGDamia1): Implement peek + int peek() override { + return -1; + } + + void flush() override { + at->stream.flush(); + } + + uint8_t connected() override { + if (available()) { return true; } + return sock_connected; + } + operator bool() override { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + protected: + // Read and dump anything remaining in the modem's internal buffer. + // Using this in the client stop() function. + // The socket will appear open in response to connected() even after it + // closes until all data is read from the buffer. + // Doing it this way allows the external mcu to find and get all of the + // data that it wants from the socket even if it was closed externally. + void inline dumpModemBuffer(uint32_t maxWaitMs) { + TINY_GSM_YIELD(); + rx.clear(); + at->maintain(); + uint32_t startMillis = millis(); + while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { + at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + rx.clear(); + at->maintain(); + } + } + + modemType* at; + uint8_t mux; + uint16_t sock_available; + bool sock_connected; + bool got_data; + RxFifo rx; + }; + + /* + * Basic functions + */ + protected: + void maintainImpl() { + // Just listen for any URC's + thisModem().waitResponse(100, NULL, NULL); + break; + } + + // Yields up to a time-out period and then reads a character from the stream + // into the mux FIFO + // TODO(SRGDamia1): Do we need to wait two _timeout periods for no + // character return? Will wait once in the first "while + // !stream.available()" and then will wait again in the stream.read() + // function. + void inline moveCharFromStreamToFifo(uint8_t mux) { + uint32_t startMillis = millis(); + while (!thisModem().stream.available() && + (millis() - startMillis < thisModem().sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char c = thisModem().stream.read(); + thisModem().sockets[mux]->rx.put(c); + } +}; + + +/* =========================================================================== +* Specialized template for modems with an internal buffer that can be read +* and queried for current size. +=========================================================================== */ +template +class TinyGsmTCP { + public: + /* + * Basic functions + */ + void maintain() { return thisModem().maintainImpl(); } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { return static_cast(*this); } + + /* + * Inner Client + */ + public: + class GsmClient : public Client { + // Make all classes created from the modem template friends + friend class TinyGsmModem; + typedef TinyGsmFifo RxFifo; + + public: + static inline String TinyGsmStringFromIp(IPAddress ip) { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return host; + } + + // Writes data out on the client using the modem send functionality + size_t write(const uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + size_t write(uint8_t c) override { return write(&c, 1); } + + size_t write(const char* str) { + if (str == NULL) return 0; + return write((const uint8_t*)str, strlen(str)); + } + + int available() override { + TINY_GSM_YIELD(); + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo, doing an extra check-in + // with the modem to see if anything has arrived without a UURC. + if (!rx.size()) { + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + at->maintain(); + } + return rx.size() + sock_available; + } + + int read(uint8_t* buf, size_t size) override { + TINY_GSM_YIELD(); + size_t cnt = 0; + uint32_t _startMillis = millis(); + // Reads characters out of the TinyGSM fifo, and from the modem chips + // internal fifo if avaiable, also double checking with the modem if + // data has arrived without issuing a UURC. + at->maintain(); + while (cnt < size) { + size_t chunk = TinyGsmMin(size - cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // Workaround: Some modules "forget" to notify about data arrival + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + // TODO(vshymanskyy): Read directly into user buffer? + at->maintain(); + if (sock_available > 0) { + int n = at->modemRead( + TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + if (n == 0) break; + } else { + break; + } + } + return cnt; + } + + int read() override { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + // TODO(SRGDamia1): Implement peek + int peek() override { return -1; } + + void flush() override { at->stream.flush(); } + + uint8_t connected() override { + if (available()) { + return true; + } + return sock_connected; + } + operator bool() override { return connected(); } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + protected: + // Read and dump anything remaining in the modem's internal buffer. + // Using this in the client stop() function. + // The socket will appear open in response to connected() even after it + // closes until all data is read from the buffer. + // Doing it this way allows the external mcu to find and get all of the + // data that it wants from the socket even if it was closed externally. + void inline dumpModemBuffer(uint32_t maxWaitMs) { + TINY_GSM_YIELD(); + rx.clear(); + at->maintain(); + uint32_t startMillis = millis(); + while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { + at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); + rx.clear(); + at->maintain(); + } + } + + modemType* at; + uint8_t mux; + uint16_t sock_available; + uint32_t prev_check; + bool sock_connected; + bool got_data; + RxFifo rx; + }; + + /* + * Basic functions + */ + protected: + void maintainImpl() { + // Keep listening for modem URC's and proactively iterate through + // sockets asking if any data is avaiable + for (int mux = 0; mux < muxCount; mux++) { + GsmClient* sock = thisModem().sockets[mux]; + if (sock && sock->got_data) { + sock->got_data = false; + sock->sock_available = thisModem().modemGetAvailable(mux); + } + } + while (thisModem().stream.available()) { + thisModem().waitResponse(15, NULL, NULL); + } + } + + // Yields up to a time-out period and then reads a character from the stream + // into the mux FIFO + // TODO(SRGDamia1): Do we need to wait two _timeout periods for no + // character return? Will wait once in the first "while + // !stream.available()" and then will wait again in the stream.read() + // function. + void inline moveCharFromStreamToFifo(uint8_t mux) { + uint32_t startMillis = millis(); + while (!thisModem().stream.available() && + (millis() - startMillis < thisModem().sockets[mux]->_timeout)) { + TINY_GSM_YIELD(); + } + char c = thisModem().stream.read(); + thisModem().sockets[mux]->rx.put(c); + } +}; + +#endif // SRC_TINYGSMTCP_H_ From be81985c83a05ecb9bb1d377496693535808d392 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 16:03:44 -0500 Subject: [PATCH 31/88] Many sub templates to inherit from! --- .clang-format | 4 +- examples/AllFunctions/AllFunctions.ino | 4 +- examples/WebClient/WebClient.ino | 2 + src/TinyGsmBattery.tpp | 98 +++ src/TinyGsmCalling.tpp | 90 ++ src/TinyGsmClient.h | 38 +- src/TinyGsmClientA6.h | 76 +- src/TinyGsmClientBG96.h | 77 +- src/TinyGsmClientESP8266.h | 110 +-- src/TinyGsmClientM590.h | 82 +- src/TinyGsmClientM95.h | 82 +- src/TinyGsmClientMC60.h | 100 +-- src/TinyGsmClientSIM5360.h | 97 +- src/TinyGsmClientSIM7000.h | 109 +-- src/TinyGsmClientSIM7600.h | 110 ++- src/TinyGsmClientSIM800.h | 94 +- src/TinyGsmClientSIM808.h | 24 +- src/TinyGsmClientSaraR4.h | 93 +- src/TinyGsmClientSequansMonarch.h | 93 +- src/TinyGsmClientUBLOX.h | 94 +- src/TinyGsmClientXBee.h | 96 +- src/TinyGsmCommon.h | 1124 +----------------------- src/TinyGsmGPRS.tpp | 158 ++++ src/TinyGsmGPS.tpp | 64 ++ src/TinyGsmGSMLocation.tpp | 51 ++ src/TinyGsmModem.tpp | 301 +++++++ src/TinyGsmSMS.tpp | 224 +++++ src/TinyGsmSSL.tpp | 71 ++ src/TinyGsmTCP.tpp | 413 +++------ src/TinyGsmTemperature.tpp | 40 + src/TinyGsmTime.tpp | 61 ++ src/TinyGsmWifi.tpp | 49 ++ tools/test_build/test_build.ino | 112 ++- 33 files changed, 1963 insertions(+), 2278 deletions(-) create mode 100644 src/TinyGsmBattery.tpp create mode 100644 src/TinyGsmCalling.tpp create mode 100644 src/TinyGsmGPRS.tpp create mode 100644 src/TinyGsmGPS.tpp create mode 100644 src/TinyGsmGSMLocation.tpp create mode 100644 src/TinyGsmModem.tpp create mode 100644 src/TinyGsmSMS.tpp create mode 100644 src/TinyGsmSSL.tpp create mode 100644 src/TinyGsmTemperature.tpp create mode 100644 src/TinyGsmTime.tpp create mode 100644 src/TinyGsmWifi.tpp diff --git a/.clang-format b/.clang-format index 60ffff7..1329b59 100644 --- a/.clang-format +++ b/.clang-format @@ -58,6 +58,8 @@ IncludeCategories: Priority: 2 - Regex: '.*' Priority: 3 + - Regex: '.*.tpp' + Priority: 4 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: true IndentPPDirectives: None @@ -80,7 +82,7 @@ PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 60 +PenaltyExcessCharacter: 600 PenaltyReturnTypeOnItsOwnLine: 50 PointerAlignment: Left PointerBindsToType: true diff --git a/examples/AllFunctions/AllFunctions.ino b/examples/AllFunctions/AllFunctions.ino index 7ba2045..c6cab92 100644 --- a/examples/AllFunctions/AllFunctions.ino +++ b/examples/AllFunctions/AllFunctions.ino @@ -245,9 +245,9 @@ void loop() { stream.print(F("Привіііт! Print number: ")); stream.print(595); res = modem.sendSMS_UTF8_end(); - } + } DBG("UTF8 SMS:", res ? "OK" : "fail"); - + #endif #if TINY_GSM_TEST_CALL && defined(CALL_TARGET) diff --git a/examples/WebClient/WebClient.ino b/examples/WebClient/WebClient.ino index 1e80494..f686fa2 100644 --- a/examples/WebClient/WebClient.ino +++ b/examples/WebClient/WebClient.ino @@ -44,7 +44,9 @@ // Chips without internal buffering (A6/A7, ESP8266, M590) // need enough space in the buffer for the entire response // else data will be lost (and the http library will fail). +#if !defined(TINY_GSM_RX_BUFFER) #define TINY_GSM_RX_BUFFER 650 +#endif // See all AT commands, if wanted // #define DUMP_AT_COMMANDS diff --git a/src/TinyGsmBattery.tpp b/src/TinyGsmBattery.tpp new file mode 100644 index 0000000..fe84379 --- /dev/null +++ b/src/TinyGsmBattery.tpp @@ -0,0 +1,98 @@ +/** + * @file TinyGsmBattery.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMBATTERY_H_ +#define SRC_TINYGSMBATTERY_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_BATTERY + +template +class TinyGsmBattery { + public: + /* + * Battery functions + */ + uint16_t getBattVoltage() { + return thisModem().getBattVoltageImpl(); + } + int8_t getBattPercent() { + return thisModem().getBattPercentImpl(); + } + uint8_t getBattChargeState() { + return thisModem().getBattChargeStateImpl(); + } + bool getBattStats(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { + return thisModem().getBattStatsImpl(chargeState, percent, milliVolts); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Battery functions + */ + protected: + // Use: float vBatt = modem.getBattVoltage() / 1000.0; + uint16_t getBattVoltageImpl() { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return 0; } + thisModem().streamSkipUntil(','); // Skip battery charge status + thisModem().streamSkipUntil(','); // Skip battery charge level + // return voltage in mV + uint16_t res = thisModem().streamGetInt(','); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + int8_t getBattPercentImpl() { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + thisModem().streamSkipUntil(','); // Skip battery charge status + // Read battery charge level + int res = thisModem().streamGetInt(','); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + uint8_t getBattChargeStateImpl() { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + // Read battery charge status + int res = thisModem().streamGetInt(','); + // Wait for final OK + thisModem().waitResponse(); + return res; + } + + bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, + uint16_t& milliVolts) { + thisModem().sendAT(GF("+CBC")); + if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } + chargeState = thisModem().streamGetInt(','); + percent = thisModem().streamGetInt(','); + milliVolts = thisModem().streamGetInt('\n'); + // Wait for final OK + thisModem().waitResponse(); + return true; + } +}; + +#endif // SRC_TINYGSMBATTERY_H_ diff --git a/src/TinyGsmCalling.tpp b/src/TinyGsmCalling.tpp new file mode 100644 index 0000000..467fe1d --- /dev/null +++ b/src/TinyGsmCalling.tpp @@ -0,0 +1,90 @@ +/** + * @file TinyGsmCalling.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMCALLING_H_ +#define SRC_TINYGSMCALLING_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_CALLING + +template +class TinyGsmCalling { + public: + /* + * Phone Call functions + */ + bool callAnswer() { + return thisModem().callAnswerImpl(); + } + bool callNumber(const String& number) { + return thisModem().callNumberImpl(number); + } + bool callHangup() { + return thisModem().callHangupImpl(); + } + bool dtmfSend(char cmd, int duration_ms = 100) { + return thisModem().dtmfSendImpl(cmd, duration_ms); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Phone Call functions + */ + protected: + bool callAnswerImpl() { + thisModem().sendAT(GF("A")); + return thisModem().waitResponse() == 1; + } + + // Returns true on pick-up, false on error/busy + bool callNumberImpl(const String& number) { + if (number == GF("last")) { + thisModem().sendAT(GF("DL")); + } else { + thisModem().sendAT(GF("D"), number, ";"); + } + int status = thisModem().waitResponse(60000L, GF("OK"), GF("BUSY"), + GF("NO ANSWER"), GF("NO CARRIER")); + switch (status) { + case 1: return true; + case 2: + case 3: return false; + default: return false; + } + } + + bool callHangupImpl() { + thisModem().sendAT(GF("H")); + return thisModem().waitResponse() == 1; + } + + // 0-9,*,#,A,B,C,D + bool dtmfSendImpl(char cmd, int duration_ms = 100) { + duration_ms = constrain(duration_ms, 100, 1000); + + thisModem().sendAT(GF("+VTD="), + duration_ms / 100); // VTD accepts in 1/10 of a second + thisModem().waitResponse(); + + thisModem().sendAT(GF("+VTS="), cmd); + return thisModem().waitResponse(10000L) == 1; + } +}; + +#endif // SRC_TINYGSMCALLING_H_ diff --git a/src/TinyGsmClient.h b/src/TinyGsmClient.h index fd23b11..cec5d68 100644 --- a/src/TinyGsmClient.h +++ b/src/TinyGsmClient.h @@ -6,35 +6,27 @@ * @date Nov 2016 */ -#ifndef SRC_TINYGSMCLIENT_h -#define SRC_TINYGSMCLIENT_h +#ifndef SRC_TINYGSMCLIENT_H_ +#define SRC_TINYGSMCLIENT_H_ #if defined(TINY_GSM_MODEM_SIM800) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientSIM800.h" typedef TinyGsmSim800 TinyGsm; typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient; typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_SSL -#define TINY_GSM_MODEM_HAS_GPS #include "TinyGsmClientSIM808.h" typedef TinyGsmSim808 TinyGsm; typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient; typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SIM900) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM800.h" typedef TinyGsmSim800 TinyGsm; typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient; #elif defined(TINY_GSM_MODEM_SIM7000) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_GPS #include "TinyGsmClientSIM7000.h" typedef TinyGsmSim7000 TinyGsm; typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient; @@ -42,92 +34,76 @@ typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient; #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM5360.h" typedef TinyGsmSim5360 TinyGsm; typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient; #elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \ defined(TINY_GSM_MODEM_SIM7500) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM7600.h" typedef TinyGsmSim7600 TinyGsm; typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient; #elif defined(TINY_GSM_MODEM_UBLOX) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientUBLOX.h" typedef TinyGsmUBLOX TinyGsm; typedef TinyGsmUBLOX::GsmClientUBLOX TinyGsmClient; typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SARAR4) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientSaraR4.h" typedef TinyGsmSaraR4 TinyGsm; typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient; typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_M95) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientM95.h" typedef TinyGsmM95 TinyGsm; typedef TinyGsmM95::GsmClientM95 TinyGsmClient; #elif defined(TINY_GSM_MODEM_BG96) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientBG96.h" typedef TinyGsmBG96 TinyGsm; typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient; #elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientA6.h" typedef TinyGsmA6 TinyGsm; typedef TinyGsmA6::GsmClientA6 TinyGsmClient; #elif defined(TINY_GSM_MODEM_M590) -#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientM590.h" typedef TinyGsmM590 TinyGsm; typedef TinyGsmM590::GsmClientM590 TinyGsmClient; #elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E) #include "TinyGsmClientMC60.h" -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_GPS typedef TinyGsmMC60 TinyGsm; typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient; #elif defined(TINY_GSM_MODEM_ESP8266) #define TINY_GSM_MODEM_HAS_WIFI -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientESP8266.h" typedef TinyGsmESP8266 TinyGsm; typedef TinyGsmESP8266::GsmClientESP8266 TinyGsmClient; typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_XBEE) -#define TINY_GSM_MODEM_HAS_GPRS #define TINY_GSM_MODEM_HAS_WIFI -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientXBee.h" typedef TinyGsmXBee TinyGsm; typedef TinyGsmXBee::GsmClientXBee TinyGsmClient; typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure; #elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH) -#define TINY_GSM_MODEM_HAS_GPRS -#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientSequansMonarch.h" -typedef TinyGsmSequansMonarch TinyGsm; -typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient; -typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch TinyGsmClientSecure; +typedef TinyGsmSequansMonarch TinyGsm; +typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient; +typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch + TinyGsmClientSecure; #else #error "Please define GSM modem model" #endif -#endif +#endif // SRC_TINYGSMCLIENT_H_ diff --git a/src/TinyGsmClientA6.h b/src/TinyGsmClientA6.h index 790b363..8fe4de9 100644 --- a/src/TinyGsmClientA6.h +++ b/src/TinyGsmClientA6.h @@ -14,7 +14,13 @@ #define TINY_GSM_MUX_COUNT 8 -#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" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -32,8 +38,20 @@ enum RegStatus { }; class TinyGsmA6 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -70,17 +88,9 @@ class TinyGsmA6 } return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { TINY_GSM_YIELD(); at->sendAT(GF("+CIPCLOSE="), mux); sock_connected = false; @@ -158,18 +168,6 @@ class TinyGsmA6 return waitResponse() == 1; } - bool thisHasSSL() { - return false; - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -203,16 +201,10 @@ class TinyGsmA6 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+CIFSR")); String res; - if (waitResponse(10000L, res) != 1) { - return ""; - } + if (waitResponse(10000L, res) != 1) { return ""; } res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL, ""); res.trim(); @@ -280,9 +272,7 @@ class TinyGsmA6 protected: String getSimCCIDImpl() { sendAT(GF("+CCID")); - if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -380,18 +370,6 @@ class TinyGsmA6 } } - /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported - /* * Time functions */ @@ -400,7 +378,7 @@ class TinyGsmA6 // Note - the clock probably has to be set manaually first /* - * Battery & temperature functions + * Battery functions */ protected: uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; @@ -430,8 +408,6 @@ class TinyGsmA6 return true; } - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - /* * Client related functions */ diff --git a/src/TinyGsmClientBG96.h b/src/TinyGsmClientBG96.h index b7b7706..b102631 100644 --- a/src/TinyGsmClientBG96.h +++ b/src/TinyGsmClientBG96.h @@ -14,7 +14,13 @@ #define TINY_GSM_MUX_COUNT 12 -#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" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -32,8 +38,20 @@ enum RegStatus { }; class TinyGsmBG96 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -70,17 +88,9 @@ class TinyGsmBG96 sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+QICLOSE="), mux); sock_connected = false; @@ -113,13 +123,14 @@ class TinyGsmBG96 public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; */ @@ -168,18 +179,6 @@ class TinyGsmBG96 } } - bool thisHasSSL() { - return false; // TODO(?): Add SSL support - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -222,12 +221,6 @@ class TinyGsmBG96 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - /* - * IP Address functions - */ - protected: - // Can follow all of the IP functions from the template - /* * GPRS functions */ @@ -265,9 +258,7 @@ class TinyGsmBG96 protected: String getSimCCIDImpl() { sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -286,18 +277,6 @@ class TinyGsmBG96 protected: // Follows all messaging functions per template - /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported - /* * Time functions */ @@ -305,10 +284,8 @@ class TinyGsmBG96 // Can follow the standard CCLK function in the template /* - * Battery & temperature functions + * Battery functions */ - protected: - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; /* * Client related functions diff --git a/src/TinyGsmClientESP8266.h b/src/TinyGsmClientESP8266.h index 2e5c37e..08bea11 100644 --- a/src/TinyGsmClientESP8266.h +++ b/src/TinyGsmClientESP8266.h @@ -14,12 +14,15 @@ #define TINY_GSM_MUX_COUNT 5 -#include "TinyGsmCommon.h" +#include "TinyGsmModem.tpp" +#include "TinyGsmSSL.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmWifi.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; -static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120; +static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120; // status of ESP8266 station interface // 2 : ESP8266 station connected to an AP and has obtained IP @@ -35,8 +38,14 @@ enum RegStatus { }; class TinyGsmESP8266 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmWifi, + public TinyGsmTCP, + public TinyGsmSSL { + friend class TinyGsmModem; + friend class TinyGsmWifi; + friend class TinyGsmTCP; + friend class TinyGsmSSL; /* * Inner Client @@ -63,24 +72,16 @@ class TinyGsmESP8266 } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { TINY_GSM_YIELD(); at->sendAT(GF("+CIPCLOSE="), mux); sock_connected = false; @@ -110,13 +111,14 @@ class TinyGsmESP8266 : GsmClientESP8266(modem, mux) {} public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; /* @@ -171,18 +173,6 @@ class TinyGsmESP8266 return res; } - bool thisHasSSL() { - return true; - } - - bool thisHasWifi() { - return true; - } - - bool thisHasGPRS() { - return false; - } - /* * Power functions */ @@ -205,12 +195,6 @@ class TinyGsmESP8266 bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; - /* - * SIM card functions - */ - protected: - // SIM card functions don't apply - /* * Generic network functions */ @@ -257,16 +241,10 @@ class TinyGsmESP8266 } } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+CIPSTA_CUR?")); int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); - if (res1 != 2) { - return ""; - } + if (res1 != 2) { return ""; } String res2 = stream.readStringUntil('"'); waitResponse(); return res2; @@ -292,56 +270,6 @@ class TinyGsmESP8266 return retVal; } - /* - * Phone Call functions - */ - protected: - bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; - bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool dtmfSendImpl(char cmd, - int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * Messaging functions - */ - protected: - String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE; - bool sendSMSImpl(const String& number, - const String& text) TINY_GSM_ATTR_NOT_AVAILABLE; - bool sendSMS_UTF16Impl(const char* const number, const void* text, - size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported - - /* - * Time functions - */ - protected: - String - getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * Battery & temperature functions - */ - protected: - uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - /* * Client related functions */ diff --git a/src/TinyGsmClientM590.h b/src/TinyGsmClientM590.h index a54357a..204a470 100644 --- a/src/TinyGsmClientM590.h +++ b/src/TinyGsmClientM590.h @@ -14,7 +14,11 @@ #define TINY_GSM_MUX_COUNT 2 -#include "TinyGsmCommon.h" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -32,8 +36,16 @@ enum RegStatus { }; class TinyGsmM590 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSMS, + public TinyGsmTime { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSMS; + friend class TinyGsmTime; /* * Inner Client @@ -67,17 +79,9 @@ class TinyGsmM590 sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { TINY_GSM_YIELD(); at->sendAT(GF("+TCPCLOSE="), mux); sock_connected = false; @@ -155,18 +159,6 @@ class TinyGsmM590 return waitResponse() == 1; } - bool thisHasSSL() { - return false; - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -204,15 +196,9 @@ class TinyGsmM590 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+XIIC?")); - if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; } streamSkipUntil(','); String res = stream.readStringUntil('\n'); waitResponse(); @@ -282,16 +268,6 @@ class TinyGsmM590 protected: // Able to follow all SIM card functions as inherited from the template - /* - * Phone Call functions - */ - protected: - bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; - bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool dtmfSendImpl(char cmd, - int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; - /* * Messaging functions */ @@ -299,34 +275,12 @@ class TinyGsmM590 bool sendSMS_UTF16Impl(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; - /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type available /* * Time functions */ protected: // Can follow the standard CCLK function in the template - /* - * Battery & temperature functions - */ - protected: - uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - /* * Client related functions */ diff --git a/src/TinyGsmClientM95.h b/src/TinyGsmClientM95.h index af63f01..585c478 100644 --- a/src/TinyGsmClientM95.h +++ b/src/TinyGsmClientM95.h @@ -15,7 +15,14 @@ #define TINY_GSM_MUX_COUNT 6 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmCalling.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTemperature.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -33,8 +40,22 @@ enum RegStatus { }; class TinyGsmM95 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmTime, + public TinyGsmBattery, + public TinyGsmTemperature { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmTime; + friend class TinyGsmBattery; + friend class TinyGsmTemperature; /* * Inner Client @@ -62,24 +83,16 @@ class TinyGsmM95 } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { uint32_t startMillis = millis(); dumpModemBuffer(maxWaitMs); at->sendAT(GF("+QICLOSE="), mux); @@ -114,13 +127,14 @@ class TinyGsmM95 public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; */ @@ -172,18 +186,6 @@ class TinyGsmM95 } } - bool thisHasSSL() { - return false; // TODO(?): Add SSL support - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -231,7 +233,6 @@ class TinyGsmM95 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - public: void setHostFormat(bool useDottedQuad) { if (useDottedQuad) { sendAT(GF("+QIDNSIP=0")); @@ -241,10 +242,6 @@ class TinyGsmM95 waitResponse(); } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+QILOCIP")); streamSkipUntil('\n'); @@ -338,9 +335,7 @@ class TinyGsmM95 protected: String getSimCCIDImpl() { sendAT(GF("+QCCID")); - if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -370,25 +365,18 @@ class TinyGsmM95 } /* - * Location functions + * Time functions */ protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported + // Can follow the standard CCLK function in the template /* - * Time functions + * Battery functions */ - protected: - // Can follow the standard CCLK function in the template + // Can follow the battery functions in the template /* - * Battery & temperature functions + * Temperature functions */ protected: float getTemperatureImpl() { diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index bb4b3e5..c6fdb40 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -17,7 +17,14 @@ #define TINY_GSM_MUX_COUNT 6 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmCalling.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmGSMLocation.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -35,8 +42,22 @@ enum RegStatus { }; class TinyGsmMC60 - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmGSMLocation, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmGSMLocation; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -64,24 +85,16 @@ class TinyGsmMC60 } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { uint32_t startMillis = millis(); dumpModemBuffer(maxWaitMs); at->sendAT(GF("+QICLOSE="), mux); @@ -116,13 +129,14 @@ class TinyGsmMC60 public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; */ @@ -174,29 +188,6 @@ class TinyGsmMC60 } } - /* - * under development - */ - // bool thisHasSSL() { - // sendAT(GF("+QIPSSL=?")); - // if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { - // return false; - // } - // return waitResponse() == 1; - // } - - bool thisHasSSL() { - return false; // TODO(?): Add SSL support - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -240,10 +231,6 @@ class TinyGsmMC60 return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+QILOCIP")); streamSkipUntil('\n'); @@ -321,21 +308,17 @@ class TinyGsmMC60 delay(1000); continue; } - int status = - waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), - GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), + GF("NOT INSERTED"), GF("PH_SIM PIN"), + GF("PH_SIM PUK")); waitResponse(); switch (status) { case 2: - case 3: - return SIM_LOCKED; + case 3: return SIM_LOCKED; case 5: - case 6: - return SIM_ANTITHEFT_LOCKED; - case 1: - return SIM_READY; - default: - return SIM_ERROR; + case 6: return SIM_ANTITHEFT_LOCKED; + case 1: return SIM_READY; + default: return SIM_ERROR; } } return SIM_ERROR; @@ -369,12 +352,6 @@ class TinyGsmMC60 protected: // Can use CIPGSMLOC as inherited from the template - /* - * GPS location functions - */ - public: - // No functions of this type supported - /* * Time functions */ @@ -382,10 +359,9 @@ class TinyGsmMC60 // Can follow the standard CCLK function in the template /* - * Battery & temperature functions + * Battery functions */ - protected: - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; + // Can follow battery functions as in the template /* * Client related functions diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index 8740cd1..b2a2651 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -14,7 +14,13 @@ #define TINY_GSM_MUX_COUNT 10 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTemperature.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -31,10 +37,22 @@ enum RegStatus { REG_UNKNOWN = 4, }; -class TinyGsmSim5360 : public TinyGsmModem { - friend class TinyGsmModem; +class TinyGsmSim5360 : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSMS, + public TinyGsmTime, + public TinyGsmBattery, + public TinyGsmTemperature { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSMS; + friend class TinyGsmTime; + friend class TinyGsmBattery; + friend class TinyGsmTemperature; /* * Inner Client @@ -64,24 +82,16 @@ class TinyGsmSim5360 : public TinyGsmModemmodemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+CIPCLOSE="), mux); sock_connected = false; @@ -112,13 +122,14 @@ class TinyGsmSim5360 : public TinyGsmModemmodemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; */ @@ -186,18 +197,6 @@ class TinyGsmSim5360 : public TinyGsmModem): Module supports SSL, but not yet implemented - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -258,17 +257,11 @@ class TinyGsmSim5360 : public TinyGsmModem { - friend class TinyGsmModem; +class TinyGsmSim7000 : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSMS, + public TinyGsmGSMLocation, + public TinyGsmGPS, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSMS; + friend class TinyGsmGSMLocation; + friend class TinyGsmGPS; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -64,24 +85,16 @@ class TinyGsmSim7000 : public TinyGsmModemmodemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+CIPCLOSE="), mux); sock_connected = false; @@ -113,13 +126,14 @@ class TinyGsmSim7000 : public TinyGsmModemmodemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; */ @@ -187,18 +201,6 @@ class TinyGsmSim7000 : public TinyGsmModem { - friend class TinyGsmModem; +class TinyGsmSim7600 : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSMS, + public TinyGsmGPS, + public TinyGsmTime, + public TinyGsmBattery, + public TinyGsmTemperature { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSMS; + friend class TinyGsmGPS; + friend class TinyGsmTime; + friend class TinyGsmBattery; + friend class TinyGsmTemperature; /* * Inner Client @@ -71,17 +92,9 @@ class TinyGsmSim7600 : public TinyGsmModemmodemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+CIPCLOSE="), mux); sock_connected = false; @@ -98,6 +111,32 @@ class TinyGsmSim7600 : public TinyGsmModemmodemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + TINY_GSM_CLIENT_CONNECT_OVERRIDES + }; + */ + /* * Constructor */ @@ -162,18 +201,6 @@ class TinyGsmSim7600 : public TinyGsmModem { - friend class TinyGsmModem; +class TinyGsmSim800 + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSSL, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmGSMLocation, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSSL; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmGSMLocation; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -64,24 +88,16 @@ class TinyGsmSim800 : public TinyGsmModemmodemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+CIPCLOSE="), mux, GF(",1")); // Quick close sock_connected = false; @@ -110,13 +126,14 @@ class TinyGsmSim800 : public TinyGsmModemmodemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; /* @@ -206,23 +223,17 @@ class TinyGsmSim800 : public TinyGsmModem +#include "TinyGsmClientSIM800.h" +#include "TinyGsmGPS.tpp" + +class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS { + friend class TinyGsmGPS; -class TinyGsmSim808 : public TinyGsmSim800 { public: explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {} + /* * GPS location functions */ - public: + protected: // enable GPS - bool enableGPS() { + bool enableGPSImpl() { // uint16_t state; sendAT(GF("+CGNSPWR=1")); @@ -30,7 +34,7 @@ class TinyGsmSim808 : public TinyGsmSim800 { return true; } - bool disableGPS() { + bool disableGPSImpl() { // uint16_t state; sendAT(GF("+CGNSPWR=0")); @@ -41,7 +45,7 @@ class TinyGsmSim808 : public TinyGsmSim800 { // get the RAW GPS output // works only with ans SIM808 V2 - String getGPSraw() { + String getGPSrawImpl() { sendAT(GF("+CGNSINF")); if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); @@ -52,8 +56,8 @@ class TinyGsmSim808 : public TinyGsmSim800 { // get GPS informations // works only with ans SIM808 V2 - bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0, - int* vsat = 0, int* usat = 0) { + bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, + int* vsat = 0, int* usat = 0) { // String buffer = ""; // char chr_buffer[12]; bool fix = false; @@ -90,8 +94,8 @@ class TinyGsmSim808 : public TinyGsmSim800 { // get GPS time // works only with SIM808 V2 - bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute, - int* second) { + bool getGPSTimeImpl(int* year, int* month, int* day, int* hour, int* minute, + int* second) { bool fix = false; char chr_buffer[12]; sendAT(GF("+CGNSINF")); diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index 9f4e052..a700ec5 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -14,7 +14,15 @@ #define TINY_GSM_MUX_COUNT 7 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmGSMLocation.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmSSL.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTemperature.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -31,10 +39,26 @@ enum RegStatus { REG_UNKNOWN = 4, }; -class TinyGsmSaraR4 : public TinyGsmModem { - friend class TinyGsmModem; +class TinyGsmSaraR4 + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSSL, + public TinyGsmBattery, + public TinyGsmGSMLocation, + public TinyGsmSMS, + public TinyGsmTemperature, + public TinyGsmTime { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSSL; + friend class TinyGsmBattery; + friend class TinyGsmGSMLocation; + friend class TinyGsmSMS; + friend class TinyGsmTemperature; + friend class TinyGsmTime; /* * Inner Client @@ -64,7 +88,7 @@ class TinyGsmSaraR4 : public TinyGsmModemmaintain(); return sock_connected; } + virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); + } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 120); + } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 120); + } }; /* @@ -249,18 +282,6 @@ class TinyGsmSaraR4 : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSSL, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmTime, + public TinyGsmTemperature { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSSL; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmTime; + friend class TinyGsmTemperature; /* * Inner Client @@ -77,24 +98,16 @@ class TinyGsmSequansMonarch } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { if (sock_connected) stop(); TINY_GSM_YIELD(); rx.clear(); sock_connected = at->modemConnect(host, port, mux, false, timeout_s); return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+SQNSH="), mux); sock_connected = false; @@ -127,7 +140,7 @@ class TinyGsmSequansMonarch bool strictSSL = false; public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); @@ -153,6 +166,7 @@ class TinyGsmSequansMonarch sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES void setStrictSSL(bool strict) { strictSSL = strict; @@ -225,18 +239,6 @@ class TinyGsmSequansMonarch while (stream.available()) { waitResponse(15, NULL, NULL); } } - bool thisHasGPRS() { - return true; - } - - bool thisHasWifi() { - return false; - } - - bool thisHasSSL() { - return true; - } - /* * Power functions */ @@ -287,16 +289,9 @@ class TinyGsmSequansMonarch RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); } - - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+CGPADDR=3")); - if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { - return ""; - } + if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; } String res = stream.readStringUntil('\"'); waitResponse(); return res; @@ -344,9 +339,7 @@ class TinyGsmSequansMonarch protected: String getSimCCIDImpl() { sendAT(GF("+SQNCCID")); - if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -367,18 +360,6 @@ class TinyGsmSequansMonarch protected: // Follows all messaging functions per template - /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported - /* * Time functions */ @@ -386,14 +367,8 @@ class TinyGsmSequansMonarch // Can follow the standard CCLK function in the template /* - * Battery & temperature functions + * Temperature functions */ - protected: - uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; float getTemperatureImpl() { sendAT(GF("+SMDTH")); diff --git a/src/TinyGsmClientUBLOX.h b/src/TinyGsmClientUBLOX.h index 20751de..553abbc 100644 --- a/src/TinyGsmClientUBLOX.h +++ b/src/TinyGsmClientUBLOX.h @@ -14,7 +14,15 @@ #define TINY_GSM_MUX_COUNT 7 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmCalling.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmGSMLocation.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmSSL.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTime.tpp" #define GSM_NL "\r\n" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -32,9 +40,25 @@ enum RegStatus { }; class TinyGsmUBLOX - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmTCP, + public TinyGsmSSL, + public TinyGsmCalling, + public TinyGsmSMS, + public TinyGsmGSMLocation, + public TinyGsmTime, + public TinyGsmBattery { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmTCP; + friend class TinyGsmSSL; + friend class TinyGsmCalling; + friend class TinyGsmSMS; + friend class TinyGsmGSMLocation; + friend class TinyGsmTime; + friend class TinyGsmBattery; /* * Inner Client @@ -64,7 +88,7 @@ class TinyGsmUBLOX } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); @@ -80,17 +104,9 @@ class TinyGsmUBLOX return sock_connected; } - int connect(IPAddress ip, uint16_t port, int timeout_s) { - return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); - } - int connect(const char* host, uint16_t port) override { - return connect(host, port, 75); - } - int connect(IPAddress ip, uint16_t port) override { - return connect(ip, port, 75); - } + TINY_GSM_CLIENT_CONNECT_OVERRIDES - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs); at->sendAT(GF("+USOCL="), mux); at->waitResponse(); // should return within 1s @@ -119,7 +135,7 @@ class TinyGsmUBLOX : GsmClientUBLOX(modem, mux) {} public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { stop(); TINY_GSM_YIELD(); rx.clear(); @@ -133,6 +149,7 @@ class TinyGsmUBLOX at->maintain(); return sock_connected; } + TINY_GSM_CLIENT_CONNECT_OVERRIDES }; /* @@ -212,18 +229,6 @@ class TinyGsmUBLOX return waitResponse() == 1; } - bool thisHasSSL() { - return true; - } - - bool thisHasWifi() { - return false; - } - - bool thisHasGPRS() { - return true; - } - /* * Power functions */ @@ -262,21 +267,13 @@ class TinyGsmUBLOX return false; } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { sendAT(GF("+UPSND=0,0")); - if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; } streamSkipUntil(','); // Skip PSD profile streamSkipUntil('\"'); // Skip request type String res = stream.readStringUntil('\"'); - if (waitResponse() != 1) { - return ""; - } + if (waitResponse() != 1) { return ""; } return res; } @@ -370,9 +367,7 @@ class TinyGsmUBLOX protected: String getIMEIImpl() { sendAT(GF("+CGSN")); - if (waitResponse(GF(GSM_NL)) != 1) { - return ""; - } + if (waitResponse(GF(GSM_NL)) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); @@ -413,12 +408,6 @@ class TinyGsmUBLOX return res; } - /* - * GPS location functions - */ - public: - // No functions of this type supported - /* * Time functions */ @@ -426,7 +415,7 @@ class TinyGsmUBLOX // Can follow the standard CCLK function in the template /* - * Battery & temperature functions + * Battery functions */ protected: uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; @@ -452,6 +441,10 @@ class TinyGsmUBLOX return true; } + /* + * Temperature functions + */ + // This would only available for a small number of modules in this group // (TOBY-L) float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; @@ -477,8 +470,9 @@ class TinyGsmUBLOX } // Enable NODELAY - sendAT(GF("+USOSO="), *mux, GF(",6,1,1")); - waitResponse(); + // NOTE: No delay allows data to go out faster, at the cost of using + // additional data from your cellular plan sendAT(GF("+USOSO="), *mux, + // GF(",6,1,1")); waitResponse(); // Enable KEEPALIVE, 30 sec // sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index 73e0822..f553f54 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -20,7 +20,14 @@ // here) #define TINY_GSM_XBEE_GUARD_TIME 1010 -#include "TinyGsmCommon.h" +#include "TinyGsmBattery.tpp" +#include "TinyGsmGPRS.tpp" +#include "TinyGsmModem.tpp" +#include "TinyGsmSMS.tpp" +#include "TinyGsmSSL.tpp" +#include "TinyGsmTCP.tpp" +#include "TinyGsmTemperature.tpp" +#include "TinyGsmWifi.tpp" #define GSM_NL "\r" static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; @@ -59,8 +66,22 @@ enum XBeeType { }; class TinyGsmXBee - : public TinyGsmModem { - friend class TinyGsmModem; + : public TinyGsmModem, + public TinyGsmGPRS, + public TinyGsmWifi, + public TinyGsmTCP, + public TinyGsmSSL, + public TinyGsmSMS, + public TinyGsmBattery, + public TinyGsmTemperature { + friend class TinyGsmModem; + friend class TinyGsmGPRS; + friend class TinyGsmWifi; + friend class TinyGsmTCP; + friend class TinyGsmSSL; + friend class TinyGsmSMS; + friend class TinyGsmBattery; + friend class TinyGsmTemperature; /* * Inner Client @@ -93,7 +114,7 @@ class TinyGsmXBee // 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 data // even if you haven't "made" any connection. - int connect(const char* host, uint16_t port, int timeout_s) { + 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 sock_connected = at->modemConnect(host, port, mux, false, timeout_s); @@ -103,7 +124,7 @@ class TinyGsmXBee return connect(host, port, 75); } - int connect(IPAddress ip, uint16_t port, int timeout_s) { + virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { if (timeout_s != 0) { DBG("Timeout [", timeout_s, "] doesn't apply here."); } @@ -116,7 +137,7 @@ class TinyGsmXBee return connect(ip, port, 0); } - void stop(uint32_t maxWaitMs) { + virtual void stop(uint32_t maxWaitMs) { at->streamClear(); // Empty anything in the buffer // empty the saved currently-in-use destination address at->modemStop(maxWaitMs); @@ -236,14 +257,17 @@ class TinyGsmXBee : GsmClientXBee(modem, mux) {} public: - int connect(const char* host, uint16_t port, int timeout_s) { + int connect(const char* host, uint16_t port, int timeout_s) override { // NOTE: Not caling stop() or yeild() here at->streamClear(); // Empty anything in the buffer before starting sock_connected = at->modemConnect(host, port, mux, true, timeout_s); return sock_connected; } + int connect(const char* host, uint16_t port) override { + return connect(host, port, 75); + } - int connect(IPAddress ip, uint16_t port, int timeout_s) { + int connect(IPAddress ip, uint16_t port, int timeout_s) override { if (timeout_s != 0) { DBG("Timeout [", timeout_s, "] doesn't apply here."); } @@ -252,6 +276,9 @@ class TinyGsmXBee sock_connected = at->modemConnect(ip, port, mux, true); return sock_connected; } + int connect(IPAddress ip, uint16_t port) override { + return connect(ip, port, 0); + } }; /* @@ -405,6 +432,7 @@ class TinyGsmXBee return sendATGetString(GF("HS")); } + /* bool thisHasSSL() { if (beeType == XBEE_S6B_WIFI) return false; @@ -425,6 +453,7 @@ class TinyGsmXBee else return true; } + */ public: XBeeType getBeeType() { @@ -692,10 +721,6 @@ class TinyGsmXBee return retVal; } - /* - * IP Address functions - */ - protected: String getLocalIPImpl() { XBEE_COMMAND_START_DECORATOR(5, "") sendAT(GF("MY")); @@ -788,7 +813,9 @@ class TinyGsmXBee return isNetworkConnected(); } - String getOperatorImpl() { return sendATGetString(GF("MN")); } + String getOperatorImpl() { + return sendATGetString(GF("MN")); + } /* * SIM card functions @@ -801,24 +828,18 @@ class TinyGsmXBee return false; } - String getSimCCIDImpl() { return sendATGetString(GF("S#")); } + String getSimCCIDImpl() { + return sendATGetString(GF("S#")); + } - String getIMEIImpl() { return sendATGetString(GF("IM")); } + String getIMEIImpl() { + return sendATGetString(GF("IM")); + } SimStatus getSimStatusImpl(uint32_t) { return SIM_READY; // unsupported } - /* - * Phone Call functions - */ - protected: - bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; - bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - bool dtmfSendImpl(char cmd, - int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; - /* * Messaging functions */ @@ -848,26 +869,7 @@ class TinyGsmXBee } /* - * Location functions - */ - protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * GPS location functions - */ - public: - // No functions of this type supported - - /* - * Time functions - */ - protected: - String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) - TINY_GSM_ATTR_NOT_IMPLEMENTED; - - /* - * Battery & temperature functions + * Battery functions */ protected: // Use: float vBatt = modem.getBattVoltage() / 1000.0; @@ -894,6 +896,10 @@ class TinyGsmXBee return true; } + /* + * Temperature functions + */ + float getTemperatureImpl() { XBEE_COMMAND_START_DECORATOR(5, static_cast(-9999)) String res = sendATGetString(GF("TP")); diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index bae5447..683795b 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -28,8 +28,6 @@ #include #endif -#include "TinyGsmFifo.h" - #ifndef TINY_GSM_YIELD_MS #define TINY_GSM_YIELD_MS 0 #endif @@ -39,10 +37,6 @@ { delay(TINY_GSM_YIELD_MS); } #endif -#if !defined(TINY_GSM_RX_BUFFER) -#define TINY_GSM_RX_BUFFER 64 -#endif - #define TINY_GSM_ATTR_NOT_AVAILABLE \ __attribute__((error("Not available on this modem type"))) #define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented"))) @@ -102,7 +96,7 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, static uint32_t rates[] = {115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800}; - for (unsigned i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) { + for (uint8_t i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) { uint32_t rate = rates[i]; if (rate < minimum || rate > maximum) continue; @@ -122,1120 +116,4 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, return 0; } -enum modemInternalBuffferType { - NO_MODEM_BUFFER = - 0, // For modules that do not store incoming data in any sort of buffer - READ_NO_CHECK = 1, // Data is stored in a buffer, but we can only read from - // the buffer, not check how much data is stored in it - READ_AND_CHECK_SIZE = 2, // Data is stored in a buffer and we can both read - // and check the size of the buffer -}; - -enum SimStatus { - SIM_ERROR = 0, - SIM_READY = 1, - SIM_LOCKED = 2, - SIM_ANTITHEFT_LOCKED = 3, -}; - -enum TinyGSMDateTimeFormat { DATE_FULL = 0, DATE_TIME = 1, DATE_DATE = 2 }; - -template -class TinyGsmModem { - public: - /* - * Basic functions - */ - bool begin(const char* pin = NULL) { - return thisModem().initImpl(pin); - } - bool init(const char* pin = NULL) { - return thisModem().initImpl(pin); - } - template - void sendAT(Args... cmd) { - thisModem().streamWrite("AT", cmd..., thisModem().gsmNL); - thisModem().stream.flush(); - TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */ - } - void setBaud(uint32_t baud) { - thisModem().setBaudImpl(baud); - } - // Test response to AT commands - bool testAT(uint32_t timeout_ms = 10000L) { - return thisModem().testATImpl(timeout_ms); - } - - // Asks for modem information via the V.25TER standard ATI command - // NOTE: The actual value and style of the response is quite varied - String getModemInfo() { - return thisModem().getModemInfoImpl(); - } - // Gets the modem name (as it calls itself) - String getModemName() { - return thisModem().getModemNameImpl(); - } - void maintain() { - return thisModem().maintainImpl(); - } - bool factoryDefault() { - return thisModem().factoryDefaultImpl(); - } - bool hasSSL() { - return thisModem().thisHasSSL(); - } - bool hasWifi() { - return thisModem().thisHasWifi(); - } - bool hasGPRS() { - return thisModem().thisHasGPRS(); - } - - /* - * Power functions - */ - bool restart() { - return thisModem().restartImpl(); - } - bool poweroff() { - return thisModem().powerOffImpl(); - } - bool radioOff() { - return thisModem().radioOffImpl(); - } - bool sleepEnable(bool enable = true) { - return thisModem().sleepEnableImpl(enable); - } - - /* - * SIM card functions - */ - // Unlocks the SIM - bool simUnlock(const char* pin) { - return thisModem().simUnlockImpl(pin); - } - // Gets the CCID of a sim card via AT+CCID - String getSimCCID() { - return thisModem().getSimCCIDImpl(); - } - // Asks for TA Serial Number Identification (IMEI) - String getIMEI() { - return thisModem().getIMEIImpl(); - } - SimStatus getSimStatus(uint32_t timeout_ms = 10000L) { - return thisModem().getSimStatusImpl(timeout_ms); - } - - /* - * Generic network functions - */ - // RegStatus getRegistrationStatus() {} - bool isNetworkConnected() { - return thisModem().isNetworkConnectedImpl(); - } - // Waits for network attachment - bool waitForNetwork(uint32_t timeout_ms = 60000L) { - return thisModem().waitForNetworkImpl(timeout_ms); - } - // Gets signal quality report - int16_t getSignalQuality() { - return thisModem().getSignalQualityImpl(); - } - - /* - * GPRS functions - */ - bool gprsConnect(const char* apn, const char* user = NULL, - const char* pwd = NULL) { - return thisModem().gprsConnectImpl(apn, user, pwd); - } - bool gprsDisconnect() { - return thisModem().gprsDisconnectImpl(); - } - // Checks if current attached to GPRS/EPS service - bool isGprsConnected() { - return thisModem().isGprsConnectedImpl(); - } - // Gets the current network operator - String getOperator() { - return thisModem().getOperatorImpl(); - } - - /* - * WiFi functions - */ - bool networkConnect(const char* ssid, const char* pwd) { - return thisModem().networkConnectImpl(ssid, pwd); - } - bool networkDisconnect() { - return thisModem().networkDisconnectImpl(); - } - - /* - * GPRS functions - */ - String getLocalIP() { - return thisModem().getLocalIPImpl(); - } - IPAddress localIP() { - return thisModem().TinyGsmIpFromString(thisModem().getLocalIP()); - } - - /* - * Phone Call functions - */ - bool callAnswer() { - return thisModem().callAnswerImpl(); - } - bool callNumber(const String& number) { - return thisModem().callNumberImpl(number); - } - bool callHangup() { - return thisModem().callHangupImpl(); - } - bool dtmfSend(char cmd, int duration_ms = 100) { - return thisModem().dtmfSendImpl(cmd, duration_ms); - } - - /* - * Messaging functions - */ - String sendUSSD(const String& code) { - return thisModem().sendUSSDImpl(code); - } - bool sendSMS(const String& number, const String& text) { - return thisModem().sendSMSImpl(number, text); - } - bool sendSMS_UTF16(const char* const number, const void* text, size_t len) { - return thisModem().sendSMS_UTF16Impl(number, text, len); - } - - /* - * Location functions - */ - String getGsmLocation() { - return thisModem().getGsmLocationImpl(); - } - - /* - * GPS location functions - */ - // No template interface or implementation of these functions - - /* - * Time functions - */ - String getGSMDateTime(TinyGSMDateTimeFormat format) { - return thisModem().getGSMDateTimeImpl(format); - } - - /* - * Battery & temperature functions - */ - uint16_t getBattVoltage() { - return thisModem().getBattVoltageImpl(); - } - int8_t getBattPercent() { - return thisModem().getBattPercentImpl(); - } - uint8_t getBattChargeState() { - return thisModem().getBattChargeStateImpl(); - } - bool getBattStats(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) { - return thisModem().getBattStatsImpl(chargeState, percent, milliVolts); - } - float getTemperature() { - return thisModem().getTemperatureImpl(); - } - - /* - * CRTP Helper - */ - protected: - const modemType& thisModem() const { - return static_cast(*this); - } - modemType& thisModem() { - return static_cast(*this); - } - - /* - * Inner Client - */ - public: - class GsmClient : public Client { - // Make all classes created from the modem template friends - friend class TinyGsmModem; - typedef TinyGsmFifo RxFifo; - - public: - // bool init(modemType* modem, uint8_t); - // int connect(const char* host, uint16_t port, int timeout_s); - - // Connect to a IP address given as an IPAddress object by - // converting said IP address to text - // int connect(IPAddress ip, uint16_t port, int timeout_s) { - // return connect(TinyGsmStringFromIp(ip).c_str(), port, - // timeout_s); - // } - // int connect(const char* host, uint16_t port) override { - // return connect(host, port, 75); - // } - // int connect(IPAddress ip, uint16_t port) override { - // return connect(ip, port, 75); - // } - - static String TinyGsmStringFromIp(IPAddress ip) { - String host; - host.reserve(16); - host += ip[0]; - host += "."; - host += ip[1]; - host += "."; - host += ip[2]; - host += "."; - host += ip[3]; - return host; - } - - // void stop(uint32_t maxWaitMs); - // void stop() override { - // stop(15000L); - // } - - // Writes data out on the client using the modem send functionality - size_t write(const uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - at->maintain(); - return at->modemSend(buf, size, mux); - } - - size_t write(uint8_t c) override { - return write(&c, 1); - } - - size_t write(const char* str) { - if (str == NULL) return 0; - return write((const uint8_t*)str, strlen(str)); - } - - int available() override { - TINY_GSM_YIELD(); - switch (bufType) { - // Returns the number of characters available in the TinyGSM fifo - case NO_MODEM_BUFFER: - if (!rx.size() && sock_connected) { at->maintain(); } - return rx.size(); - - // Returns the combined number of characters available in the TinyGSM - // fifo and the modem chips internal fifo. - case READ_NO_CHECK: - if (!rx.size()) { at->maintain(); } - return rx.size() + sock_available; - - // Returns the combined number of characters available in the TinyGSM - // fifo and the modem chips internal fifo, doing an extra check-in - // with the modem to see if anything has arrived without a UURC. - case READ_AND_CHECK_SIZE: - if (!rx.size()) { - if (millis() - prev_check > 500) { - got_data = true; - prev_check = millis(); - } - at->maintain(); - } - return rx.size() + sock_available; - } - } - - int read(uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - size_t cnt = 0; - uint32_t _startMillis = millis(); - - switch (bufType) { - // Reads characters out of the TinyGSM fifo, waiting for any URC's - // from the modem for new data if there's nothing in the fifo. - case NO_MODEM_BUFFER: - while (cnt < size && millis() - _startMillis < _timeout) { - size_t chunk = TinyGsmMin(size - cnt, rx.size()); - if (chunk > 0) { - rx.get(buf, chunk); - buf += chunk; - cnt += chunk; - continue; - } /* TODO: Read directly into user buffer? */ - if (!rx.size() && sock_connected) { at->maintain(); } - } - return cnt; - - // Reads characters out of the TinyGSM fifo, and from the modem chip's - // internal fifo if avaiable. - case READ_NO_CHECK: - at->maintain(); - while (cnt < size) { - size_t chunk = TinyGsmMin(size - cnt, rx.size()); - if (chunk > 0) { - rx.get(buf, chunk); - buf += chunk; - cnt += chunk; - continue; - } /* TODO: Read directly into user buffer? */ - at->maintain(); - if (sock_available > 0) { - int n = at->modemRead( - TinyGsmMin((uint16_t)rx.free(), sock_available), mux); - if (n == 0) break; - } else { - break; - } - } - return cnt; - - // Reads characters out of the TinyGSM fifo, and from the modem chips - // internal fifo if avaiable, also double checking with the modem if - // data has arrived without issuing a UURC. - case READ_AND_CHECK_SIZE: - at->maintain(); - while (cnt < size) { - size_t chunk = TinyGsmMin(size - cnt, rx.size()); - if (chunk > 0) { - rx.get(buf, chunk); - buf += chunk; - cnt += chunk; - continue; - } - // Workaround: Some modules "forget" to notify about data arrival - if (millis() - prev_check > 500) { - got_data = true; - prev_check = millis(); - } - // TODO(vshymanskyy): Read directly into user buffer? - at->maintain(); - if (sock_available > 0) { - int n = at->modemRead( - TinyGsmMin((uint16_t)rx.free(), sock_available), mux); - if (n == 0) break; - } else { - break; - } - } - return cnt; - } - } - - int read() override { - uint8_t c; - if (read(&c, 1) == 1) { return c; } - return -1; - } - - // TODO(SRGDamia1): Implement peek - int peek() override { - return -1; - } - - void flush() override { - at->stream.flush(); - } - - uint8_t connected() override { - if (available()) { return true; } - return sock_connected; - } - operator bool() override { - return connected(); - } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - protected: - // Read and dump anything remaining in the modem's internal buffer. - // Using this in the client stop() function. - // The socket will appear open in response to connected() even after it - // closes until all data is read from the buffer. - // Doing it this way allows the external mcu to find and get all of the - // data that it wants from the socket even if it was closed externally. - void dumpModemBuffer(uint32_t maxWaitMs) { - TINY_GSM_YIELD(); - rx.clear(); - at->maintain(); - uint32_t startMillis = millis(); - while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { - at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); - rx.clear(); - at->maintain(); - } - } - - modemType* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; - }; - - /* - * Inner Secure Client - */ - - /* - * Constructor - */ - - /* - * Basic functions - */ - protected: - void setBaudImpl(uint32_t baud) { - thisModem().sendAT(GF("+IPR="), baud); - thisModem().waitResponse(); - } - - bool testATImpl(uint32_t timeout_ms = 10000L) { - for (uint32_t start = millis(); millis() - start < timeout_ms;) { - thisModem().sendAT(GF("")); - if (thisModem().waitResponse(200) == 1) { return true; } - delay(100); - } - return false; - } - - String getModemInfoImpl() { - thisModem().sendAT(GF("I")); - String res; - if (thisModem().waitResponse(1000L, res) != 1) { return ""; } - // Do the replaces twice so we cover both \r and \r\n type endings - res.replace("\r\nOK\r\n", ""); - res.replace("\rOK\r", ""); - res.replace("\r\n", " "); - res.replace("\r", " "); - res.trim(); - return res; - } - - String getModemNameImpl() { - thisModem().sendAT(GF("+CGMI")); - String res1; - if (thisModem().waitResponse(1000L, res1) != 1) { return "unknown"; } - res1.replace("\r\nOK\r\n", ""); - res1.replace("\rOK\r", ""); - res1.trim(); - - thisModem().sendAT(GF("+GMM")); - String res2; - if (thisModem().waitResponse(1000L, res2) != 1) { return "unknown"; } - res1.replace("\r\nOK\r\n", ""); - res1.replace("\rOK\r", ""); - res2.trim(); - - String name = res1 + String(' ') + res2; - DBG("### Modem:", name); - return name; - } - - void maintainImpl() { - switch (bufType) { - case READ_AND_CHECK_SIZE: - // Keep listening for modem URC's and proactively iterate through - // sockets asking if any data is avaiable - for (int mux = 0; mux < muxCount; mux++) { - GsmClient* sock = thisModem().sockets[mux]; - if (sock && sock->got_data) { - sock->got_data = false; - sock->sock_available = thisModem().modemGetAvailable(mux); - } - } - while (thisModem().stream.available()) { - thisModem().waitResponse(15, NULL, NULL); - } - break; - default: - // Just listen for any URC's - thisModem().waitResponse(100, NULL, NULL); - break; - } - } - - bool factoryDefaultImpl() { - thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write - thisModem().waitResponse(); - thisModem().sendAT(GF("+IPR=0")); // Auto-baud - thisModem().waitResponse(); - thisModem().sendAT(GF("&W")); // Write configuration - return thisModem().waitResponse() == 1; - } - - /* - * Power functions - */ - protected: - bool radioOffImpl() { - thisModem().sendAT(GF("+CFUN=0")); - if (thisModem().waitResponse(10000L) != 1) { return false; } - delay(3000); - return true; - } - - bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; - - /* - * SIM card functions - */ - protected: - // Unlocks a sim via the 3GPP TS command AT+CPIN - bool simUnlockImpl(const char* pin) { - if (pin && strlen(pin) > 0) { - thisModem().sendAT(GF("+CPIN=\""), pin, GF("\"")); - return thisModem().waitResponse() == 1; - } - return true; - } - - // Gets the CCID of a sim card via AT+CCID - String getSimCCIDImpl() { - thisModem().sendAT(GF("+CCID")); - if (thisModem().waitResponse(GF("+CCID:")) != 1) { return ""; } - String res = thisModem().stream.readStringUntil('\n'); - thisModem().waitResponse(); - res.trim(); - return res; - } - - // Asks for TA Serial Number Identification (IMEI) via the V.25TER standard - // AT+GSN command - String getIMEIImpl() { - thisModem().sendAT(GF("+GSN")); - String res = thisModem().stream.readStringUntil('\n'); - thisModem().waitResponse(); - res.trim(); - return res; - } - - SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { - for (uint32_t start = millis(); millis() - start < timeout_ms;) { - thisModem().sendAT(GF("+CPIN?")); - if (thisModem().waitResponse(GF("+CPIN:")) != 1) { - delay(1000); - continue; - } - int status = thisModem().waitResponse(GF("READY"), GF("SIM PIN"), - GF("SIM PUK"), GF("NOT INSERTED"), - GF("NOT READY")); - thisModem().waitResponse(); - switch (status) { - case 2: - case 3: return SIM_LOCKED; - case 1: return SIM_READY; - default: return SIM_ERROR; - } - } - return SIM_ERROR; - } - - /* - * Generic network functions - */ - protected: - // Gets the modem's registration status via CREG/CGREG/CEREG - // CREG = Generic network registration - // CGREG = GPRS service registration - // CEREG = EPS registration for LTE modules - int getRegistrationStatusXREG(const char* regCommand) { - thisModem().sendAT('+', regCommand, '?'); - // check for any of the three for simplicity - int resp = thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"), - GF("+CEREG:")); - if (resp != 1 && resp != 2 && resp != 3) { return -1; } - thisModem().streamSkipUntil(','); /* Skip format (0) */ - int status = thisModem().streamGetInt('\n'); - thisModem().waitResponse(); - return status; - } - - bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) { - for (uint32_t start = millis(); millis() - start < timeout_ms;) { - if (thisModem().isNetworkConnected()) { return true; } - delay(250); - } - return false; - } - - // Gets signal quality report according to 3GPP TS command AT+CSQ - int16_t getSignalQualityImpl() { - thisModem().sendAT(GF("+CSQ")); - if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; } - int res = thisModem().streamGetInt(','); - thisModem().waitResponse(); - return res; - } - - /* - * GPRS functions - */ - protected: - // Checks if current attached to GPRS/EPS service - bool isGprsConnectedImpl() { - thisModem().sendAT(GF("+CGATT?")); - if (thisModem().waitResponse(GF("+CGATT:")) != 1) { return false; } - int res = thisModem().streamGetInt('\n'); - thisModem().waitResponse(); - if (res != 1) { return false; } - - return thisModem().localIP() != IPAddress(0, 0, 0, 0); - } - - // Gets the current network operator via the 3GPP TS command AT+COPS - String getOperatorImpl() { - thisModem().sendAT(GF("+COPS?")); - if (thisModem().waitResponse(GF("+COPS:")) != 1) { return ""; } - thisModem().streamSkipUntil('"'); /* Skip mode and format */ - String res = thisModem().stream.readStringUntil('"'); - thisModem().waitResponse(); - return res; - } - - /* - * WiFi functions - */ - - bool networkConnectImpl(const char* ssid, const char* pwd) { - return false; - } - bool networkDisconnectImpl() { - return thisModem().gprsConnectImpl(); - } - - /* - * IP Address functions - */ - protected: - String getLocalIPImpl() { - thisModem().sendAT(GF("+CGPADDR=1")); - if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; } - thisModem().streamSkipUntil(','); // Skip context id - String res = thisModem().stream.readStringUntil('\r'); - if (thisModem().waitResponse() != 1) { return ""; } - return res; - } - - static IPAddress TinyGsmIpFromString(const String& strIP) { - int Parts[4] = { - 0, - }; - int Part = 0; - for (uint8_t i = 0; i < strIP.length(); i++) { - char c = strIP[i]; - if (c == '.') { - Part++; - if (Part > 3) { return IPAddress(0, 0, 0, 0); } - continue; - } else if (c >= '0' && c <= '9') { - Parts[Part] *= 10; - Parts[Part] += c - '0'; - } else { - if (Part == 3) break; - } - } - return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]); - } - - /* - * Phone Call functions - */ - protected: - bool callAnswerImpl() { - thisModem().sendAT(GF("A")); - return thisModem().waitResponse() == 1; - } - - // Returns true on pick-up, false on error/busy - bool callNumberImpl(const String& number) { - if (number == GF("last")) { - thisModem().sendAT(GF("DL")); - } else { - thisModem().sendAT(GF("D"), number, ";"); - } - int status = thisModem().waitResponse(60000L, GF("OK"), GF("BUSY"), - GF("NO ANSWER"), GF("NO CARRIER")); - switch (status) { - case 1: return true; - case 2: - case 3: return false; - default: return false; - } - } - - bool callHangupImpl() { - thisModem().sendAT(GF("H")); - return thisModem().waitResponse() == 1; - } - - // 0-9,*,#,A,B,C,D - bool dtmfSendImpl(char cmd, int duration_ms = 100) { - duration_ms = constrain(duration_ms, 100, 1000); - - thisModem().sendAT(GF("+VTD="), - duration_ms / 100); // VTD accepts in 1/10 of a second - thisModem().waitResponse(); - - thisModem().sendAT(GF("+VTS="), cmd); - return thisModem().waitResponse(10000L) == 1; - } - - /* - * Messaging functions - */ - protected: - static inline String TinyGsmDecodeHex7bit(String& instr) { - String result; - byte reminder = 0; - int bitstate = 7; - for (unsigned i = 0; i < instr.length(); i += 2) { - char buf[4] = { - 0, - }; - buf[0] = instr[i]; - buf[1] = instr[i + 1]; - byte b = strtol(buf, NULL, 16); - - byte bb = b << (7 - bitstate); - char c = (bb + reminder) & 0x7F; - result += c; - reminder = b >> bitstate; - bitstate--; - if (bitstate == 0) { - char cc = reminder; - result += cc; - reminder = 0; - bitstate = 7; - } - } - return result; - } - - static inline String TinyGsmDecodeHex8bit(String& instr) { - String result; - for (unsigned i = 0; i < instr.length(); i += 2) { - char buf[4] = { - 0, - }; - buf[0] = instr[i]; - buf[1] = instr[i + 1]; - char b = strtol(buf, NULL, 16); - result += b; - } - return result; - } - - static inline String TinyGsmDecodeHex16bit(String& instr) { - String result; - for (unsigned i = 0; i < instr.length(); i += 4) { - char buf[4] = { - 0, - }; - buf[0] = instr[i]; - buf[1] = instr[i + 1]; - char b = strtol(buf, NULL, 16); - if (b) { // If high byte is non-zero, we can't handle it ;( -#if defined(TINY_GSM_UNICODE_TO_HEX) - result += "\\x"; - result += instr.substring(i, i + 4); -#else - result += "?"; -#endif - } else { - buf[0] = instr[i + 2]; - buf[1] = instr[i + 3]; - b = strtol(buf, NULL, 16); - result += b; - } - } - return result; - } - - String sendUSSDImpl(const String& code) { - // Set preferred message format to text mode - thisModem().sendAT(GF("+CMGF=1")); - thisModem().waitResponse(); - // Set 8-bit hexadecimal alphabet (3GPP TS 23.038) - thisModem().sendAT(GF("+CSCS=\"HEX\"")); - thisModem().waitResponse(); - // Send the message - thisModem().sendAT(GF("+CUSD=1,\""), code, GF("\"")); - if (thisModem().waitResponse() != 1) { return ""; } - if (thisModem().waitResponse(10000L, GF("+CUSD:")) != 1) { return ""; } - thisModem().stream.readStringUntil('"'); - String hex = thisModem().stream.readStringUntil('"'); - thisModem().stream.readStringUntil(','); - int dcs = thisModem().streamGetInt('\n'); - - if (dcs == 15) { - return TinyGsmDecodeHex8bit(hex); - } else if (dcs == 72) { - return TinyGsmDecodeHex16bit(hex); - } else { - return hex; - } - } - - bool sendSMSImpl(const String& number, const String& text) { - // Set preferred message format to text mode - thisModem().sendAT(GF("+CMGF=1")); - thisModem().waitResponse(); - // Set GSM 7 bit default alphabet (3GPP TS 23.038) - thisModem().sendAT(GF("+CSCS=\"GSM\"")); - thisModem().waitResponse(); - thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); - if (thisModem().waitResponse(GF(">")) != 1) { return false; } - thisModem().stream.print(text); // Actually send the message - thisModem().stream.write(static_cast(0x1A)); // Terminate the message - thisModem().stream.flush(); - return thisModem().waitResponse(60000L) == 1; - } - - // Common methods for UTF8/UTF16 SMS. - // Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800 - class UTF8Print : public Print { - public: - explicit UTF8Print(Print& p) : p(p) {} - size_t write(const uint8_t c) override { - if (prv < 0xC0) { - if (c < 0xC0) printHex(c); - prv = c; - } else { - uint16_t v = uint16_t(prv) << 8 | c; - v -= (v >> 8 == 0xD0) ? 0xCC80 : 0xCD40; - printHex(v); - prv = 0; - } - return 1; - } - - private: - Print& p; - uint8_t prv = 0; - void printHex(const uint16_t v) { - uint8_t c = v >> 8; - if (c < 0x10) p.print('0'); - p.print(c, HEX); - c = v & 0xFF; - if (c < 0x10) p.print('0'); - p.print(c, HEX); - } - }; - - bool sendSMS_UTF8_begin(const char* const number) { - thisModem().sendAT(GF("+CMGF=1")); - thisModem().waitResponse(); - thisModem().sendAT(GF("+CSCS=\"HEX\"")); - thisModem().waitResponse(); - thisModem().sendAT(GF("+CSMP=17,167,0,8")); - thisModem().waitResponse(); - - thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); - return thisModem().waitResponse(GF(">")) == 1; - } - bool sendSMS_UTF8_end() { - thisModem().stream.write(static_cast(0x1A)); - thisModem().stream.flush(); - return thisModem().waitResponse(60000L) == 1; - } - UTF8Print sendSMS_UTF8_stream() { - return UTF8Print(thisModem().stream); - } - - bool sendSMS_UTF16Impl(const char* const number, const void* text, - size_t len) { - if (!sendSMS_UTF8_begin(number)) { return false; } - - uint16_t* t = reinterpret_cast(text); - for (size_t i = 0; i < len; i++) { - uint8_t c = t[i] >> 8; - if (c < 0x10) { thisModem().stream.print('0'); } - thisModem().stream.print(c, HEX); - c = t[i] & 0xFF; - if (c < 0x10) { thisModem().stream.print('0'); } - thisModem().stream.print(c, HEX); - } - - return sendSMS_UTF8_end(); - } - - /* - * Location functions - */ - protected: - String getGsmLocationImpl() { - thisModem().sendAT(GF("+CIPGSMLOC=1,1")); - if (thisModem().waitResponse(10000L, GF("+CIPGSMLOC:")) != 1) { return ""; } - String res = thisModem().stream.readStringUntil('\n'); - thisModem().waitResponse(); - res.trim(); - return res; - } - - /* - * GPS location functions - */ - public: - /* - * Time functions - */ - protected: - String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) { - thisModem().sendAT(GF("+CCLK?")); - if (thisModem().waitResponse(2000L, GF("+CCLK: \"")) != 1) { return ""; } - - String res; - - switch (format) { - case DATE_FULL: res = thisModem().stream.readStringUntil('"'); break; - case DATE_TIME: - thisModem().streamSkipUntil(','); - res = thisModem().stream.readStringUntil('"'); - break; - case DATE_DATE: res = thisModem().stream.readStringUntil(','); break; - } - return res; - } - - /* - * Battery & temperature functions - */ - protected: - // Use: float vBatt = modem.getBattVoltage() / 1000.0; - uint16_t getBattVoltageImpl() { - thisModem().sendAT(GF("+CBC")); - if (thisModem().waitResponse(GF("+CBC:")) != 1) { return 0; } - thisModem().streamSkipUntil(','); // Skip battery charge status - thisModem().streamSkipUntil(','); // Skip battery charge level - // return voltage in mV - uint16_t res = thisModem().streamGetInt(','); - // Wait for final OK - thisModem().waitResponse(); - return res; - } - - int8_t getBattPercentImpl() { - thisModem().sendAT(GF("+CBC")); - if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } - thisModem().streamSkipUntil(','); // Skip battery charge status - // Read battery charge level - int res = thisModem().streamGetInt(','); - // Wait for final OK - thisModem().waitResponse(); - return res; - } - - uint8_t getBattChargeStateImpl() { - thisModem().sendAT(GF("+CBC")); - if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } - // Read battery charge status - int res = thisModem().streamGetInt(','); - // Wait for final OK - thisModem().waitResponse(); - return res; - } - - bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, - uint16_t& milliVolts) { - thisModem().sendAT(GF("+CBC")); - if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; } - chargeState = thisModem().streamGetInt(','); - percent = thisModem().streamGetInt(','); - milliVolts = thisModem().streamGetInt('\n'); - // Wait for final OK - thisModem().waitResponse(); - return true; - } - - float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; - - /* - * Client related functions - */ - protected: - /* - Utilities - */ - - // Utility templates for writing/skipping characters on a stream - template - void streamWrite(T last) { - thisModem().stream.print(last); - } - - template - void streamWrite(T head, Args... tail) { - thisModem().stream.print(head); - thisModem().streamWrite(tail...); - } - - int16_t streamGetInt(char lastChar) { - char buf[6]; - size_t bytesRead = thisModem().stream.readBytesUntil( - lastChar, buf, static_cast(6)); - if (bytesRead) { - int16_t res = atoi(buf); - return res; - } else { - return -9999; - } - } - - float streamGetFloat(char lastChar) { - char buf[12]; - size_t bytesRead = thisModem().stream.readBytesUntil( - lastChar, buf, static_cast(12)); - if (bytesRead) { - float res = atof(buf); - return res; - } else { - return static_cast(-9999); - } - } - - bool streamSkipUntil(const char c, const uint32_t timeout_ms = 1000L) { - uint32_t startMillis = millis(); - while (millis() - startMillis < timeout_ms) { - while (millis() - startMillis < timeout_ms && - !thisModem().stream.available()) { - TINY_GSM_YIELD(); - } - if (thisModem().stream.read() == c) { return true; } - } - return false; - } - - void streamClear() { - while (thisModem().stream.available()) { - thisModem().waitResponse(50, NULL, NULL); - } - } - - // Yields up to a time-out period and then reads a character from the stream - // into the mux FIFO - // TODO(SRGDamia1): Do we need to wait two _timeout periods for no - // character return? Will wait once in the first "while - // !stream.available()" and then will wait again in the stream.read() - // function. - void moveCharFromStreamToFifo(uint8_t mux) { - uint32_t startMillis = millis(); - while (!thisModem().stream.available() && - (millis() - startMillis < thisModem().sockets[mux]->_timeout)) { - TINY_GSM_YIELD(); - } - char c = thisModem().stream.read(); - thisModem().sockets[mux]->rx.put(c); - } -}; - #endif // SRC_TINYGSMCOMMON_H_ diff --git a/src/TinyGsmGPRS.tpp b/src/TinyGsmGPRS.tpp new file mode 100644 index 0000000..00bf1b7 --- /dev/null +++ b/src/TinyGsmGPRS.tpp @@ -0,0 +1,158 @@ +/** + * @file TinyGsmGPRS.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMGPRS_H_ +#define SRC_TINYGSMGPRS_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_GPRS + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, + SIM_ANTITHEFT_LOCKED = 3, +}; + +template +class TinyGsmGPRS { + public: + /* + * SIM card functions + */ + // Unlocks the SIM + bool simUnlock(const char* pin) { + return thisModem().simUnlockImpl(pin); + } + // Gets the CCID of a sim card via AT+CCID + String getSimCCID() { + return thisModem().getSimCCIDImpl(); + } + // Asks for TA Serial Number Identification (IMEI) + String getIMEI() { + return thisModem().getIMEIImpl(); + } + SimStatus getSimStatus(uint32_t timeout_ms = 10000L) { + return thisModem().getSimStatusImpl(timeout_ms); + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, + const char* pwd = NULL) { + return thisModem().gprsConnectImpl(apn, user, pwd); + } + bool gprsDisconnect() { + return thisModem().gprsDisconnectImpl(); + } + // Checks if current attached to GPRS/EPS service + bool isGprsConnected() { + return thisModem().isGprsConnectedImpl(); + } + // Gets the current network operator + String getOperator() { + return thisModem().getOperatorImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * SIM card functions + */ + protected: + // Unlocks a sim via the 3GPP TS command AT+CPIN + bool simUnlockImpl(const char* pin) { + if (pin && strlen(pin) > 0) { + thisModem().sendAT(GF("+CPIN=\""), pin, GF("\"")); + return thisModem().waitResponse() == 1; + } + return true; + } + + // Gets the CCID of a sim card via AT+CCID + String getSimCCIDImpl() { + thisModem().sendAT(GF("+CCID")); + if (thisModem().waitResponse(GF("+CCID:")) != 1) { return ""; } + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + + // Asks for TA Serial Number Identification (IMEI) via the V.25TER standard + // AT+GSN command + String getIMEIImpl() { + thisModem().sendAT(GF("+GSN")); + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + thisModem().sendAT(GF("+CPIN?")); + if (thisModem().waitResponse(GF("+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = thisModem().waitResponse(GF("READY"), GF("SIM PIN"), + GF("SIM PUK"), GF("NOT INSERTED"), + GF("NOT READY")); + thisModem().waitResponse(); + switch (status) { + case 2: + case 3: return SIM_LOCKED; + case 1: return SIM_READY; + default: return SIM_ERROR; + } + } + return SIM_ERROR; + } + + /* + * GPRS functions + */ + protected: + bool thisHasGPRS() { + return true; + } + // Checks if current attached to GPRS/EPS service + bool isGprsConnectedImpl() { + thisModem().sendAT(GF("+CGATT?")); + if (thisModem().waitResponse(GF("+CGATT:")) != 1) { return false; } + int res = thisModem().streamGetInt('\n'); + thisModem().waitResponse(); + if (res != 1) { return false; } + + return thisModem().localIP() != IPAddress(0, 0, 0, 0); + } + + // Gets the current network operator via the 3GPP TS command AT+COPS + String getOperatorImpl() { + thisModem().sendAT(GF("+COPS?")); + if (thisModem().waitResponse(GF("+COPS:")) != 1) { return ""; } + thisModem().streamSkipUntil('"'); /* Skip mode and format */ + String res = thisModem().stream.readStringUntil('"'); + thisModem().waitResponse(); + return res; + } +}; + +#endif // SRC_TINYGSMGPRS_H_ diff --git a/src/TinyGsmGPS.tpp b/src/TinyGsmGPS.tpp new file mode 100644 index 0000000..e6dc76a --- /dev/null +++ b/src/TinyGsmGPS.tpp @@ -0,0 +1,64 @@ +/** + * @file TinyGsmGPS.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMGPS_H_ +#define SRC_TINYGSMGPS_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_GPS + +template +class TinyGsmGPS { + public: + /* + * GPS location functions + */ + bool enableGPS() { + return thisModem().enableGPSImpl(); + } + bool disableGPS() { + return thisModem().disableGPSImpl(); + } + String getGPSraw() { + return thisModem().getGPSrawImpl(); + } + bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute, + int* second) { + return thisModem().getGPSTimeImpl(year, month, day, hour, minute, second); + } + bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0) { + return thisModem().getGPSImpl(lat, lon, speed, alt); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * GPS location functions + */ + + bool enableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool disableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + String getGPSrawImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool getGPSTimeImpl(int* year, int* month, int* day, int* hour, int* minute, + int* second) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool getGPSImpl(float* lat, float* lon, float* speed = 0, + int* alt = 0) TINY_GSM_ATTR_NOT_IMPLEMENTED; +}; + + +#endif // SRC_TINYGSMGPS_H_ diff --git a/src/TinyGsmGSMLocation.tpp b/src/TinyGsmGSMLocation.tpp new file mode 100644 index 0000000..d5f8e43 --- /dev/null +++ b/src/TinyGsmGSMLocation.tpp @@ -0,0 +1,51 @@ +/** + * @file TinyGsmGSMLocation.h + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMGSMLOCATION_H_ +#define SRC_TINYGSMGSMLOCATION_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_GSM_LOCATION + +template +class TinyGsmGSMLocation { + public: + /* + * Location functions + */ + String getGsmLocation() { + return thisModem().getGsmLocationImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Location functions + */ + protected: + String getGsmLocationImpl() { + thisModem().sendAT(GF("+CIPGSMLOC=1,1")); + if (thisModem().waitResponse(10000L, GF("+CIPGSMLOC:")) != 1) { return ""; } + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } +}; + +#endif // SRC_TINYGSMGSMLOCATION_H_ diff --git a/src/TinyGsmModem.tpp b/src/TinyGsmModem.tpp new file mode 100644 index 0000000..33c252e --- /dev/null +++ b/src/TinyGsmModem.tpp @@ -0,0 +1,301 @@ +/** + * @file TinyGsmModem.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMMODEM_H_ +#define SRC_TINYGSMMODEM_H_ + +#include "TinyGsmCommon.h" + +template +class TinyGsmModem { + public: + /* + * Basic functions + */ + bool begin(const char* pin = NULL) { + return thisModem().initImpl(pin); + } + bool init(const char* pin = NULL) { + return thisModem().initImpl(pin); + } + template + void sendAT(Args... cmd) { + thisModem().streamWrite("AT", cmd..., thisModem().gsmNL); + thisModem().stream.flush(); + TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */ + } + void setBaud(uint32_t baud) { + thisModem().setBaudImpl(baud); + } + // Test response to AT commands + bool testAT(uint32_t timeout_ms = 10000L) { + return thisModem().testATImpl(timeout_ms); + } + + // Asks for modem information via the V.25TER standard ATI command + // NOTE: The actual value and style of the response is quite varied + String getModemInfo() { + return thisModem().getModemInfoImpl(); + } + // Gets the modem name (as it calls itself) + String getModemName() { + return thisModem().getModemNameImpl(); + } + bool factoryDefault() { + return thisModem().factoryDefaultImpl(); + } + + /* + * Power functions + */ + bool restart() { + return thisModem().restartImpl(); + } + bool poweroff() { + return thisModem().powerOffImpl(); + } + bool radioOff() { + return thisModem().radioOffImpl(); + } + bool sleepEnable(bool enable = true) { + return thisModem().sleepEnableImpl(enable); + } + + /* + * Generic network functions + */ + // RegStatus getRegistrationStatus() {} + bool isNetworkConnected() { + return thisModem().isNetworkConnectedImpl(); + } + // Waits for network attachment + bool waitForNetwork(uint32_t timeout_ms = 60000L) { + return thisModem().waitForNetworkImpl(timeout_ms); + } + // Gets signal quality report + int16_t getSignalQuality() { + return thisModem().getSignalQualityImpl(); + } + String getLocalIP() { + return thisModem().getLocalIPImpl(); + } + IPAddress localIP() { + return thisModem().TinyGsmIpFromString(thisModem().getLocalIP()); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Basic functions + */ + protected: + void setBaudImpl(uint32_t baud) { + thisModem().sendAT(GF("+IPR="), baud); + thisModem().waitResponse(); + } + + bool testATImpl(uint32_t timeout_ms = 10000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + thisModem().sendAT(GF("")); + if (thisModem().waitResponse(200) == 1) { return true; } + delay(100); + } + return false; + } + + String getModemInfoImpl() { + thisModem().sendAT(GF("I")); + String res; + if (thisModem().waitResponse(1000L, res) != 1) { return ""; } + // Do the replaces twice so we cover both \r and \r\n type endings + res.replace("\r\nOK\r\n", ""); + res.replace("\rOK\r", ""); + res.replace("\r\n", " "); + res.replace("\r", " "); + res.trim(); + return res; + } + + String getModemNameImpl() { + thisModem().sendAT(GF("+CGMI")); + String res1; + if (thisModem().waitResponse(1000L, res1) != 1) { return "unknown"; } + res1.replace("\r\nOK\r\n", ""); + res1.replace("\rOK\r", ""); + res1.trim(); + + thisModem().sendAT(GF("+GMM")); + String res2; + if (thisModem().waitResponse(1000L, res2) != 1) { return "unknown"; } + res1.replace("\r\nOK\r\n", ""); + res1.replace("\rOK\r", ""); + res2.trim(); + + String name = res1 + String(' ') + res2; + DBG("### Modem:", name); + return name; + } + + bool factoryDefaultImpl() { + thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write + thisModem().waitResponse(); + thisModem().sendAT(GF("+IPR=0")); // Auto-baud + thisModem().waitResponse(); + thisModem().sendAT(GF("&W")); // Write configuration + return thisModem().waitResponse() == 1; + } + + /* + * Power functions + */ + protected: + bool radioOffImpl() { + thisModem().sendAT(GF("+CFUN=0")); + if (thisModem().waitResponse(10000L) != 1) { return false; } + delay(3000); + return true; + } + + bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + /* + * Generic network functions + */ + protected: + // Gets the modem's registration status via CREG/CGREG/CEREG + // CREG = Generic network registration + // CGREG = GPRS service registration + // CEREG = EPS registration for LTE modules + int getRegistrationStatusXREG(const char* regCommand) { + thisModem().sendAT('+', regCommand, '?'); + // check for any of the three for simplicity + int resp = thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"), + GF("+CEREG:")); + if (resp != 1 && resp != 2 && resp != 3) { return -1; } + thisModem().streamSkipUntil(','); /* Skip format (0) */ + int status = thisModem().streamGetInt('\n'); + thisModem().waitResponse(); + return status; + } + + bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) { + for (uint32_t start = millis(); millis() - start < timeout_ms;) { + if (thisModem().isNetworkConnected()) { return true; } + delay(250); + } + return false; + } + + // Gets signal quality report according to 3GPP TS command AT+CSQ + int16_t getSignalQualityImpl() { + thisModem().sendAT(GF("+CSQ")); + if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; } + int res = thisModem().streamGetInt(','); + thisModem().waitResponse(); + return res; + } + + String getLocalIPImpl() { + thisModem().sendAT(GF("+CGPADDR=1")); + if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; } + thisModem().streamSkipUntil(','); // Skip context id + String res = thisModem().stream.readStringUntil('\r'); + if (thisModem().waitResponse() != 1) { return ""; } + return res; + } + + static IPAddress TinyGsmIpFromString(const String& strIP) { + int Parts[4] = { + 0, + }; + int Part = 0; + for (uint8_t i = 0; i < strIP.length(); i++) { + char c = strIP[i]; + if (c == '.') { + Part++; + if (Part > 3) { return IPAddress(0, 0, 0, 0); } + continue; + } else if (c >= '0' && c <= '9') { + Parts[Part] *= 10; + Parts[Part] += c - '0'; + } else { + if (Part == 3) break; + } + } + return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]); + } + + /* + Utilities + */ + protected: + // Utility templates for writing/skipping characters on a stream + template + void inline streamWrite(T last) { + thisModem().stream.print(last); + } + + template + void inline streamWrite(T head, Args... tail) { + thisModem().stream.print(head); + thisModem().streamWrite(tail...); + } + + int16_t inline streamGetInt(char lastChar) { + char buf[6]; + size_t bytesRead = thisModem().stream.readBytesUntil( + lastChar, buf, static_cast(6)); + if (bytesRead) { + int16_t res = atoi(buf); + return res; + } else { + return -9999; + } + } + + float inline streamGetFloat(char lastChar) { + char buf[12]; + size_t bytesRead = thisModem().stream.readBytesUntil( + lastChar, buf, static_cast(12)); + if (bytesRead) { + float res = atof(buf); + return res; + } else { + return static_cast(-9999); + } + } + + bool inline streamSkipUntil(const char c, const uint32_t timeout_ms = 1000L) { + uint32_t startMillis = millis(); + while (millis() - startMillis < timeout_ms) { + while (millis() - startMillis < timeout_ms && + !thisModem().stream.available()) { + TINY_GSM_YIELD(); + } + if (thisModem().stream.read() == c) { return true; } + } + return false; + } + + void inline streamClear() { + while (thisModem().stream.available()) { + thisModem().waitResponse(50, NULL, NULL); + } + } +}; + +#endif // SRC_TINYGSMMODEM_H_ diff --git a/src/TinyGsmSMS.tpp b/src/TinyGsmSMS.tpp new file mode 100644 index 0000000..15ecc7f --- /dev/null +++ b/src/TinyGsmSMS.tpp @@ -0,0 +1,224 @@ +/** + * @file TinyGsmSMS.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMSMS_H_ +#define SRC_TINYGSMSMS_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_SMS + +template +class TinyGsmSMS { + public: + /* + * Messaging functions + */ + String sendUSSD(const String& code) { + return thisModem().sendUSSDImpl(code); + } + bool sendSMS(const String& number, const String& text) { + return thisModem().sendSMSImpl(number, text); + } + bool sendSMS_UTF16(const char* const number, const void* text, size_t len) { + return thisModem().sendSMS_UTF16Impl(number, text, len); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Messaging functions + */ + protected: + static inline String TinyGsmDecodeHex7bit(String& instr) { + String result; + byte reminder = 0; + int bitstate = 7; + for (uint8_t i = 0; i < instr.length(); i += 2) { + char buf[4] = { + 0, + }; + buf[0] = instr[i]; + buf[1] = instr[i + 1]; + byte b = strtol(buf, NULL, 16); + + byte bb = b << (7 - bitstate); + char c = (bb + reminder) & 0x7F; + result += c; + reminder = b >> bitstate; + bitstate--; + if (bitstate == 0) { + char cc = reminder; + result += cc; + reminder = 0; + bitstate = 7; + } + } + return result; + } + + static inline String TinyGsmDecodeHex8bit(String& instr) { + String result; + for (uint8_t i = 0; i < instr.length(); i += 2) { + char buf[4] = { + 0, + }; + buf[0] = instr[i]; + buf[1] = instr[i + 1]; + char b = strtol(buf, NULL, 16); + result += b; + } + return result; + } + + static inline String TinyGsmDecodeHex16bit(String& instr) { + String result; + for (uint8_t i = 0; i < instr.length(); i += 4) { + char buf[4] = { + 0, + }; + buf[0] = instr[i]; + buf[1] = instr[i + 1]; + char b = strtol(buf, NULL, 16); + if (b) { // If high byte is non-zero, we can't handle it ;( +#if defined(TINY_GSM_UNICODE_TO_HEX) + result += "\\x"; + result += instr.substring(i, i + 4); +#else + result += "?"; +#endif + } else { + buf[0] = instr[i + 2]; + buf[1] = instr[i + 3]; + b = strtol(buf, NULL, 16); + result += b; + } + } + return result; + } + + String sendUSSDImpl(const String& code) { + // Set preferred message format to text mode + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + // Set 8-bit hexadecimal alphabet (3GPP TS 23.038) + thisModem().sendAT(GF("+CSCS=\"HEX\"")); + thisModem().waitResponse(); + // Send the message + thisModem().sendAT(GF("+CUSD=1,\""), code, GF("\"")); + if (thisModem().waitResponse() != 1) { return ""; } + if (thisModem().waitResponse(10000L, GF("+CUSD:")) != 1) { return ""; } + thisModem().stream.readStringUntil('"'); + String hex = thisModem().stream.readStringUntil('"'); + thisModem().stream.readStringUntil(','); + int dcs = thisModem().streamGetInt('\n'); + + if (dcs == 15) { + return TinyGsmDecodeHex8bit(hex); + } else if (dcs == 72) { + return TinyGsmDecodeHex16bit(hex); + } else { + return hex; + } + } + + bool sendSMSImpl(const String& number, const String& text) { + // Set preferred message format to text mode + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + // Set GSM 7 bit default alphabet (3GPP TS 23.038) + thisModem().sendAT(GF("+CSCS=\"GSM\"")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); + if (thisModem().waitResponse(GF(">")) != 1) { return false; } + thisModem().stream.print(text); // Actually send the message + thisModem().stream.write(static_cast(0x1A)); // Terminate the message + thisModem().stream.flush(); + return thisModem().waitResponse(60000L) == 1; + } + + // Common methods for UTF8/UTF16 SMS. + // Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800 + class UTF8Print : public Print { + public: + explicit UTF8Print(Print& p) : p(p) {} + size_t write(const uint8_t c) override { + if (prv < 0xC0) { + if (c < 0xC0) printHex(c); + prv = c; + } else { + uint16_t v = uint16_t(prv) << 8 | c; + v -= (v >> 8 == 0xD0) ? 0xCC80 : 0xCD40; + printHex(v); + prv = 0; + } + return 1; + } + + private: + Print& p; + uint8_t prv = 0; + void printHex(const uint16_t v) { + uint8_t c = v >> 8; + if (c < 0x10) p.print('0'); + p.print(c, HEX); + c = v & 0xFF; + if (c < 0x10) p.print('0'); + p.print(c, HEX); + } + }; + + bool sendSMS_UTF8_begin(const char* const number) { + thisModem().sendAT(GF("+CMGF=1")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CSCS=\"HEX\"")); + thisModem().waitResponse(); + thisModem().sendAT(GF("+CSMP=17,167,0,8")); + thisModem().waitResponse(); + + thisModem().sendAT(GF("+CMGS=\""), number, GF("\"")); + return thisModem().waitResponse(GF(">")) == 1; + } + bool sendSMS_UTF8_end() { + thisModem().stream.write(static_cast(0x1A)); + thisModem().stream.flush(); + return thisModem().waitResponse(60000L) == 1; + } + UTF8Print sendSMS_UTF8_stream() { + return UTF8Print(thisModem().stream); + } + + bool sendSMS_UTF16Impl(const char* const number, const void* text, + size_t len) { + if (!sendSMS_UTF8_begin(number)) { return false; } + + uint16_t* t = + const_cast(reinterpret_cast(text)); + for (size_t i = 0; i < len; i++) { + uint8_t c = t[i] >> 8; + if (c < 0x10) { thisModem().stream.print('0'); } + thisModem().stream.print(c, HEX); + c = t[i] & 0xFF; + if (c < 0x10) { thisModem().stream.print('0'); } + thisModem().stream.print(c, HEX); + } + + return sendSMS_UTF8_end(); + } +}; + +#endif // SRC_TINYGSMSMS_H_ diff --git a/src/TinyGsmSSL.tpp b/src/TinyGsmSSL.tpp new file mode 100644 index 0000000..32bca14 --- /dev/null +++ b/src/TinyGsmSSL.tpp @@ -0,0 +1,71 @@ +/** + * @file TinyGsmSSL.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMSSL_H_ +#define SRC_TINYGSMSSL_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_SSL + + +template +class TinyGsmSSL { + public: + /* + * SSL functions + */ + bool addCertificate(const char* filename) { + return thisModem().addCertificateImpl(filename); + } + bool deleteCertificate() { + return thisModem().deleteCertificateImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Inner Secure Client + */ + /* + public: + class GsmClientSecure : public GsmClient { + public: + GsmClientSecureSim800() {} + + explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 1) + : GsmClientSim800(modem, mux) {} + + public: + int connect(const char* host, uint16_t port, int timeout_s) { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true, timeout_s); + return sock_connected; + } + };*/ + + /* + * SSL functions + */ + protected: + bool addCertificateImpl(const char* filename) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool deleteCertificateImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; +}; + +#endif // SRC_TINYGSMSSL_H_ diff --git a/src/TinyGsmTCP.tpp b/src/TinyGsmTCP.tpp index 1044159..46c71c5 100644 --- a/src/TinyGsmTCP.tpp +++ b/src/TinyGsmTCP.tpp @@ -11,7 +11,26 @@ #include "TinyGsmCommon.h" -#define TINY_GSM_HAS_TCP +#define TINY_GSM_MODEM_HAS_TCP + +#include "TinyGsmFifo.h" + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 64 +#endif + +// Because of the ordering of resolution of overrides in templates, hese need to +// be written out every time. This macro is to shorten that. +#define TINY_GSM_CLIENT_CONNECT_OVERRIDES \ + virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { \ + return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); \ + } \ + int connect(const char* host, uint16_t port) override { \ + return connect(host, port, 75); \ + } \ + int connect(IPAddress ip, uint16_t port) override { \ + return connect(ip, port, 75); \ + } enum modemInternalBuffferType { NO_MODEM_BUFFER = @@ -24,15 +43,7 @@ enum modemInternalBuffferType { // The fully generic template is empty template -class TinyGsmTCP {}; - -// Partially specialized templates - -/* =========================================================================== -* Specialized template for modems no internal buffer -=========================================================================== */ -template -class TinyGsmTCP { +class TinyGsmTCP { public: /* * Basic functions @@ -58,10 +69,26 @@ class TinyGsmTCP { public: class GsmClient : public Client { // Make all classes created from the modem template friends - friend class TinyGsmModem; + friend class TinyGsmTCP; typedef TinyGsmFifo RxFifo; public: + // bool init(modemType* modem, uint8_t); + // int connect(const char* host, uint16_t port, int timeout_s); + + // Connect to a IP address given as an IPAddress object by + // converting said IP address to text + // virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { + // return connect(TinyGsmStringFromIp(ip).c_str(), port, + // timeout_s); + // } + // int connect(const char* host, uint16_t port) override { + // return connect(host, port, 75); + // } + // int connect(IPAddress ip, uint16_t port) override { + // return connect(ip, port, 75); + // } + static inline String TinyGsmStringFromIp(IPAddress ip) { String host; host.reserve(16); @@ -75,6 +102,11 @@ class TinyGsmTCP { return host; } + // void stop(uint32_t maxWaitMs); + // void stop() override { + // stop(15000L); + // } + // Writes data out on the client using the modem send functionality size_t write(const uint8_t* buf, size_t size) override { TINY_GSM_YIELD(); @@ -93,17 +125,42 @@ class TinyGsmTCP { int available() override { TINY_GSM_YIELD(); + switch (bufType) { // Returns the number of characters available in the TinyGSM fifo + case NO_MODEM_BUFFER: if (!rx.size() && sock_connected) { at->maintain(); } return rx.size(); + + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo. + case READ_NO_CHECK: + if (!rx.size()) { at->maintain(); } + return rx.size() + sock_available; + + // Returns the combined number of characters available in the TinyGSM + // fifo and the modem chips internal fifo, doing an extra check-in + // with the modem to see if anything has arrived without a UURC. + case READ_AND_CHECK_SIZE: + if (!rx.size()) { + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + at->maintain(); + } + return rx.size() + sock_available; + } } int read(uint8_t* buf, size_t size) override { TINY_GSM_YIELD(); size_t cnt = 0; uint32_t _startMillis = millis(); + + switch (bufType) { // Reads characters out of the TinyGSM fifo, waiting for any URC's // from the modem for new data if there's nothing in the fifo. + case NO_MODEM_BUFFER: while (cnt < size && millis() - _startMillis < _timeout) { size_t chunk = TinyGsmMin(size - cnt, rx.size()); if (chunk > 0) { @@ -115,134 +172,10 @@ class TinyGsmTCP { if (!rx.size() && sock_connected) { at->maintain(); } } return cnt; - } - - int read() override { - uint8_t c; - if (read(&c, 1) == 1) { return c; } - return -1; - } - - // TODO(SRGDamia1): Implement peek - int peek() override { - return -1; - } - - void flush() override { - at->stream.flush(); - } - - uint8_t connected() override { - if (available()) { return true; } - return sock_connected; - } - operator bool() override { - return connected(); - } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - protected: - modemType* at; - uint8_t mux; - bool sock_connected; - RxFifo rx; - }; - - /* - * Basic functions - */ - protected: - void maintainImpl() { - // Just listen for any URC's - thisModem().waitResponse(100, NULL, NULL); - } -}; - -/* =========================================================================== -* Specialized template for modems with an internal buffer that can be read -* but NOT queried for current size. -=========================================================================== */ -template -class TinyGsmTCP { - public: - /* - * Basic functions - */ - void maintain() { - return thisModem().maintainImpl(); - } - - /* - * CRTP Helper - */ - protected: - inline const modemType& thisModem() const { - return static_cast(*this); - } - inline modemType& thisModem() { - return static_cast(*this); - } - - /* - * Inner Client - */ - public: - class GsmClient : public Client { - // Make all classes created from the modem template friends - friend class TinyGsmModem; - typedef TinyGsmFifo RxFifo; - - public: - static inline String TinyGsmStringFromIp(IPAddress ip) { - String host; - host.reserve(16); - host += ip[0]; - host += "."; - host += ip[1]; - host += "."; - host += ip[2]; - host += "."; - host += ip[3]; - return host; - } - - // Writes data out on the client using the modem send functionality - size_t write(const uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - at->maintain(); - return at->modemSend(buf, size, mux); - } - - size_t write(uint8_t c) override { - return write(&c, 1); - } - - size_t write(const char* str) { - if (str == NULL) return 0; - return write((const uint8_t*)str, strlen(str)); - } - - int available() override { - TINY_GSM_YIELD(); - - // Returns the combined number of characters available in the TinyGSM - // fifo and the modem chips internal fifo. - if (!rx.size()) { at->maintain(); } - return rx.size() + sock_available; - } - - int read(uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - size_t cnt = 0; - uint32_t _startMillis = millis(); // Reads characters out of the TinyGSM fifo, and from the modem chip's // internal fifo if avaiable. + case READ_NO_CHECK: at->maintain(); while (cnt < size) { size_t chunk = TinyGsmMin(size - cnt, rx.size()); @@ -262,172 +195,11 @@ class TinyGsmTCP { } } return cnt; - } - - int read() override { - uint8_t c; - if (read(&c, 1) == 1) { return c; } - return -1; - } - - // TODO(SRGDamia1): Implement peek - int peek() override { - return -1; - } - - void flush() override { - at->stream.flush(); - } - uint8_t connected() override { - if (available()) { return true; } - return sock_connected; - } - operator bool() override { - return connected(); - } - - /* - * Extended API - */ - - String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; - - protected: - // Read and dump anything remaining in the modem's internal buffer. - // Using this in the client stop() function. - // The socket will appear open in response to connected() even after it - // closes until all data is read from the buffer. - // Doing it this way allows the external mcu to find and get all of the - // data that it wants from the socket even if it was closed externally. - void inline dumpModemBuffer(uint32_t maxWaitMs) { - TINY_GSM_YIELD(); - rx.clear(); - at->maintain(); - uint32_t startMillis = millis(); - while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { - at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); - rx.clear(); - at->maintain(); - } - } - - modemType* at; - uint8_t mux; - uint16_t sock_available; - bool sock_connected; - bool got_data; - RxFifo rx; - }; - - /* - * Basic functions - */ - protected: - void maintainImpl() { - // Just listen for any URC's - thisModem().waitResponse(100, NULL, NULL); - break; - } - - // Yields up to a time-out period and then reads a character from the stream - // into the mux FIFO - // TODO(SRGDamia1): Do we need to wait two _timeout periods for no - // character return? Will wait once in the first "while - // !stream.available()" and then will wait again in the stream.read() - // function. - void inline moveCharFromStreamToFifo(uint8_t mux) { - uint32_t startMillis = millis(); - while (!thisModem().stream.available() && - (millis() - startMillis < thisModem().sockets[mux]->_timeout)) { - TINY_GSM_YIELD(); - } - char c = thisModem().stream.read(); - thisModem().sockets[mux]->rx.put(c); - } -}; - - -/* =========================================================================== -* Specialized template for modems with an internal buffer that can be read -* and queried for current size. -=========================================================================== */ -template -class TinyGsmTCP { - public: - /* - * Basic functions - */ - void maintain() { return thisModem().maintainImpl(); } - - /* - * CRTP Helper - */ - protected: - inline const modemType& thisModem() const { - return static_cast(*this); - } - inline modemType& thisModem() { return static_cast(*this); } - - /* - * Inner Client - */ - public: - class GsmClient : public Client { - // Make all classes created from the modem template friends - friend class TinyGsmModem; - typedef TinyGsmFifo RxFifo; - - public: - static inline String TinyGsmStringFromIp(IPAddress ip) { - String host; - host.reserve(16); - host += ip[0]; - host += "."; - host += ip[1]; - host += "."; - host += ip[2]; - host += "."; - host += ip[3]; - return host; - } - - // Writes data out on the client using the modem send functionality - size_t write(const uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - at->maintain(); - return at->modemSend(buf, size, mux); - } - - size_t write(uint8_t c) override { return write(&c, 1); } - - size_t write(const char* str) { - if (str == NULL) return 0; - return write((const uint8_t*)str, strlen(str)); - } - - int available() override { - TINY_GSM_YIELD(); - // Returns the combined number of characters available in the TinyGSM - // fifo and the modem chips internal fifo, doing an extra check-in - // with the modem to see if anything has arrived without a UURC. - if (!rx.size()) { - if (millis() - prev_check > 500) { - got_data = true; - prev_check = millis(); - } - at->maintain(); - } - return rx.size() + sock_available; - } - - int read(uint8_t* buf, size_t size) override { - TINY_GSM_YIELD(); - size_t cnt = 0; - uint32_t _startMillis = millis(); // Reads characters out of the TinyGSM fifo, and from the modem chips // internal fifo if avaiable, also double checking with the modem if // data has arrived without issuing a UURC. + case READ_AND_CHECK_SIZE: at->maintain(); while (cnt < size) { size_t chunk = TinyGsmMin(size - cnt, rx.size()); @@ -439,7 +211,7 @@ class TinyGsmTCP { } // Workaround: Some modules "forget" to notify about data arrival if (millis() - prev_check > 500) { - got_data = true; + got_data = true; prev_check = millis(); } // TODO(vshymanskyy): Read directly into user buffer? @@ -453,28 +225,31 @@ class TinyGsmTCP { } } return cnt; + } } int read() override { uint8_t c; - if (read(&c, 1) == 1) { - return c; - } + if (read(&c, 1) == 1) { return c; } return -1; } // TODO(SRGDamia1): Implement peek - int peek() override { return -1; } + int peek() override { + return -1; + } - void flush() override { at->stream.flush(); } + void flush() override { + at->stream.flush(); + } uint8_t connected() override { - if (available()) { - return true; - } + if (available()) { return true; } return sock_connected; } - operator bool() override { return connected(); } + operator bool() override { + return connected(); + } /* * Extended API @@ -502,12 +277,12 @@ class TinyGsmTCP { } modemType* at; - uint8_t mux; - uint16_t sock_available; - uint32_t prev_check; - bool sock_connected; - bool got_data; - RxFifo rx; + uint8_t mux; + uint16_t sock_available; + uint32_t prev_check; + bool sock_connected; + bool got_data; + RxFifo rx; }; /* @@ -515,18 +290,26 @@ class TinyGsmTCP { */ protected: void maintainImpl() { + switch (bufType) { + case READ_AND_CHECK_SIZE: // Keep listening for modem URC's and proactively iterate through // sockets asking if any data is avaiable for (int mux = 0; mux < muxCount; mux++) { GsmClient* sock = thisModem().sockets[mux]; if (sock && sock->got_data) { - sock->got_data = false; + sock->got_data = false; sock->sock_available = thisModem().modemGetAvailable(mux); } } while (thisModem().stream.available()) { thisModem().waitResponse(15, NULL, NULL); } + break; + default: + // Just listen for any URC's + thisModem().waitResponse(100, NULL, NULL); + break; + } } // Yields up to a time-out period and then reads a character from the stream diff --git a/src/TinyGsmTemperature.tpp b/src/TinyGsmTemperature.tpp new file mode 100644 index 0000000..215f250 --- /dev/null +++ b/src/TinyGsmTemperature.tpp @@ -0,0 +1,40 @@ +/** + * @file TinyGsmTemperature.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMTEMPERATURE_H_ +#define SRC_TINYGSMTEMPERATURE_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_TEMPERATURE + +template +class TinyGsmTemperature { + public: + /* + * Temperature functions + */ + float getTemperature() { + return thisModem().getTemperatureImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; +}; + +#endif // SRC_TINYGSMTEMPERATURE_H_ diff --git a/src/TinyGsmTime.tpp b/src/TinyGsmTime.tpp new file mode 100644 index 0000000..f6fb796 --- /dev/null +++ b/src/TinyGsmTime.tpp @@ -0,0 +1,61 @@ +/** + * @file TinyGsmTime.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMTIME_H_ +#define SRC_TINYGSMTIME_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_TIME + +enum TinyGSMDateTimeFormat { DATE_FULL = 0, DATE_TIME = 1, DATE_DATE = 2 }; + +template +class TinyGsmTime { + public: + /* + * Time functions + */ + String getGSMDateTime(TinyGSMDateTimeFormat format) { + return thisModem().getGSMDateTimeImpl(format); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * Time functions + */ + protected: + String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) { + thisModem().sendAT(GF("+CCLK?")); + if (thisModem().waitResponse(2000L, GF("+CCLK: \"")) != 1) { return ""; } + + String res; + + switch (format) { + case DATE_FULL: res = thisModem().stream.readStringUntil('"'); break; + case DATE_TIME: + thisModem().streamSkipUntil(','); + res = thisModem().stream.readStringUntil('"'); + break; + case DATE_DATE: res = thisModem().stream.readStringUntil(','); break; + } + return res; + } +}; + +#endif // SRC_TINYGSMTIME_H_ diff --git a/src/TinyGsmWifi.tpp b/src/TinyGsmWifi.tpp new file mode 100644 index 0000000..cbf92bb --- /dev/null +++ b/src/TinyGsmWifi.tpp @@ -0,0 +1,49 @@ +/** + * @file TinyGsmWifi.tpp + * @author Volodymyr Shymanskyy + * @license LGPL-3.0 + * @copyright Copyright (c) 2016 Volodymyr Shymanskyy + * @date Nov 2016 + */ + +#ifndef SRC_TINYGSMWIFI_H_ +#define SRC_TINYGSMWIFI_H_ + +#include "TinyGsmCommon.h" + +#define TINY_GSM_MODEM_HAS_WIFI + +template +class TinyGsmWifi { + public: + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) { + return thisModem().networkConnectImpl(ssid, pwd); + } + bool networkDisconnect() { + return thisModem().networkDisconnectImpl(); + } + + /* + * CRTP Helper + */ + protected: + inline const modemType& thisModem() const { + return static_cast(*this); + } + inline modemType& thisModem() { + return static_cast(*this); + } + + /* + * WiFi functions + */ + + bool networkConnectImpl(const char* ssid, + const char* pwd) TINY_GSM_ATTR_NOT_IMPLEMENTED; + bool networkDisconnectImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; +}; + +#endif // SRC_TINYGSMWIFI_H_ diff --git a/tools/test_build/test_build.ino b/tools/test_build/test_build.ino index e5b0db7..1e90809 100644 --- a/tools/test_build/test_build.ino +++ b/tools/test_build/test_build.ino @@ -3,15 +3,13 @@ * DO NOT USE THIS - this is just a compilation test! * **************************************************************/ -#define TINY_GSM_MODEM_SIM800 - #include TinyGsm modem(Serial); TinyGsmClient client(modem); #if defined(TINY_GSM_MODEM_HAS_SSL) - TinyGsmClientSecure client_secure(modem); +TinyGsmClientSecure client_secure(modem); #endif char server[] = "somewhere"; @@ -23,7 +21,6 @@ void setup() { } void loop() { - // Test the basic functions // modem.init(); modem.begin(); @@ -33,9 +30,6 @@ void loop() { modem.getModemInfo(); modem.getModemName(); modem.maintain(); - modem.hasSSL(); - modem.hasWifi(); - modem.hasGPRS(); // Test Power functions modem.restart(); @@ -43,27 +37,78 @@ void loop() { modem.radioOff(); modem.poweroff(); - // Test the SIM card functions - #if defined(TINY_GSM_MODEM_HAS_GPRS) +// Test the SIM card functions +#if defined(TINY_GSM_MODEM_HAS_GPRS) modem.getSimCCID(); modem.getIMEI(); modem.getSimStatus(); modem.getOperator(); - #endif +#endif + +// Test the calling functions +#if defined(TINY_GSM_MODEM_HAS_CALLING) + modem.callNumber(String("+380000000000")); + modem.callAnswer(); + modem.callHangup(); +#endif + +// Test the SMS functions +#if defined(TINY_GSM_MODEM_HAS_SMS) + modem.sendUSSD("*111#"); + modem.sendSMS(String("+380000000000"), String("Hello from ")); + modem.sendSMS_UTF16("+380000000000", "Hello", 5); +#endif + +// Test the GSM location functions +#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION) + modem.getGsmLocation(); +#endif + +// Test the Network time function +#if defined(TINY_GSM_MODEM_HAS_TIME) + modem.getGSMDateTime(DATE_FULL); +#endif + +// Test the Network time function +#if defined(TINY_GSM_MODEM_HAS_TIME) + modem.getGSMDateTime(DATE_FULL); +#endif + +// Test the GPS functions +#if defined(TINY_GSM_MODEM_HAS_GPS) + modem.enableGPS(); + modem.getGPSraw(); + float latitude = -9999; + float longitude = -9999; + modem.getGPS(&latitude, &longitude); +#endif + +// Test Battery functions +#if defined(TINY_GSM_MODEM_HAS_BATTERY) + uint8_t chargeState = 0; + int8_t chargePercent = 0; + uint16_t milliVolts = 0; + modem.getBattStats(chargeState, chargePercent, milliVolts); +#endif + +// Test the temperature function +#if defined(TINY_GSM_MODEM_HAS_TEMPERATURE) + modem.getTemperature(); +#endif // Test the Networking functions modem.getRegistrationStatus(); modem.getSignalQuality(); modem.localIP(); - #if defined(TINY_GSM_MODEM_HAS_GPRS) - modem.waitForNetwork(); - modem.gprsConnect("YourAPN", "", ""); - #endif - #if defined(TINY_GSM_MODEM_HAS_WIFI) - modem.networkConnect("YourSSID", "YourWiFiPass"); - modem.waitForNetwork(); - #endif +#if defined(TINY_GSM_MODEM_HAS_GPRS) + modem.waitForNetwork(); + modem.gprsConnect("YourAPN", "", ""); +#endif +#if defined(TINY_GSM_MODEM_HAS_WIFI) + modem.networkConnect("YourSSID", "YourWiFiPass"); + modem.waitForNetwork(); +#endif client.connect(server, 80); @@ -82,12 +127,31 @@ void loop() { client.stop(); - #if defined(TINY_GSM_MODEM_HAS_GPRS) - modem.gprsDisconnect(); - #endif - #if defined(TINY_GSM_MODEM_HAS_WIFI) - modem.networkDisconnect(); - #endif +#if defined(TINY_GSM_MODEM_HAS_SSL) + client_secure.connect(server, 443); + + // Make a HTTP GET request: + client_secure.print(String("GET ") + resource + " HTTP/1.0\r\n"); + client_secure.print(String("Host: ") + server + "\r\n"); + client_secure.print("Connection: close\r\n\r\n"); + + timeout = millis(); + while (client_secure.connected() && millis() - timeout < 10000L) { + while (client_secure.available()) { + client_secure.read(); + timeout = millis(); + } + } + + client_secure.stop(); +#endif + +#if defined(TINY_GSM_MODEM_HAS_GPRS) + modem.gprsDisconnect(); +#endif +#if defined(TINY_GSM_MODEM_HAS_WIFI) + modem.networkDisconnect(); +#endif // Test battery and temperature functions // modem.getBattVoltage(); From cef8aefefc6d71d5ea55033c6c91ee5d401c73b0 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 16:32:38 -0500 Subject: [PATCH 32/88] Added IMSI --- src/TinyGsmClientXBee.h | 4 ++++ src/TinyGsmCommon.h | 15 --------------- src/TinyGsmGPRS.tpp | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/TinyGsmClientXBee.h b/src/TinyGsmClientXBee.h index f553f54..deba450 100644 --- a/src/TinyGsmClientXBee.h +++ b/src/TinyGsmClientXBee.h @@ -836,6 +836,10 @@ class TinyGsmXBee return sendATGetString(GF("IM")); } + String getIMSIImpl() { + return sendATGetString(GF("II")); + } + SimStatus getSimStatusImpl(uint32_t) { return SIM_READY; // unsupported } diff --git a/src/TinyGsmCommon.h b/src/TinyGsmCommon.h index 6efc403..683795b 100644 --- a/src/TinyGsmCommon.h +++ b/src/TinyGsmCommon.h @@ -117,18 +117,3 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, } #endif // SRC_TINYGSMCOMMON_H_ - -// Asks for International Mobile Subscriber Identity IMSI via the AT+CIMI command -#define TINY_GSM_MODEM_GET_IMSI_CIMI() \ - String getIMSI() { \ - sendAT(GF("+CIMI")); \ - if (waitResponse(GF(GSM_NL)) != 1) { \ - return ""; \ - } \ - String res = stream.readStringUntil('\n'); \ - waitResponse(); \ - res.trim(); \ - return res; \ - } - - diff --git a/src/TinyGsmGPRS.tpp b/src/TinyGsmGPRS.tpp index 00bf1b7..7a08598 100644 --- a/src/TinyGsmGPRS.tpp +++ b/src/TinyGsmGPRS.tpp @@ -38,6 +38,10 @@ class TinyGsmGPRS { String getIMEI() { return thisModem().getIMEIImpl(); } + // Asks for International Mobile Subscriber Identity IMSI + String getIMSI() { + return thisModem().getIMSIImpl(); + } SimStatus getSimStatus(uint32_t timeout_ms = 10000L) { return thisModem().getSimStatusImpl(timeout_ms); } @@ -105,6 +109,16 @@ class TinyGsmGPRS { return res; } + // Asks for International Mobile Subscriber Identity IMSI via the AT+CIMI + // command + String getIMSIImpl() { + thisModem().sendAT(GF("+CIMI")); + String res = thisModem().stream.readStringUntil('\n'); + thisModem().waitResponse(); + res.trim(); + return res; + } + SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { for (uint32_t start = millis(); millis() - start < timeout_ms;) { thisModem().sendAT(GF("+CPIN?")); From d3dd88d13b6257160c7b25c0ca3b0ade549ec380 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 16:46:56 -0500 Subject: [PATCH 33/88] Update example --- tools/Diagnostics/Diagnostics.ino | 4 +++- tools/FactoryReset/FactoryReset.ino | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/Diagnostics/Diagnostics.ino b/tools/Diagnostics/Diagnostics.ino index c44aa48..86bf842 100644 --- a/tools/Diagnostics/Diagnostics.ino +++ b/tools/Diagnostics/Diagnostics.ino @@ -45,7 +45,9 @@ // Chips without internal buffering (A6/A7, ESP8266, M590) // need enough space in the buffer for the entire response // else data will be lost (and the http library will fail). +#ifndef TINY_GSM_RX_BUFFER #define TINY_GSM_RX_BUFFER 1024 +#endif // See all AT commands, if wanted // #define DUMP_AT_COMMANDS @@ -106,7 +108,7 @@ const char resource[] = "/TinyGSM/logo.txt"; TinyGsm modem(SerialAT); #endif -#ifdef USE_SSL +#ifdef USE_SSL && defined TINY_GSM_MODEM_HAS_SSL TinyGsmClientSecure client(modem); const int port = 443; #else diff --git a/tools/FactoryReset/FactoryReset.ino b/tools/FactoryReset/FactoryReset.ino index 615d981..91cde6d 100644 --- a/tools/FactoryReset/FactoryReset.ino +++ b/tools/FactoryReset/FactoryReset.ino @@ -48,7 +48,7 @@ void setup() { delay(10); // Set GSM module baud rate - SerialAT.begin(115200); + SerialAT.begin(9600); delay(3000); if (!modem.init()) { From 1f5159f9b0722909618c2837fdb09a21d4e5c516 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Tue, 11 Feb 2020 19:10:07 -0500 Subject: [PATCH 34/88] Update diagnostics --- examples/AllFunctions/AllFunctions.ino | 141 ++++++++++++++++++------- src/TinyGsmTCP.tpp | 1 - tools/Diagnostics/Diagnostics.ino | 2 +- tools/test_build/test_build.ino | 5 - 4 files changed, 102 insertions(+), 47 deletions(-) diff --git a/examples/AllFunctions/AllFunctions.ino b/examples/AllFunctions/AllFunctions.ino index c6cab92..4b04583 100644 --- a/examples/AllFunctions/AllFunctions.ino +++ b/examples/AllFunctions/AllFunctions.ino @@ -56,11 +56,16 @@ */ #define TINY_GSM_TEST_GPRS true #define TINY_GSM_TEST_WIFI false -#define TINY_GSM_TEST_CALL true -#define TINY_GSM_TEST_SMS true -#define TINY_GSM_TEST_USSD true +#define TINY_GSM_TEST_TCP true +#define TINY_GSM_TEST_SSL true +#define TINY_GSM_TEST_CALL false +#define TINY_GSM_TEST_SMS false +#define TINY_GSM_TEST_USSD false #define TINY_GSM_TEST_BATTERY true -#define TINY_GSM_TEST_GPS false +#define TINY_GSM_TEST_TEMPERATURE true +#define TINY_GSM_TEST_GSM_LOCATION true +#define TINY_GSM_TEST_TIME true +#define TINY_GSM_TEST_GPS true // powerdown modem after tests #define TINY_GSM_POWERDOWN false @@ -80,18 +85,16 @@ const char gprsPass[] = ""; const char wifiSSID[] = "YourSSID"; const char wifiPass[] = "YourWiFiPass"; +// Server details to test TCP/SSL +const char server[] = "vsh.pp.ua"; +const char resource[] = "/TinyGSM/logo.txt"; + #include #if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS #undef TINY_GSM_TEST_GPRS -#undef TINY_GSM_TEST_CALL -#undef TINY_GSM_TEST_SMS -#undef TINY_GSM_TEST_USSD #undef TINY_GSM_TEST_WIFI #define TINY_GSM_TEST_GPRS false -#define TINY_GSM_TEST_CALL false -#define TINY_GSM_TEST_SMS false -#define TINY_GSM_TEST_USSD false #define TINY_GSM_TEST_WIFI true #endif #if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI @@ -100,10 +103,6 @@ const char wifiPass[] = "YourWiFiPass"; #define TINY_GSM_USE_GPRS true #define TINY_GSM_USE_WIFI false #endif -#if TINY_GSM_TEST_GPS && not defined TINY_GSM_MODEM_HAS_GPS -#undef TINY_GSM_TEST_GPS -#define TINY_GSM_TEST_GPS false -#endif #ifdef DUMP_AT_COMMANDS #include @@ -123,25 +122,23 @@ void setup() { // !!!!!!!!!!! DBG("Wait..."); + delay(6000); // Set GSM module baud rate - TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); - //SerialAT.begin(115200); - delay(3000); + TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX); + // SerialAT.begin(9600); } void loop() { - // Restart takes quite some time // To skip it, call init() instead of restart() DBG("Initializing modem..."); if (!modem.restart()) { - // if (!modem.init()) { + // if (!modem.init()) { DBG("Failed to restart modem, delaying 10s and retrying"); - delay(3000); - // restart autobaud in case GSM just rebooted - TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); delay(10000); + // restart autobaud in case GSM just rebooted + // TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX); return; } @@ -153,7 +150,7 @@ void loop() { #if TINY_GSM_TEST_GPRS // Unlock your SIM card with a PIN if needed - if ( GSM_PIN && modem.getSimStatus() != 3 ) { + if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); } #endif @@ -199,6 +196,9 @@ void loop() { String imei = modem.getIMEI(); DBG("IMEI:", imei); + String imsi = modem.getIMSI(); + DBG("IMSI:", imsi); + String cop = modem.getOperator(); DBG("Operator:", cop); @@ -207,19 +207,9 @@ void loop() { int csq = modem.getSignalQuality(); DBG("Signal quality:", csq); - - // This is only supported on SIMxxx series - // String gsmLoc = modem.getGsmLocation(); - // DBG("GSM location:", gsmLoc); - - // This is only supported on SIMxxx series - // String gsmTime = modem.getGSMDateTime(DATE_TIME); - // DBG("GSM Time:", gsmTime); - // String gsmDate = modem.getGSMDateTime(DATE_DATE); - // DBG("GSM Date:", gsmDate); #endif -#if TINY_GSM_TEST_USSD +#if TINY_GSM_TEST_USSD && defined TINY_GSM_MODEM_HAS_SMS String ussd_balance = modem.sendUSSD("*111#"); DBG("Balance (USSD):", ussd_balance); @@ -227,20 +217,78 @@ void loop() { DBG("Phone number (USSD):", ussd_phone_num); #endif -#if TINY_GSM_TEST_GPS +#if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP + TinyGsmClient client(modem); + const int port = 80; + DBG("Connecting to ", server); + if (!client.connect(server, port)) { + DBG("... failed"); + } else { + // Make a HTTP GET request: + client.print(String("GET ") + resource + " HTTP/1.0\r\n"); + client.print(String("Host: ") + server + "\r\n"); + client.print("Connection: close\r\n\r\n"); + + // Wait for data to arrive + while (client.connected() && !client.available()) { + delay(100); + }; + + // Read data + uint32_t timeout = millis(); + while (client.connected() && millis() - timeout < 10000L) { + while (client.available()) { + SerialMon.write(client.read()); + timeout = millis(); + } + } + client.stop(); + } +#endif + +#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL + TinyGsmClientSecure secureClient(modem); + const int securePort = 443; + DBG("Connecting to ", server); + if (!secureClient.connect(server, securePort)) { + DBG("... failed"); + } else { + // Make a HTTP GET request: + secureClient.print(String("GET ") + resource + " HTTP/1.0\r\n"); + secureClient.print(String("Host: ") + server + "\r\n"); + secureClient.print("Connection: close\r\n\r\n"); + + // Wait for data to arrive + while (secureClient.connected() && !secureClient.available()) { + delay(100); + }; + + // Read data + uint32_t timeoutS = millis(); + while (secureClient.connected() && millis() - timeoutS < 10000L) { + while (secureClient.available()) { + SerialMon.write(secureClient.read()); + timeoutS = millis(); + } + } + secureClient.stop(); + } +#endif + +#if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS modem.enableGPS(); String gps_raw = modem.getGPSraw(); modem.disableGPS(); DBG("GPS raw data:", gps_raw); #endif -#if TINY_GSM_TEST_SMS && defined(SMS_TARGET) +#if TINY_GSM_TEST_SMS && defined TINY_GSM_MODEM_HAS_SMS && defined SMS_TARGET res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei); DBG("SMS:", res ? "OK" : "fail"); // This is only supported on SIMxxx series res = modem.sendSMS_UTF8_begin(SMS_TARGET); - if(res) { + if (res) { auto stream = modem.sendSMS_UTF8_stream(); stream.print(F("Привіііт! Print number: ")); stream.print(595); @@ -250,7 +298,8 @@ void loop() { #endif -#if TINY_GSM_TEST_CALL && defined(CALL_TARGET) +#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \ + defined CALL_TARGET DBG("Calling:", CALL_TARGET); // This is NOT supported on M590 @@ -264,7 +313,7 @@ void loop() { modem.dtmfSend('A', 1000); // Play DTMF 0..4, default duration (100ms) - for (char tone='0'; tone<='4'; tone++) { + for (char tone = '0'; tone <= '4'; tone++) { modem.dtmfSend(tone); } @@ -275,7 +324,7 @@ void loop() { } #endif -#if TINY_GSM_TEST_BATTERY +#if TINY_GSM_TEST_BATTERY && defined TINY_GSM_MODEM_HAS_BATTERY uint8_t chargeState = -99; int8_t percent = -99; uint16_t milliVolts = -9999; @@ -283,11 +332,23 @@ void loop() { DBG("Battery charge state:", chargeState); DBG("Battery charge 'percent':", percent); DBG("Battery voltage:", milliVolts / 1000.0F); +#endif +#if TINY_GSM_TEST_TEMPERATURE && defined TINY_GSM_MODEM_HAS_TEMPERATURE float temp = modem.getTemperature(); DBG("Chip temperature:", temp); #endif +#if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION + String location = modem.getGsmLocation(); + DBG("GSM Based Location:", location); +#endif + +#if TINY_GSM_TEST_TIME && defined TINY_GSM_MODEM_HAS_TIME + String time = modem.getGSMDateTime(DATE_FULL); + DBG("Current Network Time:", time); +#endif + #if TINY_GSM_TEST_GPRS modem.gprsDisconnect(); if (!modem.isGprsConnected()) { diff --git a/src/TinyGsmTCP.tpp b/src/TinyGsmTCP.tpp index 46c71c5..7c47ec7 100644 --- a/src/TinyGsmTCP.tpp +++ b/src/TinyGsmTCP.tpp @@ -41,7 +41,6 @@ enum modemInternalBuffferType { // and check the size of the buffer }; -// The fully generic template is empty template class TinyGsmTCP { public: diff --git a/tools/Diagnostics/Diagnostics.ino b/tools/Diagnostics/Diagnostics.ino index 86bf842..c49f673 100644 --- a/tools/Diagnostics/Diagnostics.ino +++ b/tools/Diagnostics/Diagnostics.ino @@ -129,7 +129,7 @@ void setup() { // Set GSM module baud rate // TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); - SerialAT.begin(115200); + SerialAT.begin(9600); delay(3000); } diff --git a/tools/test_build/test_build.ino b/tools/test_build/test_build.ino index 1e90809..3866c27 100644 --- a/tools/test_build/test_build.ino +++ b/tools/test_build/test_build.ino @@ -69,11 +69,6 @@ void loop() { modem.getGSMDateTime(DATE_FULL); #endif -// Test the Network time function -#if defined(TINY_GSM_MODEM_HAS_TIME) - modem.getGSMDateTime(DATE_FULL); -#endif - // Test the GPS functions #if defined(TINY_GSM_MODEM_HAS_GPS) modem.enableGPS(); From 899c1d823385d71dd726d56a09006b5a74eab7c5 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 12 Feb 2020 18:54:36 -0500 Subject: [PATCH 35/88] Remove GSMLocation from MC60 Signed-off-by: Sara Damiano --- src/TinyGsmClientMC60.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/TinyGsmClientMC60.h b/src/TinyGsmClientMC60.h index c6fdb40..df637f2 100644 --- a/src/TinyGsmClientMC60.h +++ b/src/TinyGsmClientMC60.h @@ -20,7 +20,6 @@ #include "TinyGsmBattery.tpp" #include "TinyGsmCalling.tpp" #include "TinyGsmGPRS.tpp" -#include "TinyGsmGSMLocation.tpp" #include "TinyGsmModem.tpp" #include "TinyGsmSMS.tpp" #include "TinyGsmTCP.tpp" @@ -47,7 +46,6 @@ class TinyGsmMC60 public TinyGsmTCP, public TinyGsmCalling, public TinyGsmSMS, - public TinyGsmGSMLocation, public TinyGsmTime, public TinyGsmBattery { friend class TinyGsmModem; @@ -55,7 +53,6 @@ class TinyGsmMC60 friend class TinyGsmTCP; friend class TinyGsmCalling; friend class TinyGsmSMS; - friend class TinyGsmGSMLocation; friend class TinyGsmTime; friend class TinyGsmBattery; @@ -346,12 +343,6 @@ class TinyGsmMC60 return false; } - /* - * Location functions - */ - protected: - // Can use CIPGSMLOC as inherited from the template - /* * Time functions */ From fe323288c42a885ccff8868b77f8c97df9be27ba Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 12 Feb 2020 18:57:51 -0500 Subject: [PATCH 36/88] Tweaks to SIM7000 Signed-off-by: Sara Damiano --- src/TinyGsmClientSIM7000.h | 16 ++++++++++++---- src/TinyGsmClientSIM800.h | 7 ++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 60f2f4f..78cc9ad 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -168,7 +168,14 @@ class TinyGsmSim7000 : public TinyGsmModem, // Enable Local Time Stamp for getting network time sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { return false; } + if (waitResponse(10000L) != 1) { return false; + } + + // Enable battery checks + sendAT(GF("+CBATCHK=1")); + if (waitResponse() != 1) { + return false; + } int ret = getSimStatus(); // if the sim isn't ready and a pin has been provided, try to unlock the sim @@ -209,8 +216,9 @@ class TinyGsmSim7000 : public TinyGsmModem, sendAT(GF("+CFUN=0")); if (waitResponse(10000L) != 1) { return false; } sendAT(GF("+CFUN=1,1")); - if (waitResponse(10000L) != 1) { return false; } - delay(3000); // TODO(SRGDamia1): Test this delay + if (waitResponse(10000L) != 1) { return false; + } + waitResponse(60000L, GF("SMS Ready")); return init(); } @@ -233,7 +241,7 @@ class TinyGsmSim7000 : public TinyGsmModem, */ public: RegStatus getRegistrationStatus() { - return (RegStatus)getRegistrationStatusXREG("CGREG"); + return (RegStatus)getRegistrationStatusXREG("CEREG"); } protected: diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index 989d0e8..0a72750 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -170,7 +170,12 @@ class TinyGsmSim800 // Enable Local Time Stamp for getting network time sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { return false; } + if (waitResponse(10000L) != 1) { return false; + } + + // Enable battery checks + sendAT(GF("+CBATCHK=1")); + waitResponse(); int ret = getSimStatus(); // if the sim isn't ready and a pin has been provided, try to unlock the sim From 3cc57881beccc43287620fb5c9fcfae098d86381 Mon Sep 17 00:00:00 2001 From: Sara Damiano Date: Wed, 12 Feb 2020 19:52:22 -0500 Subject: [PATCH 37/88] Redo GSM location and GPS stringlessly Signed-off-by: Sara Damiano --- src/TinyGsmClientSIM5360.h | 10 ++++ src/TinyGsmClientSIM7000.h | 92 ++++++++++++++---------------------- src/TinyGsmClientSIM7600.h | 93 ++++++++++++++++++++++++------------ src/TinyGsmClientSIM800.h | 29 ++---------- src/TinyGsmClientSIM808.h | 85 ++++++++++++++------------------- src/TinyGsmClientSaraR4.h | 87 ++++++++++++++++++++++++++++++++-- src/TinyGsmClientUBLOX.h | 74 ++++++++++++++++++++++++++++- src/TinyGsmGPS.tpp | 22 +++++---- src/TinyGsmGSMLocation.tpp | 96 ++++++++++++++++++++++++++++++++++++-- 9 files changed, 409 insertions(+), 179 deletions(-) diff --git a/src/TinyGsmClientSIM5360.h b/src/TinyGsmClientSIM5360.h index b2a2651..c28a83e 100644 --- a/src/TinyGsmClientSIM5360.h +++ b/src/TinyGsmClientSIM5360.h @@ -16,6 +16,7 @@ #include "TinyGsmBattery.tpp" #include "TinyGsmGPRS.tpp" +#include "TinyGsmGSMLocation.tpp" #include "TinyGsmModem.tpp" #include "TinyGsmSMS.tpp" #include "TinyGsmTCP.tpp" @@ -43,6 +44,7 @@ class TinyGsmSim5360 : public TinyGsmModem, TINY_GSM_MUX_COUNT>, public TinyGsmSMS, public TinyGsmTime, + public TinyGsmGSMLocation, public TinyGsmBattery, public TinyGsmTemperature { friend class TinyGsmModem; @@ -51,6 +53,7 @@ class TinyGsmSim5360 : public TinyGsmModem, TINY_GSM_MUX_COUNT>; friend class TinyGsmSMS; friend class TinyGsmTime; + friend class TinyGsmGSMLocation; friend class TinyGsmBattery; friend class TinyGsmTemperature; @@ -401,6 +404,13 @@ class TinyGsmSim5360 : public TinyGsmModem, protected: // Follows all messaging functions per template + /* + * Location functions + */ + protected: + // SIM5360 and SIM7100 can return a GSM-based location from CLBS as per the + // template; SIM5320 doesn't not appear to be able to + /* * Time functions */ diff --git a/src/TinyGsmClientSIM7000.h b/src/TinyGsmClientSIM7000.h index 78cc9ad..5eab2a3 100644 --- a/src/TinyGsmClientSIM7000.h +++ b/src/TinyGsmClientSIM7000.h @@ -17,7 +17,6 @@ #include "TinyGsmBattery.tpp" #include "TinyGsmGPRS.tpp" #include "TinyGsmGPS.tpp" -#include "TinyGsmGSMLocation.tpp" #include "TinyGsmModem.tpp" #include "TinyGsmSMS.tpp" #include "TinyGsmTCP.tpp" @@ -43,7 +42,6 @@ class TinyGsmSim7000 : public TinyGsmModem, public TinyGsmTCP, public TinyGsmSMS, - public TinyGsmGSMLocation, public TinyGsmGPS, public TinyGsmTime, public TinyGsmBattery { @@ -52,7 +50,6 @@ class TinyGsmSim7000 : public TinyGsmModem, friend class TinyGsmTCP; friend class TinyGsmSMS; - friend class TinyGsmGSMLocation; friend class TinyGsmGPS; friend class TinyGsmTime; friend class TinyGsmBattery; @@ -390,13 +387,6 @@ class TinyGsmSim7000 : public TinyGsmModem, protected: // Follows all messaging functions per template - /* - * Location functions - */ - protected: - // Can return a location from CIPGSMLOC as per the template - - /* * GPS location functions */ @@ -426,16 +416,45 @@ class TinyGsmSim7000 : public TinyGsmModem, // get GPS informations bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, - int* vsat = 0, int* usat = 0) { - // String buffer = ""; + int* vsat = 0, int* usat = 0, int* year = 0, int* month = 0, + int* day = 0, int* hour = 0, int* minute = 0, + int* second = 0) { bool fix = false; sendAT(GF("+CGNSINF")); if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } - streamSkipUntil(','); // GNSS run status - if (streamGetInt(',') == 1) fix = true; // fix status - streamSkipUntil(','); // UTC date & Time + streamSkipUntil(','); // GNSS run status + if (streamGetInt(',') == 1) fix = true; // fix status + + // UTC date & Time + char dtSBuff[7] = {'\0'}; + stream.readBytes(dtSBuff, 4); // Four digit year + dtSBuff[4] = '\0'; // null terminate buffer + if (year != NULL) *year = atoi(dtSBuff); // Convert to int + + stream.readBytes(dtSBuff, 2); // Two digit month + dtSBuff[2] = '\0'; + if (month != NULL) *month = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit day + dtSBuff[2] = '\0'; + if (day != NULL) *day = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit hour + dtSBuff[2] = '\0'; + if (hour != NULL) *hour = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit minute + dtSBuff[2] = '\0'; + if (minute != NULL) *minute = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds + dtSBuff[6] = '\0'; + if (second != NULL) *second = atoi(dtSBuff); + // *secondWithSS = atof(dtSBuff); + streamSkipUntil(','); // Throw away the final comma + *lat = streamGetFloat(','); // Latitude *lon = streamGetFloat(','); // Longitude if (alt != NULL) *alt = streamGetFloat(','); // MSL Altitude @@ -459,49 +478,6 @@ class TinyGsmSim7000 : public TinyGsmModem, return fix; } - // get GPS time - bool getGPSTimeImpl(int* year, int* month, int* day, int* hour, int* minute, - int* second) { - bool fix = false; - char chr_buffer[12]; - sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } - - for (int i = 0; i < 3; i++) { - String buffer = stream.readStringUntil(','); - buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); - switch (i) { - case 0: - // mode - break; - case 1: - // fixstatus - if (buffer.toInt() == 1) { fix = buffer.toInt(); } - break; - case 2: - *year = buffer.substring(0, 4).toInt(); - *month = buffer.substring(4, 6).toInt(); - *day = buffer.substring(6, 8).toInt(); - *hour = buffer.substring(8, 10).toInt(); - *minute = buffer.substring(10, 12).toInt(); - *second = buffer.substring(12, 14).toInt(); - break; - - default: - // if nothing else matches, do the default - // default is optional - break; - } - } - streamSkipUntil('\n'); - waitResponse(); - - if (fix) { - return true; - } else { - return false; - } - } /* * Time functions diff --git a/src/TinyGsmClientSIM7600.h b/src/TinyGsmClientSIM7600.h index 1fda2d2..78bebbd 100644 --- a/src/TinyGsmClientSIM7600.h +++ b/src/TinyGsmClientSIM7600.h @@ -17,6 +17,7 @@ #include "TinyGsmBattery.tpp" #include "TinyGsmGPRS.tpp" #include "TinyGsmGPS.tpp" +#include "TinyGsmGSMLocation.tpp" #include "TinyGsmModem.tpp" #include "TinyGsmSMS.tpp" #include "TinyGsmTCP.tpp" @@ -43,6 +44,7 @@ class TinyGsmSim7600 : public TinyGsmModem, public TinyGsmTCP, public TinyGsmSMS, + public TinyGsmGSMLocation, public TinyGsmGPS, public TinyGsmTime, public TinyGsmBattery, @@ -53,6 +55,7 @@ class TinyGsmSim7600 : public TinyGsmModem, TINY_GSM_MUX_COUNT>; friend class TinyGsmSMS; friend class TinyGsmGPS; + friend class TinyGsmGSMLocation; friend class TinyGsmTime; friend class TinyGsmBattery; friend class TinyGsmTemperature; @@ -85,7 +88,7 @@ class TinyGsmSim7600 : public TinyGsmModem, } public: - int connect(const char* host, uint16_t port, int timeout_s) { + virtual int connect(const char* host, uint16_t port, int timeout_s) { stop(); TINY_GSM_YIELD(); rx.clear(); @@ -396,8 +399,7 @@ class TinyGsmSim7600 : public TinyGsmModem, * Location functions */ protected: - String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; - + // Can return a GSM-based location from CLBS as per the template /* * GPS location functions @@ -427,39 +429,72 @@ class TinyGsmSim7600 : public TinyGsmModem, } // get GPS informations - bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0) { + bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, + int* vsat = 0, int* usat = 0, int* year = 0, int* month = 0, + int* day = 0, int* hour = 0, int* minute = 0, + int* second = 0) { // String buffer = ""; - bool fix = false; sendAT(GF("+CGNSSINFO")); if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; } - // streamSkipUntil(','); // mode - if (streamGetInt(',') == 1) - fix = true; // TODO(?) Shouldn't this be 2=2D Fix or 3=3DFix? - streamSkipUntil(','); // GPS satellite valid numbers - streamSkipUntil(','); // GLONASS satellite valid numbers - streamSkipUntil(','); // BEIDOU satellite valid numbers - *lat = streamGetFloat(','); // Latitude - streamSkipUntil(','); // N/S Indicator, N=north or S=south - *lon = streamGetFloat(','); // Longitude - streamSkipUntil(','); // E/W Indicator, E=east or W=west - streamSkipUntil(','); // Date. Output format is ddmmyy - streamSkipUntil(','); // UTC Time. Output format is hhmmss.s - if (alt != NULL) - *alt = streamGetFloat(','); // MSL Altitude. Unit is meters - if (speed != NULL) - *speed = streamGetFloat(','); // Speed Over Ground. Unit is knots. - streamSkipUntil(','); // Course. Degrees. - streamSkipUntil(','); // After set, will report GPS every x seconds - streamSkipUntil(','); // Position Dilution Of Precision - streamSkipUntil(','); // Horizontal Dilution Of Precision - streamSkipUntil(','); // Vertical Dilution Of Precision - streamSkipUntil('\n'); // TODO(?) is one more field reported?? + uint8_t fixMode = streamGetInt(','); // mode 2=2D Fix or 3=3DFix + // TODO(?) Can 1 be returned + if (fixMode == 1 || fixMode == 2 || fixMode == 3) { + streamSkipUntil(','); // GPS satellite valid numbers + streamSkipUntil(','); // GLONASS satellite valid numbers + streamSkipUntil(','); // BEIDOU satellite valid numbers + *lat = streamGetFloat(','); // Latitude + streamSkipUntil(','); // N/S Indicator, N=north or S=south + *lon = streamGetFloat(','); // Longitude + streamSkipUntil(','); // E/W Indicator, E=east or W=west + + // Date. Output format is ddmmyy + char dtSBuff[5] = {'\0'}; + stream.readBytes(dtSBuff, 2); // Two digit day + dtSBuff[2] = '\0'; // null terminate buffer + if (day != NULL) *day = atoi(dtSBuff); // Convert to int + + stream.readBytes(dtSBuff, 2); // Two digit month + dtSBuff[2] = '\0'; + if (month != NULL) *month = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit year + dtSBuff[2] = '\0'; + if (year != NULL) *year = atoi(dtSBuff); + streamSkipUntil(','); // Throw away the final comma + + // UTC Time. Output format is hhmmss.s + stream.readBytes(dtSBuff, 2); // Two digit hour + dtSBuff[2] = '\0'; + if (hour != NULL) *hour = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit minute + dtSBuff[2] = '\0'; + if (minute != NULL) *minute = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds + dtSBuff[6] = '\0'; + if (second != NULL) *second = atoi(dtSBuff); + // *secondWithSS = atof(dtSBuff); + streamSkipUntil(','); // Throw away the final comma + + if (alt != NULL) + *alt = streamGetFloat(','); // MSL Altitude. Unit is meters + if (speed != NULL) + *speed = streamGetFloat(','); // Speed Over Ground. Unit is knots. + streamSkipUntil(','); // Course. Degrees. + streamSkipUntil(','); // After set, will report GPS every x seconds + streamSkipUntil(','); // Position Dilution Of Precision + streamSkipUntil(','); // Horizontal Dilution Of Precision + streamSkipUntil(','); // Vertical Dilution Of Precision + streamSkipUntil('\n'); // TODO(?) is one more field reported?? - waitResponse(); + waitResponse(); - return fix; + return true; + } + return false; } /* diff --git a/src/TinyGsmClientSIM800.h b/src/TinyGsmClientSIM800.h index 0a72750..f0abd1e 100644 --- a/src/TinyGsmClientSIM800.h +++ b/src/TinyGsmClientSIM800.h @@ -170,8 +170,7 @@ class TinyGsmSim800 // Enable Local Time Stamp for getting network time sendAT(GF("+CLTS=1")); - if (waitResponse(10000L) != 1) { return false; - } + if (waitResponse(10000L) != 1) { return false; } // Enable battery checks sendAT(GF("+CBATCHK=1")); @@ -408,30 +407,10 @@ class TinyGsmSim800 * Location functions */ protected: - // Can return a location from CIPGSMLOC as per the template + // Depending on the exacty model and firmware revision, should return a + // GSM-based location from CLBS as per the template + // TODO(?): Check number of digits in year (2 or 4) - String getGsmLocation() { - sendAT(GF("+CIPGSMLOC=1,1")); - if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - - String getBaseStationGsmLocation() { - sendAT(GF("+CLBS=1,1")); - if (waitResponse(10000L, GF(GSM_NL "+CLBS:")) != 1) { - return ""; - } - String res = stream.readStringUntil('\n'); - waitResponse(); - res.trim(); - return res; - } - /* * GPS location functions */ diff --git a/src/TinyGsmClientSIM808.h b/src/TinyGsmClientSIM808.h index d2853f5..8017fc0 100644 --- a/src/TinyGsmClientSIM808.h +++ b/src/TinyGsmClientSIM808.h @@ -57,17 +57,45 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS { // get GPS informations // works only with ans SIM808 V2 bool getGPSImpl(float* lat, float* lon, float* speed = 0, int* alt = 0, - int* vsat = 0, int* usat = 0) { - // String buffer = ""; - // char chr_buffer[12]; + int* vsat = 0, int* usat = 0, int* year = 0, int* month = 0, + int* day = 0, int* hour = 0, int* minute = 0, + int* second = 0) { bool fix = false; sendAT(GF("+CGNSINF")); if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } - streamSkipUntil(','); // GNSS run status - if (streamGetInt(',') == 1) fix = true; // fix status - streamSkipUntil(','); // UTC date & Time + streamSkipUntil(','); // GNSS run status + if (streamGetInt(',') == 1) fix = true; // fix status + + // UTC date & Time + char dtSBuff[7] = {'\0'}; + stream.readBytes(dtSBuff, 4); // Four digit year + dtSBuff[4] = '\0'; // null terminate buffer + if (year != NULL) *year = atoi(dtSBuff); // Convert to int + + stream.readBytes(dtSBuff, 2); // Two digit month + dtSBuff[2] = '\0'; + if (month != NULL) *month = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit day + dtSBuff[2] = '\0'; + if (day != NULL) *day = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit hour + dtSBuff[2] = '\0'; + if (hour != NULL) *hour = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 2); // Two digit minute + dtSBuff[2] = '\0'; + if (minute != NULL) *minute = atoi(dtSBuff); + + stream.readBytes(dtSBuff, 6); // 6 digit second with subseconds + dtSBuff[6] = '\0'; + if (second != NULL) *second = atoi(dtSBuff); + // *secondWithSS = atof(dtSBuff); + streamSkipUntil(','); // Throw away the final comma + *lat = streamGetFloat(','); // Latitude *lon = streamGetFloat(','); // Longitude if (alt != NULL) *alt = streamGetFloat(','); // MSL Altitude @@ -91,51 +119,6 @@ class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS { return fix; } - - // get GPS time - // works only with SIM808 V2 - bool getGPSTimeImpl(int* year, int* month, int* day, int* hour, int* minute, - int* second) { - bool fix = false; - char chr_buffer[12]; - sendAT(GF("+CGNSINF")); - if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } - - for (int i = 0; i < 3; i++) { - String buffer = stream.readStringUntil(','); - buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); - switch (i) { - case 0: - // mode - break; - case 1: - // fixstatus - if (buffer.toInt() == 1) { fix = buffer.toInt(); } - break; - case 2: - *year = buffer.substring(0, 4).toInt(); - *month = buffer.substring(4, 6).toInt(); - *day = buffer.substring(6, 8).toInt(); - *hour = buffer.substring(8, 10).toInt(); - *minute = buffer.substring(10, 12).toInt(); - *second = buffer.substring(12, 14).toInt(); - break; - - default: - // if nothing else matches, do the default - // default is optional - break; - } - } - streamSkipUntil('\n'); - waitResponse(); - - if (fix) { - return true; - } else { - return false; - } - } }; #endif // SRC_TINYGSMCLIENTSIM808_H_ diff --git a/src/TinyGsmClientSaraR4.h b/src/TinyGsmClientSaraR4.h index a700ec5..65dab14 100644 --- a/src/TinyGsmClientSaraR4.h +++ b/src/TinyGsmClientSaraR4.h @@ -425,15 +425,96 @@ class TinyGsmSaraR4 * Location functions */ protected: - String getGsmLocationImpl() { - sendAT(GF("+ULOC=2,3,0,120,1")); - if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } + String getGsmLocationRawImpl() { + // AT+ULOC=,,,, + // - 2: single shot position + // - 2: use cellular CellLocate® location information + // - 0: standard (single-hypothesis) response + // - Timeout period in seconds + // - Target accuracy in meters (1 - 999999) + sendAT(GF("+ULOC=2,2,0,120,1")); + // wait for first "OK" + if (waitResponse(10000L) != 1) { return ""; } + // wait for the final result - wait full timeout time + if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); return res; } + bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0, + int* year = 0, int* month = 0, int* day = 0, + int* hour = 0, int* minute = 0, int* second = 0) { + // AT+ULOC=,,,, + // - 2: single shot position + // - 2: use cellular CellLocate® location information + // - 0: standard (single-hypothesis) response + // - Timeout period in seconds + // - Target accuracy in meters (1 - 999999) + sendAT(GF("+ULOC=2,2,0,120,1")); + // wait for first "OK" + if (waitResponse(10000L) != 1) { return false; } + // wait for the final result - wait full timeout time + if (waitResponse(120000L, GF(GSM_NL "+UULOC:")) != 1) { return false; } + + // +UULOC: ,