Split SIM7000, add SIM7070, NTP
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/build_examples.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build_examples.yaml
									
									
									
									
										vendored
									
									
								
							@@ -32,6 +32,8 @@ jobs:
 | 
			
		||||
            TINY_GSM_MODEM_SIM5360,
 | 
			
		||||
            TINY_GSM_MODEM_SIM7600,
 | 
			
		||||
            TINY_GSM_MODEM_SIM7000,
 | 
			
		||||
            TINY_GSM_MODEM_SIM7000SSL,
 | 
			
		||||
            TINY_GSM_MODEM_SIM7070,
 | 
			
		||||
            TINY_GSM_MODEM_UBLOX,
 | 
			
		||||
            TINY_GSM_MODEM_SARAR4,
 | 
			
		||||
            TINY_GSM_MODEM_XBEE,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
								
							@@ -17,6 +17,31 @@ If you like **TinyGSM** - give it a star, or fork it and contribute!
 | 
			
		||||
You can also join our chat:
 | 
			
		||||
[](https://gitter.im/tinygsm)
 | 
			
		||||
 | 
			
		||||
- [Supported modems](#supported-modems)
 | 
			
		||||
  - [Supported boards/modules](#supported-boardsmodules)
 | 
			
		||||
- [Features](#features)
 | 
			
		||||
- [Getting Started](#getting-started)
 | 
			
		||||
    - [First Steps](#first-steps)
 | 
			
		||||
    - [Writing your own code](#writing-your-own-code)
 | 
			
		||||
    - [If you have any issues](#if-you-have-any-issues)
 | 
			
		||||
- [How does it work?](#how-does-it-work)
 | 
			
		||||
- [API Reference](#api-reference)
 | 
			
		||||
- [Troubleshooting](#troubleshooting)
 | 
			
		||||
  - [Ensure stable data & power connection](#ensure-stable-data--power-connection)
 | 
			
		||||
  - [Baud rates](#baud-rates)
 | 
			
		||||
  - [Broken initial configuration](#broken-initial-configuration)
 | 
			
		||||
  - [Diagnostics sketch](#diagnostics-sketch)
 | 
			
		||||
  - [Web request formatting problems - "but it works with PostMan"](#web-request-formatting-problems---but-it-works-with-postman)
 | 
			
		||||
  - [SoftwareSerial problems](#softwareserial-problems)
 | 
			
		||||
  - [ESP32 Notes](#esp32-notes)
 | 
			
		||||
    - [HardwareSerial](#hardwareserial)
 | 
			
		||||
    - [HttpClient](#httpclient)
 | 
			
		||||
  - [SAMD21](#samd21)
 | 
			
		||||
  - [Goouuu Tech IOT-GA6 vs AI-Thinker A6 confusion](#goouuu-tech-iot-ga6-vs-ai-thinker-a6-confusion)
 | 
			
		||||
  - [SIM800 and SSL](#sim800-and-ssl)
 | 
			
		||||
  - [Which versions of the SIM7000 code to use](#which-versions-of-the-sim7000-code-to-use)
 | 
			
		||||
  - [License](#license)
 | 
			
		||||
 | 
			
		||||
### Arduino Client interface support
 | 
			
		||||
This library is easy to integrate with lots of sketches which use Ethernet or WiFi.
 | 
			
		||||
**PubSubClient ([MQTT](http://mqtt.org/))**, **[Blynk](http://blynk.cc)**, **HTTP Client** and **File Download** examples are provided.
 | 
			
		||||
@@ -41,6 +66,7 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
 | 
			
		||||
- SIMCom WCDMA/HSPA/HSPA+ Modules (SIM5360, SIM5320, SIM5300E, SIM5300E/A)
 | 
			
		||||
- SIMCom LTE Modules (SIM7100E, SIM7500E, SIM7500A, SIM7600C, SIM7600E)
 | 
			
		||||
- SIMCom SIM7000E/A/G CAT-M1/NB-IoT Module
 | 
			
		||||
- SIMCom SIM7070/SIM7080/SIM7090 CAT-M1/NB-IoT Module ***(alpha)***
 | 
			
		||||
- AI-Thinker A6, A6C, A7, A20
 | 
			
		||||
- ESP8266 (AT commands interface, similar to GSM modems)
 | 
			
		||||
- Digi XBee WiFi and Cellular (using XBee command mode)
 | 
			
		||||
@@ -86,7 +112,8 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
 | 
			
		||||
        - Sequans Monarch - 6
 | 
			
		||||
        - SIM 800/900 - 5
 | 
			
		||||
        - SIM 5360/5320/5300/7100 - 10
 | 
			
		||||
        - SIM7000 - 2 (8 possible without SSL, only 2 with)
 | 
			
		||||
        - SIM7000 - 8 possible without SSL, only 2 with
 | 
			
		||||
        - SIM 7070/7080/7090 - 12
 | 
			
		||||
        - SIM 7500/7600/7800 - 10
 | 
			
		||||
        - u-blox 2G/3G - 7
 | 
			
		||||
        - u-blox SARA R4/N4 - 7
 | 
			
		||||
@@ -96,7 +123,7 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
 | 
			
		||||
- SSL/TLS (HTTPS)
 | 
			
		||||
    - Supported on:
 | 
			
		||||
        - SIM800, SIM7000, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
 | 
			
		||||
        - Note:  only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
 | 
			
		||||
        - Note:  **only some device models or firmware revisions have this feature** (SIM8xx R14.18, A7, etc.)
 | 
			
		||||
    - Not yet supported on:
 | 
			
		||||
        - Quectel modems, SIM 5360/5320/7100, SIM 7500/7600/7800
 | 
			
		||||
    - Not possible on:
 | 
			
		||||
@@ -207,7 +234,7 @@ The general flow of your code should be:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### If you have any issues:
 | 
			
		||||
#### If you have any issues
 | 
			
		||||
 | 
			
		||||
  1. Read the whole README (you're looking at it!), particularly the troubleshooting section below.
 | 
			
		||||
  2. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
 | 
			
		||||
@@ -238,6 +265,13 @@ Improving the power supply actually solves stability problems in **many** cases!
 | 
			
		||||
- Do not put your wires next to noisy signal sources (buck converters, antennas, oscillators etc.)
 | 
			
		||||
- If everything else seems to be working but you are unable to connect to the network, check your power supply!
 | 
			
		||||
 | 
			
		||||
### Baud rates
 | 
			
		||||
 | 
			
		||||
Most modules support some sort of "auto-bauding" feature where the module will attempt to adjust it's baud rate to match what it is receiving.
 | 
			
		||||
TinyGSM also implements its own auto bauding function (`TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);`).
 | 
			
		||||
While very useful when initially connecting to a module and doing tests, these should **NOT** be used in any sort of production code.
 | 
			
		||||
Once you've established communication with the module, set the baud rate using the `setBaud(#)` function and stick with that rate.
 | 
			
		||||
 | 
			
		||||
### Broken initial configuration
 | 
			
		||||
 | 
			
		||||
Sometimes (especially if you played with AT commands), your module configuration may become invalid.
 | 
			
		||||
@@ -338,6 +372,24 @@ Please [refer to this comment](https://github.com/vshymanskyy/TinyGSM/issues/102
 | 
			
		||||
 | 
			
		||||
It turns out that **Goouuu Tech IOT-GA6** is not the same as **AI-Thinker A6**. Unfortunately IOT-GA6 is not supported out of the box yet. There are some hints that IOT-GA6 firmware may be updated to match A6... See [this topic](https://github.com/vshymanskyy/TinyGSM/issues/164).
 | 
			
		||||
 | 
			
		||||
### SIM800 and SSL
 | 
			
		||||
 | 
			
		||||
Some, but not all, versions of the SIM800 support SSL.
 | 
			
		||||
Having SSL support depends on the firmware version and the individual module.
 | 
			
		||||
Users have had varying levels of success in using SSL on the SIM800 even with apparently identical firmware.
 | 
			
		||||
If you need SSL and it does not appear to be working on your SIM800, try a different module or try using a secondary SSL library.
 | 
			
		||||
 | 
			
		||||
### Which versions of the SIM7000 code to use
 | 
			
		||||
 | 
			
		||||
There are two versions of the SIM7000 code, one using `TINY_GSM_MODEM_SIM7000` and another with `TINY_GSM_MODEM_SIM7000SSL`.
 | 
			
		||||
The `TINY_GSM_MODEM_SIM7000` version *does not support SSL*.
 | 
			
		||||
The `TINY_GSM_MODEM_SIM7000SSL` version supports both SSL *and unsecured connections*.
 | 
			
		||||
So why are there two versions?
 | 
			
		||||
The "SSL" version uses the SIM7000's "application" commands while the other uses the "TCP-IP toolkit".
 | 
			
		||||
Depending on your region/firmware, one or the other may not work for you.
 | 
			
		||||
Try both and use whichever is more stable.
 | 
			
		||||
If you do not need SSL, I recommend starting with `TINY_GSM_MODEM_SIM7000`.
 | 
			
		||||
 | 
			
		||||
__________
 | 
			
		||||
 | 
			
		||||
### License
 | 
			
		||||
 
 | 
			
		||||
@@ -164,9 +164,7 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_GPRS
 | 
			
		||||
  // Unlock your SIM card with a PIN if needed
 | 
			
		||||
  if (GSM_PIN && modem.getSimStatus() != 3) {
 | 
			
		||||
    modem.simUnlock(GSM_PIN);
 | 
			
		||||
  }
 | 
			
		||||
  if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_WIFI
 | 
			
		||||
@@ -190,9 +188,7 @@ void loop() {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (modem.isNetworkConnected()) {
 | 
			
		||||
    DBG("Network connected");
 | 
			
		||||
  }
 | 
			
		||||
  if (modem.isNetworkConnected()) { DBG("Network connected"); }
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_GPRS
 | 
			
		||||
  DBG("Connecting to", apn);
 | 
			
		||||
@@ -233,7 +229,7 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP
 | 
			
		||||
  TinyGsmClient client(modem, 0);
 | 
			
		||||
  const int port = 80;
 | 
			
		||||
  const int     port = 80;
 | 
			
		||||
  DBG("Connecting to ", server);
 | 
			
		||||
  if (!client.connect(server, port)) {
 | 
			
		||||
    DBG("... failed");
 | 
			
		||||
@@ -252,7 +248,7 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
    // Read data
 | 
			
		||||
    start = millis();
 | 
			
		||||
    while (client.connected() && millis() - start < 5000L) {
 | 
			
		||||
    while (client.connected() && millis() - start < 10000L) {
 | 
			
		||||
      while (client.available()) {
 | 
			
		||||
        SerialMon.write(client.read());
 | 
			
		||||
        start = millis();
 | 
			
		||||
@@ -264,7 +260,7 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
 | 
			
		||||
  TinyGsmClientSecure secureClient(modem, 1);
 | 
			
		||||
  const int securePort = 443;
 | 
			
		||||
  const int           securePort = 443;
 | 
			
		||||
  DBG("Connecting to ", server);
 | 
			
		||||
  if (!secureClient.connect(server, securePort)) {
 | 
			
		||||
    DBG("... failed");
 | 
			
		||||
@@ -294,7 +290,7 @@ void loop() {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
 | 
			
		||||
    defined CALL_TARGET
 | 
			
		||||
    defined                       CALL_TARGET
 | 
			
		||||
  DBG("Calling:", CALL_TARGET);
 | 
			
		||||
 | 
			
		||||
  // This is NOT supported on M590
 | 
			
		||||
@@ -308,9 +304,7 @@ void loop() {
 | 
			
		||||
    modem.dtmfSend('A', 1000);
 | 
			
		||||
 | 
			
		||||
    // Play DTMF 0..4, default duration (100ms)
 | 
			
		||||
    for (char tone = '0'; tone <= '4'; tone++) {
 | 
			
		||||
      modem.dtmfSend(tone);
 | 
			
		||||
    }
 | 
			
		||||
    for (char tone = '0'; tone <= '4'; tone++) { modem.dtmfSend(tone); }
 | 
			
		||||
 | 
			
		||||
    delay(5000);
 | 
			
		||||
 | 
			
		||||
@@ -344,7 +338,7 @@ void loop() {
 | 
			
		||||
  int   day      = 0;
 | 
			
		||||
  int   hour     = 0;
 | 
			
		||||
  int   min      = 0;
 | 
			
		||||
  int sec = 0;
 | 
			
		||||
  int   sec      = 0;
 | 
			
		||||
  for (int8_t i = 15; i; i--) {
 | 
			
		||||
    DBG("Requesting current GSM location");
 | 
			
		||||
    if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
 | 
			
		||||
@@ -384,7 +378,7 @@ void loop() {
 | 
			
		||||
  for (int8_t i = 15; i; i--) {
 | 
			
		||||
    DBG("Requesting current GPS/GNSS/GLONASS location");
 | 
			
		||||
    if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
 | 
			
		||||
                    &year2, &month2, &day2, &hour2, &min2, &sec2)) {
 | 
			
		||||
                     &year2, &month2, &day2, &hour2, &min2, &sec2)) {
 | 
			
		||||
      DBG("Latitude:", String(lat2, 8), "\tLongitude:", String(lon2, 8));
 | 
			
		||||
      DBG("Speed:", speed2, "\tAltitude:", alt2);
 | 
			
		||||
      DBG("Visible Satellites:", vsat2, "\tUsed Satellites:", usat2);
 | 
			
		||||
@@ -405,17 +399,17 @@ void loop() {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_TEST_TIME && defined TINY_GSM_MODEM_HAS_TIME
 | 
			
		||||
  int year3 = 0;
 | 
			
		||||
  int month3 = 0;
 | 
			
		||||
  int day3 = 0;
 | 
			
		||||
  int hour3 = 0;
 | 
			
		||||
  int min3 = 0;
 | 
			
		||||
  int sec3 = 0;
 | 
			
		||||
  int   year3    = 0;
 | 
			
		||||
  int   month3   = 0;
 | 
			
		||||
  int   day3     = 0;
 | 
			
		||||
  int   hour3    = 0;
 | 
			
		||||
  int   min3     = 0;
 | 
			
		||||
  int   sec3     = 0;
 | 
			
		||||
  float timezone = 0;
 | 
			
		||||
  for (int8_t i = 5; i; i--) {
 | 
			
		||||
    DBG("Requesting current network time");
 | 
			
		||||
    if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,
 | 
			
		||||
                                 &timezone)) {
 | 
			
		||||
                             &timezone)) {
 | 
			
		||||
      DBG("Year:", year3, "\tMonth:", month3, "\tDay:", day3);
 | 
			
		||||
      DBG("Hour:", hour3, "\tMinute:", min3, "\tSecond:", sec3);
 | 
			
		||||
      DBG("Timezone:", timezone);
 | 
			
		||||
@@ -470,7 +464,5 @@ void loop() {
 | 
			
		||||
  DBG("End of tests.");
 | 
			
		||||
 | 
			
		||||
  // Do nothing forevermore
 | 
			
		||||
  while (true) {
 | 
			
		||||
    modem.maintain();
 | 
			
		||||
  }
 | 
			
		||||
  while (true) { modem.maintain(); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "TinyGSM",
 | 
			
		||||
  "version": "0.10.9",
 | 
			
		||||
  "version": "0.11.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": [
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,19 @@ typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
 | 
			
		||||
#include "TinyGsmClientSIM7000.h"
 | 
			
		||||
typedef TinyGsmSim7000                   TinyGsm;
 | 
			
		||||
typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient;
 | 
			
		||||
typedef TinyGsmSim7000::GsmClientSecureSIM7000 TinyGsmClientSecure;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_SIM7000SSL)
 | 
			
		||||
#include "TinyGsmClientSIM7000SSL.h"
 | 
			
		||||
typedef TinyGsmSim7000SSL                            TinyGsm;
 | 
			
		||||
typedef TinyGsmSim7000SSL::GsmClientSim7000SSL       TinyGsmClient;
 | 
			
		||||
typedef TinyGsmSim7000SSL::GsmClientSecureSIM7000SSL TinyGsmClientSecure;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_SIM7070) || defined(TINY_GSM_MODEM_SIM7080) || \
 | 
			
		||||
    defined(TINY_GSM_MODEM_SIM7090)
 | 
			
		||||
#include "TinyGsmClientSIM70x0.h"
 | 
			
		||||
typedef TinyGsmSim70x0                         TinyGsm;
 | 
			
		||||
typedef TinyGsmSim70x0::GsmClientSim70x0       TinyGsmClient;
 | 
			
		||||
typedef TinyGsmSim70x0::GsmClientSecureSIM70x0 TinyGsmClientSecure;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
 | 
			
		||||
    defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmTemperature.tpp"
 | 
			
		||||
#include "TinyGsmTime.tpp"
 | 
			
		||||
#include "TinyGsmNTP.tpp"
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM    = "OK" GSM_NL;
 | 
			
		||||
@@ -49,6 +50,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmCalling<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmSMS<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmTime<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmNTP<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmGPS<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmBattery<TinyGsmBG96>,
 | 
			
		||||
                    public TinyGsmTemperature<TinyGsmBG96> {
 | 
			
		||||
@@ -58,6 +60,7 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
 | 
			
		||||
  friend class TinyGsmCalling<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmSMS<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmNTP<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmGPS<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmBG96>;
 | 
			
		||||
  friend class TinyGsmTemperature<TinyGsmBG96>;
 | 
			
		||||
@@ -477,6 +480,27 @@ class TinyGsmBG96 : public TinyGsmModem<TinyGsmBG96>,
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  byte NTPServerSyncImpl(String server = "pool.ntp.org", byte TimeZone = 3) {
 | 
			
		||||
    // Request network synchronization
 | 
			
		||||
    // AT+QNTP=<contextID>,<server>[,<port>][,<autosettime>]
 | 
			
		||||
    sendAT(GF("+QNTP=1,\""), server, '"');
 | 
			
		||||
    if (waitResponse(10000L, GF("+QNTP:"))) {
 | 
			
		||||
      String result = stream.readStringUntil(',');
 | 
			
		||||
      streamSkipUntil('\n');
 | 
			
		||||
      result.trim();
 | 
			
		||||
      if (TinyGsmIsValidNumber(result)) { return result.toInt(); }
 | 
			
		||||
    } else {
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String ShowNTPErrorImpl(byte error) TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmTemperature.tpp"
 | 
			
		||||
#include "TinyGsmTime.tpp"
 | 
			
		||||
#include "TinyGsmNTP.tpp"
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM    = "OK" GSM_NL;
 | 
			
		||||
@@ -47,6 +48,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>,
 | 
			
		||||
                       public TinyGsmSMS<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmTime<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmNTP<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmGSMLocation<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmBattery<TinyGsmSim5360>,
 | 
			
		||||
                       public TinyGsmTemperature<TinyGsmSim5360> {
 | 
			
		||||
@@ -55,6 +57,7 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
 | 
			
		||||
  friend class TinyGsmTCP<TinyGsmSim5360, TINY_GSM_MUX_COUNT>;
 | 
			
		||||
  friend class TinyGsmSMS<TinyGsmSim5360>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmSim5360>;
 | 
			
		||||
  friend class TinyGsmNTP<TinyGsmSim5360>;
 | 
			
		||||
  friend class TinyGsmGSMLocation<TinyGsmSim5360>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmSim5360>;
 | 
			
		||||
  friend class TinyGsmTemperature<TinyGsmSim5360>;
 | 
			
		||||
@@ -270,12 +273,17 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String setNetworkMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
  int16_t getNetworkMode() {
 | 
			
		||||
    sendAT(GF("+CNMP?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
 | 
			
		||||
    int16_t mode = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
    return mode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setNetworkMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
@@ -435,6 +443,11 @@ class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360>,
 | 
			
		||||
 protected:
 | 
			
		||||
  // Can follow the standard CCLK function in the template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -12,49 +12,17 @@
 | 
			
		||||
// #define TINY_GSM_DEBUG Serial
 | 
			
		||||
// #define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 2
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 8
 | 
			
		||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
 | 
			
		||||
 | 
			
		||||
#include "TinyGsmBattery.tpp"
 | 
			
		||||
#include "TinyGsmGPRS.tpp"
 | 
			
		||||
#include "TinyGsmGPS.tpp"
 | 
			
		||||
#include "TinyGsmModem.tpp"
 | 
			
		||||
#include "TinyGsmSMS.tpp"
 | 
			
		||||
#include "TinyGsmClientSIM70xx.h"
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmTime.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;
 | 
			
		||||
#if defined       TINY_GSM_DEBUG
 | 
			
		||||
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
 | 
			
		||||
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_NO_RESULT    = -1,
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmGPRS<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>,
 | 
			
		||||
                       public TinyGsmSMS<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmGPS<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmTime<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmBattery<TinyGsmSim7000> {
 | 
			
		||||
  friend class TinyGsmModem<TinyGsmSim7000>;
 | 
			
		||||
  friend class TinyGsmGPRS<TinyGsmSim7000>;
 | 
			
		||||
class TinyGsmSim7000 : public TinyGsmSim70xx<TinyGsmSim7000>,
 | 
			
		||||
                       public TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT> {
 | 
			
		||||
  friend class TinyGsmSim70xx<TinyGsmSim7000>;
 | 
			
		||||
  friend class TinyGsmTCP<TinyGsmSim7000, TINY_GSM_MUX_COUNT>;
 | 
			
		||||
  friend class TinyGsmSMS<TinyGsmSim7000>;
 | 
			
		||||
  friend class TinyGsmGPS<TinyGsmSim7000>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmSim7000>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmSim7000>;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Client
 | 
			
		||||
@@ -99,7 +67,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
 | 
			
		||||
    void stop(uint32_t maxWaitMs) {
 | 
			
		||||
      dumpModemBuffer(maxWaitMs);
 | 
			
		||||
      at->sendAT(GF("+CACLOSE="), mux);
 | 
			
		||||
      at->sendAT(GF("+CIPCLOSE="), mux);
 | 
			
		||||
      sock_connected = false;
 | 
			
		||||
      at->waitResponse(3000);
 | 
			
		||||
    }
 | 
			
		||||
@@ -117,79 +85,14 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Secure Client
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  class GsmClientSecureSIM7000 : public GsmClientSim7000 {
 | 
			
		||||
   public:
 | 
			
		||||
    GsmClientSecureSIM7000() {}
 | 
			
		||||
 | 
			
		||||
    GsmClientSecureSIM7000(TinyGsmSim7000& modem, uint8_t mux = 0)
 | 
			
		||||
        : GsmClientSim7000(modem, mux) {}
 | 
			
		||||
 | 
			
		||||
   public:
 | 
			
		||||
    bool setCertificate(const String& certificateName) {
 | 
			
		||||
      return at->setCertificate(certificateName, mux);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  boolean isValidNumber(String str) {
 | 
			
		||||
    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; }
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
 | 
			
		||||
    // Set GPRS bearer profile to associate with NTP sync
 | 
			
		||||
    sendAT(GF("+CNTPCID=1"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) { return -1; }
 | 
			
		||||
 | 
			
		||||
    // Set NTP server and timezone
 | 
			
		||||
    sendAT(GF("+CNTP="), server, ',', String(TimeZone));
 | 
			
		||||
    if (waitResponse(10000L) != 1) { return -1; }
 | 
			
		||||
 | 
			
		||||
    // Request network synchronization
 | 
			
		||||
    sendAT(GF("+CNTP"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) {
 | 
			
		||||
      String result = stream.readStringUntil('\n');
 | 
			
		||||
      result.trim();
 | 
			
		||||
      if (isValidNumber(result)) { return result.toInt(); }
 | 
			
		||||
    } else {
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  // NOTE:  Use modem TINYGSMSIM7000SSL for a secure client!
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Constructor
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  explicit TinyGsmSim7000(Stream& stream) : stream(stream), certificates() {
 | 
			
		||||
  explicit TinyGsmSim7000(Stream& stream)
 | 
			
		||||
      : TinyGsmSim70xx<TinyGsmSim7000>(stream) {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -235,165 +138,23 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemNameImpl() {
 | 
			
		||||
    String name = "SIMCom SIM7000";
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+GMM"));
 | 
			
		||||
    String res2;
 | 
			
		||||
    if (waitResponse(1000L, res2) != 1) { return name; }
 | 
			
		||||
    res2.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res2.replace("_", " ");
 | 
			
		||||
    res2.trim();
 | 
			
		||||
 | 
			
		||||
    name = res2;
 | 
			
		||||
    return name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefaultImpl() {  // these commands aren't supported
 | 
			
		||||
    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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool restartImpl(const char* pin = NULL) {
 | 
			
		||||
    if (!setPhoneFunctionality(0)) { return false; }
 | 
			
		||||
    if (!setPhoneFunctionality(1, true)) { return false; }
 | 
			
		||||
    waitResponse(10000L, GF("SMS Ready"), GF("RDY"));
 | 
			
		||||
    return init(pin);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool powerOffImpl() {
 | 
			
		||||
    sendAT(GF("+CPOWD=1"));
 | 
			
		||||
    return waitResponse(GF("NORMAL POWER DOWN")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
 | 
			
		||||
    sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
 | 
			
		||||
    return waitResponse(10000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    RegStatus epsStatus = (RegStatus)getRegistrationStatusXREG("CEREG");
 | 
			
		||||
    // If we're connected on EPS, great!
 | 
			
		||||
    if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
 | 
			
		||||
      return epsStatus;
 | 
			
		||||
    } else {
 | 
			
		||||
      // Otherwise, check GPRS network status
 | 
			
		||||
      // We could be using GPRS fall-back or the board could be being moody
 | 
			
		||||
      return (RegStatus)getRegistrationStatusXREG("CGREG");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
 | 
			
		||||
    if (mux >= TINY_GSM_MUX_COUNT) return false;
 | 
			
		||||
    certificates[mux] = certificateName;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  bool isNetworkConnectedImpl() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  String getNetworkModes() {
 | 
			
		||||
    // Get the help string, not the setting value
 | 
			
		||||
    sendAT(GF("+CNMP=?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool getNetworkMode(int16_t& mode) {
 | 
			
		||||
    sendAT(GF("+CNMP?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
 | 
			
		||||
    mode = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String setNetworkMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    if (waitResponse() != 1) return "";
 | 
			
		||||
    return "OK";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getPreferredModes() {
 | 
			
		||||
    // Get the help string, not the setting value
 | 
			
		||||
    sendAT(GF("+CMNB=?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool getPreferredMode(int16_t& mode) {
 | 
			
		||||
    sendAT(GF("+CMNB?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return false; }
 | 
			
		||||
    mode = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String setPreferredMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CMNB="), mode);
 | 
			
		||||
    if (waitResponse() != 1) return "";
 | 
			
		||||
    return "OK";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool getNetworkSystemMode(bool& n, int16_t& stat) {
 | 
			
		||||
    // n: whether to automatically report the system mode info
 | 
			
		||||
    // stat: the current service. 0 if it not connected
 | 
			
		||||
    sendAT(GF("+CNSMOD?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { return false; }
 | 
			
		||||
    n    = streamGetIntBefore(',') != 0;
 | 
			
		||||
    stat = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String setNetworkSystemMode(bool n) {
 | 
			
		||||
    // n: whether to automatically report the system mode info
 | 
			
		||||
    sendAT(GF("+CNSMOD="), int8_t(n));
 | 
			
		||||
    if (waitResponse() != 1) return "";
 | 
			
		||||
    return "OK";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
    sendAT(GF("+CNACT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
 | 
			
		||||
    streamSkipUntil('\"');
 | 
			
		||||
    String res = stream.readStringUntil('\"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CIFSR;E0"));
 | 
			
		||||
    String res;
 | 
			
		||||
    if (waitResponse(10000L, res) != 1) { return ""; }
 | 
			
		||||
    res.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res.replace(GSM_NL, "");
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -405,24 +166,23 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
                       const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // Open data connection
 | 
			
		||||
    sendAT(GF("+CNACT=1,\""), apn, GF("\""));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Set the Bearer for the IP
 | 
			
		||||
    sendAT(GF(
 | 
			
		||||
        "+SAPBR=3,1,\"Contype\",\"GPRS\""));  // Set the connection type to GPRS
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the connection type to GPRS
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');  // Set the APN
 | 
			
		||||
    // Set the APN
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the user name
 | 
			
		||||
    if (user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');  // Set the user name
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    // Set the password
 | 
			
		||||
    if (pwd && strlen(pwd) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');  // Set the password
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -430,6 +190,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
    sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Attach to GPRS
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Activate the PDP context
 | 
			
		||||
    sendAT(GF("+CGACT=1,1"));
 | 
			
		||||
    waitResponse(60000L);
 | 
			
		||||
@@ -441,24 +205,39 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
    sendAT(GF("+SAPBR=2,1"));
 | 
			
		||||
    if (waitResponse(30000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Attach to GPRS
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    // Set the TCP application toolkit to multi-IP
 | 
			
		||||
    sendAT(GF("+CIPMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Put the TCP application toolkit in "quick send" mode
 | 
			
		||||
    // (thus no extra "Send OK")
 | 
			
		||||
    sendAT(GF("+CIPQSEND=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Set the TCP application toolkit to get data manually
 | 
			
		||||
    sendAT(GF("+CIPRXGET=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Start the TCP application toolkit task and set APN, USER NAME, PASSWORD
 | 
			
		||||
    sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Check data connection
 | 
			
		||||
    // Bring up the TCP application toolkit wireless connection with GPRS or CSD
 | 
			
		||||
    sendAT(GF("+CIICR"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CNACT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return false; }
 | 
			
		||||
    int res = streamGetIntBefore(',');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    // Get local IP address for the TCP application toolkit
 | 
			
		||||
    // only assigned after connection
 | 
			
		||||
    sendAT(GF("+CIFSR;E0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    return res == 1;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnectImpl() {
 | 
			
		||||
    // Shut the TCP/IP connection
 | 
			
		||||
    // CNACT will close *all* open connections
 | 
			
		||||
    sendAT(GF("+CNACT=0"));
 | 
			
		||||
    // Shut the TCP application toolkit connection
 | 
			
		||||
    // CIPSHUT will close *all* open TCP application toolkit connections
 | 
			
		||||
    sendAT(GF("+CIPSHUT"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGATT=0"));  // Deactivate the bearer context
 | 
			
		||||
@@ -471,15 +250,7 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Doesn't return the "+CCID" before the number
 | 
			
		||||
  String getSimCCIDImpl() {
 | 
			
		||||
    sendAT(GF("+CCID"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
@@ -491,113 +262,18 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
   * GPS/GNSS/GLONASS location functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // enable GPS
 | 
			
		||||
  bool enableGPSImpl() {
 | 
			
		||||
    sendAT(GF("+CGNSPWR=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool disableGPSImpl() {
 | 
			
		||||
    sendAT(GF("+CGNSPWR=0"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // get the RAW GPS output
 | 
			
		||||
  String getGPSrawImpl() {
 | 
			
		||||
    sendAT(GF("+CGNSINF"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // get GPS informations
 | 
			
		||||
  bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
 | 
			
		||||
                  int* vsat = 0, int* usat = 0, float* accuracy = 0,
 | 
			
		||||
                  int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
 | 
			
		||||
                  int* minute = 0, int* second = 0) {
 | 
			
		||||
    sendAT(GF("+CGNSINF"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil(',');                // GNSS run status
 | 
			
		||||
    if (streamGetIntBefore(',') == 1) {  // fix status
 | 
			
		||||
      // init variables
 | 
			
		||||
      float ilat         = 0;
 | 
			
		||||
      float ilon         = 0;
 | 
			
		||||
      float ispeed       = 0;
 | 
			
		||||
      float ialt         = 0;
 | 
			
		||||
      int   ivsat        = 0;
 | 
			
		||||
      int   iusat        = 0;
 | 
			
		||||
      float iaccuracy    = 0;
 | 
			
		||||
      int   iyear        = 0;
 | 
			
		||||
      int   imonth       = 0;
 | 
			
		||||
      int   iday         = 0;
 | 
			
		||||
      int   ihour        = 0;
 | 
			
		||||
      int   imin         = 0;
 | 
			
		||||
      float secondWithSS = 0;
 | 
			
		||||
 | 
			
		||||
      // UTC date & Time
 | 
			
		||||
      iyear  = streamGetIntLength(4);  // Four digit year
 | 
			
		||||
      imonth = streamGetIntLength(2);  // Two digit month
 | 
			
		||||
      iday   = streamGetIntLength(2);  // Two digit day
 | 
			
		||||
      ihour  = streamGetIntLength(2);  // Two digit hour
 | 
			
		||||
      imin   = streamGetIntLength(2);  // Two digit minute
 | 
			
		||||
      secondWithSS =
 | 
			
		||||
          streamGetFloatBefore(',');  // 6 digit second with subseconds
 | 
			
		||||
 | 
			
		||||
      ilat   = streamGetFloatBefore(',');  // Latitude
 | 
			
		||||
      ilon   = streamGetFloatBefore(',');  // Longitude
 | 
			
		||||
      ialt   = streamGetFloatBefore(',');  // MSL Altitude. Unit is meters
 | 
			
		||||
      ispeed = streamGetFloatBefore(',');  // Speed Over Ground. Unit is knots.
 | 
			
		||||
      streamSkipUntil(',');                // Course Over Ground. Degrees.
 | 
			
		||||
      streamSkipUntil(',');                // Fix Mode
 | 
			
		||||
      streamSkipUntil(',');                // Reserved1
 | 
			
		||||
      iaccuracy =
 | 
			
		||||
          streamGetFloatBefore(',');    // Horizontal Dilution Of Precision
 | 
			
		||||
      streamSkipUntil(',');             // Position Dilution Of Precision
 | 
			
		||||
      streamSkipUntil(',');             // Vertical Dilution Of Precision
 | 
			
		||||
      streamSkipUntil(',');             // Reserved2
 | 
			
		||||
      ivsat = streamGetIntBefore(',');  // GNSS Satellites in View
 | 
			
		||||
      iusat = streamGetIntBefore(',');  // GNSS Satellites Used
 | 
			
		||||
      streamSkipUntil(',');             // GLONASS Satellites Used
 | 
			
		||||
      streamSkipUntil(',');             // Reserved3
 | 
			
		||||
      streamSkipUntil(',');             // C/N0 max
 | 
			
		||||
      streamSkipUntil(',');             // HPA
 | 
			
		||||
      streamSkipUntil('\n');            // VPA
 | 
			
		||||
 | 
			
		||||
      // Set pointers
 | 
			
		||||
      if (lat != NULL) *lat = ilat;
 | 
			
		||||
      if (lon != NULL) *lon = ilon;
 | 
			
		||||
      if (speed != NULL) *speed = ispeed;
 | 
			
		||||
      if (alt != NULL) *alt = ialt;
 | 
			
		||||
      if (vsat != NULL) *vsat = ivsat;
 | 
			
		||||
      if (usat != NULL) *usat = iusat;
 | 
			
		||||
      if (accuracy != NULL) *accuracy = iaccuracy;
 | 
			
		||||
      if (iyear < 2000) iyear += 2000;
 | 
			
		||||
      if (year != NULL) *year = iyear;
 | 
			
		||||
      if (month != NULL) *month = imonth;
 | 
			
		||||
      if (day != NULL) *day = iday;
 | 
			
		||||
      if (hour != NULL) *hour = ihour;
 | 
			
		||||
      if (minute != NULL) *minute = imin;
 | 
			
		||||
      if (second != NULL) *second = static_cast<int>(secondWithSS);
 | 
			
		||||
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil('\n');  // toss the row of commas
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Time functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can follow CCLK as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -610,161 +286,106 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
 protected:
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux,
 | 
			
		||||
                    bool ssl = false, int timeout_s = 75) {
 | 
			
		||||
    if (ssl) { DBG("SSL only supported using application on SIM7000!"); }
 | 
			
		||||
    uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CACID="), mux);
 | 
			
		||||
    if (waitResponse(timeout_ms) != 1) return false;
 | 
			
		||||
 | 
			
		||||
    if (ssl) {
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"sslversion\",0,3"));  // TLS 1.2
 | 
			
		||||
      if (waitResponse() != 1) return false;
 | 
			
		||||
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"ctxindex\",0"));
 | 
			
		||||
      if (waitResponse() != 1) return false;
 | 
			
		||||
 | 
			
		||||
      if (certificates[mux] != "") {
 | 
			
		||||
        sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(),
 | 
			
		||||
               "\"");
 | 
			
		||||
        if (waitResponse() != 1) return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CASSLCFG="), mux, ',', GF("ssl,"), ssl);
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CASSLCFG="), mux, ',', GF("protocol,0"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CAOPEN="), mux, ',', GF("\""), host, GF("\","), port);
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { return 0; }
 | 
			
		||||
    streamSkipUntil(',');  // Skip mux
 | 
			
		||||
 | 
			
		||||
    int8_t res = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    return 0 == res;
 | 
			
		||||
    // when not using SSL, the TCP application toolkit is more stable
 | 
			
		||||
    sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host,
 | 
			
		||||
           GF("\","), port);
 | 
			
		||||
    return (1 ==
 | 
			
		||||
            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)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CASEND="), mux, ',', (uint16_t)len);
 | 
			
		||||
    sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) { return 0; }
 | 
			
		||||
 | 
			
		||||
    stream.write(reinterpret_cast<const uint8_t*>(buff), len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CASEND:")) != 1) { return 0; }
 | 
			
		||||
    streamSkipUntil(',');                            // Skip mux
 | 
			
		||||
    if (streamGetIntBefore(',') != 0) { return 0; }  // If result != success
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { return 0; }
 | 
			
		||||
    streamSkipUntil(',');  // Skip mux
 | 
			
		||||
    return streamGetIntBefore('\n');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CARECV="), mux, ',', (uint16_t)size);
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+CARECV:")) != 1) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stream.read();
 | 
			
		||||
    if (stream.peek() == '0') {
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int16_t len_confirmed = streamGetIntBefore(',');
 | 
			
		||||
    if (len_confirmed <= 0) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < len_confirmed; i++) {
 | 
			
		||||
#ifdef TINY_GSM_USE_HEX
 | 
			
		||||
    sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
 | 
			
		||||
    if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
 | 
			
		||||
#else
 | 
			
		||||
    sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
 | 
			
		||||
    if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
 | 
			
		||||
#endif
 | 
			
		||||
    streamSkipUntil(',');  // Skip Rx mode 2/normal or 3/HEX
 | 
			
		||||
    streamSkipUntil(',');  // Skip mux
 | 
			
		||||
    int16_t len_requested = streamGetIntBefore(',');
 | 
			
		||||
    //  ^^ Requested number of data bytes (1-1460 bytes)to be read
 | 
			
		||||
    int16_t len_confirmed = streamGetIntBefore('\n');
 | 
			
		||||
    // ^^ Confirmed number of data bytes to be read, which may be less than
 | 
			
		||||
    // requested. 0 indicates that no data can be read.
 | 
			
		||||
    // SRGD NOTE:  Contrary to above (which is copied from AT command manual)
 | 
			
		||||
    // this is actually be the number of bytes that will be remaining in the
 | 
			
		||||
    // buffer after the read.
 | 
			
		||||
    for (int i = 0; i < len_requested; i++) {
 | 
			
		||||
      uint32_t startMillis = millis();
 | 
			
		||||
#ifdef TINY_GSM_USE_HEX
 | 
			
		||||
      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();
 | 
			
		||||
      }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
#endif
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    // DBG("### READ:", len_requested, "from", mux);
 | 
			
		||||
    // sockets[mux]->sock_available = modemGetAvailable(mux);
 | 
			
		||||
    auto diff = int64_t(size) - int64_t(len_confirmed);
 | 
			
		||||
    if (diff < 0) diff = 0;
 | 
			
		||||
    sockets[mux]->sock_available = diff;
 | 
			
		||||
    sockets[mux]->sock_available = len_confirmed;
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return len_confirmed;
 | 
			
		||||
    return len_requested;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
 | 
			
		||||
    if (!sockets[mux]->sock_connected) {
 | 
			
		||||
      sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
    sendAT(GF("+CIPRXGET=4,"), mux);
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    if (waitResponse(GF("+CIPRXGET:")) == 1) {
 | 
			
		||||
      streamSkipUntil(',');  // Skip mode 4
 | 
			
		||||
      streamSkipUntil(',');  // Skip mux
 | 
			
		||||
      result = streamGetIntBefore('\n');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    if (!sockets[mux]->sock_connected) return 0;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CARECV?"));
 | 
			
		||||
 | 
			
		||||
    int8_t readMux = -1;
 | 
			
		||||
    size_t result  = 0;
 | 
			
		||||
    while (readMux != mux) {
 | 
			
		||||
      if (waitResponse(GF("+CARECV:")) != 1) {
 | 
			
		||||
        sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
        return 0;
 | 
			
		||||
      };
 | 
			
		||||
      readMux = streamGetIntBefore(',');
 | 
			
		||||
      result  = streamGetIntBefore('\n');
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // DBG("### Available:", result, "on", mux);
 | 
			
		||||
    if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CASTATE?"));
 | 
			
		||||
    int8_t readMux = -1;
 | 
			
		||||
    while (readMux != mux) {
 | 
			
		||||
      if (waitResponse(3000, GF("+CASTATE:"), GFP(GSM_OK)) != 1) { return 0; }
 | 
			
		||||
      readMux = streamGetIntBefore(',');
 | 
			
		||||
    }
 | 
			
		||||
    int8_t res = streamGetIntBefore('\n');
 | 
			
		||||
    sendAT(GF("+CIPSTATUS="), mux);
 | 
			
		||||
    waitResponse(GF("+CIPSTATUS"));
 | 
			
		||||
    int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
 | 
			
		||||
                              GF(",\"CLOSING\""), GF(",\"REMOTE CLOSING\""),
 | 
			
		||||
                              GF(",\"INITIAL\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return 1 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  bool modemGetConnected(const char* host, uint16_t port, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CAOPEN?"));
 | 
			
		||||
    int8_t readMux = -1;
 | 
			
		||||
    while (readMux != mux) {
 | 
			
		||||
      if (waitResponse(GF("+CAOPEN:")) != 1) return 0;
 | 
			
		||||
      readMux = streamGetIntBefore(',');
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil('\"');
 | 
			
		||||
 | 
			
		||||
    size_t hostLen = strlen(host);
 | 
			
		||||
 | 
			
		||||
    char buffer[hostLen];
 | 
			
		||||
    stream.readBytesUntil('\"', buffer, hostLen);
 | 
			
		||||
    streamSkipUntil(',');
 | 
			
		||||
    uint16_t connectedPort = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    bool samePort                = connectedPort == port;
 | 
			
		||||
    bool sameHost                = memcmp(buffer, host, hostLen) == 0;
 | 
			
		||||
    sockets[mux]->sock_connected = sameHost && samePort;
 | 
			
		||||
 | 
			
		||||
    return sockets[mux]->sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Utilities
 | 
			
		||||
   */
 | 
			
		||||
@@ -828,30 +449,6 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
          } else {
 | 
			
		||||
            data += mode;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CARECV:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore(',');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          // DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CADATAIND:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          // DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CASTATE:"))) {
 | 
			
		||||
          int8_t mux   = streamGetIntBefore(',');
 | 
			
		||||
          int8_t state = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            if (state != 1) {
 | 
			
		||||
              sockets[mux]->sock_connected = false;
 | 
			
		||||
              DBG("### Closed: ", mux);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
 | 
			
		||||
          int8_t  mux = streamGetIntBefore(',');
 | 
			
		||||
          int16_t len = streamGetIntBefore('\n');
 | 
			
		||||
@@ -887,6 +484,10 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
              '\n');  // Refresh Network Daylight Saving Time by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Daylight savings time state updated.");
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Unexpected module reset!");
 | 
			
		||||
          init();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout_ms);
 | 
			
		||||
@@ -926,13 +527,8 @@ class TinyGsmSim7000 : public TinyGsmModem<TinyGsmSim7000>,
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  Stream& stream;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  GsmClientSim7000* sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
  String            certificates[TINY_GSM_MUX_COUNT];
 | 
			
		||||
  const char*       gsmNL = GSM_NL;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // SRC_TINYGSMCLIENTSIM7000_H_
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										646
									
								
								src/TinyGsmClientSIM7000SSL.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								src/TinyGsmClientSIM7000SSL.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,646 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientSim7000SSL.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SRC_TINYGSMCLIENTSIM7000SSL_H_
 | 
			
		||||
#define SRC_TINYGSMCLIENTSIM7000SSL_H_
 | 
			
		||||
 | 
			
		||||
// #define TINY_GSM_DEBUG Serial
 | 
			
		||||
// #define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 2
 | 
			
		||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
 | 
			
		||||
 | 
			
		||||
#include "TinyGsmClientSIM70xx.h"
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmSSL.tpp"
 | 
			
		||||
 | 
			
		||||
class TinyGsmSim7000SSL
 | 
			
		||||
    : public TinyGsmSim70xx<TinyGsmSim7000SSL>,
 | 
			
		||||
      public TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>,
 | 
			
		||||
      public TinyGsmSSL<TinyGsmSim7000SSL> {
 | 
			
		||||
  friend class TinyGsmSim70xx<TinyGsmSim7000SSL>;
 | 
			
		||||
  friend class TinyGsmTCP<TinyGsmSim7000SSL, TINY_GSM_MUX_COUNT>;
 | 
			
		||||
  friend class TinyGsmSSL<TinyGsmSim7000SSL>;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Client
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  class GsmClientSim7000SSL : public GsmClient {
 | 
			
		||||
    friend class TinyGsmSim7000SSL;
 | 
			
		||||
 | 
			
		||||
   public:
 | 
			
		||||
    GsmClientSim7000SSL() {}
 | 
			
		||||
 | 
			
		||||
    explicit GsmClientSim7000SSL(TinyGsmSim7000SSL& modem, uint8_t mux = 0) {
 | 
			
		||||
      init(&modem, mux);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool init(TinyGsmSim7000SSL* modem, uint8_t mux = 0) {
 | 
			
		||||
      this->at       = modem;
 | 
			
		||||
      sock_available = 0;
 | 
			
		||||
      prev_check     = 0;
 | 
			
		||||
      sock_connected = false;
 | 
			
		||||
      got_data       = false;
 | 
			
		||||
 | 
			
		||||
      if (mux < TINY_GSM_MUX_COUNT) {
 | 
			
		||||
        this->mux = mux;
 | 
			
		||||
      } else {
 | 
			
		||||
        this->mux = (mux % TINY_GSM_MUX_COUNT);
 | 
			
		||||
      }
 | 
			
		||||
      at->sockets[this->mux] = this;
 | 
			
		||||
 | 
			
		||||
      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;
 | 
			
		||||
    }
 | 
			
		||||
    TINY_GSM_CLIENT_CONNECT_OVERRIDES
 | 
			
		||||
 | 
			
		||||
    void stop(uint32_t maxWaitMs) {
 | 
			
		||||
      dumpModemBuffer(maxWaitMs);
 | 
			
		||||
      at->sendAT(GF("+CACLOSE="), mux);
 | 
			
		||||
      sock_connected = false;
 | 
			
		||||
      at->waitResponse(3000);
 | 
			
		||||
    }
 | 
			
		||||
    void stop() override {
 | 
			
		||||
      stop(15000L);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Extended API
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Secure Client
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  class GsmClientSecureSIM7000SSL : public GsmClientSim7000SSL {
 | 
			
		||||
   public:
 | 
			
		||||
    GsmClientSecureSIM7000SSL() {}
 | 
			
		||||
 | 
			
		||||
    GsmClientSecureSIM7000SSL(TinyGsmSim7000SSL& modem, uint8_t mux = 0)
 | 
			
		||||
        : GsmClientSim7000SSL(modem, mux) {}
 | 
			
		||||
 | 
			
		||||
   public:
 | 
			
		||||
    bool setCertificate(const String& certificateName) {
 | 
			
		||||
      return at->setCertificate(certificateName, mux);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
    TINY_GSM_CLIENT_CONNECT_OVERRIDES
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Constructor
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  explicit TinyGsmSim7000SSL(Stream& stream)
 | 
			
		||||
      : TinyGsmSim70xx<TinyGsmSim7000SSL>(stream),
 | 
			
		||||
        certificates() {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool initImpl(const char* pin = NULL) {
 | 
			
		||||
    DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
 | 
			
		||||
    DBG(GF("### TinyGSM Compiled Module:  TinyGsmClientSIM7000SSL"));
 | 
			
		||||
 | 
			
		||||
    if (!testAT()) { 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; }
 | 
			
		||||
 | 
			
		||||
    // Enable battery checks
 | 
			
		||||
    sendAT(GF("+CBATCHK=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    SimStatus 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);
 | 
			
		||||
    } 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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
    sendAT(GF("+CNACT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
 | 
			
		||||
    streamSkipUntil('\"');
 | 
			
		||||
    String res = stream.readStringUntil('\"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Secure socket layer functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
 | 
			
		||||
    if (mux >= TINY_GSM_MUX_COUNT) return false;
 | 
			
		||||
    certificates[mux] = certificateName;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool gprsConnectImpl(const char* apn, const char* user = NULL,
 | 
			
		||||
                       const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the connection type to GPRS
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the APN
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the user name
 | 
			
		||||
    if (user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    // Set the password
 | 
			
		||||
    if (pwd && strlen(pwd) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Define the PDP context
 | 
			
		||||
    sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Attach to GPRS
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Activate the PDP context
 | 
			
		||||
    sendAT(GF("+CGACT=1,1"));
 | 
			
		||||
    waitResponse(60000L);
 | 
			
		||||
 | 
			
		||||
    // Open the definied GPRS bearer context
 | 
			
		||||
    sendAT(GF("+SAPBR=1,1"));
 | 
			
		||||
    waitResponse(85000L);
 | 
			
		||||
    // Query the GPRS bearer context status
 | 
			
		||||
    sendAT(GF("+SAPBR=2,1"));
 | 
			
		||||
    if (waitResponse(30000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the user name and password
 | 
			
		||||
    // AT+CNCFG=<ip_type>[,<APN>[,<usename>,<password>[,<authentication>]]]
 | 
			
		||||
    //<ip_type> 0: Dual PDN Stack
 | 
			
		||||
    //          1: Internet Protocol Version 4
 | 
			
		||||
    //          2: Internet Protocol Version 6
 | 
			
		||||
    //<authentication> 0: NONE
 | 
			
		||||
    //                 1: PAP
 | 
			
		||||
    //                 2: CHAP
 | 
			
		||||
    //                 3: PAP or CHAP
 | 
			
		||||
    if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+CNCFG=1,\""), apn, "\",\"", "\",\"", user, pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    } else if (user && strlen(user) > 0) {
 | 
			
		||||
      // Set the user name only
 | 
			
		||||
      sendAT(GF("+CNCFG=1,\""), apn, "\",\"", user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    } else {
 | 
			
		||||
      // Set the APN only
 | 
			
		||||
      sendAT(GF("+CNCFG=1,\""), apn, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Activate application network connection
 | 
			
		||||
    // This is for most other supported applications outside of the
 | 
			
		||||
    // TCP application toolkit (ie, SSL)
 | 
			
		||||
    // AT+CNACT=<mode>,<action>
 | 
			
		||||
    // <mode> 0: Deactive
 | 
			
		||||
    //        1: Active
 | 
			
		||||
    //        2: Auto Active
 | 
			
		||||
    int res    = 0;
 | 
			
		||||
    int ntries = 0;
 | 
			
		||||
    while (res != 1 && ntries < 5) {
 | 
			
		||||
      sendAT(GF("+CNACT=1,\""), apn, GF("\""));
 | 
			
		||||
      res = waitResponse(60000L, GF(GSM_NL "+APP PDP: ACTIVE"),
 | 
			
		||||
                         GF(GSM_NL "+APP PDP: DEACTIVE"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      ntries++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // return res == 1;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnectImpl() {
 | 
			
		||||
    // Shut down the general application TCP/IP connection
 | 
			
		||||
    // CNACT will close *all* open application connections
 | 
			
		||||
    sendAT(GF("+CNACT=0"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGATT=0"));  // Deactivate the bearer context
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all messaging functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPS/GNSS/GLONASS location functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Time functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can follow CCLK as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all battery functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * 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;
 | 
			
		||||
 | 
			
		||||
    // set the connection (mux) identifier to use
 | 
			
		||||
    sendAT(GF("+CACID="), mux);
 | 
			
		||||
    if (waitResponse(timeout_ms) != 1) return false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (ssl) {
 | 
			
		||||
      // set the ssl version
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"sslversion\",0,3"));  // TLS 1.2
 | 
			
		||||
      if (waitResponse(5000L) != 1) return false;
 | 
			
		||||
 | 
			
		||||
      // set the PDP context to apply SSL to
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"ctxindex\",0"));
 | 
			
		||||
      if (waitResponse(5000L, GF("+CSSLCFG:")) != 1) return false;
 | 
			
		||||
      streamSkipUntil('\n');  // read out the certificate information
 | 
			
		||||
      waitResponse();
 | 
			
		||||
 | 
			
		||||
      if (certificates[mux] != "") {
 | 
			
		||||
        // apply the correct certificate to the connection
 | 
			
		||||
        sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(),
 | 
			
		||||
               "\"");
 | 
			
		||||
        if (waitResponse(5000L) != 1) return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // enable or disable ssl
 | 
			
		||||
    sendAT(GF("+CASSLCFG="), mux, ',', GF("ssl,"), ssl);
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // set the protocol
 | 
			
		||||
    // 0:  TCP; 1: UDP
 | 
			
		||||
    sendAT(GF("+CASSLCFG="), mux, ',', GF("protocol,0"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // set the SSL SNI (server name indication)
 | 
			
		||||
    sendAT(GF("+CSSLCFG=\"sni\","), mux, ',', GF("\""), host, GF("\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // actually open the connection
 | 
			
		||||
    // AT+CAOPEN=<cid>[,<conn_type>],<server>,<port>
 | 
			
		||||
    // <cid> TCP/UDP identifier
 | 
			
		||||
    // <conn_type> "TCP" or "UDP"
 | 
			
		||||
    sendAT(GF("+CAOPEN="), mux, GF(",\"TCP\",\""), host, GF("\","), port);
 | 
			
		||||
    if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { return 0; }
 | 
			
		||||
    // returns OK/r/n/r/n+CAOPEN: <cid>,<result>
 | 
			
		||||
    // <result> 0: Success
 | 
			
		||||
    //          1: Socket error
 | 
			
		||||
    //          2: No memory
 | 
			
		||||
    //          3: Connection limit
 | 
			
		||||
    //          4: Parameter invalid
 | 
			
		||||
    //          6: Invalid IP address
 | 
			
		||||
    //          7: Not support the function
 | 
			
		||||
    //          12: Can’t bind the port
 | 
			
		||||
    //          13: Can’t listen the port
 | 
			
		||||
    //          20: Can’t resolv the host
 | 
			
		||||
    //          21: Network not active
 | 
			
		||||
    //          23: Remote refuse
 | 
			
		||||
    //          24: Certificate’s time expired
 | 
			
		||||
    //          25: Certificate’s common name does not match
 | 
			
		||||
    //          26: Certificate’s common name does not match and time expired
 | 
			
		||||
    //          27: Connect failed
 | 
			
		||||
    streamSkipUntil(',');  // Skip mux
 | 
			
		||||
 | 
			
		||||
    // make sure the connection really opened
 | 
			
		||||
    int8_t res = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    return 0 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CASEND="), mux, ',', (uint16_t)len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) { return 0; }
 | 
			
		||||
 | 
			
		||||
    stream.write(reinterpret_cast<const uint8_t*>(buff), len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CASEND:")) != 1) { return 0; }
 | 
			
		||||
    streamSkipUntil(',');                            // Skip mux
 | 
			
		||||
    if (streamGetIntBefore(',') != 0) { return 0; }  // If result != success
 | 
			
		||||
    return streamGetIntBefore('\n');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CARECV="), mux, ',', (uint16_t)size);
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+CARECV:")) != 1) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stream.read();
 | 
			
		||||
    if (stream.peek() == '0') {
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int16_t len_confirmed = streamGetIntBefore(',');
 | 
			
		||||
    if (len_confirmed <= 0) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < len_confirmed; i++) {
 | 
			
		||||
      uint32_t startMillis = millis();
 | 
			
		||||
      while (!stream.available() &&
 | 
			
		||||
             (millis() - startMillis < sockets[mux]->_timeout)) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    // DBG("### READ:", len_requested, "from", mux);
 | 
			
		||||
    // sockets[mux]->sock_available = modemGetAvailable(mux);
 | 
			
		||||
    auto diff = int64_t(size) - int64_t(len_confirmed);
 | 
			
		||||
    if (diff < 0) diff = 0;
 | 
			
		||||
    sockets[mux]->sock_available = diff;
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return len_confirmed;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CARECV?"));
 | 
			
		||||
 | 
			
		||||
    int8_t readMux = -1;
 | 
			
		||||
    size_t result  = 0;
 | 
			
		||||
    while (readMux != mux) {
 | 
			
		||||
      if (waitResponse(GF("+CARECV:")) != 1) {
 | 
			
		||||
        sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
        return 0;
 | 
			
		||||
      };
 | 
			
		||||
      readMux = streamGetIntBefore(',');
 | 
			
		||||
      result  = streamGetIntBefore('\n');
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    // DBG("### Available:", result, "on", mux);
 | 
			
		||||
    if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CASTATE?"));
 | 
			
		||||
    int8_t readMux = -1;
 | 
			
		||||
    while (readMux != mux) {
 | 
			
		||||
      if (waitResponse(3000, GF("+CASTATE:"), GFP(GSM_OK)) != 1) { return 0; }
 | 
			
		||||
      readMux = streamGetIntBefore(',');
 | 
			
		||||
    }
 | 
			
		||||
    int8_t res = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return 1 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Utilities
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  // TODO(vshymanskyy): Optimize this!
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, String& data,
 | 
			
		||||
                      GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    /*String r1s(r1); r1s.trim();
 | 
			
		||||
    String r2s(r2); r2s.trim();
 | 
			
		||||
    String r3s(r3); r3s.trim();
 | 
			
		||||
    String r4s(r4); r4s.trim();
 | 
			
		||||
    String r5s(r5); r5s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    uint8_t  index       = 0;
 | 
			
		||||
    uint32_t startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
        int8_t a = stream.read();
 | 
			
		||||
        if (a <= 0) continue;  // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += static_cast<char>(a);
 | 
			
		||||
        if (r1 && data.endsWith(r1)) {
 | 
			
		||||
          index = 1;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r2 && data.endsWith(r2)) {
 | 
			
		||||
          index = 2;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r3 && data.endsWith(r3)) {
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
          if (r3 == GFP(GSM_CME_ERROR)) {
 | 
			
		||||
            streamSkipUntil('\n');  // Read out the error
 | 
			
		||||
          }
 | 
			
		||||
#endif
 | 
			
		||||
          index = 3;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r4 && data.endsWith(r4)) {
 | 
			
		||||
          index = 4;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r5 && data.endsWith(r5)) {
 | 
			
		||||
          index = 5;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CARECV:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore(',');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CADATAIND:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CASTATE:"))) {
 | 
			
		||||
          int8_t mux   = streamGetIntBefore(',');
 | 
			
		||||
          int8_t state = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            if (state != 1) {
 | 
			
		||||
              sockets[mux]->sock_connected = false;
 | 
			
		||||
              DBG("### Closed: ", mux);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int8_t nl   = data.lastIndexOf(GSM_NL, data.length() - 8);
 | 
			
		||||
          int8_t coma = data.indexOf(',', nl + 2);
 | 
			
		||||
          int8_t mux  = data.substring(nl + 2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        } else if (data.endsWith(GF("*PSNWID:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh network name by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network name updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("*PSUTTZ:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh time and time zone by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network time and time zone updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("+CTZV:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh network time zone by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network time zone updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("DST: "))) {
 | 
			
		||||
          streamSkipUntil(
 | 
			
		||||
              '\n');  // Refresh Network Daylight Saving Time by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Daylight savings time state updated.");
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Unexpected module reset!");
 | 
			
		||||
          init();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout_ms);
 | 
			
		||||
  finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) { DBG("### Unhandled:", data); }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    // data.replace(GSM_NL, "/");
 | 
			
		||||
    // DBG('<', index, '>', data);
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  GsmClientSim7000SSL* sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
  String               certificates[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // SRC_TINYGSMCLIENTSIM7000SSL_H_
 | 
			
		||||
							
								
								
									
										676
									
								
								src/TinyGsmClientSIM70x0.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										676
									
								
								src/TinyGsmClientSIM70x0.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,676 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientSim70x0.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SRC_TINYGSMCLIENTSIM70X0_H_
 | 
			
		||||
#define SRC_TINYGSMCLIENTSIM70X0_H_
 | 
			
		||||
 | 
			
		||||
// #define TINY_GSM_DEBUG Serial
 | 
			
		||||
// #define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 12
 | 
			
		||||
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
 | 
			
		||||
 | 
			
		||||
#include "TinyGsmClientSIM70xx.h"
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmSSL.tpp"
 | 
			
		||||
 | 
			
		||||
class TinyGsmSim70x0 : public TinyGsmSim70xx<TinyGsmSim70x0>,
 | 
			
		||||
                       public TinyGsmTCP<TinyGsmSim70x0, TINY_GSM_MUX_COUNT>,
 | 
			
		||||
                       public TinyGsmSSL<TinyGsmSim70x0> {
 | 
			
		||||
  friend class TinyGsmSim70xx<TinyGsmSim70x0>;
 | 
			
		||||
  friend class TinyGsmTCP<TinyGsmSim70x0, TINY_GSM_MUX_COUNT>;
 | 
			
		||||
  friend class TinyGsmSSL<TinyGsmSim70x0>;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Client
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  class GsmClientSim70x0 : public GsmClient {
 | 
			
		||||
    friend class TinyGsmSim70x0;
 | 
			
		||||
 | 
			
		||||
   public:
 | 
			
		||||
    GsmClientSim70x0() {}
 | 
			
		||||
 | 
			
		||||
    explicit GsmClientSim70x0(TinyGsmSim70x0& modem, uint8_t mux = 0) {
 | 
			
		||||
      init(&modem, mux);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool init(TinyGsmSim70x0* modem, uint8_t mux = 0) {
 | 
			
		||||
      this->at       = modem;
 | 
			
		||||
      sock_available = 0;
 | 
			
		||||
      prev_check     = 0;
 | 
			
		||||
      sock_connected = false;
 | 
			
		||||
      got_data       = false;
 | 
			
		||||
 | 
			
		||||
      if (mux < TINY_GSM_MUX_COUNT) {
 | 
			
		||||
        this->mux = mux;
 | 
			
		||||
      } else {
 | 
			
		||||
        this->mux = (mux % TINY_GSM_MUX_COUNT);
 | 
			
		||||
      }
 | 
			
		||||
      at->sockets[this->mux] = this;
 | 
			
		||||
 | 
			
		||||
      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;
 | 
			
		||||
    }
 | 
			
		||||
    TINY_GSM_CLIENT_CONNECT_OVERRIDES
 | 
			
		||||
 | 
			
		||||
    void stop(uint32_t maxWaitMs) {
 | 
			
		||||
      dumpModemBuffer(maxWaitMs);
 | 
			
		||||
      at->sendAT(GF("+CACLOSE="), mux);
 | 
			
		||||
      sock_connected = false;
 | 
			
		||||
      at->waitResponse(3000);
 | 
			
		||||
    }
 | 
			
		||||
    void stop() override {
 | 
			
		||||
      stop(15000L);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Extended API
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Inner Secure Client
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  class GsmClientSecureSIM70x0 : public GsmClientSim70x0 {
 | 
			
		||||
   public:
 | 
			
		||||
    GsmClientSecureSIM70x0() {}
 | 
			
		||||
 | 
			
		||||
    GsmClientSecureSIM70x0(TinyGsmSim70x0& modem, uint8_t mux = 0)
 | 
			
		||||
        : GsmClientSim70x0(modem, mux) {}
 | 
			
		||||
 | 
			
		||||
   public:
 | 
			
		||||
    bool setCertificate(const String& certificateName) {
 | 
			
		||||
      return at->setCertificate(certificateName, mux);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
    TINY_GSM_CLIENT_CONNECT_OVERRIDES
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Constructor
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  explicit TinyGsmSim70x0(Stream& stream)
 | 
			
		||||
      : TinyGsmSim70xx<TinyGsmSim70x0>(stream),
 | 
			
		||||
        certificates() {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool initImpl(const char* pin = NULL) {
 | 
			
		||||
    DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
 | 
			
		||||
    DBG(GF("### TinyGSM Compiled Module:  TinyGsmClientSIM70x0"));
 | 
			
		||||
 | 
			
		||||
    if (!testAT()) { 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; }
 | 
			
		||||
 | 
			
		||||
    // Enable battery checks
 | 
			
		||||
    sendAT(GF("+CBATCHK=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    SimStatus 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);
 | 
			
		||||
    } 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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
    sendAT(GF("+CNACT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNACT:")) != 1) { return ""; }
 | 
			
		||||
    streamSkipUntil('\"');
 | 
			
		||||
    String res = stream.readStringUntil('\"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Secure socket layer functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool setCertificate(const String& certificateName, const uint8_t mux = 0) {
 | 
			
		||||
    if (mux >= TINY_GSM_MUX_COUNT) return false;
 | 
			
		||||
    certificates[mux] = certificateName;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool gprsConnectImpl(const char* apn, const char* user = NULL,
 | 
			
		||||
                       const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the connection type to GPRS
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the APN
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the user name
 | 
			
		||||
    if (user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    // Set the password
 | 
			
		||||
    if (pwd && strlen(pwd) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Define the PDP context
 | 
			
		||||
    sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Attach to GPRS
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Activate the PDP context
 | 
			
		||||
    sendAT(GF("+CGACT=1,1"));
 | 
			
		||||
    waitResponse(60000L);
 | 
			
		||||
 | 
			
		||||
    // Open the definied GPRS bearer context
 | 
			
		||||
    sendAT(GF("+SAPBR=1,1"));
 | 
			
		||||
    waitResponse(85000L);
 | 
			
		||||
    // Query the GPRS bearer context status
 | 
			
		||||
    sendAT(GF("+SAPBR=2,1"));
 | 
			
		||||
    if (waitResponse(30000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the user name and password
 | 
			
		||||
    // AT+CNCFG=<pdpidx>,<ip_type>,[<APN>,[<usename>,<password>,[<authentication>]]]
 | 
			
		||||
    // <pdpidx> PDP Context Identifier (1 is setup above)
 | 
			
		||||
    // <ip_type> 0: Dual PDN Stack
 | 
			
		||||
    //           1: Internet Protocol Version 4
 | 
			
		||||
    //           2: Internet Protocol Version 6
 | 
			
		||||
    // <authentication> 0: NONE
 | 
			
		||||
    //                  1: PAP
 | 
			
		||||
    //                  2: CHAP
 | 
			
		||||
    //                  3: PAP or CHAP
 | 
			
		||||
    if (pwd && strlen(pwd) > 0 && user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+CNCFG=1,1,\""), apn, "\",\"", "\",\"", user, pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    } else if (user && strlen(user) > 0) {
 | 
			
		||||
      // Set the user name only
 | 
			
		||||
      sendAT(GF("+CNCFG=1,1,\""), apn, "\",\"", user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    } else {
 | 
			
		||||
      // Set the APN only
 | 
			
		||||
      sendAT(GF("+CNCFG=1,1,\""), apn, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Activate application network connection
 | 
			
		||||
    // This is for most other supported applications outside of the
 | 
			
		||||
    // TCP application toolkit (ie, SSL)
 | 
			
		||||
    // AT+CNACT=<pdpidx>,<action>
 | 
			
		||||
    // <pdpidx> PDP Context Identifier (1 is setup above)
 | 
			
		||||
    // <action> 0: Deactive
 | 
			
		||||
    //          1: Active
 | 
			
		||||
    //          2: Auto Active
 | 
			
		||||
    int res    = 0;
 | 
			
		||||
    int ntries = 0;
 | 
			
		||||
    while (res != 1 && ntries < 5) {
 | 
			
		||||
      sendAT(GF("+CNACT=1,1,\""), apn, GF("\""));
 | 
			
		||||
      res = waitResponse(60000L, GF(GSM_NL "+APP PDP: ACTIVE"),
 | 
			
		||||
                         GF(GSM_NL "+APP PDP: DEACTIVE"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      ntries++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // return res == 1;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnectImpl() {
 | 
			
		||||
    // Shut down the general application TCP/IP connection
 | 
			
		||||
    // CNACT will close *all* open application connections
 | 
			
		||||
    sendAT(GF("+CNACT=1,0"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGATT=0"));  // Deactivate the bearer context
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all messaging functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPS/GNSS/GLONASS location functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows the SIM70xx template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Time functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can follow CCLK as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all battery functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * 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;
 | 
			
		||||
 | 
			
		||||
    // set the connection (mux) identifier to use
 | 
			
		||||
    sendAT(GF("+CACID="), mux);
 | 
			
		||||
    if (waitResponse(timeout_ms) != 1) return false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (ssl) {
 | 
			
		||||
      // set the ssl version
 | 
			
		||||
      // AT+CSSLCFG="SSLVERSION",<ctxindex>,<sslversion>
 | 
			
		||||
      // <ctxindex> PDP context identifier
 | 
			
		||||
      // <sslversion> 0: QAPI_NET_SSL_PROTOCOL_UNKNOWN
 | 
			
		||||
      //              1: QAPI_NET_SSL_PROTOCOL_TLS_1_0
 | 
			
		||||
      //              2: QAPI_NET_SSL_PROTOCOL_TLS_1_1
 | 
			
		||||
      //              3: QAPI_NET_SSL_PROTOCOL_TLS_1_2
 | 
			
		||||
      //              4: QAPI_NET_SSL_PROTOCOL_DTLS_1_0
 | 
			
		||||
      //              5: QAPI_NET_SSL_PROTOCOL_DTLS_1_2
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"SSLVERSION\",0,3"));  // TLS 1.2
 | 
			
		||||
      if (waitResponse(5000L) != 1) return false;
 | 
			
		||||
 | 
			
		||||
      // set the PDP context to apply SSL to
 | 
			
		||||
      // AT+CSSLCFG="CTXINDEX",<ctxindex>
 | 
			
		||||
      // <ctxindex> PDP context identifier
 | 
			
		||||
      sendAT(GF("+CSSLCFG=\"CTXINDEX\",0"));
 | 
			
		||||
      if (waitResponse(5000L, GF("+CSSLCFG:")) != 1) return false;
 | 
			
		||||
      streamSkipUntil('\n');  // read out the certificate information
 | 
			
		||||
      waitResponse();
 | 
			
		||||
 | 
			
		||||
      if (certificates[mux] != "") {
 | 
			
		||||
        // apply the correct certificate to the connection
 | 
			
		||||
        // AT+CASSLCFG=<cid>,"CACERT",<caname>
 | 
			
		||||
        // <cid> Application connection ID (set with AT+CACID above)
 | 
			
		||||
        // <certname> certificate name
 | 
			
		||||
        sendAT(GF("+CASSLCFG="), mux, ",CACERT,\"", certificates[mux].c_str(),
 | 
			
		||||
               "\"");
 | 
			
		||||
        if (waitResponse(5000L) != 1) return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // enable or disable ssl
 | 
			
		||||
    // AT+CASSLCFG=<cid>,"SSL",<sslFlag>
 | 
			
		||||
    // <cid> Application connection ID (set with AT+CACID above)
 | 
			
		||||
    // <sslFlag> 0: Not support SSL
 | 
			
		||||
    //           1: Support SSL
 | 
			
		||||
    sendAT(GF("+CASSLCFG="), mux, ',', GF("SSL,"), ssl);
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // set the SSL SNI (server name indication)
 | 
			
		||||
    sendAT(GF("+CSSLCFG=\"SNI\","), mux, ',', GF("\""), host, GF("\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // actually open the connection
 | 
			
		||||
    // AT+CAOPEN=<cid>,<pdp_index>,<conn_type>,<server>,<port>[,<recv_mode>]
 | 
			
		||||
    // <cid> TCP/UDP identifier
 | 
			
		||||
    // <pdp_index> Index of PDP connection; we set up PCP context 1 above
 | 
			
		||||
    // <conn_type> "TCP" or "UDP"
 | 
			
		||||
    // <recv_mode> 0: The received data can only be read manually using
 | 
			
		||||
    // AT+CARECV=<cid>
 | 
			
		||||
    //             1: After receiving the data, it will automatically report
 | 
			
		||||
    //             URC:
 | 
			
		||||
    //                +CAURC:
 | 
			
		||||
    //                "recv",<id>,<length>,<remoteIP>,<remote_port><CR><LF><data>
 | 
			
		||||
    sendAT(GF("+CAOPEN="), mux, GF(",0,\"TCP\",\""), host, GF("\","), port, ',',
 | 
			
		||||
           0);
 | 
			
		||||
    if (waitResponse(timeout_ms, GF(GSM_NL "+CAOPEN:")) != 1) { return 0; }
 | 
			
		||||
    // returns OK/r/n/r/n+CAOPEN: <cid>,<result>
 | 
			
		||||
    // <result> 0: Success
 | 
			
		||||
    //          1: Socket error
 | 
			
		||||
    //          2: No memory
 | 
			
		||||
    //          3: Connection limit
 | 
			
		||||
    //          4: Parameter invalid
 | 
			
		||||
    //          6: Invalid IP address
 | 
			
		||||
    //          7: Not support the function
 | 
			
		||||
    //          12: Can’t bind the port
 | 
			
		||||
    //          13: Can’t listen the port
 | 
			
		||||
    //          20: Can’t resolve the host
 | 
			
		||||
    //          21: Network not active
 | 
			
		||||
    //          23: Remote refuse
 | 
			
		||||
    //          24: Certificate’s time expired
 | 
			
		||||
    //          25: Certificate’s common name does not match
 | 
			
		||||
    //          26: Certificate’s common name does not match and time expired
 | 
			
		||||
    //          27: Connect failed
 | 
			
		||||
    streamSkipUntil(',');  // Skip mux
 | 
			
		||||
 | 
			
		||||
    // make sure the connection really opened
 | 
			
		||||
    int8_t res = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    return 0 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+CASEND="), mux, ',', (uint16_t)len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) { return 0; }
 | 
			
		||||
 | 
			
		||||
    stream.write(reinterpret_cast<const uint8_t*>(buff), len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CASEND:")) != 1) { return 0; }
 | 
			
		||||
    streamSkipUntil(',');                            // Skip mux
 | 
			
		||||
    if (streamGetIntBefore(',') != 0) { return 0; }  // If result != success
 | 
			
		||||
    return streamGetIntBefore('\n');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CARECV="), mux, ',', (uint16_t)size);
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+CARECV:")) != 1) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stream.read();
 | 
			
		||||
    if (stream.peek() == '0') {
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int16_t len_confirmed = streamGetIntBefore(',');
 | 
			
		||||
    if (len_confirmed <= 0) {
 | 
			
		||||
      sockets[mux]->sock_available = 0;
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < len_confirmed; i++) {
 | 
			
		||||
      uint32_t startMillis = millis();
 | 
			
		||||
      while (!stream.available() &&
 | 
			
		||||
             (millis() - startMillis < sockets[mux]->_timeout)) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    // DBG("### READ:", len_requested, "from", mux);
 | 
			
		||||
    // sockets[mux]->sock_available = modemGetAvailable(mux);
 | 
			
		||||
    auto diff = int64_t(size) - int64_t(len_confirmed);
 | 
			
		||||
    if (diff < 0) diff = 0;
 | 
			
		||||
    sockets[mux]->sock_available = diff;
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return len_confirmed;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    // NOTE: This gets how many characters are available on all connections
 | 
			
		||||
    sendAT(GF("+CARECV?"));
 | 
			
		||||
    for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
 | 
			
		||||
      if (waitResponse(3000, GF(GSM_NL "+CARECV: ")) != 1) { break; }
 | 
			
		||||
      size_t result = 0;
 | 
			
		||||
      // if (streamGetIntBefore(',') != muxNo) { // check the mux no
 | 
			
		||||
      //   DBG("### Warning: misaligned mux numbers!");
 | 
			
		||||
      // }
 | 
			
		||||
      streamSkipUntil(',');  // skip mux [use muxNo]
 | 
			
		||||
      result                 = streamGetIntBefore('\n');
 | 
			
		||||
      GsmClientSim70x0* sock = sockets[mux];
 | 
			
		||||
      if (sock && muxNo == mux) { sock->sock_available = result; }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();  // Should be an OK at the end
 | 
			
		||||
    modemGetConnected(mux);
 | 
			
		||||
    if (!sockets[mux]) return 0;
 | 
			
		||||
    return sockets[mux]->sock_available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    // NOTE:  This gets the state of all connections
 | 
			
		||||
    sendAT(GF("+CASTATE?"));
 | 
			
		||||
 | 
			
		||||
    for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
 | 
			
		||||
      if (waitResponse(3000, GF(GSM_NL "+CASTATE: ")) != 1) { break; }
 | 
			
		||||
      uint8_t status = 0;
 | 
			
		||||
      // if (streamGetIntBefore(',') != muxNo) { // check the mux no
 | 
			
		||||
      //   DBG("### Warning: misaligned mux numbers!");
 | 
			
		||||
      // }
 | 
			
		||||
      streamSkipUntil(',');        // skip mux [use muxNo]
 | 
			
		||||
      status = stream.parseInt();  // Read the status
 | 
			
		||||
      // 0: Closed by remote server or internal error
 | 
			
		||||
      // 1: Connected to remote server
 | 
			
		||||
      // 2: Listening (server mode)
 | 
			
		||||
      GsmClientSim70x0* sock = sockets[mux];
 | 
			
		||||
      if (sock && muxNo == mux) { sock->sock_connected = (status == 1); }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();  // Should be an OK at the end
 | 
			
		||||
    return sockets[mux]->sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Utilities
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  // TODO(vshymanskyy): Optimize this!
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, String& data,
 | 
			
		||||
                      GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    /*String r1s(r1); r1s.trim();
 | 
			
		||||
    String r2s(r2); r2s.trim();
 | 
			
		||||
    String r3s(r3); r3s.trim();
 | 
			
		||||
    String r4s(r4); r4s.trim();
 | 
			
		||||
    String r5s(r5); r5s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    uint8_t  index       = 0;
 | 
			
		||||
    uint32_t startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
        int8_t a = stream.read();
 | 
			
		||||
        if (a <= 0) continue;  // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += static_cast<char>(a);
 | 
			
		||||
        if (r1 && data.endsWith(r1)) {
 | 
			
		||||
          index = 1;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r2 && data.endsWith(r2)) {
 | 
			
		||||
          index = 2;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r3 && data.endsWith(r3)) {
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
          if (r3 == GFP(GSM_CME_ERROR)) {
 | 
			
		||||
            streamSkipUntil('\n');  // Read out the error
 | 
			
		||||
          }
 | 
			
		||||
#endif
 | 
			
		||||
          index = 3;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r4 && data.endsWith(r4)) {
 | 
			
		||||
          index = 4;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (r5 && data.endsWith(r5)) {
 | 
			
		||||
          index = 5;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CARECV:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore(',');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CADATAIND:"))) {
 | 
			
		||||
          int8_t mux = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+CASTATE:"))) {
 | 
			
		||||
          int8_t mux   = streamGetIntBefore(',');
 | 
			
		||||
          int8_t state = streamGetIntBefore('\n');
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            if (state != 1) {
 | 
			
		||||
              sockets[mux]->sock_connected = false;
 | 
			
		||||
              DBG("### Closed: ", mux);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int8_t nl   = data.lastIndexOf(GSM_NL, data.length() - 8);
 | 
			
		||||
          int8_t coma = data.indexOf(',', nl + 2);
 | 
			
		||||
          int8_t mux  = data.substring(nl + 2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        } else if (data.endsWith(GF("*PSNWID:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh network name by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network name updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("*PSUTTZ:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh time and time zone by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network time and time zone updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("+CTZV:"))) {
 | 
			
		||||
          streamSkipUntil('\n');  // Refresh network time zone by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Network time zone updated.");
 | 
			
		||||
        } else if (data.endsWith(GF("DST: "))) {
 | 
			
		||||
          streamSkipUntil(
 | 
			
		||||
              '\n');  // Refresh Network Daylight Saving Time by network
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Daylight savings time state updated.");
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "SMS Ready" GSM_NL))) {
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Unexpected module reset!");
 | 
			
		||||
          init();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout_ms);
 | 
			
		||||
  finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) { DBG("### Unhandled:", data); }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    // data.replace(GSM_NL, "/");
 | 
			
		||||
    // DBG('<', index, '>', data);
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  GsmClientSim70x0* sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
  String            certificates[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // SRC_TINYGSMCLIENTSIM70X0_H_
 | 
			
		||||
							
								
								
									
										456
									
								
								src/TinyGsmClientSIM70xx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										456
									
								
								src/TinyGsmClientSIM70xx.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,456 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientSIM70xx.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SRC_TINYGSMCLIENTSIM70XX_H_
 | 
			
		||||
#define SRC_TINYGSMCLIENTSIM70XX_H_
 | 
			
		||||
 | 
			
		||||
// #define TINY_GSM_DEBUG Serial
 | 
			
		||||
// #define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#include "TinyGsmBattery.tpp"
 | 
			
		||||
#include "TinyGsmGPRS.tpp"
 | 
			
		||||
#include "TinyGsmGPS.tpp"
 | 
			
		||||
#include "TinyGsmModem.tpp"
 | 
			
		||||
#include "TinyGsmSMS.tpp"
 | 
			
		||||
#include "TinyGsmTime.tpp"
 | 
			
		||||
#include "TinyGsmNTP.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;
 | 
			
		||||
#if defined       TINY_GSM_DEBUG
 | 
			
		||||
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
 | 
			
		||||
static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_NO_RESULT    = -1,
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class modemType>
 | 
			
		||||
class TinyGsmSim70xx : public TinyGsmModem<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmGPRS<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmSMS<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmGPS<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmTime<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmNTP<TinyGsmSim70xx<modemType>>,
 | 
			
		||||
                       public TinyGsmBattery<TinyGsmSim70xx<modemType>> {
 | 
			
		||||
  friend class TinyGsmModem<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmGPRS<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmSMS<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmGPS<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmNTP<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmSim70xx<modemType>>;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * CRTP Helper
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  inline const modemType& thisModem() const {
 | 
			
		||||
    return static_cast<const modemType&>(*this);
 | 
			
		||||
  }
 | 
			
		||||
  inline modemType& thisModem() {
 | 
			
		||||
    return static_cast<modemType&>(*this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Constructor
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  explicit TinyGsmSim70xx(Stream& stream) : stream(stream) {}
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool initImpl(const char* pin = NULL) {
 | 
			
		||||
    return thisModem().initImpl(pin);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemNameImpl() {
 | 
			
		||||
    String name = "SIMCom SIM7000";
 | 
			
		||||
 | 
			
		||||
    thisModem().sendAT(GF("+GMM"));
 | 
			
		||||
    String res2;
 | 
			
		||||
    if (thisModem().waitResponse(5000L, res2) != 1) { return name; }
 | 
			
		||||
    res2.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res2.replace("_", " ");
 | 
			
		||||
    res2.trim();
 | 
			
		||||
 | 
			
		||||
    name = res2;
 | 
			
		||||
    return name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefaultImpl() {           // these commands aren't supported
 | 
			
		||||
    thisModem().sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    thisModem().sendAT(GF("+IPR=0"));  // Auto-baud
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    thisModem().sendAT(GF("+IFC=0,0"));  // No Flow Control
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    thisModem().sendAT(GF("+ICF=3,3"));  // 8 data 0 parity 1 stop
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    thisModem().sendAT(GF("+CSCLK=0"));  // Disable Slow Clock
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    thisModem().sendAT(GF("&W"));  // Write configuration
 | 
			
		||||
    return thisModem().waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  bool restartImpl(const char* pin = NULL) {
 | 
			
		||||
    thisModem().sendAT(GF("E0"));  // Echo Off
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    if (!thisModem().setPhoneFunctionality(0)) { return false; }
 | 
			
		||||
    if (!thisModem().setPhoneFunctionality(1, true)) { return false; }
 | 
			
		||||
    thisModem().waitResponse(30000L, GF("SMS Ready"));
 | 
			
		||||
    return thisModem().initImpl(pin);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool powerOffImpl() {
 | 
			
		||||
    thisModem().sendAT(GF("+CPOWD=1"));
 | 
			
		||||
    return thisModem().waitResponse(GF("NORMAL POWER DOWN")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // During sleep, the SIM70xx module has its serial communication disabled.
 | 
			
		||||
  // In order to reestablish communication pull the DRT-pin of the SIM70xx
 | 
			
		||||
  // 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) {
 | 
			
		||||
    thisModem().sendAT(GF("+CSCLK="), enable);
 | 
			
		||||
    return thisModem().waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
 | 
			
		||||
    thisModem().sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
 | 
			
		||||
    return thisModem().waitResponse(10000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    RegStatus epsStatus =
 | 
			
		||||
        (RegStatus)thisModem().getRegistrationStatusXREG("CEREG");
 | 
			
		||||
    // If we're connected on EPS, great!
 | 
			
		||||
    if (epsStatus == REG_OK_HOME || epsStatus == REG_OK_ROAMING) {
 | 
			
		||||
      return epsStatus;
 | 
			
		||||
    } else {
 | 
			
		||||
      // Otherwise, check GPRS network status
 | 
			
		||||
      // We could be using GPRS fall-back or the board could be being moody
 | 
			
		||||
      return (RegStatus)thisModem().getRegistrationStatusXREG("CGREG");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  bool isNetworkConnectedImpl() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  String getNetworkModes() {
 | 
			
		||||
    // Get the help string, not the setting value
 | 
			
		||||
    thisModem().sendAT(GF("+CNMP=?"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int16_t getNetworkMode() {
 | 
			
		||||
    thisModem().sendAT(GF("+CNMP?"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
 | 
			
		||||
    int16_t mode = thisModem().streamGetIntBefore('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return mode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setNetworkMode(uint8_t mode) {
 | 
			
		||||
    // 2 Automatic
 | 
			
		||||
    // 13 GSM only
 | 
			
		||||
    // 38 LTE only
 | 
			
		||||
    // 51 GSM and LTE only
 | 
			
		||||
    thisModem().sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    return thisModem().waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getPreferredModes() {
 | 
			
		||||
    // Get the help string, not the setting value
 | 
			
		||||
    thisModem().sendAT(GF("+CMNB=?"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int16_t getPreferredMode() {
 | 
			
		||||
    thisModem().sendAT(GF("+CMNB?"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL "+CMNB:")) != 1) { return false; }
 | 
			
		||||
    int16_t mode = thisModem().streamGetIntBefore('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return mode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setPreferredMode(uint8_t mode) {
 | 
			
		||||
    // 1 CAT-M
 | 
			
		||||
    // 2 NB-IoT
 | 
			
		||||
    // 3 CAT-M and NB-IoT
 | 
			
		||||
    thisModem().sendAT(GF("+CMNB="), mode);
 | 
			
		||||
    return thisModem().waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool getNetworkSystemMode(bool& n, int16_t& stat) {
 | 
			
		||||
    // n: whether to automatically report the system mode info
 | 
			
		||||
    // stat: the current service. 0 if it not connected
 | 
			
		||||
    thisModem().sendAT(GF("+CNSMOD?"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL "+CNSMOD:")) != 1) { return false; }
 | 
			
		||||
    n    = thisModem().streamGetIntBefore(',') != 0;
 | 
			
		||||
    stat = thisModem().streamGetIntBefore('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setNetworkSystemMode(bool n) {
 | 
			
		||||
    // n: whether to automatically report the system mode info
 | 
			
		||||
    thisModem().sendAT(GF("+CNSMOD="), int8_t(n));
 | 
			
		||||
    return thisModem().waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
    return thisModem().getLocalIPImpl();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // should implement in sub-classes
 | 
			
		||||
  bool gprsConnectImpl(const char* apn, const char* user = NULL,
 | 
			
		||||
                       const char* pwd = NULL) {
 | 
			
		||||
    return thisModem().gprsConnectImpl(apn, user, pwd);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnectImpl() {
 | 
			
		||||
    return thisModem().gprsDisconnectImpl();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Doesn't return the "+CCID" before the number
 | 
			
		||||
  String getSimCCIDImpl() {
 | 
			
		||||
    thisModem().sendAT(GF("+CCID"));
 | 
			
		||||
    if (thisModem().waitResponse(GF(GSM_NL)) != 1) { return ""; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all messaging functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPS/GNSS/GLONASS location functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // enable GPS
 | 
			
		||||
  bool enableGPSImpl() {
 | 
			
		||||
    thisModem().sendAT(GF("+CGNSPWR=1"));
 | 
			
		||||
    if (thisModem().waitResponse() != 1) { return false; }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool disableGPSImpl() {
 | 
			
		||||
    thisModem().sendAT(GF("+CGNSPWR=0"));
 | 
			
		||||
    if (thisModem().waitResponse() != 1) { return false; }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // get the RAW GPS output
 | 
			
		||||
  String getGPSrawImpl() {
 | 
			
		||||
    thisModem().sendAT(GF("+CGNSINF"));
 | 
			
		||||
    if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // get GPS informations
 | 
			
		||||
  bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
 | 
			
		||||
                  int* vsat = 0, int* usat = 0, float* accuracy = 0,
 | 
			
		||||
                  int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
 | 
			
		||||
                  int* minute = 0, int* second = 0) {
 | 
			
		||||
    thisModem().sendAT(GF("+CGNSINF"));
 | 
			
		||||
    if (thisModem().waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    thisModem().streamSkipUntil(',');                // GNSS run status
 | 
			
		||||
    if (thisModem().streamGetIntBefore(',') == 1) {  // fix status
 | 
			
		||||
      // init variables
 | 
			
		||||
      float ilat         = 0;
 | 
			
		||||
      float ilon         = 0;
 | 
			
		||||
      float ispeed       = 0;
 | 
			
		||||
      float ialt         = 0;
 | 
			
		||||
      int   ivsat        = 0;
 | 
			
		||||
      int   iusat        = 0;
 | 
			
		||||
      float iaccuracy    = 0;
 | 
			
		||||
      int   iyear        = 0;
 | 
			
		||||
      int   imonth       = 0;
 | 
			
		||||
      int   iday         = 0;
 | 
			
		||||
      int   ihour        = 0;
 | 
			
		||||
      int   imin         = 0;
 | 
			
		||||
      float secondWithSS = 0;
 | 
			
		||||
 | 
			
		||||
      // UTC date & Time
 | 
			
		||||
      iyear        = thisModem().streamGetIntLength(4);  // Four digit year
 | 
			
		||||
      imonth       = thisModem().streamGetIntLength(2);  // Two digit month
 | 
			
		||||
      iday         = thisModem().streamGetIntLength(2);  // Two digit day
 | 
			
		||||
      ihour        = thisModem().streamGetIntLength(2);  // Two digit hour
 | 
			
		||||
      imin         = thisModem().streamGetIntLength(2);  // Two digit minute
 | 
			
		||||
      secondWithSS = thisModem().streamGetFloatBefore(
 | 
			
		||||
          ',');  // 6 digit second with subseconds
 | 
			
		||||
 | 
			
		||||
      ilat = thisModem().streamGetFloatBefore(',');  // Latitude
 | 
			
		||||
      ilon = thisModem().streamGetFloatBefore(',');  // Longitude
 | 
			
		||||
      ialt = thisModem().streamGetFloatBefore(
 | 
			
		||||
          ',');  // MSL Altitude. Unit is meters
 | 
			
		||||
      ispeed = thisModem().streamGetFloatBefore(
 | 
			
		||||
          ',');                          // Speed Over Ground. Unit is knots.
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Course Over Ground. Degrees.
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Fix Mode
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Reserved1
 | 
			
		||||
      iaccuracy = thisModem().streamGetFloatBefore(
 | 
			
		||||
          ',');                          // Horizontal Dilution Of Precision
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Position Dilution Of Precision
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Vertical Dilution Of Precision
 | 
			
		||||
      thisModem().streamSkipUntil(',');  // Reserved2
 | 
			
		||||
      ivsat = thisModem().streamGetIntBefore(',');  // GNSS Satellites in View
 | 
			
		||||
      iusat = thisModem().streamGetIntBefore(',');  // GNSS Satellites Used
 | 
			
		||||
      thisModem().streamSkipUntil(',');             // GLONASS Satellites Used
 | 
			
		||||
      thisModem().streamSkipUntil(',');             // Reserved3
 | 
			
		||||
      thisModem().streamSkipUntil(',');             // C/N0 max
 | 
			
		||||
      thisModem().streamSkipUntil(',');             // HPA
 | 
			
		||||
      thisModem().streamSkipUntil('\n');            // VPA
 | 
			
		||||
 | 
			
		||||
      // Set pointers
 | 
			
		||||
      if (lat != NULL) *lat = ilat;
 | 
			
		||||
      if (lon != NULL) *lon = ilon;
 | 
			
		||||
      if (speed != NULL) *speed = ispeed;
 | 
			
		||||
      if (alt != NULL) *alt = ialt;
 | 
			
		||||
      if (vsat != NULL) *vsat = ivsat;
 | 
			
		||||
      if (usat != NULL) *usat = iusat;
 | 
			
		||||
      if (accuracy != NULL) *accuracy = iaccuracy;
 | 
			
		||||
      if (iyear < 2000) iyear += 2000;
 | 
			
		||||
      if (year != NULL) *year = iyear;
 | 
			
		||||
      if (month != NULL) *month = imonth;
 | 
			
		||||
      if (day != NULL) *day = iday;
 | 
			
		||||
      if (hour != NULL) *hour = ihour;
 | 
			
		||||
      if (minute != NULL) *minute = imin;
 | 
			
		||||
      if (second != NULL) *second = static_cast<int>(secondWithSS);
 | 
			
		||||
 | 
			
		||||
      thisModem().waitResponse();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    thisModem().streamSkipUntil('\n');  // toss the row of commas
 | 
			
		||||
    thisModem().waitResponse();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Time functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can follow CCLK as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  // Follows all battery functions per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
  // should implement in sub-classes
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Utilities
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  // should implement in sub-classes
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, String& data,
 | 
			
		||||
                      GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    String data;
 | 
			
		||||
    return thisModem().waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
 | 
			
		||||
                      GsmConstStr r2 = GFP(GSM_ERROR),
 | 
			
		||||
#if defined TINY_GSM_DEBUG
 | 
			
		||||
                      GsmConstStr r3 = GFP(GSM_CME_ERROR),
 | 
			
		||||
                      GsmConstStr r4 = GFP(GSM_CMS_ERROR),
 | 
			
		||||
#else
 | 
			
		||||
                      GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,
 | 
			
		||||
#endif
 | 
			
		||||
                      GsmConstStr r5 = NULL) {
 | 
			
		||||
    return thisModem().waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  Stream& stream;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  const char* gsmNL = GSM_NL;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // SRC_TINYGSMCLIENTSIM70XX_H_
 | 
			
		||||
@@ -24,6 +24,8 @@
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmTemperature.tpp"
 | 
			
		||||
#include "TinyGsmTime.tpp"
 | 
			
		||||
#include "TinyGsmNTP.tpp"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM    = "OK" GSM_NL;
 | 
			
		||||
@@ -50,6 +52,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmGSMLocation<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmGPS<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmTime<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmNTP<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmBattery<TinyGsmSim7600>,
 | 
			
		||||
                       public TinyGsmTemperature<TinyGsmSim7600> {
 | 
			
		||||
  friend class TinyGsmModem<TinyGsmSim7600>;
 | 
			
		||||
@@ -59,6 +62,7 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
 | 
			
		||||
  friend class TinyGsmGPS<TinyGsmSim7600>;
 | 
			
		||||
  friend class TinyGsmGSMLocation<TinyGsmSim7600>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmSim7600>;
 | 
			
		||||
  friend class TinyGsmNTP<TinyGsmSim7600>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmSim7600>;
 | 
			
		||||
  friend class TinyGsmTemperature<TinyGsmSim7600>;
 | 
			
		||||
 | 
			
		||||
@@ -271,12 +275,17 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String setNetworkMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
  int16_t getNetworkMode() {
 | 
			
		||||
    sendAT(GF("+CNMP?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return false; }
 | 
			
		||||
    int16_t mode = streamGetIntBefore('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
    return mode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool setNetworkMode(uint8_t mode) {
 | 
			
		||||
    sendAT(GF("+CNMP="), mode);
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getLocalIPImpl() {
 | 
			
		||||
@@ -558,6 +567,11 @@ class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600>,
 | 
			
		||||
 protected:
 | 
			
		||||
  // Can follow the standard CCLK function in the template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@
 | 
			
		||||
#include "TinyGsmSSL.tpp"
 | 
			
		||||
#include "TinyGsmTCP.tpp"
 | 
			
		||||
#include "TinyGsmTime.tpp"
 | 
			
		||||
#include "TinyGsmNTP.tpp"
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM    = "OK" GSM_NL;
 | 
			
		||||
@@ -51,6 +52,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
                      public TinyGsmSMS<TinyGsmSim800>,
 | 
			
		||||
                      public TinyGsmGSMLocation<TinyGsmSim800>,
 | 
			
		||||
                      public TinyGsmTime<TinyGsmSim800>,
 | 
			
		||||
                      public TinyGsmNTP<TinyGsmSim800>,
 | 
			
		||||
                      public TinyGsmBattery<TinyGsmSim800> {
 | 
			
		||||
  friend class TinyGsmModem<TinyGsmSim800>;
 | 
			
		||||
  friend class TinyGsmGPRS<TinyGsmSim800>;
 | 
			
		||||
@@ -60,6 +62,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
  friend class TinyGsmSMS<TinyGsmSim800>;
 | 
			
		||||
  friend class TinyGsmGSMLocation<TinyGsmSim800>;
 | 
			
		||||
  friend class TinyGsmTime<TinyGsmSim800>;
 | 
			
		||||
  friend class TinyGsmNTP<TinyGsmSim800>;
 | 
			
		||||
  friend class TinyGsmBattery<TinyGsmSim800>;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
@@ -315,20 +318,23 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
                       const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // Set the Bearer for the IP
 | 
			
		||||
    sendAT(GF(
 | 
			
		||||
        "+SAPBR=3,1,\"Contype\",\"GPRS\""));  // Set the connection type to GPRS
 | 
			
		||||
    // Bearer settings for applications based on IP
 | 
			
		||||
    // Set the connection type to GPRS
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');  // Set the APN
 | 
			
		||||
    // Set the APN
 | 
			
		||||
    sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Set the user name
 | 
			
		||||
    if (user && strlen(user) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');  // Set the user name
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    // Set the password
 | 
			
		||||
    if (pwd && strlen(pwd) > 0) {
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');  // Set the password
 | 
			
		||||
      sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"');
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -351,8 +357,6 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) { return false; }
 | 
			
		||||
 | 
			
		||||
    // TODO(?): wait AT+CGATT?
 | 
			
		||||
 | 
			
		||||
    // Set to multi-IP
 | 
			
		||||
    sendAT(GF("+CIPMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) { return false; }
 | 
			
		||||
@@ -447,6 +451,11 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
 protected:
 | 
			
		||||
  // Can follow the standard CCLK function in the template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -456,50 +465,7 @@ class TinyGsmSim800 : public TinyGsmModem<TinyGsmSim800>,
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
 public:
 | 
			
		||||
  boolean isValidNumber(String str) {
 | 
			
		||||
    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; }
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
 | 
			
		||||
    // Set GPRS bearer profile to associate with NTP sync
 | 
			
		||||
    sendAT(GF("+CNTPCID=1"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) { return -1; }
 | 
			
		||||
 | 
			
		||||
    // Set NTP server and timezone
 | 
			
		||||
    sendAT(GF("+CNTP="), server, ',', String(TimeZone));
 | 
			
		||||
    if (waitResponse(10000L) != 1) { return -1; }
 | 
			
		||||
 | 
			
		||||
    // Request network synchronization
 | 
			
		||||
    sendAT(GF("+CNTP"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) {
 | 
			
		||||
      String result = stream.readStringUntil('\n');
 | 
			
		||||
      result.trim();
 | 
			
		||||
      if (isValidNumber(result)) { return result.toInt(); }
 | 
			
		||||
    } else {
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  // Can sync with server using CNTP as per template
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										92
									
								
								src/TinyGsmNTP.tpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/TinyGsmNTP.tpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmNTP.tpp
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef SRC_TINYGSMNTP_H_
 | 
			
		||||
#define SRC_TINYGSMNTP_H_
 | 
			
		||||
 | 
			
		||||
#include "TinyGsmCommon.h"
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MODEM_HAS_NTP
 | 
			
		||||
 | 
			
		||||
template <class modemType>
 | 
			
		||||
class TinyGsmNTP {
 | 
			
		||||
 public:
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  boolean TinyGsmIsValidNumber(String str) {
 | 
			
		||||
    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; }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
 | 
			
		||||
    return thisModem().NTPServerSyncImpl(server, TimeZone);
 | 
			
		||||
  }
 | 
			
		||||
  String ShowNTPError(byte error) {
 | 
			
		||||
    return thisModem().ShowNTPErrorImpl(error);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * CRTP Helper
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  inline const modemType& thisModem() const {
 | 
			
		||||
    return static_cast<const modemType&>(*this);
 | 
			
		||||
  }
 | 
			
		||||
  inline modemType& thisModem() {
 | 
			
		||||
    return static_cast<modemType&>(*this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * NTP server functions
 | 
			
		||||
   */
 | 
			
		||||
 protected:
 | 
			
		||||
  byte NTPServerSyncImpl(String server = "pool.ntp.org", byte TimeZone = 3) {
 | 
			
		||||
    // Set GPRS bearer profile to associate with NTP sync
 | 
			
		||||
    // this may fail, it's not supported by all modules
 | 
			
		||||
    thisModem().sendAT(GF("+CNTPCID=1"));
 | 
			
		||||
    thisModem().waitResponse(10000L);
 | 
			
		||||
 | 
			
		||||
    // Set NTP server and timezone
 | 
			
		||||
    thisModem().sendAT(GF("+CNTP="), server, ',', String(TimeZone));
 | 
			
		||||
    if (thisModem().waitResponse(10000L) != 1) { return -1; }
 | 
			
		||||
 | 
			
		||||
    // Request network synchronization
 | 
			
		||||
    thisModem().sendAT(GF("+CNTP"));
 | 
			
		||||
    if (thisModem().waitResponse(10000L, GF("+CNTP:"))) {
 | 
			
		||||
      String result = thisModem().stream.readStringUntil('\n');
 | 
			
		||||
      result.trim();
 | 
			
		||||
      if (TinyGsmIsValidNumber(result)) { return result.toInt(); }
 | 
			
		||||
    } else {
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String ShowNTPErrorImpl(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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // SRC_TINYGSMNTP_H_
 | 
			
		||||
		Reference in New Issue
	
	Block a user