mirror of
				https://github.com/KevinMidboe/TinyGSM.git
				synced 2025-10-29 18:00:18 +00:00 
			
		
		
		
	Creating a super-class for modems
This commit is contained in:
		
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							@@ -35,29 +35,29 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
Feature \ Modem              | SIM8xx | u-Blox | A6/A7/A20 | M590 | ESP8266 | XBee
 | 
			
		||||
---                          | ---    | ---    | ---       | ---  | ---     | ---
 | 
			
		||||
Feature \ Modem              | SIM8xx | u-Blox | A6/A7/A20 | M590 | ESP8266 | XBee | Quectel M95 |
 | 
			
		||||
---                          | ---    | ---    | ---       | ---  | ---     | ---  | ----------- |
 | 
			
		||||
**Data connections**
 | 
			
		||||
TCP (HTTP, MQTT, Blynk, ...) | ✔      | ✔      | ✔         | ✔    | ✔       | ✔
 | 
			
		||||
UDP                          | ◌      | ◌      |           |      |         | ◌
 | 
			
		||||
SSL/TLS (HTTPS)              | ✔¹     | ✔      | 🅧        | 🅧    | ✔¹      | ✔¹
 | 
			
		||||
TCP (HTTP, MQTT, Blynk, ...) | ✔      | ✔      | ✔         | ✔    | ✔       | ✔    | ✔           |
 | 
			
		||||
UDP                          | ◌      | ◌      |           |      |         | ◌    | ◌           |
 | 
			
		||||
SSL/TLS (HTTPS)              | ✔¹     | ✔      | 🅧        | 🅧    | ✔¹      | ✔¹    |             |
 | 
			
		||||
**USSD**
 | 
			
		||||
Sending USSD requests        | ✔      |        | ✔         | ✔    | 🅧       |
 | 
			
		||||
Decoding 7,8,16-bit response | ✔      |        | ✔         | ✔    | 🅧      |
 | 
			
		||||
Sending USSD requests        | ✔      |        | ✔         | ✔    | 🅧       |      |             |
 | 
			
		||||
Decoding 7,8,16-bit response | ✔      |        | ✔         | ✔    | 🅧      |      |             |
 | 
			
		||||
**SMS**
 | 
			
		||||
Sending                      | ✔      | ✔      | ✔         | ✔    | 🅧      | ✔
 | 
			
		||||
Sending Unicode              | ✔      |        | ◌         | 🅧   | 🅧      |
 | 
			
		||||
Reading                      |        |        |           |      | 🅧      |
 | 
			
		||||
Incoming message event       |        |        |           | ?    | 🅧      |
 | 
			
		||||
Sending                      | ✔      | ✔      | ✔         | ✔    | 🅧      | ✔    | ✔           |
 | 
			
		||||
Sending Unicode              | ✔      |        | ◌         | 🅧   | 🅧      |       | ?           |
 | 
			
		||||
Reading                      |        |        |           |      | 🅧      |      | ?           |
 | 
			
		||||
Incoming message event       |        |        |           | ?    | 🅧      |      |             |
 | 
			
		||||
**Calls**
 | 
			
		||||
Dial, hangup                 | ✔      |        | ✔         | 🅧   | 🅧      | 🅧
 | 
			
		||||
Receiving calls              | ✔      |        | ✔         | 🅧   | 🅧      | 🅧
 | 
			
		||||
Incoming event (RING)        | ◌      |        | ◌         | 🅧   | 🅧      | 🅧
 | 
			
		||||
DTMF sending                 | ✔      |        | ✔         | 🅧   | 🅧      | 🅧
 | 
			
		||||
DTMF decoding                | ◌      |        | 🅧        | 🅧   | 🅧      | 🅧
 | 
			
		||||
Dial, hangup                 | ✔      |        | ✔         | 🅧   | 🅧      | 🅧     | ?           |
 | 
			
		||||
Receiving calls              | ✔      |        | ✔         | 🅧   | 🅧      | 🅧     | ?           |
 | 
			
		||||
Incoming event (RING)        | ◌      |        | ◌         | 🅧   | 🅧      | 🅧     | ?           |
 | 
			
		||||
DTMF sending                 | ✔      |        | ✔         | 🅧   | 🅧      | 🅧     | ?           |
 | 
			
		||||
DTMF decoding                | ◌      |        | 🅧        | 🅧   | 🅧      | 🅧     | ?           |
 | 
			
		||||
**Location**
 | 
			
		||||
GSM location service         | ✔      | ✔      | 🅧        | 🅧   | 🅧      | ✔
 | 
			
		||||
GPS/GNSS                     | ✔¹     | 🅧     | ◌¹        | 🅧   | 🅧      | 🅧
 | 
			
		||||
GSM location service         | ✔      | ✔      | 🅧        | 🅧   | 🅧      | ✔ | 🅧 |
 | 
			
		||||
GPS/GNSS                     | ✔¹     | 🅧     | ◌¹        | 🅧   | 🅧      | 🅧 | 🅧 |
 | 
			
		||||
 | 
			
		||||
✔ - implemented  ◌ - planned  🅧 - not available on this modem  
 | 
			
		||||
¹ - only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)  
 | 
			
		||||
@@ -72,6 +72,8 @@ GPS/GNSS                     | ✔¹     | 🅧     | ◌¹        | 🅧   | 
 | 
			
		||||
- Neoway M590
 | 
			
		||||
