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
|
## 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**
|
**Data connections**
|
||||||
TCP (HTTP, MQTT, Blynk, ...) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔
|
TCP (HTTP, MQTT, Blynk, ...) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
|
||||||
UDP | ◌ | ◌ | | | | ◌
|
UDP | ◌ | ◌ | | | | ◌ | ◌ |
|
||||||
SSL/TLS (HTTPS) | ✔¹ | ✔ | 🅧 | 🅧 | ✔¹ | ✔¹
|
SSL/TLS (HTTPS) | ✔¹ | ✔ | 🅧 | 🅧 | ✔¹ | ✔¹ | |
|
||||||
**USSD**
|
**USSD**
|
||||||
Sending USSD requests | ✔ | | ✔ | ✔ | 🅧 |
|
Sending USSD requests | ✔ | | ✔ | ✔ | 🅧 | | |
|
||||||
Decoding 7,8,16-bit response | ✔ | | ✔ | ✔ | 🅧 |
|
Decoding 7,8,16-bit response | ✔ | | ✔ | ✔ | 🅧 | | |
|
||||||
**SMS**
|
**SMS**
|
||||||
Sending | ✔ | ✔ | ✔ | ✔ | 🅧 | ✔
|
Sending | ✔ | ✔ | ✔ | ✔ | 🅧 | ✔ | ✔ |
|
||||||
Sending Unicode | ✔ | | ◌ | 🅧 | 🅧 |
|
Sending Unicode | ✔ | | ◌ | 🅧 | 🅧 | | ? |
|
||||||
Reading | | | | | 🅧 |
|
Reading | | | | | 🅧 | | ? |
|
||||||
Incoming message event | | | | ? | 🅧 |
|
Incoming message event | | | | ? | 🅧 | | |
|
||||||
**Calls**
|
**Calls**
|
||||||
Dial, hangup | ✔ | | ✔ | 🅧 | 🅧 | 🅧
|
Dial, hangup | ✔ | | ✔ | 🅧 | 🅧 | 🅧 | ? |
|
||||||
Receiving calls | ✔ | | ✔ | 🅧 | 🅧 | 🅧
|
Receiving calls | ✔ | | ✔ | 🅧 | 🅧 | 🅧 | ? |
|
||||||
Incoming event (RING) | ◌ | | ◌ | 🅧 | 🅧 | 🅧
|
Incoming event (RING) | ◌ | | ◌ | 🅧 | 🅧 | 🅧 | ? |
|
||||||
DTMF sending | ✔ | | ✔ | 🅧 | 🅧 | 🅧
|
DTMF sending | ✔ | | ✔ | 🅧 | 🅧 | 🅧 | ? |
|
||||||
DTMF decoding | ◌ | | 🅧 | 🅧 | 🅧 | 🅧
|
DTMF decoding | ◌ | | 🅧 | 🅧 | 🅧 | 🅧 | ? |
|
||||||
**Location**
|
**Location**
|
||||||
GSM location service | ✔ | ✔ | 🅧 | 🅧 | 🅧 | ✔
|
GSM location service | ✔ | ✔ | 🅧 | 🅧 | 🅧 | ✔ | 🅧 |
|
||||||
GPS/GNSS | ✔¹ | 🅧 | ◌¹ | 🅧 | 🅧 | 🅧
|
GPS/GNSS | ✔¹ | 🅧 | ◌¹ | 🅧 | 🅧 | 🅧 | 🅧 |
|
||||||
|
|
||||||
✔ - implemented ◌ - planned 🅧 - not available on this modem
|
✔ - implemented ◌ - planned 🅧 - not available on this modem
|
||||||
¹ - only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
¹ - only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
||||||
@@ -72,6 +72,8 @@ GPS/GNSS | ✔¹ | 🅧 | ◌¹ | 🅧 |
|
|||||||
- Neoway M590
|
- Neoway M590
|
||||||
- u-blox Cellular Modems (LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
|
- u-blox Cellular Modems (LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
|
||||||
- Quectel BG96 ***(alpha)***
|
- Quectel BG96 ***(alpha)***
|
||||||
|
- Quectel M95 ***(alpha)***
|
||||||
|
- Quectel MC60 ***(alpha)***
|
||||||
|
|
||||||
### Supported boards/modules
|
### Supported boards/modules
|
||||||
- Arduino MKR GSM 1400
|
- 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).
|
- ... 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:
|
More modems may be supported later:
|
||||||
- [ ] Quectel M10, M35, M95, UG95, EC21
|
|
||||||
- [ ] Sequans Monarch LTE Cat M1/NB1
|
- [ ] Sequans Monarch LTE Cat M1/NB1
|
||||||
|
- [ ] Quectel M10, UG95
|
||||||
- [ ] SIMCom SIM5320, SIM5360, SIM5216, SIM7xxx
|
- [ ] SIMCom SIM5320, SIM5360, SIM5216, SIM7xxx
|
||||||
- [ ] Telit GL865
|
- [ ] Telit GL865
|
||||||
- [ ] ZTE MG2639
|
- [ ] ZTE MG2639
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
// #define TINY_GSM_MODEM_A6
|
// #define TINY_GSM_MODEM_A6
|
||||||
// #define TINY_GSM_MODEM_A7
|
// #define TINY_GSM_MODEM_A7
|
||||||
// #define TINY_GSM_MODEM_M590
|
// #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)
|
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
||||||
#define SerialMon Serial
|
#define SerialMon Serial
|
||||||
@@ -34,6 +36,22 @@
|
|||||||
//#define DUMP_AT_COMMANDS
|
//#define DUMP_AT_COMMANDS
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#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
|
// Set phone numbers, if you want to test SMS and Calls
|
||||||
//#define SMS_TARGET "+380xxxxxxxxx"
|
//#define SMS_TARGET "+380xxxxxxxxx"
|
||||||
//#define CALL_TARGET "+380xxxxxxxxx"
|
//#define CALL_TARGET "+380xxxxxxxxx"
|
||||||
@@ -64,7 +82,7 @@ void setup() {
|
|||||||
delay(3000);
|
delay(3000);
|
||||||
|
|
||||||
// Set GSM module baud rate
|
// Set GSM module baud rate
|
||||||
TinyGsmAutoBaud(SerialAT);
|
TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@@ -73,6 +91,10 @@ void loop() {
|
|||||||
// To skip it, call init() instead of restart()
|
// To skip it, call init() instead of restart()
|
||||||
DBG("Initializing modem...");
|
DBG("Initializing modem...");
|
||||||
if (!modem.restart()) {
|
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);
|
delay(10000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -80,8 +102,10 @@ void loop() {
|
|||||||
String modemInfo = modem.getModemInfo();
|
String modemInfo = modem.getModemInfo();
|
||||||
DBG("Modem:", modemInfo);
|
DBG("Modem:", modemInfo);
|
||||||
|
|
||||||
// Unlock your SIM card with a PIN
|
// Unlock your SIM card with a PIN if needed
|
||||||
//modem.simUnlock("1234");
|
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||||
|
modem.simUnlock(GSM_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
DBG("Waiting for network...");
|
DBG("Waiting for network...");
|
||||||
if (!modem.waitForNetwork()) {
|
if (!modem.waitForNetwork()) {
|
||||||
@@ -93,11 +117,13 @@ void loop() {
|
|||||||
DBG("Network connected");
|
DBG("Network connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TINY_GSM_USE_GPRS
|
||||||
DBG("Connecting to", apn);
|
DBG("Connecting to", apn);
|
||||||
if (!modem.gprsConnect(apn, user, pass)) {
|
if (!modem.gprsConnect(apn, user, pass)) {
|
||||||
delay(10000);
|
delay(10000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool res = modem.isGprsConnected();
|
bool res = modem.isGprsConnected();
|
||||||
DBG("GPRS status:", res ? "connected" : "not connected");
|
DBG("GPRS status:", res ? "connected" : "not connected");
|
||||||
@@ -110,9 +136,10 @@ void loop() {
|
|||||||
|
|
||||||
String cop = modem.getOperator();
|
String cop = modem.getOperator();
|
||||||
DBG("Operator:", cop);
|
DBG("Operator:", cop);
|
||||||
|
|
||||||
IPAddress local = modem.localIP();
|
IPAddress local = modem.localIP();
|
||||||
DBG("Local IP:", local);
|
DBG("Local IP:", local);
|
||||||
|
#endif
|
||||||
|
|
||||||
int csq = modem.getSignalQuality();
|
int csq = modem.getSignalQuality();
|
||||||
DBG("Signal quality:", csq);
|
DBG("Signal quality:", csq);
|
||||||
@@ -140,15 +167,16 @@ void loop() {
|
|||||||
|
|
||||||
String ussd_phone_num = modem.sendUSSD("*161#");
|
String ussd_phone_num = modem.sendUSSD("*161#");
|
||||||
DBG("Phone number (USSD):", ussd_phone_num);
|
DBG("Phone number (USSD):", ussd_phone_num);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TINY_GSM_MODEM_SIM808)
|
#if defined(TINY_GSM_MODEM_HAS_GPS)
|
||||||
modem.enableGPS();
|
modem.enableGPS();
|
||||||
String gps_raw = modem.getGPSraw();
|
String gps_raw = modem.getGPSraw();
|
||||||
modem.disableGPS();
|
modem.disableGPS();
|
||||||
DBG("GPS raw data:", gps_raw);
|
DBG("GPS raw data:", gps_raw);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SMS_TARGET)
|
#if TINY_GSM_USE_SMS && defined(SMS_TARGET)
|
||||||
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
||||||
DBG("SMS:", res ? "OK" : "fail");
|
DBG("SMS:", res ? "OK" : "fail");
|
||||||
|
|
||||||
@@ -157,7 +185,7 @@ void loop() {
|
|||||||
DBG("UTF16 SMS:", res ? "OK" : "fail");
|
DBG("UTF16 SMS:", res ? "OK" : "fail");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CALL_TARGET)
|
#if TINY_GSM_USE_CALL && defined(CALL_TARGET)
|
||||||
DBG("Calling:", CALL_TARGET);
|
DBG("Calling:", CALL_TARGET);
|
||||||
|
|
||||||
// This is NOT supported on M590
|
// This is NOT supported on M590
|
||||||
@@ -182,21 +210,24 @@ void loop() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_USE_GPRS
|
||||||
modem.gprsDisconnect();
|
modem.gprsDisconnect();
|
||||||
if (!modem.isGprsConnected()) {
|
if (!modem.isGprsConnected()) {
|
||||||
DBG("GPRS disconnected");
|
DBG("GPRS disconnected");
|
||||||
} else {
|
} else {
|
||||||
DBG("GPRS disconnect: Failed.");
|
DBG("GPRS disconnect: Failed.");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_POWERDOWN
|
||||||
// Try to power-off (modem may decide to restart automatically)
|
// Try to power-off (modem may decide to restart automatically)
|
||||||
// To turn off modem completely, please use Reset/Enable pins
|
// To turn off modem completely, please use Reset/Enable pins
|
||||||
modem.poweroff();
|
modem.poweroff();
|
||||||
DBG("Poweroff.");
|
DBG("Poweroff.");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Do nothing forevermore
|
// Do nothing forevermore
|
||||||
while (true) {
|
while (true) {
|
||||||
modem.maintain();
|
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",
|
"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",
|
"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",
|
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968",
|
||||||
"authors":
|
"authors":
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
name=TinyGSM
|
name=TinyGSM
|
||||||
version=0.3.5
|
version=0.3.6
|
||||||
author=Volodymyr Shymanskyy
|
author=Volodymyr Shymanskyy
|
||||||
maintainer=Volodymyr Shymanskyy
|
maintainer=Volodymyr Shymanskyy
|
||||||
sentence=A small Arduino library for GPRS modules, that just works.
|
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
|
category=Communication
|
||||||
url=https://github.com/vshymanskyy/TinyGSM
|
url=https://github.com/vshymanskyy/TinyGSM
|
||||||
architectures=*
|
architectures=*
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#endif
|
#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
|
#define TINY_GSM_MODEM_HAS_GPS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -38,6 +38,12 @@
|
|||||||
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
|
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
|
||||||
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
|
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)
|
#elif defined(TINY_GSM_MODEM_BG96)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#include <TinyGsmClientBG96.h>
|
#include <TinyGsmClientBG96.h>
|
||||||
@@ -56,6 +62,11 @@
|
|||||||
typedef TinyGsmM590 TinyGsm;
|
typedef TinyGsmM590 TinyGsm;
|
||||||
typedef TinyGsmM590::GsmClient TinyGsmClient;
|
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)
|
#elif defined(TINY_GSM_MODEM_ESP8266)
|
||||||
#define TINY_GSM_MODEM_HAS_WIFI
|
#define TINY_GSM_MODEM_HAS_WIFI
|
||||||
#include <TinyGsmClientESP8266.h>
|
#include <TinyGsmClientESP8266.h>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ enum RegStatus {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmA6
|
class TinyGsmA6 : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -178,7 +178,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmA6(Stream& stream)
|
TinyGsmA6(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -186,11 +186,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin() {
|
|
||||||
return init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init() {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -208,6 +205,15 @@ public:
|
|||||||
return true;
|
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) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -251,6 +257,14 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -367,22 +381,6 @@ public:
|
|||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
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
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
@@ -441,6 +439,10 @@ public:
|
|||||||
return (res == 1);
|
return (res == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+CIFSR"));
|
sendAT(GF("+CIFSR"));
|
||||||
String res;
|
String res;
|
||||||
@@ -453,10 +455,6 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
@@ -606,6 +604,10 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client related functions
|
||||||
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t* mux) {
|
||||||
@@ -650,30 +652,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ enum RegStatus {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmBG96
|
class TinyGsmBG96 : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -115,7 +115,7 @@ public:
|
|||||||
|
|
||||||
virtual int available() {
|
virtual int available() {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
if (!rx.size()) {
|
if (!rx.size() && sock_connected) {
|
||||||
at->maintain();
|
at->maintain();
|
||||||
}
|
}
|
||||||
return rx.size() + sock_available;
|
return rx.size() + sock_available;
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
at->maintain();
|
at->maintain();
|
||||||
size_t cnt = 0;
|
size_t cnt = 0;
|
||||||
while (cnt < size) {
|
while (cnt < size && sock_connected) {
|
||||||
size_t chunk = TinyGsmMin(size-cnt, rx.size());
|
size_t chunk = TinyGsmMin(size-cnt, rx.size());
|
||||||
if (chunk > 0) {
|
if (chunk > 0) {
|
||||||
rx.get(buf, chunk);
|
rx.get(buf, chunk);
|
||||||
@@ -179,30 +179,30 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class GsmClientSecure : public GsmClient
|
// class GsmClientSecure : public GsmClient
|
||||||
{
|
// {
|
||||||
public:
|
// public:
|
||||||
GsmClientSecure() {}
|
// GsmClientSecure() {}
|
||||||
|
//
|
||||||
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
|
// GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
|
||||||
: GsmClient(modem, mux)
|
// : GsmClient(modem, mux)
|
||||||
{}
|
// {}
|
||||||
|
//
|
||||||
public:
|
// public:
|
||||||
virtual int connect(const char *host, uint16_t port) {
|
// virtual int connect(const char *host, uint16_t port) {
|
||||||
stop();
|
// stop();
|
||||||
TINY_GSM_YIELD();
|
// TINY_GSM_YIELD();
|
||||||
rx.clear();
|
// rx.clear();
|
||||||
sock_connected = at->modemConnect(host, port, mux, true);
|
// sock_connected = at->modemConnect(host, port, mux, true);
|
||||||
return sock_connected;
|
// return sock_connected;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmBG96(Stream& stream)
|
TinyGsmBG96(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -210,11 +210,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin() {
|
|
||||||
return init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init() {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -226,6 +223,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getModemName() {
|
||||||
|
return "Quectel BG96";
|
||||||
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -280,6 +281,14 @@ public:
|
|||||||
return false; // TODO: For now
|
return false; // TODO: For now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -401,44 +410,30 @@ public:
|
|||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
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
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
||||||
gprsDisconnect();
|
gprsDisconnect();
|
||||||
|
|
||||||
|
//Configure the TCPIP Context
|
||||||
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Activate GPRS/CSD Context
|
||||||
sendAT(GF("+QIACT=1"));
|
sendAT(GF("+QIACT=1"));
|
||||||
if (waitResponse(150000L) != 1) {
|
if (waitResponse(150000L) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Attach to Packet Domain service - is this necessary?
|
||||||
sendAT(GF("+CGATT=1"));
|
sendAT(GF("+CGATT=1"));
|
||||||
if (waitResponse(60000L) != 1) {
|
if (waitResponse(60000L) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,12 +458,13 @@ public:
|
|||||||
return localIP() != 0;
|
return localIP() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+CGPADDR=1"));
|
sendAT(GF("+QILOCIP"));
|
||||||
if (waitResponse(10000L, GF(GSM_NL "+CGPADDR:")) != 1) {
|
stream.readStringUntil('\n');
|
||||||
return "";
|
|
||||||
}
|
|
||||||
streamSkipUntil(',');
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) {
|
||||||
return "";
|
return "";
|
||||||
@@ -476,10 +472,6 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
@@ -535,6 +527,8 @@ public:
|
|||||||
bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
|
bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
|
||||||
sendAT(GF("+CMGF=1"));
|
sendAT(GF("+CMGF=1"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
sendAT(GF("+CSCS=\"HEX\""));
|
||||||
|
waitResponse();
|
||||||
sendAT(GF("+CSMP=17,167,0,8"));
|
sendAT(GF("+CSMP=17,167,0,8"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -567,14 +561,42 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Battery functions
|
* 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:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
|
||||||
int rsp;
|
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"));
|
sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
|
||||||
rsp = waitResponse();
|
rsp = waitResponse();
|
||||||
|
|
||||||
@@ -660,30 +682,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ enum RegStatus {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmESP8266
|
class TinyGsmESP8266 : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -191,10 +191,11 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmESP8266(Stream& stream)
|
TinyGsmESP8266(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -202,11 +203,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin() {
|
|
||||||
return init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init() {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -225,6 +223,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getModemName() {
|
||||||
|
return "ESP8266";
|
||||||
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -266,6 +268,14 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -362,6 +372,10 @@ public:
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+CIPSTA_CUR??"));
|
sendAT(GF("+CIPSTA_CUR??"));
|
||||||
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
||||||
@@ -373,33 +387,9 @@ public:
|
|||||||
return res2;
|
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:
|
protected:
|
||||||
|
|
||||||
@@ -438,30 +428,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ enum RegStatus {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmM590
|
class TinyGsmM590 : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -175,7 +175,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmM590(Stream& stream)
|
TinyGsmM590(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -183,11 +183,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin() {
|
|
||||||
return init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init() {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -204,6 +201,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getModemName() {
|
||||||
|
return "Neoway M590";
|
||||||
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -255,6 +256,14 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -375,22 +384,6 @@ public:
|
|||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
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
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
@@ -447,6 +440,10 @@ public:
|
|||||||
return res == 1;
|
return res == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+XIIC?"));
|
sendAT(GF("+XIIC?"));
|
||||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
||||||
@@ -459,10 +456,6 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
@@ -538,6 +531,10 @@ public:
|
|||||||
|
|
||||||
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client related functions
|
||||||
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux) {
|
||||||
@@ -595,30 +592,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
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
|
DATE_DATE = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmSim800 : public TinyGsmModem
|
||||||
class TinyGsmSim800
|
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -217,7 +216,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmSim800(Stream& stream)
|
TinyGsmSim800(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -225,11 +224,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin() {
|
|
||||||
return init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init() {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -243,6 +239,19 @@ public:
|
|||||||
return true;
|
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) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -312,6 +321,14 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -455,22 +472,6 @@ public:
|
|||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
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
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
@@ -591,6 +592,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+CIFSR;E0"));
|
sendAT(GF("+CIFSR;E0"));
|
||||||
String res;
|
String res;
|
||||||
@@ -603,9 +608,6 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
@@ -800,6 +802,10 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client related functions
|
||||||
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
|
||||||
@@ -894,30 +900,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public:
|
|||||||
|
|
||||||
// enable GPS
|
// enable GPS
|
||||||
bool enableGPS() {
|
bool enableGPS() {
|
||||||
uint16_t state;
|
// uint16_t state;
|
||||||
|
|
||||||
sendAT(GF("+CGNSPWR=1"));
|
sendAT(GF("+CGNSPWR=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) {
|
||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool disableGPS() {
|
bool disableGPS() {
|
||||||
uint16_t state;
|
// uint16_t state;
|
||||||
|
|
||||||
sendAT(GF("+CGNSPWR=0"));
|
sendAT(GF("+CGNSPWR=0"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) {
|
||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
// works only with ans SIM808 V2
|
// works only with ans SIM808 V2
|
||||||
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
|
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
|
||||||
//String buffer = "";
|
//String buffer = "";
|
||||||
char chr_buffer[12];
|
// char chr_buffer[12];
|
||||||
bool fix = false;
|
bool fix = false;
|
||||||
|
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ enum RegStatus {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmUBLOX
|
class TinyGsmUBLOX : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -123,7 +123,7 @@ public:
|
|||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
at->maintain();
|
at->maintain();
|
||||||
size_t cnt = 0;
|
size_t cnt = 0;
|
||||||
while (cnt < size) {
|
while (cnt < size && sock_connected) {
|
||||||
size_t chunk = TinyGsmMin(size-cnt, rx.size());
|
size_t chunk = TinyGsmMin(size-cnt, rx.size());
|
||||||
if (chunk > 0) {
|
if (chunk > 0) {
|
||||||
rx.get(buf, chunk);
|
rx.get(buf, chunk);
|
||||||
@@ -201,7 +201,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmUBLOX(Stream& stream)
|
TinyGsmUBLOX(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{
|
{
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
@@ -209,9 +209,6 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
bool begin(const char* pin = NULL) {
|
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
bool init(const char* pin = NULL) {
|
||||||
if (!testAT()) {
|
if (!testAT()) {
|
||||||
@@ -228,6 +225,10 @@ public:
|
|||||||
return (getSimStatus() == SIM_READY);
|
return (getSimStatus() == SIM_READY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getModemName() {
|
||||||
|
return "u-blox Cellular Modem";
|
||||||
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaud(unsigned long baud) {
|
||||||
sendAT(GF("+IPR="), baud);
|
sendAT(GF("+IPR="), baud);
|
||||||
}
|
}
|
||||||
@@ -280,6 +281,14 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGPRS() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
@@ -400,22 +409,6 @@ public:
|
|||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
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
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
@@ -481,6 +474,10 @@ public:
|
|||||||
return localIP() != 0;
|
return localIP() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
sendAT(GF("+UPSND=0,0"));
|
sendAT(GF("+UPSND=0,0"));
|
||||||
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
|
||||||
@@ -495,10 +492,6 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
@@ -566,6 +559,10 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client related functions
|
||||||
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) {
|
||||||
@@ -659,30 +656,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ enum XBeeType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmXBee
|
class TinyGsmXBee : public TinyGsmModem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -207,17 +207,14 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
TinyGsmXBee(Stream& stream)
|
TinyGsmXBee(Stream& stream)
|
||||||
: stream(stream)
|
: TinyGsmModem(stream), stream(stream)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* 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
|
guardTime = 1100; // Start with a default guard time of 1 second
|
||||||
|
|
||||||
if (!commandMode(10)) return false; // Try up to 10 times for the init
|
if (!commandMode(10)) return false; // Try up to 10 times for the init
|
||||||
@@ -242,6 +239,10 @@ public:
|
|||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getModemName() {
|
||||||
|
return getBeeName();
|
||||||
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaud(unsigned long baud) {
|
||||||
if (!commandMode()) return;
|
if (!commandMode()) return;
|
||||||
switch(baud)
|
switch(baud)
|
||||||
@@ -309,6 +310,16 @@ public:
|
|||||||
else return true;
|
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() {
|
XBeeType getBeeType() {
|
||||||
return beeType;
|
return beeType;
|
||||||
}
|
}
|
||||||
@@ -321,6 +332,7 @@ public:
|
|||||||
case XBEE3_LTE1_ATT: return "Digi XBee3™ Cellular LTE CAT 1";
|
case XBEE3_LTE1_ATT: return "Digi XBee3™ Cellular LTE CAT 1";
|
||||||
case XBEE3_LTEM_ATT: return "Digi XBee3™ Cellular LTE-M";
|
case XBEE3_LTEM_ATT: return "Digi XBee3™ Cellular LTE-M";
|
||||||
case XBEE3_LTENB: return "Digi XBee3™ Cellular NB-IoT";
|
case XBEE3_LTENB: return "Digi XBee3™ Cellular NB-IoT";
|
||||||
|
default: return "Digi XBee®";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,6 +567,10 @@ fail:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IP Address functions
|
||||||
|
*/
|
||||||
|
|
||||||
String getLocalIP() {
|
String getLocalIP() {
|
||||||
if (!commandMode()) return ""; // Return immediately
|
if (!commandMode()) return ""; // Return immediately
|
||||||
sendAT(GF("MY"));
|
sendAT(GF("MY"));
|
||||||
@@ -566,10 +582,6 @@ fail:
|
|||||||
return IPaddr;
|
return IPaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPRS functions
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
@@ -639,6 +651,10 @@ fail:
|
|||||||
|
|
||||||
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client related functions
|
||||||
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) {
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) {
|
||||||
@@ -704,63 +720,15 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Utilities */
|
/*
|
||||||
|
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...);
|
|
||||||
}
|
|
||||||
|
|
||||||
void streamClear(void) {
|
void streamClear(void) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available()) { stream.read(); }
|
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>
|
template<typename... Args>
|
||||||
void sendAT(Args... cmd) {
|
void sendAT(Args... cmd) {
|
||||||
streamWrite("AT", cmd..., GSM_NL);
|
streamWrite("AT", cmd..., GSM_NL);
|
||||||
@@ -825,6 +793,7 @@ finish:
|
|||||||
// DBG("<<< ", data);
|
// DBG("<<< ", data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//DBG('<', index, '>');
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,6 +811,45 @@ finish:
|
|||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
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:
|
public:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
#define DBG_PLAIN(...)
|
||||||
#define DBG(...)
|
#define DBG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -194,4 +195,135 @@ String TinyGsmDecodeHex16bit(String &instr) {
|
|||||||
return result;
|
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
|
#endif
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* DO NOT USE THIS - this is just a compilation test!
|
* DO NOT USE THIS - this is just a compilation test!
|
||||||
*
|
*
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
#define TINY_GSM_MODEM_SIM800
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
|
|
||||||
@@ -77,4 +78,3 @@ void loop() {
|
|||||||
modem.networkDisconnect();
|
modem.networkDisconnect();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user