- u-blox Cellular Modems (LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
 | 
			
		||||
- Quectel BG96 ***(alpha)***
 | 
			
		||||
- Quectel M95 ***(alpha)***
 | 
			
		||||
- Quectel MC60 ***(alpha)***
 | 
			
		||||
 | 
			
		||||
### Supported boards/modules
 | 
			
		||||
- Arduino MKR GSM 1400
 | 
			
		||||
@@ -84,8 +86,8 @@ GPS/GNSS                     | ✔¹     | 🅧     | ◌¹        | 🅧   | 
 | 
			
		||||
- ... other modules, based on supported modems. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
 | 
			
		||||
 | 
			
		||||
More modems may be supported later:
 | 
			
		||||
- [ ] Quectel M10, M35, M95, UG95, EC21
 | 
			
		||||
- [ ] Sequans Monarch LTE Cat M1/NB1
 | 
			
		||||
- [ ] Quectel M10, UG95
 | 
			
		||||
- [ ] SIMCom SIM5320, SIM5360, SIM5216, SIM7xxx
 | 
			
		||||
- [ ] Telit GL865
 | 
			
		||||
- [ ] ZTE MG2639
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,8 @@
 | 
			
		||||
// #define TINY_GSM_MODEM_A6
 | 
			
		||||
// #define TINY_GSM_MODEM_A7
 | 
			
		||||
// #define TINY_GSM_MODEM_M590
 | 
			
		||||
// #define TINY_GSM_MODEM_MC60
 | 
			
		||||
// #define TINY_GSM_MODEM_MC60E
 | 
			
		||||
 | 
			
		||||
// Set serial for debug console (to the Serial Monitor, speed 115200)
 | 
			
		||||
#define SerialMon Serial
 | 
			
		||||
@@ -34,6 +36,22 @@
 | 
			
		||||
//#define DUMP_AT_COMMANDS
 | 
			
		||||
#define TINY_GSM_DEBUG SerialMon
 | 
			
		||||
 | 
			
		||||
#define GSM_AUTOBAUD_MIN 9600
 | 
			
		||||
#define GSM_AUTOBAUD_MAX 38400
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Test enabled
 | 
			
		||||
 */
 | 
			
		||||
#define TINY_GSM_USE_GPRS true
 | 
			
		||||
#define TINY_GSM_USE_CALL true
 | 
			
		||||
#define TINY_GSM_USE_SMS true
 | 
			
		||||
#define TINY_GSM_USE_USSD true
 | 
			
		||||
// powerdown modem after tests
 | 
			
		||||
#define TINY_GSM_POWERDOWN false
 | 
			
		||||
 | 
			
		||||
// set GSM PIN, if any
 | 
			
		||||
#define GSM_PIN ""
 | 
			
		||||
 | 
			
		||||
// Set phone numbers, if you want to test SMS and Calls
 | 
			
		||||
//#define SMS_TARGET  "+380xxxxxxxxx"
 | 
			
		||||
//#define CALL_TARGET "+380xxxxxxxxx"
 | 
			
		||||
@@ -64,7 +82,7 @@ void setup() {
 | 
			
		||||
  delay(3000);
 | 
			
		||||
 | 
			
		||||
  // Set GSM module baud rate
 | 
			
		||||
  TinyGsmAutoBaud(SerialAT);
 | 
			
		||||
  TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void loop() {
 | 
			
		||||
@@ -73,6 +91,10 @@ void loop() {
 | 
			
		||||
  // To skip it, call init() instead of restart()
 | 
			
		||||
  DBG("Initializing modem...");
 | 
			
		||||
  if (!modem.restart()) {
 | 
			
		||||
    DBG("Failed to restart modem, delayin 10s and retring");
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    // restart autobaud in case GSM just rebooted
 | 
			
		||||
    TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
 | 
			
		||||
    delay(10000);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@@ -80,8 +102,10 @@ void loop() {
 | 
			
		||||
  String modemInfo = modem.getModemInfo();
 | 
			
		||||
  DBG("Modem:", modemInfo);
 | 
			
		||||
 | 
			
		||||
  // Unlock your SIM card with a PIN
 | 
			
		||||
  //modem.simUnlock("1234");
 | 
			
		||||
  // Unlock your SIM card with a PIN if needed
 | 
			
		||||
  if ( GSM_PIN && modem.getSimStatus() != 3 ) { 
 | 
			
		||||
    modem.simUnlock(GSM_PIN);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  DBG("Waiting for network...");
 | 
			
		||||
  if (!modem.waitForNetwork()) {
 | 
			
		||||
@@ -93,11 +117,13 @@ void loop() {
 | 
			
		||||
    DBG("Network connected");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_USE_GPRS
 | 
			
		||||
  DBG("Connecting to", apn);
 | 
			
		||||
  if (!modem.gprsConnect(apn, user, pass)) {
 | 
			
		||||
    delay(10000);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  bool res = modem.isGprsConnected();
 | 
			
		||||
  DBG("GPRS status:", res ? "connected" : "not connected");
 | 
			
		||||
@@ -110,9 +136,10 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
  String cop = modem.getOperator();
 | 
			
		||||
  DBG("Operator:", cop);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  IPAddress local = modem.localIP();
 | 
			
		||||
  DBG("Local IP:", local);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  int csq = modem.getSignalQuality();
 | 
			
		||||
  DBG("Signal quality:", csq);
 | 
			
		||||
@@ -140,15 +167,16 @@ void loop() {
 | 
			
		||||
 | 
			
		||||
  String ussd_phone_num = modem.sendUSSD("*161#");
 | 
			
		||||
  DBG("Phone number (USSD):", ussd_phone_num);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(TINY_GSM_MODEM_SIM808)
 | 
			
		||||
#if defined(TINY_GSM_MODEM_HAS_GPS)
 | 
			
		||||
  modem.enableGPS();
 | 
			
		||||
  String gps_raw = modem.getGPSraw();
 | 
			
		||||
  modem.disableGPS();
 | 
			
		||||
  DBG("GPS raw data:", gps_raw);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(SMS_TARGET)
 | 
			
		||||
#if TINY_GSM_USE_SMS && defined(SMS_TARGET)
 | 
			
		||||
  res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
 | 
			
		||||
  DBG("SMS:", res ? "OK" : "fail");
 | 
			
		||||
 | 
			
		||||
@@ -157,7 +185,7 @@ void loop() {
 | 
			
		||||
  DBG("UTF16 SMS:", res ? "OK" : "fail");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(CALL_TARGET)
 | 
			
		||||
#if TINY_GSM_USE_CALL && defined(CALL_TARGET)
 | 
			
		||||
  DBG("Calling:", CALL_TARGET);
 | 
			
		||||
 | 
			
		||||
  // This is NOT supported on M590
 | 
			
		||||
@@ -182,21 +210,24 @@ void loop() {
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_USE_GPRS
 | 
			
		||||
  modem.gprsDisconnect();
 | 
			
		||||
  if (!modem.isGprsConnected()) {
 | 
			
		||||
    DBG("GPRS disconnected");
 | 
			
		||||
  } else {
 | 
			
		||||
    DBG("GPRS disconnect: Failed.");
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if TINY_GSM_POWERDOWN 
 | 
			
		||||
  // Try to power-off (modem may decide to restart automatically)
 | 
			
		||||
  // To turn off modem completely, please use Reset/Enable pins
 | 
			
		||||
  modem.poweroff();
 | 
			
		||||
  DBG("Poweroff.");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Do nothing forevermore
 | 
			
		||||
  while (true) {
 | 
			
		||||
    modem.maintain();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Digi XBee 3G Global Users Guide - 90001541.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Digi XBee 3G Global Users Guide - 90001541.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Digi XBee3 LTEC1 Users Guide - 90002253.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Digi XBee3 LTEC1 Users Guide - 90002253.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/ESP8266 - AT Command Examples 1.3.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/ESP8266 - AT Command Examples 1.3.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/ESP8266 - AT Instruction Set v2.0.0.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/ESP8266 - AT Instruction Set v2.0.0.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Gemalto ELS31 AT Commands.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Gemalto ELS31 AT Commands.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Quectel_GSM_SSL_TCP_Application_Note.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Quectel_GSM_SSL_TCP_Application_Note.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Quectel_GSM_TCPIP_Recommended_Process_V1.2.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Quectel_GSM_TCPIP_Recommended_Process_V1.2.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Quectel_M95_GSM_Specification_V3.1.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Quectel_M95_GSM_Specification_V3.1.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Quectel_M95_at_commands_manual_v1.3.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Quectel_M95_at_commands_manual_v1.3.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Quectel_MC60_AT_Commands_Manual_V1.1.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Quectel_MC60_AT_Commands_Manual_V1.1.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/SIM800 Hardware Design V1.08.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/SIM800 Hardware Design V1.08.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/SIM800 Series AT Command Manual V1.09.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/SIM800 Series AT Command Manual V1.09.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/SIM800 Series AT Command Manual V1.10.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/SIM800 Series AT Command Manual V1.10.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/SIM800+Series Bluetooth Application Note V1.04.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/SIM800+Series Bluetooth Application Note V1.04.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/SIM800+Series Email Application Note V1.00.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/SIM800+Series Email Application Note V1.00.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Sequans Monarch AT Commands.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Sequans Monarch AT Commands.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Telit CE910 AT Commands Reference Guide r5.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Telit CE910 AT Commands Reference Guide r5.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Telit HE910 AT Command Reference Guide r0.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Telit HE910 AT Command Reference Guide r0.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Telit LE910 AT Commands Reference Guide r14.1.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Telit LE910 AT Commands Reference Guide r14.1.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Telit ME910C1 AT Commands Reference Guide r2.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Telit ME910C1 AT Commands Reference Guide r2.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/Telit Modules Software User Guide 2G3G4G r20.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/Telit Modules Software User Guide 2G3G4G r20.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/u-blox Cellular ATCommands R57 (UBX-13002752).pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/u-blox Cellular ATCommands R57 (UBX-13002752).pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								extras/doc/u-blox SARA-G3 DataSheet (UBX-13000993).pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								extras/doc/u-blox SARA-G3 DataSheet (UBX-13000993).pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "TinyGSM",
 | 
			
		||||
  "version": "0.3.5",
 | 
			
		||||
  "version": "0.3.6",
 | 
			
		||||
  "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports GSM modules with AT command interface: SIM800, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900, SIM900A, SIM900D, SIM908, SIM968",
 | 
			
		||||
  "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968",
 | 
			
		||||
  "authors":
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
name=TinyGSM
 | 
			
		||||
version=0.3.5
 | 
			
		||||
version=0.3.6
 | 
			
		||||
author=Volodymyr Shymanskyy
 | 
			
		||||
maintainer=Volodymyr Shymanskyy
 | 
			
		||||
sentence=A small Arduino library for GPRS modules, that just works.
 | 
			
		||||
paragraph=Includes examples for Blynk, MQTT, File Download, and Web Client. Supports GSM modules with AT command interface: SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968
 | 
			
		||||
paragraph=Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM and wifi modules with AT command interfaces.
 | 
			
		||||
category=Communication
 | 
			
		||||
url=https://github.com/vshymanskyy/TinyGSM
 | 
			
		||||
architectures=*
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_SSL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7)
 | 
			
		||||
#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7) || defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -38,6 +38,12 @@
 | 
			
		||||
  typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
 | 
			
		||||
  typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_M95)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPRS
 | 
			
		||||
  #include <TinyGsmClientM95.h>
 | 
			
		||||
  typedef TinyGsmM95 TinyGsm;
 | 
			
		||||
  typedef TinyGsmM95::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_BG96)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_GPRS
 | 
			
		||||
  #include <TinyGsmClientBG96.h>
 | 
			
		||||
@@ -56,6 +62,11 @@
 | 
			
		||||
  typedef TinyGsmM590 TinyGsm;
 | 
			
		||||
  typedef TinyGsmM590::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
  #include <TinyGsmClientMC60.h>
 | 
			
		||||
  typedef TinyGsmMC60 TinyGsm;
 | 
			
		||||
  typedef TinyGsmMC60::GsmClient TinyGsmClient;
 | 
			
		||||
 | 
			
		||||
#elif defined(TINY_GSM_MODEM_ESP8266)
 | 
			
		||||
  #define TINY_GSM_MODEM_HAS_WIFI
 | 
			
		||||
  #include <TinyGsmClientESP8266.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmA6
 | 
			
		||||
class TinyGsmA6 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -178,7 +178,7 @@ private:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmA6(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -186,11 +186,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -208,6 +205,15 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_A6)
 | 
			
		||||
      return "AI-Thinker A6";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_A7)
 | 
			
		||||
      return "AI-Thinker A7";
 | 
			
		||||
    #endif
 | 
			
		||||
    return "AI-Thinker A6";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -251,6 +257,14 @@ public:
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -367,22 +381,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -441,6 +439,10 @@ public:
 | 
			
		||||
    return (res == 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIFSR"));
 | 
			
		||||
    String res;
 | 
			
		||||
@@ -453,10 +455,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -606,6 +604,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t* mux) {
 | 
			
		||||
@@ -650,30 +652,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmBG96
 | 
			
		||||
class TinyGsmBG96 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -115,7 +115,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size()) {
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
@@ -125,7 +125,7 @@ public:
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size) {
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
@@ -179,30 +179,30 @@ private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GsmClientSecure : public GsmClient
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  GsmClientSecure() {}
 | 
			
		||||
 | 
			
		||||
  GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
 | 
			
		||||
    : GsmClient(modem, mux)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmBG96(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -210,11 +210,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -226,6 +223,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Quectel BG96";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -280,6 +281,14 @@ public:
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -401,44 +410,30 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    //Configure the TCPIP Context
 | 
			
		||||
    sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT=1"));
 | 
			
		||||
    if (waitResponse(150000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Attach to Packet Domain service - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGATT=1"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -463,12 +458,13 @@ public:
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CGPADDR=1"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CGPADDR:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(',');
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
@@ -476,10 +472,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -535,6 +527,8 @@ public:
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
@@ -567,14 +561,42 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
  uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    int rsp;
 | 
			
		||||
    // <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE",
 | 
			
		||||
    // "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer)
 | 
			
		||||
    sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
 | 
			
		||||
    rsp = waitResponse();
 | 
			
		||||
 | 
			
		||||
@@ -660,30 +682,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmESP8266
 | 
			
		||||
class TinyGsmESP8266 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -191,10 +191,11 @@ public:
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmESP8266(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -202,11 +203,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -225,6 +223,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "ESP8266";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -266,6 +268,14 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -362,6 +372,10 @@ public:
 | 
			
		||||
    return retVal;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIPSTA_CUR??"));
 | 
			
		||||
    int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
 | 
			
		||||
@@ -373,33 +387,9 @@ public:
 | 
			
		||||
    return res2;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool gprsDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
@@ -438,30 +428,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmM590
 | 
			
		||||
class TinyGsmM590 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -175,7 +175,7 @@ private:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmM590(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -183,11 +183,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -204,6 +201,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Neoway M590";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -255,6 +256,14 @@ public:
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -375,22 +384,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -447,6 +440,10 @@ public:
 | 
			
		||||
    return res == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+XIIC?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
 | 
			
		||||
@@ -459,10 +456,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -538,6 +531,10 @@ public:
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux) {
 | 
			
		||||
@@ -595,30 +592,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										843
									
								
								src/TinyGsmClientM95.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										843
									
								
								src/TinyGsmClientM95.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,843 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientM95.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com>
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TinyGsmClientM95_h
 | 
			
		||||
#define TinyGsmClientM95_h
 | 
			
		||||
 | 
			
		||||
//#define TINY_GSM_DEBUG Serial
 | 
			
		||||
//#define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#if !defined(TINY_GSM_RX_BUFFER)
 | 
			
		||||
  #define TINY_GSM_RX_BUFFER 64
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 6
 | 
			
		||||
 | 
			
		||||
#include <TinyGsmCommon.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
 | 
			
		||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
 | 
			
		||||
 | 
			
		||||
enum SimStatus {
 | 
			
		||||
  SIM_ERROR = 0,
 | 
			
		||||
  SIM_READY = 1,
 | 
			
		||||
  SIM_LOCKED = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmM95 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
class GsmClient : public Client
 | 
			
		||||
{
 | 
			
		||||
  friend class TinyGsmM95;
 | 
			
		||||
  typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  GsmClient() {}
 | 
			
		||||
 | 
			
		||||
  GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
 | 
			
		||||
    init(&modem, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(TinyGsmM95* modem, uint8_t mux = 1) {
 | 
			
		||||
    this->at = modem;
 | 
			
		||||
    this->mux = mux;
 | 
			
		||||
    sock_available = 0;
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    got_data = false;
 | 
			
		||||
 | 
			
		||||
    at->sockets[mux] = this;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int connect(IPAddress ip, uint16_t port) {
 | 
			
		||||
    String host; host.reserve(16);
 | 
			
		||||
    host += ip[0];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[1];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[2];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[3];
 | 
			
		||||
    return connect(host.c_str(), port);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual void stop() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->sendAT(GF("+QICLOSE="), mux);
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    at->waitResponse(60000L, GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
 | 
			
		||||
    rx.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    return at->modemSend(buf, size, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(uint8_t c) {
 | 
			
		||||
    return write(&c, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const char *str) {
 | 
			
		||||
    if (str == NULL) return 0;
 | 
			
		||||
    return write((const uint8_t *)str, strlen(str));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read(uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
        buf += chunk;
 | 
			
		||||
        cnt += chunk;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      // TODO: Read directly into user buffer?
 | 
			
		||||
      at->maintain();
 | 
			
		||||
      if (sock_available > 0) {
 | 
			
		||||
        at->modemRead(rx.free(), mux);
 | 
			
		||||
      } else {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return cnt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read() {
 | 
			
		||||
    uint8_t c;
 | 
			
		||||
    if (read(&c, 1) == 1) {
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int peek() { return -1; } //TODO
 | 
			
		||||
  virtual void flush() { at->stream.flush(); }
 | 
			
		||||
 | 
			
		||||
  virtual uint8_t connected() {
 | 
			
		||||
    if (available()) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
  virtual operator bool() { return connected(); }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Extended API
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  TinyGsmM95*   at;
 | 
			
		||||
  uint8_t       mux;
 | 
			
		||||
  uint16_t      sock_available;
 | 
			
		||||
  bool          sock_connected;
 | 
			
		||||
  bool          got_data;
 | 
			
		||||
  RxFifo        rx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmM95(Stream& stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("&FZE0"));  // Factory + Reset + Echo Off
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef TINY_GSM_DEBUG
 | 
			
		||||
    sendAT(GF("+CMEE=2"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    getSimStatus();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "Quectel M95";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool testAT(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF(""));
 | 
			
		||||
      if (waitResponse(200) == 1) {
 | 
			
		||||
        delay(100);
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(100);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void maintain() {
 | 
			
		||||
    for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
 | 
			
		||||
      GsmClient* sock = sockets[mux];
 | 
			
		||||
      if (sock && sock->got_data) {
 | 
			
		||||
        sock->got_data = false;
 | 
			
		||||
        sock->sock_available = modemGetAvailable(mux);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    while (stream.available()) {
 | 
			
		||||
      waitResponse(10, NULL, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefault() {
 | 
			
		||||
    sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+IPR=0"));   // Auto-baud
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("&W"));       // Write configuration
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemInfo() {
 | 
			
		||||
    sendAT(GF("I"));
 | 
			
		||||
    String res;
 | 
			
		||||
    if (waitResponse(1000L, res) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    res.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res.replace(GSM_NL, " ");
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasSSL() {
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool restart() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=1"));
 | 
			
		||||
    if (waitResponse(10000L, GF("Call Ready"), GF("OK"), GF("FAIL")) == 3) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool poweroff() {
 | 
			
		||||
    sendAT(GF("+QPOWD"));
 | 
			
		||||
    return waitResponse(GF("POWERED DOWN")) == 1; // TODO
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool radioOff() {
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool simUnlock(const char *pin) {
 | 
			
		||||
    sendAT(GF("+CPIN=\""), pin, GF("\""));
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getSimCCID() {
 | 
			
		||||
    sendAT(GF("+ICCID"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getIMEI() {
 | 
			
		||||
    sendAT(GF("+GSN"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL)) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SimStatus getSimStatus(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF("+CPIN?"));
 | 
			
		||||
      if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
 | 
			
		||||
        delay(1000);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      switch (status) {
 | 
			
		||||
        case 2:
 | 
			
		||||
        case 3:  return SIM_LOCKED;
 | 
			
		||||
        case 1:  return SIM_READY;
 | 
			
		||||
        default: return SIM_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return SIM_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    sendAT(GF("+CREG?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
 | 
			
		||||
      return REG_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip format (0)
 | 
			
		||||
    int status = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return (RegStatus)status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getOperator() {
 | 
			
		||||
    sendAT(GF("+COPS?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil('"'); // Skip mode and format
 | 
			
		||||
    String res = stream.readStringUntil('"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int getSignalQuality() {
 | 
			
		||||
    sendAT(GF("+CSQ"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
 | 
			
		||||
      return 99;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isNetworkConnected() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setHostFormat( bool useDottedQuad ) {
 | 
			
		||||
    if ( useDottedQuad ) {
 | 
			
		||||
      sendAT(GF("+QIDNSIP=0"));
 | 
			
		||||
    } else {
 | 
			
		||||
      sendAT(GF("+QIDNSIP=1"));
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // select foreground context 0 = VIRTUAL_UART_1
 | 
			
		||||
    sendAT(GF("+QIFGCNT=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Select GPRS (=1) as the Bearer
 | 
			
		||||
    sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Start TCPIP Task and Set APN, User Name and Password
 | 
			
		||||
    sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" );
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT"));
 | 
			
		||||
    if (waitResponse(10000) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Enable multiple TCP/IP connections
 | 
			
		||||
    sendAT(GF("+QIMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Request an IP header for received data ("IPD(data length):")
 | 
			
		||||
    sendAT(GF("+QIHEAD=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
 | 
			
		||||
    sendAT(GF("+QINDI=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnect() {
 | 
			
		||||
    sendAT(GF("+QIDEACT"));
 | 
			
		||||
    return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isGprsConnected() {
 | 
			
		||||
    sendAT(GF("+CGATT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    if (res != 1)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String sendUSSD(const String& code) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CUSD=1,\""), code, GF("\""));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil('"');
 | 
			
		||||
    String hex = stream.readStringUntil('"');
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int dcs = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dcs == 15) {
 | 
			
		||||
      return TinyGsmDecodeHex8bit(hex);
 | 
			
		||||
    } else if (dcs == 72) {
 | 
			
		||||
      return TinyGsmDecodeHex16bit(hex);
 | 
			
		||||
    } else {
 | 
			
		||||
      return hex;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS(const String& number, const String& text) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    //Set GSM 7 bit default alphabet (3GPP TS 23.038)
 | 
			
		||||
    sendAT(GF("+CSCS=\"GSM\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.print(text);
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t* t = (uint16_t*)text;
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      uint8_t c = t[i] >> 8;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
      c = t[i] & 0xFF;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Delete all SMS */
 | 
			
		||||
  bool deleteAllSMS() {
 | 
			
		||||
    sendAT(GF("+QMGDA=6"));
 | 
			
		||||
    if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    sendAT(GF("+QIOPEN="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
 | 
			
		||||
    int rsp = waitResponse(75000L,
 | 
			
		||||
                           GF("CONNECT OK" GSM_NL),
 | 
			
		||||
                           GF("CONNECT FAIL" GSM_NL),
 | 
			
		||||
                           GF("ALREADY CONNECT" GSM_NL));
 | 
			
		||||
    if ( rsp != 1 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return (1 == rsp);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISEND="), mux, ',', len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((uint8_t*)buff, len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool allAcknowledged = false;
 | 
			
		||||
    // bool failed = false;
 | 
			
		||||
    while ( !allAcknowledged ) {
 | 
			
		||||
      sendAT( GF("+QISACK"));
 | 
			
		||||
      if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        streamSkipUntil(','); /** Skip total */
 | 
			
		||||
        streamSkipUntil(','); /** Skip acknowledged data size */
 | 
			
		||||
        if ( stream.readStringUntil('\n').toInt() == 0 ) {
 | 
			
		||||
          allAcknowledged = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse(5000L);
 | 
			
		||||
 | 
			
		||||
    // streamSkipUntil(','); // Skip mux
 | 
			
		||||
    // return stream.readStringUntil('\n').toInt();
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, ',', size);
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    size_t len = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      while (!stream.available()) { TINY_GSM_YIELD(); }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    DBG("### READ:", mux, ",", len);
 | 
			
		||||
    return len;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, GF(",0"));
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) == 1) {
 | 
			
		||||
      streamSkipUntil(','); // Skip total received
 | 
			
		||||
      streamSkipUntil(','); // Skip have read
 | 
			
		||||
      result = stream.readStringUntil('\n').toInt();
 | 
			
		||||
      DBG("### STILL:", mux, "has", result);
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    if (!result) {
 | 
			
		||||
      sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISTATE=1,"), mux);
 | 
			
		||||
    //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+QISTATE:")))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil(','); // Skip mux
 | 
			
		||||
    streamSkipUntil(','); // Skip socket type
 | 
			
		||||
    streamSkipUntil(','); // Skip remote ip
 | 
			
		||||
    streamSkipUntil(','); // Skip remote port
 | 
			
		||||
    streamSkipUntil(','); // Skip local port
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt(); // socket state
 | 
			
		||||
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
 | 
			
		||||
    return 2 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    //DBG("### AT:", cmd...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: Optimize this!
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout, String& data,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /*String r1s(r1); r1s.trim();
 | 
			
		||||
    String r2s(r2); r2s.trim();
 | 
			
		||||
    String r3s(r3); r3s.trim();
 | 
			
		||||
    String r4s(r4); r4s.trim();
 | 
			
		||||
    String r5s(r5); r5s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    int index = 0;
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        int a = stream.read();
 | 
			
		||||
        if (a <= 0) continue; // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += (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)) {
 | 
			
		||||
          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 "+QIRD:"))) {
 | 
			
		||||
          streamSkipUntil(',');  // Skip the context
 | 
			
		||||
          streamSkipUntil(',');  // Skip the role
 | 
			
		||||
          int mux = stream.readStringUntil('\n').toInt();
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int nl = data.lastIndexOf(GSM_NL, data.length()-8);
 | 
			
		||||
          int coma = data.indexOf(',', nl+2);
 | 
			
		||||
          int mux = data.substring(nl+2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout);
 | 
			
		||||
finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) {
 | 
			
		||||
        DBG("### Unhandled:", data);
 | 
			
		||||
      }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout, data, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  GsmClient*    sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										874
									
								
								src/TinyGsmClientMC60.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										874
									
								
								src/TinyGsmClientMC60.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,874 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file       TinyGsmClientMC60.h
 | 
			
		||||
 * @author     Volodymyr Shymanskyy
 | 
			
		||||
 * @license    LGPL-3.0
 | 
			
		||||
 * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
 | 
			
		||||
 * @date       Nov 2016
 | 
			
		||||
 *
 | 
			
		||||
 * @MC60 support added by Tamas Dajka 2017.10.15 - with fixes by Sara Damiano
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef TinyGsmClientMC60_h
 | 
			
		||||
#define TinyGsmClientMC60_h
 | 
			
		||||
 | 
			
		||||
//#define TINY_GSM_DEBUG Serial
 | 
			
		||||
//#define TINY_GSM_USE_HEX
 | 
			
		||||
 | 
			
		||||
#if !defined(TINY_GSM_RX_BUFFER)
 | 
			
		||||
  #define TINY_GSM_RX_BUFFER 64
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define TINY_GSM_MUX_COUNT 6
 | 
			
		||||
 | 
			
		||||
#include <TinyGsmCommon.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_NL "\r\n"
 | 
			
		||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
 | 
			
		||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
 | 
			
		||||
 | 
			
		||||
enum SimStatus {
 | 
			
		||||
  SIM_ERROR = 0,
 | 
			
		||||
  SIM_READY = 1,
 | 
			
		||||
  SIM_LOCKED = 2,
 | 
			
		||||
  SIM_ANTITHEFT_LOCKED = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum RegStatus {
 | 
			
		||||
  REG_UNREGISTERED = 0,
 | 
			
		||||
  REG_SEARCHING    = 2,
 | 
			
		||||
  REG_DENIED       = 3,
 | 
			
		||||
  REG_OK_HOME      = 1,
 | 
			
		||||
  REG_OK_ROAMING   = 5,
 | 
			
		||||
  REG_UNKNOWN      = 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmMC60 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
class GsmClient : public Client
 | 
			
		||||
{
 | 
			
		||||
  friend class TinyGsmMC60;
 | 
			
		||||
  typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  GsmClient() {}
 | 
			
		||||
 | 
			
		||||
  GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) {
 | 
			
		||||
    init(&modem, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(TinyGsmMC60* modem, uint8_t mux = 1) {
 | 
			
		||||
    this->at = modem;
 | 
			
		||||
    this->mux = mux;
 | 
			
		||||
    sock_available = 0;
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    got_data = false;
 | 
			
		||||
 | 
			
		||||
    at->sockets[mux] = this;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
    stop();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    rx.clear();
 | 
			
		||||
    sock_connected = at->modemConnect(host, port, mux);
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int connect(IPAddress ip, uint16_t port) {
 | 
			
		||||
    String host; host.reserve(16);
 | 
			
		||||
    host += ip[0];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[1];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[2];
 | 
			
		||||
    host += ".";
 | 
			
		||||
    host += ip[3];
 | 
			
		||||
    return connect(host.c_str(), port);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual void stop() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->sendAT(GF("+QICLOSE="), mux);
 | 
			
		||||
    sock_connected = false;
 | 
			
		||||
    at->waitResponse(60000L, GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
 | 
			
		||||
    rx.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    return at->modemSend(buf, size, mux);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(uint8_t c) {
 | 
			
		||||
    return write(&c, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual size_t write(const char *str) {
 | 
			
		||||
    if (str == NULL) return 0;
 | 
			
		||||
    return write((const uint8_t *)str, strlen(str));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int available() {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    if (!rx.size() && sock_connected) {
 | 
			
		||||
      at->maintain();
 | 
			
		||||
    }
 | 
			
		||||
    return rx.size() + sock_available;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read(uint8_t *buf, size_t size) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
        buf += chunk;
 | 
			
		||||
        cnt += chunk;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      // TODO: Read directly into user buffer?
 | 
			
		||||
      at->maintain();
 | 
			
		||||
      if (sock_available > 0) {
 | 
			
		||||
        at->modemRead(rx.free(), mux);
 | 
			
		||||
      } else {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return cnt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int read() {
 | 
			
		||||
    uint8_t c;
 | 
			
		||||
    if (read(&c, 1) == 1) {
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  virtual int peek() { return -1; } //TODO
 | 
			
		||||
  virtual void flush() { at->stream.flush(); }
 | 
			
		||||
 | 
			
		||||
  virtual uint8_t connected() {
 | 
			
		||||
    if (available()) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return sock_connected;
 | 
			
		||||
  }
 | 
			
		||||
  virtual operator bool() { return connected(); }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Extended API
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  TinyGsmMC60*  at;
 | 
			
		||||
  uint8_t       mux;
 | 
			
		||||
  uint16_t      sock_available;
 | 
			
		||||
  bool          sock_connected;
 | 
			
		||||
  bool          got_data;
 | 
			
		||||
  RxFifo        rx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// class GsmClientSecure : public GsmClient
 | 
			
		||||
// {
 | 
			
		||||
// public:
 | 
			
		||||
//   GsmClientSecure() {}
 | 
			
		||||
//
 | 
			
		||||
//   GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
 | 
			
		||||
//     : GsmClient(modem, mux)
 | 
			
		||||
//   {}
 | 
			
		||||
//
 | 
			
		||||
// public:
 | 
			
		||||
//   virtual int connect(const char *host, uint16_t port) {
 | 
			
		||||
//     stop();
 | 
			
		||||
//     TINY_GSM_YIELD();
 | 
			
		||||
//     rx.clear();
 | 
			
		||||
//     sock_connected = at->modemConnect(host, port, mux, true);
 | 
			
		||||
//     return sock_connected;
 | 
			
		||||
//   }
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmMC60(Stream& stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("&FZ"));  // Factory + Reset
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("E0"));   // Echo Off
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    getSimStatus();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_MC60)
 | 
			
		||||
      return "Quectel MC60";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_MC60E)
 | 
			
		||||
      return "Quectel MC60E";
 | 
			
		||||
    #endif
 | 
			
		||||
      return "Quectel MC60";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool testAT(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF(""));
 | 
			
		||||
      if (waitResponse(200) == 1) {
 | 
			
		||||
        delay(100);
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(100);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void maintain() {
 | 
			
		||||
    for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
 | 
			
		||||
      GsmClient* sock = sockets[mux];
 | 
			
		||||
      if (sock && sock->got_data) {
 | 
			
		||||
        sock->got_data = false;
 | 
			
		||||
        sock->sock_available = modemGetAvailable(mux);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    while (stream.available()) {
 | 
			
		||||
      waitResponse(10, NULL, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool factoryDefault() {
 | 
			
		||||
    sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+IPR=0"));   // Auto-baud
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("&W"));       // Write configuration
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemInfo() {
 | 
			
		||||
    sendAT(GF("I"));
 | 
			
		||||
    String res;
 | 
			
		||||
    if (waitResponse(1000L, res) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    res.replace(GSM_NL "OK" GSM_NL, "");
 | 
			
		||||
    res.replace(GSM_NL, " ");
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
  * under development
 | 
			
		||||
  */
 | 
			
		||||
  // bool hasSSL() {
 | 
			
		||||
  //   sendAT(GF("+QIPSSL=?"));
 | 
			
		||||
  //   if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
 | 
			
		||||
  //     return false;
 | 
			
		||||
  //   }
 | 
			
		||||
  //   return waitResponse() == 1;
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  bool hasSSL() {
 | 
			
		||||
    return false;  // TODO: For now
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool restart() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=1,1"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool poweroff() {
 | 
			
		||||
    sendAT(GF("+QPOWD=1"));
 | 
			
		||||
    return waitResponse(GF("NORMAL POWER DOWN")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool radioOff() {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    sendAT(GF("+CFUN=0"));
 | 
			
		||||
    if (waitResponse(10000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    delay(3000);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  bool simUnlock(const char *pin) {
 | 
			
		||||
    sendAT(GF("+CPIN=\""), pin, GF("\""));
 | 
			
		||||
    return waitResponse() == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getSimCCID() {
 | 
			
		||||
    sendAT(GF("+ICCID"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getIMEI() {
 | 
			
		||||
    sendAT(GF("+GSN"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL)) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SimStatus getSimStatus(unsigned long timeout = 10000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      sendAT(GF("+CPIN?"));
 | 
			
		||||
      if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
 | 
			
		||||
        delay(1000);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK"));
 | 
			
		||||
      waitResponse();
 | 
			
		||||
      switch (status) {
 | 
			
		||||
        case 2:
 | 
			
		||||
        case 3:  return SIM_LOCKED;
 | 
			
		||||
        case 5:
 | 
			
		||||
        case 6:  return SIM_ANTITHEFT_LOCKED;
 | 
			
		||||
        case 1:  return SIM_READY;
 | 
			
		||||
        default: return SIM_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return SIM_ERROR;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  RegStatus getRegistrationStatus() {
 | 
			
		||||
    sendAT(GF("+CREG?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
 | 
			
		||||
      return REG_UNKNOWN;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip format (0)
 | 
			
		||||
    int status = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return (RegStatus)status;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getOperator() {
 | 
			
		||||
    sendAT(GF("+COPS?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil('"'); // Skip mode and format
 | 
			
		||||
    String res = stream.readStringUntil('"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Generic network functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int getSignalQuality() {
 | 
			
		||||
    sendAT(GF("+CSQ"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
 | 
			
		||||
      return 99;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isNetworkConnected() {
 | 
			
		||||
    RegStatus s = getRegistrationStatus();
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
  bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    gprsDisconnect();
 | 
			
		||||
 | 
			
		||||
    // select foreground context 0 = VIRTUAL_UART_1
 | 
			
		||||
    sendAT(GF("+QIFGCNT=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Select GPRS (=1) as the Bearer
 | 
			
		||||
    sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Define PDP context - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // Activate PDP context - is this necessary?
 | 
			
		||||
    sendAT(GF("+CGACT=1,1"));
 | 
			
		||||
    waitResponse(60000L);
 | 
			
		||||
 | 
			
		||||
    //Start TCPIP Task and Set APN, User Name and Password
 | 
			
		||||
    sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" );
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Activate GPRS/CSD Context
 | 
			
		||||
    sendAT(GF("+QIACT"));
 | 
			
		||||
    if (waitResponse(60000L) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Enable multiple TCP/IP connections
 | 
			
		||||
    sendAT(GF("+QIMUX=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Request an IP header for received data ("IPD(data length):")
 | 
			
		||||
    sendAT(GF("+QIHEAD=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Set Method to Handle Received TCP/IP Data - Retrieve Data by Command
 | 
			
		||||
    sendAT(GF("+QINDI=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check that we have a local IP address
 | 
			
		||||
    if (localIP() != 0) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool gprsDisconnect() {
 | 
			
		||||
    sendAT(GF("+QIDEACT"));
 | 
			
		||||
    return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool isGprsConnected() {
 | 
			
		||||
    sendAT(GF("+CGATT?"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    int res = stream.readStringUntil('\n').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    if (res != 1)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+QILOCIP"));
 | 
			
		||||
    stream.readStringUntil('\n');
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Messaging functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String sendUSSD(const String& code) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CUSD=1,\""), code, GF("\""));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil('"');
 | 
			
		||||
    String hex = stream.readStringUntil('"');
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int dcs = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dcs == 15) {
 | 
			
		||||
      return TinyGsmDecodeHex8bit(hex);
 | 
			
		||||
    } else if (dcs == 72) {
 | 
			
		||||
      return TinyGsmDecodeHex16bit(hex);
 | 
			
		||||
    } else {
 | 
			
		||||
      return hex;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS(const String& number, const String& text) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    //Set GSM 7 bit default alphabet (3GPP TS 23.038)
 | 
			
		||||
    sendAT(GF("+CSCS=\"GSM\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.print(text);
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
 | 
			
		||||
    sendAT(GF("+CMGF=1"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSCS=\"HEX\""));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    sendAT(GF("+CSMP=17,167,0,8"));
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CMGS=\""), number, GF("\""));
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint16_t* t = (uint16_t*)text;
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      uint8_t c = t[i] >> 8;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
      c = t[i] & 0xFF;
 | 
			
		||||
      if (c < 0x10) { stream.print('0'); }
 | 
			
		||||
      stream.print(c, HEX);
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((char)0x1A);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    return waitResponse(60000L) == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** Delete all SMS */
 | 
			
		||||
  bool deleteAllSMS() {
 | 
			
		||||
    sendAT(GF("+QMGDA=6"));
 | 
			
		||||
    if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Location functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getGsmLocation() {
 | 
			
		||||
    sendAT(GF("+CIPGSMLOC=1,1"));
 | 
			
		||||
    if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
    String res = stream.readStringUntil('\n');
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    res.trim();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Battery functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Use: float vBatt = modem.getBattVoltage() / 1000.0;
 | 
			
		||||
  uint16_t getBattVoltage() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
    streamSkipUntil(','); // Skip
 | 
			
		||||
 | 
			
		||||
    uint16_t res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() {
 | 
			
		||||
    sendAT(GF("+CBC"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    stream.readStringUntil(',');
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt();
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
    sendAT(GF("+QIOPEN="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
 | 
			
		||||
    int rsp = waitResponse(75000L,
 | 
			
		||||
                           GF("CONNECT OK" GSM_NL),
 | 
			
		||||
                           GF("CONNECT FAIL" GSM_NL),
 | 
			
		||||
                           GF("ALREADY CONNECT" GSM_NL));
 | 
			
		||||
    if ( rsp != 1 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return (1 == rsp);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int modemSend(const void* buff, size_t len, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISEND="), mux, ',', len);
 | 
			
		||||
    if (waitResponse(GF(">")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    stream.write((uint8_t*)buff, len);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool allAcknowledged = false;
 | 
			
		||||
    // bool failed = false;
 | 
			
		||||
    while ( !allAcknowledged ) {
 | 
			
		||||
      sendAT( GF("+QISACK"));
 | 
			
		||||
      if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
      } else {
 | 
			
		||||
        streamSkipUntil(','); /** Skip total */
 | 
			
		||||
        streamSkipUntil(','); /** Skip acknowledged data size */
 | 
			
		||||
        if ( stream.readStringUntil('\n').toInt() == 0 ) {
 | 
			
		||||
          allAcknowledged = true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse(5000L);
 | 
			
		||||
 | 
			
		||||
    // streamSkipUntil(','); // Skip mux
 | 
			
		||||
    // return stream.readStringUntil('\n').toInt();
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemRead(size_t size, uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, ',', size);
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) != 1) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    size_t len = stream.readStringUntil('\n').toInt();
 | 
			
		||||
 | 
			
		||||
    for (size_t i=0; i<len; i++) {
 | 
			
		||||
      while (!stream.available()) { TINY_GSM_YIELD(); }
 | 
			
		||||
      char c = stream.read();
 | 
			
		||||
      sockets[mux]->rx.put(c);
 | 
			
		||||
    }
 | 
			
		||||
    waitResponse();
 | 
			
		||||
    DBG("### READ:", mux, ",", len);
 | 
			
		||||
    return len;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t modemGetAvailable(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QIRD="), mux, GF(",0"));
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    if (waitResponse(GF("+QIRD:")) == 1) {
 | 
			
		||||
      streamSkipUntil(','); // Skip total received
 | 
			
		||||
      streamSkipUntil(','); // Skip have read
 | 
			
		||||
      result = stream.readStringUntil('\n').toInt();
 | 
			
		||||
      DBG("### STILL:", mux, "has", result);
 | 
			
		||||
      waitResponse();
 | 
			
		||||
    }
 | 
			
		||||
    if (!result) {
 | 
			
		||||
      sockets[mux]->sock_connected = modemGetConnected(mux);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool modemGetConnected(uint8_t mux) {
 | 
			
		||||
    sendAT(GF("+QISTATE=1,"), mux);
 | 
			
		||||
    //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
 | 
			
		||||
 | 
			
		||||
    if (waitResponse(GF("+QISTATE:")))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    streamSkipUntil(','); // Skip mux
 | 
			
		||||
    streamSkipUntil(','); // Skip socket type
 | 
			
		||||
    streamSkipUntil(','); // Skip remote ip
 | 
			
		||||
    streamSkipUntil(','); // Skip remote port
 | 
			
		||||
    streamSkipUntil(','); // Skip local port
 | 
			
		||||
    int res = stream.readStringUntil(',').toInt(); // socket state
 | 
			
		||||
 | 
			
		||||
    waitResponse();
 | 
			
		||||
 | 
			
		||||
    // 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
 | 
			
		||||
    return 2 == res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
    stream.flush();
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    //DBG("### AT:", cmd...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: Optimize this!
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout, String& data,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=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();
 | 
			
		||||
    String r6s(r6); r6s.trim();
 | 
			
		||||
    DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
 | 
			
		||||
    data.reserve(64);
 | 
			
		||||
    int index = 0;
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    do {
 | 
			
		||||
      TINY_GSM_YIELD();
 | 
			
		||||
      while (stream.available() > 0) {
 | 
			
		||||
        int a = stream.read();
 | 
			
		||||
        if (a <= 0) continue; // Skip 0x00 bytes, just in case
 | 
			
		||||
        data += (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)) {
 | 
			
		||||
          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 (r6 && data.endsWith(r6)) {
 | 
			
		||||
          index = 6;
 | 
			
		||||
          goto finish;
 | 
			
		||||
        } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) {
 | 
			
		||||
          streamSkipUntil(',');  // Skip the context
 | 
			
		||||
          streamSkipUntil(',');  // Skip the role
 | 
			
		||||
          int mux = stream.readStringUntil('\n').toInt();
 | 
			
		||||
          DBG("### Got Data:", mux);
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->got_data = true;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
 | 
			
		||||
          int nl = data.lastIndexOf(GSM_NL, data.length()-8);
 | 
			
		||||
          int coma = data.indexOf(',', nl+2);
 | 
			
		||||
          int mux = data.substring(nl+2, coma).toInt();
 | 
			
		||||
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
 | 
			
		||||
            sockets[mux]->sock_connected = false;
 | 
			
		||||
          }
 | 
			
		||||
          data = "";
 | 
			
		||||
          DBG("### Closed: ", mux);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } while (millis() - startMillis < timeout);
 | 
			
		||||
finish:
 | 
			
		||||
    if (!index) {
 | 
			
		||||
      data.trim();
 | 
			
		||||
      if (data.length()) {
 | 
			
		||||
        DBG("### Unhandled:", data);
 | 
			
		||||
      }
 | 
			
		||||
      data = "";
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(uint32_t timeout,
 | 
			
		||||
                       GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    String data;
 | 
			
		||||
    return waitResponse(timeout, data, r1, r2, r3, r4, r5, r6);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
 | 
			
		||||
                       GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
 | 
			
		||||
  {
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5, r6);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  GsmClient*    sockets[TINY_GSM_MUX_COUNT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -45,8 +45,7 @@ enum TinyGSMDateTimeFormat {
 | 
			
		||||
  DATE_DATE = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmSim800
 | 
			
		||||
class TinyGsmSim800 : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -217,7 +216,7 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmSim800(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -225,11 +224,8 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -243,6 +239,19 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    #if defined(TINY_GSM_MODEM_SIM800)
 | 
			
		||||
      return "SIMCom SIM800";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM808)
 | 
			
		||||
      return "SIMCom SIM808";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM868)
 | 
			
		||||
      return "SIMCom SIM868";
 | 
			
		||||
    #elif defined(TINY_GSM_MODEM_SIM900)
 | 
			
		||||
      return "SIMCom SIM900";
 | 
			
		||||
    #endif
 | 
			
		||||
    return "SIMCom SIM800";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -312,6 +321,14 @@ public:
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -455,22 +472,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -591,6 +592,10 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+CIFSR;E0"));
 | 
			
		||||
    String res;
 | 
			
		||||
@@ -603,9 +608,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
@@ -800,6 +802,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
 | 
			
		||||
@@ -894,30 +900,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(const char c, const unsigned long timeout = 3000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  // enable GPS
 | 
			
		||||
  bool enableGPS() {
 | 
			
		||||
    uint16_t state;
 | 
			
		||||
    // uint16_t state;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSPWR=1"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
@@ -38,7 +38,7 @@ public:
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool disableGPS() {
 | 
			
		||||
    uint16_t state;
 | 
			
		||||
    // uint16_t state;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSPWR=0"));
 | 
			
		||||
    if (waitResponse() != 1) {
 | 
			
		||||
@@ -65,7 +65,7 @@ public:
 | 
			
		||||
  // works only with ans SIM808 V2
 | 
			
		||||
  bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
 | 
			
		||||
    //String buffer = "";
 | 
			
		||||
    char chr_buffer[12];
 | 
			
		||||
    // char chr_buffer[12];
 | 
			
		||||
    bool fix = false;
 | 
			
		||||
 | 
			
		||||
    sendAT(GF("+CGNSINF"));
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ enum RegStatus {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmUBLOX
 | 
			
		||||
class TinyGsmUBLOX : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -123,7 +123,7 @@ public:
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    at->maintain();
 | 
			
		||||
    size_t cnt = 0;
 | 
			
		||||
    while (cnt < size) {
 | 
			
		||||
    while (cnt < size && sock_connected) {
 | 
			
		||||
      size_t chunk = TinyGsmMin(size-cnt, rx.size());
 | 
			
		||||
      if (chunk > 0) {
 | 
			
		||||
        rx.get(buf, chunk);
 | 
			
		||||
@@ -201,7 +201,7 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmUBLOX(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {
 | 
			
		||||
    memset(sockets, 0, sizeof(sockets));
 | 
			
		||||
  }
 | 
			
		||||
@@ -209,9 +209,6 @@ public:
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin(const char* pin = NULL) {
 | 
			
		||||
    return init(pin);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    if (!testAT()) {
 | 
			
		||||
@@ -228,6 +225,10 @@ public:
 | 
			
		||||
    return (getSimStatus() == SIM_READY);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return "u-blox Cellular Modem";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    sendAT(GF("+IPR="), baud);
 | 
			
		||||
  }
 | 
			
		||||
@@ -280,6 +281,14 @@ public:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -400,22 +409,6 @@ public:
 | 
			
		||||
    return (s == REG_OK_HOME || s == REG_OK_ROAMING);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions
 | 
			
		||||
   */
 | 
			
		||||
  bool networkConnect(const char* ssid, const char* pwd) TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
  bool networkDisconnect() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -481,6 +474,10 @@ public:
 | 
			
		||||
    return localIP() != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    sendAT(GF("+UPSND=0,0"));
 | 
			
		||||
    if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
 | 
			
		||||
@@ -495,10 +492,6 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Phone Call functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -566,6 +559,10 @@ public:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) {
 | 
			
		||||
@@ -659,30 +656,9 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool streamSkipUntil(char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (millis() - startMillis < timeout) {
 | 
			
		||||
      while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
        TINY_GSM_YIELD();
 | 
			
		||||
      }
 | 
			
		||||
      if (stream.read() == c)
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ enum XBeeType {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmXBee
 | 
			
		||||
class TinyGsmXBee : public TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
@@ -207,17 +207,14 @@ public:
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmXBee(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
    : TinyGsmModem(stream), stream(stream)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
  bool begin() {
 | 
			
		||||
    return init();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool init() {
 | 
			
		||||
  bool init(const char* pin = NULL) {
 | 
			
		||||
    guardTime = 1100;  // Start with a default guard time of 1 second
 | 
			
		||||
 | 
			
		||||
    if (!commandMode(10)) return false;  // Try up to 10 times for the init
 | 
			
		||||
@@ -242,6 +239,10 @@ public:
 | 
			
		||||
    return ret_val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getModemName() {
 | 
			
		||||
    return getBeeName();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setBaud(unsigned long baud) {
 | 
			
		||||
    if (!commandMode()) return;
 | 
			
		||||
    switch(baud)
 | 
			
		||||
@@ -309,6 +310,16 @@ public:
 | 
			
		||||
    else return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasWifi() {
 | 
			
		||||
    if (beeType == XBEE_S6B_WIFI) return true;
 | 
			
		||||
    else return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool hasGPRS() {
 | 
			
		||||
    if (beeType == XBEE_S6B_WIFI) return false;
 | 
			
		||||
    else return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  XBeeType getBeeType() {
 | 
			
		||||
    return beeType;
 | 
			
		||||
  }
 | 
			
		||||
@@ -321,6 +332,7 @@ public:
 | 
			
		||||
      case XBEE3_LTE1_ATT: return "Digi XBee3™ Cellular LTE CAT 1";
 | 
			
		||||
      case XBEE3_LTEM_ATT: return "Digi XBee3™ Cellular LTE-M";
 | 
			
		||||
      case XBEE3_LTENB: return "Digi XBee3™ Cellular NB-IoT";
 | 
			
		||||
      default:  return "Digi XBee®";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -555,6 +567,10 @@ fail:
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  String getLocalIP() {
 | 
			
		||||
    if (!commandMode()) return "";  // Return immediately
 | 
			
		||||
    sendAT(GF("MY"));
 | 
			
		||||
@@ -566,10 +582,6 @@ fail:
 | 
			
		||||
    return IPaddr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions
 | 
			
		||||
   */
 | 
			
		||||
@@ -639,6 +651,10 @@ fail:
 | 
			
		||||
 | 
			
		||||
  int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Client related functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
  bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) {
 | 
			
		||||
@@ -704,63 +720,15 @@ protected:
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  /* Utilities */
 | 
			
		||||
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  void streamWrite(T last) {
 | 
			
		||||
    stream.print(last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename T, typename... Args>
 | 
			
		||||
  void streamWrite(T head, Args... tail) {
 | 
			
		||||
    stream.print(head);
 | 
			
		||||
    streamWrite(tail...);
 | 
			
		||||
  }
 | 
			
		||||
  /*
 | 
			
		||||
   Utilities
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  void streamClear(void) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    while (stream.available()) { stream.read(); }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool commandMode(int retries = 2) {
 | 
			
		||||
    int triesMade = 0;
 | 
			
		||||
    bool success = false;
 | 
			
		||||
    streamClear();  // Empty everything in the buffer before starting
 | 
			
		||||
    while (!success and triesMade < retries) {
 | 
			
		||||
      // Cannot send anything for 1 "guard time" before entering command mode
 | 
			
		||||
      // Default guard time is 1s, but the init fxn decreases it to 250 ms
 | 
			
		||||
      delay(guardTime);
 | 
			
		||||
      streamWrite(GF("+++"));  // enter command mode
 | 
			
		||||
      DBG("+++");
 | 
			
		||||
      success = (1 == waitResponse(guardTime*2));
 | 
			
		||||
      triesMade ++;
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool writeChanges(void) {
 | 
			
		||||
    sendAT(GF("WR"));  // Write changes to flash
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    sendAT(GF("AC"));  // Apply changes
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void exitCommand(void) {
 | 
			
		||||
    sendAT(GF("CN"));  // Exit command mode
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String readResponse(uint32_t timeout = 1000) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (!stream.available() && millis() - startMillis < timeout) {};
 | 
			
		||||
    String res = stream.readStringUntil('\r');  // lines end with carriage returns
 | 
			
		||||
    res.trim();
 | 
			
		||||
    DBG("<<< ", res);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template<typename... Args>
 | 
			
		||||
  void sendAT(Args... cmd) {
 | 
			
		||||
    streamWrite("AT", cmd..., GSM_NL);
 | 
			
		||||
@@ -825,6 +793,7 @@ finish:
 | 
			
		||||
        // DBG("<<< ", data);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    //DBG('<', index, '>');
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -842,6 +811,45 @@ finish:
 | 
			
		||||
    return waitResponse(1000, r1, r2, r3, r4, r5);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool commandMode(int retries = 2) {
 | 
			
		||||
    int triesMade = 0;
 | 
			
		||||
    bool success = false;
 | 
			
		||||
    streamClear();  // Empty everything in the buffer before starting
 | 
			
		||||
    while (!success and triesMade < retries) {
 | 
			
		||||
      // Cannot send anything for 1 "guard time" before entering command mode
 | 
			
		||||
      // Default guard time is 1s, but the init fxn decreases it to 250 ms
 | 
			
		||||
      delay(guardTime);
 | 
			
		||||
      streamWrite(GF("+++"));  // enter command mode
 | 
			
		||||
      DBG("+++");
 | 
			
		||||
      success = (1 == waitResponse(guardTime*2));
 | 
			
		||||
      triesMade ++;
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool writeChanges(void) {
 | 
			
		||||
    sendAT(GF("WR"));  // Write changes to flash
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    sendAT(GF("AC"));  // Apply changes
 | 
			
		||||
    if (1 != waitResponse()) return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void exitCommand(void) {
 | 
			
		||||
    sendAT(GF("CN"));  // Exit command mode
 | 
			
		||||
    waitResponse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String readResponse(uint32_t timeout = 1000) {
 | 
			
		||||
    TINY_GSM_YIELD();
 | 
			
		||||
    unsigned long startMillis = millis();
 | 
			
		||||
    while (!stream.available() && millis() - startMillis < timeout) {};
 | 
			
		||||
    String res = stream.readStringUntil('\r');  // lines end with carriage returns
 | 
			
		||||
    res.trim();
 | 
			
		||||
    DBG("<<< ", res);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ namespace {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
  #define DBG_PLAIN(...)
 | 
			
		||||
  #define DBG(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -194,4 +195,135 @@ String TinyGsmDecodeHex16bit(String &instr) {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TinyGsmModem
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
  TinyGsmModem(Stream& stream)
 | 
			
		||||
    : stream(stream)
 | 
			
		||||
  {}
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Basic functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // Prepare the modem for further functionality
 | 
			
		||||
  virtual bool init(const char* pin = NULL) = 0;
 | 
			
		||||
  // Begin is redundant with init
 | 
			
		||||
  virtual bool begin(const char* pin = NULL) {
 | 
			
		||||
    return init(pin);
 | 
			
		||||
  }
 | 
			
		||||
  // Returns a string with the chip name
 | 
			
		||||
  virtual String getModemName() = 0;
 | 
			
		||||
  // Sets the serial communication baud rate
 | 
			
		||||
  virtual void setBaud(unsigned long baud) = 0;
 | 
			
		||||
  // Checks that the modem is responding to standard AT commands
 | 
			
		||||
  virtual bool testAT(unsigned long timeout = 10000L) = 0;
 | 
			
		||||
  // Holds open communication with the modem waiting for data to come in
 | 
			
		||||
  virtual void maintain() = 0;
 | 
			
		||||
  // Resets all modem chip settings to factor defaults
 | 
			
		||||
  virtual bool factoryDefault() = 0;
 | 
			
		||||
  // Returns the response to a get info request.  The format varies by modem.
 | 
			
		||||
  virtual String getModemInfo() = 0;
 | 
			
		||||
  // Answers whether types of communication are available on this modem
 | 
			
		||||
  virtual bool hasSSL() = 0;
 | 
			
		||||
  virtual bool hasWifi() = 0;
 | 
			
		||||
  virtual bool hasGPRS() = 0;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Power functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool restart() = 0;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * SIM card functions - only apply to cellular modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool simUnlock(const char *pin) { return false; }
 | 
			
		||||
  virtual String getSimCCID() { return ""; }
 | 
			
		||||
  virtual String getIMEI() { return ""; }
 | 
			
		||||
  virtual String getOperator() { return ""; }
 | 
			
		||||
 | 
			
		||||
 /*
 | 
			
		||||
  * Generic network functions
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
  virtual int getSignalQuality() = 0;
 | 
			
		||||
  // NOTE:  this returns whether the modem is registered on the cellular or WiFi
 | 
			
		||||
  // network NOT whether GPRS or other internet connections are available
 | 
			
		||||
  virtual bool isNetworkConnected() = 0;
 | 
			
		||||
  virtual bool waitForNetwork(unsigned long timeout = 60000L) {
 | 
			
		||||
    for (unsigned long start = millis(); millis() - start < timeout; ) {
 | 
			
		||||
      if (isNetworkConnected()) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      delay(250);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * WiFi functions - only apply to WiFi modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool networkConnect(const char* ssid, const char* pwd) { return false; }
 | 
			
		||||
  virtual bool networkDisconnect() { return false; }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * GPRS functions - only apply to cellular modems
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  virtual bool gprsDisconnect() { return false; }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * IP Address functions
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  virtual String getLocalIP() = 0;
 | 
			
		||||
  virtual IPAddress localIP() {
 | 
			
		||||
    return TinyGsmIpFromString(getLocalIP());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     Utilities
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void streamWrite(T last) {
 | 
			
		||||
      stream.print(last);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename... Args>
 | 
			
		||||
    void streamWrite(T head, Args... tail) {
 | 
			
		||||
      stream.print(head);
 | 
			
		||||
      streamWrite(tail...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool streamSkipUntil(const char c, const unsigned long timeout = 1000L) {
 | 
			
		||||
      unsigned long startMillis = millis();
 | 
			
		||||
      while (millis() - startMillis < timeout) {
 | 
			
		||||
        while (millis() - startMillis < timeout && !stream.available()) {
 | 
			
		||||
          TINY_GSM_YIELD();
 | 
			
		||||
        }
 | 
			
		||||
        if (stream.read() == c)
 | 
			
		||||
          return true;
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  Stream&       stream;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
 *  DO NOT USE THIS - this is just a compilation test!
 | 
			
		||||
 *
 | 
			
		||||
 **************************************************************/
 | 
			
		||||
#define TINY_GSM_MODEM_SIM800
 | 
			
		||||
 | 
			
		||||
#include <TinyGsmClient.h>
 | 
			
		||||
 | 
			
		||||
@@ -77,4 +78,3 @@ void loop() {
 | 
			
		||||
    modem.networkDisconnect();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user