mirror of
https://github.com/KevinMidboe/TinyGSM.git
synced 2026-07-24 10:42:05 +00:00
+112
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: Google
|
||||||
|
AccessModifierOffset: -1
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: false
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignConsecutiveDeclarations: true
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: false
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: "^ IWYU pragma:"
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<ext/.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '.*.tpp'
|
||||||
|
Priority: 4
|
||||||
|
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ""
|
||||||
|
MacroBlockEnd: ""
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: None
|
||||||
|
# ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 25
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 600
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 50
|
||||||
|
PointerAlignment: Left
|
||||||
|
PointerBindsToType: true
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 2
|
||||||
|
UseTab: Never
|
||||||
|
---
|
||||||
@@ -22,7 +22,7 @@ with your board before submitting any issues.
|
|||||||
|
|
||||||
Main processor board: <!-- Uno, Zero, ESP32, Particle, etc -->
|
Main processor board: <!-- Uno, Zero, ESP32, Particle, etc -->
|
||||||
Modem: <!-- Brand, model, variant, firmware version -->
|
Modem: <!-- Brand, model, variant, firmware version -->
|
||||||
TinyGSM version: <!-- always try to use the latest (0.9.17) -->
|
TinyGSM version: <!-- always try to use the latest (0.10.0) -->
|
||||||
Code: <!-- Example name or paste in your code -->
|
Code: <!-- Example name or paste in your code -->
|
||||||
|
|
||||||
### Scenario, steps to reproduce
|
### Scenario, steps to reproduce
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
.clang_complete
|
.clang_complete
|
||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
platformio.ini
|
platformio.ini
|
||||||
|
extra_envs.ini
|
||||||
lib/readme.txt
|
lib/readme.txt
|
||||||
include/readme.txt
|
include/readme.txt
|
||||||
.atomrc.cson
|
.atomrc.cson
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
|
|||||||
- Neoway M590
|
- Neoway M590
|
||||||
- u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
|
- u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
|
||||||
- u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_)
|
- u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_)
|
||||||
- Sequans Monarch LTE Cat M1/NB1
|
- Sequans Monarch LTE Cat M1/NB1 (VZM20Q)
|
||||||
- Quectel BG96
|
- Quectel BG96
|
||||||
- Quectel M95
|
- Quectel M95
|
||||||
- Quectel MC60 ***(alpha)***
|
- Quectel MC60 ***(alpha)***
|
||||||
@@ -83,26 +83,29 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
|||||||
- SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
|
- SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
|
||||||
- Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
- Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
||||||
- Not yet supported on:
|
- Not yet supported on:
|
||||||
- Quectel modems, SIM7000, SIM5360/5320/7100/7500/7600
|
- Quectel modems, SIM7000, SIM5360/5320, SIM7100/7500/7600
|
||||||
- Not possible on:
|
- Not possible on:
|
||||||
- SIM900, A6/A7, M560, XBee _WiFi_
|
- SIM900, A6/A7, Neoway M590, XBee _WiFi_
|
||||||
|
|
||||||
**USSD**
|
**USSD**
|
||||||
- Sending USSD requests and decoding 7,8,16-bit responses
|
- Sending USSD requests and decoding 7,8,16-bit responses
|
||||||
- Supported on:
|
- Supported on:
|
||||||
- SIM800/SIM900, SIM7000
|
- All SIMCom modems, Quectel modems, most u-blox
|
||||||
- Not yet supported on:
|
- Not possible on:
|
||||||
- Quectel modems, SIM5360/5320/7100/7500/7600, XBee
|
- XBee, u-blox SARA R4/N4, ESP8266 (obviously)
|
||||||
|
|
||||||
**SMS**
|
**SMS**
|
||||||
- Only _sending_ SMS is supported, not receiving
|
- Only _sending_ SMS is supported, not receiving
|
||||||
- Supported on:
|
- Supported on all cellular modules
|
||||||
- SIM800/SIM900, SIM7000, XBee
|
|
||||||
- Not yet supported on:
|
|
||||||
- Quectel modems, SIM5360/5320/7100/7500/7600
|
|
||||||
|
|
||||||
**Voice Calls**
|
**Voice Calls**
|
||||||
- Only Supported on SIM800 and A6/A7/A20
|
- Supported on:
|
||||||
|
- SIM800/SIM900, A6/A7, Quectel modems, u-blox
|
||||||
|
- Not yet supported on:
|
||||||
|
- SIM7000, SIM5360/5320/7100, SIM7500/7600/7800, VZM20Q (Monarch)
|
||||||
|
- Not possible on:
|
||||||
|
- XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously)
|
||||||
|
- Functions:
|
||||||
- Dial, hangup
|
- Dial, hangup
|
||||||
- Receiving calls
|
- Receiving calls
|
||||||
- Incoming event (RING)
|
- Incoming event (RING)
|
||||||
@@ -111,9 +114,9 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
|||||||
|
|
||||||
**Location**
|
**Location**
|
||||||
- GPS/GNSS
|
- GPS/GNSS
|
||||||
- SIM808 and SIM7000 only
|
- SIM808, SIM7000, SIM7500/7600/7800 only
|
||||||
- GSM location service
|
- GSM location service
|
||||||
- SIM800, SIM and SIM7000 only
|
- SIM800, SIM7000, Quectel, u-blox
|
||||||
|
|
||||||
**Credits**
|
**Credits**
|
||||||
- Primary Authors/Contributors:
|
- Primary Authors/Contributors:
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Allow references to be used to change values
|
||||||
|
filter=-runtime/references
|
||||||
|
filter=-build/namespaces
|
||||||
@@ -49,18 +49,23 @@
|
|||||||
|
|
||||||
// Range to attempt to autobaud
|
// Range to attempt to autobaud
|
||||||
#define GSM_AUTOBAUD_MIN 9600
|
#define GSM_AUTOBAUD_MIN 9600
|
||||||
#define GSM_AUTOBAUD_MAX 38400
|
#define GSM_AUTOBAUD_MAX 115200
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests enabled
|
* Tests enabled
|
||||||
*/
|
*/
|
||||||
#define TINY_GSM_TEST_GPRS true
|
#define TINY_GSM_TEST_GPRS true
|
||||||
#define TINY_GSM_TEST_WIFI false
|
#define TINY_GSM_TEST_WIFI false
|
||||||
|
#define TINY_GSM_TEST_TCP true
|
||||||
|
#define TINY_GSM_TEST_SSL true
|
||||||
#define TINY_GSM_TEST_CALL true
|
#define TINY_GSM_TEST_CALL true
|
||||||
#define TINY_GSM_TEST_SMS true
|
#define TINY_GSM_TEST_SMS true
|
||||||
#define TINY_GSM_TEST_USSD true
|
#define TINY_GSM_TEST_USSD true
|
||||||
#define TINY_GSM_TEST_BATTERY true
|
#define TINY_GSM_TEST_BATTERY true
|
||||||
#define TINY_GSM_TEST_GPS false
|
#define TINY_GSM_TEST_TEMPERATURE true
|
||||||
|
#define TINY_GSM_TEST_GSM_LOCATION true
|
||||||
|
#define TINY_GSM_TEST_TIME true
|
||||||
|
#define TINY_GSM_TEST_GPS true
|
||||||
// powerdown modem after tests
|
// powerdown modem after tests
|
||||||
#define TINY_GSM_POWERDOWN false
|
#define TINY_GSM_POWERDOWN false
|
||||||
|
|
||||||
@@ -80,18 +85,16 @@ const char gprsPass[] = "";
|
|||||||
const char wifiSSID[] = "YourSSID";
|
const char wifiSSID[] = "YourSSID";
|
||||||
const char wifiPass[] = "YourWiFiPass";
|
const char wifiPass[] = "YourWiFiPass";
|
||||||
|
|
||||||
|
// Server details to test TCP/SSL
|
||||||
|
const char server[] = "vsh.pp.ua";
|
||||||
|
const char resource[] = "/TinyGSM/logo.txt";
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
|
|
||||||
#if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
|
#if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
|
||||||
#undef TINY_GSM_TEST_GPRS
|
#undef TINY_GSM_TEST_GPRS
|
||||||
#undef TINY_GSM_TEST_CALL
|
|
||||||
#undef TINY_GSM_TEST_SMS
|
|
||||||
#undef TINY_GSM_TEST_USSD
|
|
||||||
#undef TINY_GSM_TEST_WIFI
|
#undef TINY_GSM_TEST_WIFI
|
||||||
#define TINY_GSM_TEST_GPRS false
|
#define TINY_GSM_TEST_GPRS false
|
||||||
#define TINY_GSM_TEST_CALL false
|
|
||||||
#define TINY_GSM_TEST_SMS false
|
|
||||||
#define TINY_GSM_TEST_USSD false
|
|
||||||
#define TINY_GSM_TEST_WIFI true
|
#define TINY_GSM_TEST_WIFI true
|
||||||
#endif
|
#endif
|
||||||
#if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
|
#if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
|
||||||
@@ -100,10 +103,6 @@ const char wifiPass[] = "YourWiFiPass";
|
|||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
#define TINY_GSM_USE_WIFI false
|
#define TINY_GSM_USE_WIFI false
|
||||||
#endif
|
#endif
|
||||||
#if TINY_GSM_TEST_GPS && not defined TINY_GSM_MODEM_HAS_GPS
|
|
||||||
#undef TINY_GSM_TEST_GPS
|
|
||||||
#define TINY_GSM_TEST_GPS false
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DUMP_AT_COMMANDS
|
#ifdef DUMP_AT_COMMANDS
|
||||||
#include <StreamDebugger.h>
|
#include <StreamDebugger.h>
|
||||||
@@ -120,28 +119,28 @@ void setup() {
|
|||||||
|
|
||||||
// !!!!!!!!!!!
|
// !!!!!!!!!!!
|
||||||
// Set your reset, enable, power pins here
|
// Set your reset, enable, power pins here
|
||||||
|
pinMode(23, OUTPUT);
|
||||||
|
digitalWrite(23, HIGH);
|
||||||
// !!!!!!!!!!!
|
// !!!!!!!!!!!
|
||||||
|
|
||||||
DBG("Wait...");
|
DBG("Wait...");
|
||||||
|
delay(6000);
|
||||||
|
|
||||||
// Set GSM module baud rate
|
// Set GSM module baud rate
|
||||||
TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
|
TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
|
||||||
// SerialAT.begin(9600);
|
// SerialAT.begin(9600);
|
||||||
delay(3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// Restart takes quite some time
|
// Restart takes quite some time
|
||||||
// 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()) {
|
||||||
// if (!modem.init()) {
|
// if (!modem.init()) {
|
||||||
DBG("Failed to restart modem, delaying 10s and retrying");
|
DBG("Failed to restart modem, delaying 10s and retrying");
|
||||||
delay(3000);
|
delay(10000L);
|
||||||
// restart autobaud in case GSM just rebooted
|
// restart autobaud in case GSM just rebooted
|
||||||
TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
// TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
|
||||||
delay(10000);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +173,7 @@ void loop() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DBG("Waiting for network...");
|
DBG("Waiting for network...");
|
||||||
if (!modem.waitForNetwork()) {
|
if (!modem.waitForNetwork(600000L)) {
|
||||||
delay(10000);
|
delay(10000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -199,6 +198,9 @@ void loop() {
|
|||||||
String imei = modem.getIMEI();
|
String imei = modem.getIMEI();
|
||||||
DBG("IMEI:", imei);
|
DBG("IMEI:", imei);
|
||||||
|
|
||||||
|
String imsi = modem.getIMSI();
|
||||||
|
DBG("IMSI:", imsi);
|
||||||
|
|
||||||
String cop = modem.getOperator();
|
String cop = modem.getOperator();
|
||||||
DBG("Operator:", cop);
|
DBG("Operator:", cop);
|
||||||
|
|
||||||
@@ -207,19 +209,9 @@ void loop() {
|
|||||||
|
|
||||||
int csq = modem.getSignalQuality();
|
int csq = modem.getSignalQuality();
|
||||||
DBG("Signal quality:", csq);
|
DBG("Signal quality:", csq);
|
||||||
|
|
||||||
// This is only supported on SIMxxx series
|
|
||||||
// String gsmLoc = modem.getGsmLocation();
|
|
||||||
// DBG("GSM location:", gsmLoc);
|
|
||||||
|
|
||||||
// This is only supported on SIMxxx series
|
|
||||||
// String gsmTime = modem.getGSMDateTime(DATE_TIME);
|
|
||||||
// DBG("GSM Time:", gsmTime);
|
|
||||||
// String gsmDate = modem.getGSMDateTime(DATE_DATE);
|
|
||||||
// DBG("GSM Date:", gsmDate);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_USSD
|
#if TINY_GSM_TEST_USSD && defined TINY_GSM_MODEM_HAS_SMS
|
||||||
String ussd_balance = modem.sendUSSD("*111#");
|
String ussd_balance = modem.sendUSSD("*111#");
|
||||||
DBG("Balance (USSD):", ussd_balance);
|
DBG("Balance (USSD):", ussd_balance);
|
||||||
|
|
||||||
@@ -227,23 +219,70 @@ void loop() {
|
|||||||
DBG("Phone number (USSD):", ussd_phone_num);
|
DBG("Phone number (USSD):", ussd_phone_num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_GPS
|
#if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP
|
||||||
modem.enableGPS();
|
TinyGsmClient client(modem, 0);
|
||||||
String gps_raw = modem.getGPSraw();
|
const int port = 80;
|
||||||
modem.disableGPS();
|
DBG("Connecting to ", server);
|
||||||
DBG("GPS raw data:", gps_raw);
|
if (!client.connect(server, port)) {
|
||||||
|
DBG("... failed");
|
||||||
|
} else {
|
||||||
|
// Make a HTTP GET request:
|
||||||
|
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
|
||||||
|
client.print(String("Host: ") + server + "\r\n");
|
||||||
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
// Wait for data to arrive
|
||||||
|
uint32_t start = millis();
|
||||||
|
while (client.connected() && !client.available() &&
|
||||||
|
millis() - start < 30000L) {
|
||||||
|
delay(100);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read data
|
||||||
|
start = millis();
|
||||||
|
while (client.connected() && millis() - start < 5000L) {
|
||||||
|
while (client.available()) {
|
||||||
|
SerialMon.write(client.read());
|
||||||
|
start = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_SMS && defined(SMS_TARGET)
|
#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||||
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
TinyGsmClientSecure secureClient(modem, 1);
|
||||||
DBG("SMS:", res ? "OK" : "fail");
|
const int securePort = 443;
|
||||||
|
DBG("Connecting to ", server);
|
||||||
|
if (!secureClient.connect(server, securePort)) {
|
||||||
|
DBG("... failed");
|
||||||
|
} else {
|
||||||
|
// Make a HTTP GET request:
|
||||||
|
secureClient.print(String("GET ") + resource + " HTTP/1.0\r\n");
|
||||||
|
secureClient.print(String("Host: ") + server + "\r\n");
|
||||||
|
secureClient.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
// This is only supported on SIMxxx series
|
// Wait for data to arrive
|
||||||
res = modem.sendSMS_UTF16(SMS_TARGET, u"Привіііт!", 9);
|
uint32_t startS = millis();
|
||||||
DBG("UTF16 SMS:", res ? "OK" : "fail");
|
while (secureClient.connected() && !secureClient.available() &&
|
||||||
|
millis() - startS < 30000L) {
|
||||||
|
delay(100);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read data
|
||||||
|
startS = millis();
|
||||||
|
while (secureClient.connected() && millis() - startS < 5000L) {
|
||||||
|
while (secureClient.available()) {
|
||||||
|
SerialMon.write(secureClient.read());
|
||||||
|
startS = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secureClient.stop();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_CALL && defined(CALL_TARGET)
|
#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
|
||||||
|
defined CALL_TARGET
|
||||||
DBG("Calling:", CALL_TARGET);
|
DBG("Calling:", CALL_TARGET);
|
||||||
|
|
||||||
// This is NOT supported on M590
|
// This is NOT supported on M590
|
||||||
@@ -268,21 +307,120 @@ void loop() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_BATTERY
|
#if TINY_GSM_TEST_SMS && defined TINY_GSM_MODEM_HAS_SMS && defined SMS_TARGET
|
||||||
uint8_t chargeState = -99;
|
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
||||||
int8_t percent = -99;
|
DBG("SMS:", res ? "OK" : "fail");
|
||||||
uint16_t milliVolts = -9999;
|
|
||||||
modem.getBattStats(chargeState, percent, milliVolts);
|
|
||||||
DBG("Battery charge state:", chargeState);
|
|
||||||
DBG("Battery charge 'percent':", percent);
|
|
||||||
DBG("Battery voltage:", milliVolts / 1000.0F);
|
|
||||||
|
|
||||||
float temp = modem.getTemperature();
|
// This is only supported on SIMxxx series
|
||||||
DBG("Chip temperature:", temp);
|
res = modem.sendSMS_UTF8_begin(SMS_TARGET);
|
||||||
|
if (res) {
|
||||||
|
auto stream = modem.sendSMS_UTF8_stream();
|
||||||
|
stream.print(F("Привіііт! Print number: "));
|
||||||
|
stream.print(595);
|
||||||
|
res = modem.sendSMS_UTF8_end();
|
||||||
|
}
|
||||||
|
DBG("UTF8 SMS:", res ? "OK" : "fail");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION
|
||||||
|
float lat = 0;
|
||||||
|
float lon = 0;
|
||||||
|
float accuracy = 0;
|
||||||
|
int year = 0;
|
||||||
|
int month = 0;
|
||||||
|
int day = 0;
|
||||||
|
int hour = 0;
|
||||||
|
int min = 0;
|
||||||
|
int sec = 0;
|
||||||
|
for (int8_t i = 15; i; i--) {
|
||||||
|
DBG("Requesting current GSM location");
|
||||||
|
if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
|
||||||
|
&min, &sec)) {
|
||||||
|
DBG("Latitude:", String(lat, 8), "\tLongitude:", String(lon, 8));
|
||||||
|
DBG("Accuracy:", accuracy);
|
||||||
|
DBG("Year:", year, "\tMonth:", month, "\tDay:", day);
|
||||||
|
DBG("Hour:", hour, "\tMinute:", min, "\tSecond:", sec);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
DBG("Couldn't get GSM location, retrying in 15s.");
|
||||||
|
delay(15000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG("Retrieving GSM location again as a string");
|
||||||
|
String location = modem.getGsmLocation();
|
||||||
|
DBG("GSM Based Location String:", location);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS
|
||||||
|
DBG("Enabling GPS/GNSS/GLONASS and waiting 15s for warm-up");
|
||||||
|
modem.enableGPS();
|
||||||
|
delay(15000L);
|
||||||
|
float lat2 = 0;
|
||||||
|
float lon2 = 0;
|
||||||
|
float speed2 = 0;
|
||||||
|
float alt2 = 0;
|
||||||
|
int vsat2 = 0;
|
||||||
|
int usat2 = 0;
|
||||||
|
float accuracy2 = 0;
|
||||||
|
int year2 = 0;
|
||||||
|
int month2 = 0;
|
||||||
|
int day2 = 0;
|
||||||
|
int hour2 = 0;
|
||||||
|
int min2 = 0;
|
||||||
|
int sec2 = 0;
|
||||||
|
for (int8_t i = 15; i; i--) {
|
||||||
|
DBG("Requesting current GPS/GNSS/GLONASS location");
|
||||||
|
if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
|
||||||
|
&year2, &month2, &day2, &hour2, &min2, &sec2)) {
|
||||||
|
DBG("Latitude:", String(lat2, 8), "\tLongitude:", String(lon2, 8));
|
||||||
|
DBG("Speed:", speed2, "\tAltitude:", alt2);
|
||||||
|
DBG("Visible Satellites:", vsat2, "\tUsed Satellites:", usat2);
|
||||||
|
DBG("Accuracy:", accuracy2);
|
||||||
|
DBG("Year:", year2, "\tMonth:", month2, "\tDay:", day2);
|
||||||
|
DBG("Hour:", hour2, "\tMinute:", min2, "\tSecond:", sec2);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
DBG("Couldn't get GPS/GNSS/GLONASS location, retrying in 15s.");
|
||||||
|
delay(15000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG("Retrieving GPS/GNSS/GLONASS location again as a string");
|
||||||
|
String gps_raw = modem.getGPSraw();
|
||||||
|
DBG("GPS/GNSS Based Location String:", gps_raw);
|
||||||
|
DBG("Disabling GPS");
|
||||||
|
modem.disableGPS();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_TEST_TIME && defined TINY_GSM_MODEM_HAS_TIME
|
||||||
|
int year3 = 0;
|
||||||
|
int month3 = 0;
|
||||||
|
int day3 = 0;
|
||||||
|
int hour3 = 0;
|
||||||
|
int min3 = 0;
|
||||||
|
int sec3 = 0;
|
||||||
|
float timezone = 0;
|
||||||
|
for (int8_t i = 5; i; i--) {
|
||||||
|
DBG("Requesting current network time");
|
||||||
|
if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,
|
||||||
|
&timezone)) {
|
||||||
|
DBG("Year:", year3, "\tMonth:", month3, "\tDay:", day3);
|
||||||
|
DBG("Hour:", hour3, "\tMinute:", min3, "\tSecond:", sec3);
|
||||||
|
DBG("Timezone:", timezone);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
DBG("Couldn't get network time, retrying in 15s.");
|
||||||
|
delay(15000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG("Retrieving time again as a string");
|
||||||
|
String time = modem.getGSMDateTime(DATE_FULL);
|
||||||
|
DBG("Current Network Time:", time);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_TEST_GPRS
|
#if TINY_GSM_TEST_GPRS
|
||||||
modem.gprsDisconnect();
|
modem.gprsDisconnect();
|
||||||
|
delay(5000L);
|
||||||
if (!modem.isGprsConnected()) {
|
if (!modem.isGprsConnected()) {
|
||||||
DBG("GPRS disconnected");
|
DBG("GPRS disconnected");
|
||||||
} else {
|
} else {
|
||||||
@@ -295,6 +433,21 @@ void loop() {
|
|||||||
DBG("WiFi disconnected");
|
DBG("WiFi disconnected");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_TEST_BATTERY && defined TINY_GSM_MODEM_HAS_BATTERY
|
||||||
|
uint8_t chargeState = -99;
|
||||||
|
int8_t percent = -99;
|
||||||
|
uint16_t milliVolts = -9999;
|
||||||
|
modem.getBattStats(chargeState, percent, milliVolts);
|
||||||
|
DBG("Battery charge state:", chargeState);
|
||||||
|
DBG("Battery charge 'percent':", percent);
|
||||||
|
DBG("Battery voltage:", milliVolts / 1000.0F);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TINY_GSM_TEST_TEMPERATURE && defined TINY_GSM_MODEM_HAS_TEMPERATURE
|
||||||
|
float temp = modem.getTemperature();
|
||||||
|
DBG("Chip temperature:", temp);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if TINY_GSM_POWERDOWN
|
#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
|
||||||
@@ -302,6 +455,8 @@ void loop() {
|
|||||||
DBG("Poweroff.");
|
DBG("Poweroff.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DBG("End of tests.");
|
||||||
|
|
||||||
// Do nothing forevermore
|
// Do nothing forevermore
|
||||||
while (true) {
|
while (true) {
|
||||||
modem.maintain();
|
modem.maintain();
|
||||||
|
|||||||
@@ -49,7 +49,9 @@
|
|||||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||||
// need enough space in the buffer for the entire response
|
// need enough space in the buffer for the entire response
|
||||||
// else data will be lost (and the http library will fail).
|
// else data will be lost (and the http library will fail).
|
||||||
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
#define TINY_GSM_RX_BUFFER 1024
|
#define TINY_GSM_RX_BUFFER 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
// #define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
@@ -217,7 +219,7 @@ void loop() {
|
|||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
// Let's see what the entire elapsed time is, from after we send the request.
|
// Let's see what the entire elapsed time is, from after we send the request.
|
||||||
unsigned long timeElapsed = millis();
|
uint32_t timeElapsed = millis();
|
||||||
|
|
||||||
SerialMon.println(F("Waiting for response header"));
|
SerialMon.println(F("Waiting for response header"));
|
||||||
|
|
||||||
@@ -246,7 +248,7 @@ void loop() {
|
|||||||
// SerialMon.print(c, HEX);
|
// SerialMon.print(c, HEX);
|
||||||
// SerialMon.print(' ');
|
// SerialMon.print(' ');
|
||||||
// if (isprint(c))
|
// if (isprint(c))
|
||||||
// SerialMon.print((char) c);
|
// SerialMon.print(reinterpret_cast<char> c);
|
||||||
// else
|
// else
|
||||||
// SerialMon.print('*');
|
// SerialMon.print('*');
|
||||||
// SerialMon.print(' ');
|
// SerialMon.print(' ');
|
||||||
@@ -301,7 +303,7 @@ void loop() {
|
|||||||
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
|
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
uint8_t c = client.read();
|
uint8_t c = client.read();
|
||||||
//SerialMon.print((char)c); // Uncomment this to show data
|
//SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show data
|
||||||
crc.update(c);
|
crc.update(c);
|
||||||
readLength++;
|
readLength++;
|
||||||
if (readLength % (contentLength / 13) == 0) {
|
if (readLength % (contentLength / 13) == 0) {
|
||||||
|
|||||||
@@ -54,7 +54,9 @@
|
|||||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||||
// need enough space in the buffer for the entire response
|
// need enough space in the buffer for the entire response
|
||||||
// else data will be lost (and the http library will fail).
|
// else data will be lost (and the http library will fail).
|
||||||
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
#endif
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
// #define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|||||||
@@ -46,7 +46,9 @@
|
|||||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||||
// need enough space in the buffer for the entire response
|
// need enough space in the buffer for the entire response
|
||||||
// else data will be lost (and the http library will fail).
|
// else data will be lost (and the http library will fail).
|
||||||
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
#endif
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
// #define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
@@ -143,11 +145,6 @@ void setup() {
|
|||||||
modem.simUnlock(GSM_PIN);
|
modem.simUnlock(GSM_PIN);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!modem.hasSSL()) {
|
|
||||||
SerialMon.println(F("SSL is not supported by this modem"));
|
|
||||||
while(true) { delay(1000); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ PubSubClient mqtt(client);
|
|||||||
#define LED_PIN 13
|
#define LED_PIN 13
|
||||||
int ledStatus = LOW;
|
int ledStatus = LOW;
|
||||||
|
|
||||||
long lastReconnectAttempt = 0;
|
uint32_t lastReconnectAttempt = 0;
|
||||||
|
|
||||||
void mqttCallback(char* topic, byte* payload, unsigned int len) {
|
void mqttCallback(char* topic, byte* payload, unsigned int len) {
|
||||||
SerialMon.print("Message arrived [");
|
SerialMon.print("Message arrived [");
|
||||||
@@ -252,7 +252,7 @@ void loop() {
|
|||||||
if (!mqtt.connected()) {
|
if (!mqtt.connected()) {
|
||||||
SerialMon.println("=== MQTT NOT CONNECTED ===");
|
SerialMon.println("=== MQTT NOT CONNECTED ===");
|
||||||
// Reconnect every 10 seconds
|
// Reconnect every 10 seconds
|
||||||
unsigned long t = millis();
|
uint32_t t = millis();
|
||||||
if (t - lastReconnectAttempt > 10000L) {
|
if (t - lastReconnectAttempt > 10000L) {
|
||||||
lastReconnectAttempt = t;
|
lastReconnectAttempt = t;
|
||||||
if (mqttConnect()) {
|
if (mqttConnect()) {
|
||||||
|
|||||||
@@ -44,7 +44,9 @@
|
|||||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||||
// need enough space in the buffer for the entire response
|
// need enough space in the buffer for the entire response
|
||||||
// else data will be lost (and the http library will fail).
|
// else data will be lost (and the http library will fail).
|
||||||
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
#endif
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
// #define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
@@ -210,7 +212,7 @@ void loop() {
|
|||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
client.println();
|
client.println();
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
// Print available data
|
// Print available data
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
#define TINY_GSM_MODEM_UBLOX
|
#define TINY_GSM_MODEM_UBLOX
|
||||||
|
|
||||||
// Increase RX buffer if needed
|
// Increase RX buffer if needed
|
||||||
//#define TINY_GSM_RX_BUFFER 512
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
|
#define TINY_GSM_RX_BUFFER 512
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ void loop() {
|
|||||||
client.print(String("Host: ") + server + "\r\n");
|
client.print(String("Host: ") + server + "\r\n");
|
||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
// Print available data
|
// Print available data
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
#define TINY_GSM_MODEM_SIM800
|
#define TINY_GSM_MODEM_SIM800
|
||||||
|
|
||||||
// Increase RX buffer if needed
|
// Increase RX buffer if needed
|
||||||
//#define TINY_GSM_RX_BUFFER 512
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
|
#define TINY_GSM_RX_BUFFER 512
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
#include <ArduinoHttpClient.h>
|
#include <ArduinoHttpClient.h>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TinyGSM",
|
"name": "TinyGSM",
|
||||||
"version": "0.9.17",
|
"version": "0.10.0",
|
||||||
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.",
|
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.",
|
||||||
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
|
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
|
||||||
"authors":
|
"authors":
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
name=TinyGSM
|
name=TinyGSM
|
||||||
version=0.9.17
|
version=0.10.0
|
||||||
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.
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmBattery.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMBATTERY_H_
|
||||||
|
#define SRC_TINYGSMBATTERY_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_BATTERY
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmBattery {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Battery functions
|
||||||
|
*/
|
||||||
|
uint16_t getBattVoltage() {
|
||||||
|
return thisModem().getBattVoltageImpl();
|
||||||
|
}
|
||||||
|
int8_t getBattPercent() {
|
||||||
|
return thisModem().getBattPercentImpl();
|
||||||
|
}
|
||||||
|
uint8_t getBattChargeState() {
|
||||||
|
return thisModem().getBattChargeStateImpl();
|
||||||
|
}
|
||||||
|
bool getBattStats(uint8_t& chargeState, int8_t& percent,
|
||||||
|
uint16_t& milliVolts) {
|
||||||
|
return thisModem().getBattStatsImpl(chargeState, percent, milliVolts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Battery functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
||||||
|
uint16_t getBattVoltageImpl() {
|
||||||
|
thisModem().sendAT(GF("+CBC"));
|
||||||
|
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return 0; }
|
||||||
|
thisModem().streamSkipUntil(','); // Skip battery charge status
|
||||||
|
thisModem().streamSkipUntil(','); // Skip battery charge level
|
||||||
|
// return voltage in mV
|
||||||
|
uint16_t res = thisModem().streamGetIntBefore(',');
|
||||||
|
// Wait for final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t getBattPercentImpl() {
|
||||||
|
thisModem().sendAT(GF("+CBC"));
|
||||||
|
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; }
|
||||||
|
thisModem().streamSkipUntil(','); // Skip battery charge status
|
||||||
|
// Read battery charge level
|
||||||
|
int8_t res = thisModem().streamGetIntBefore(',');
|
||||||
|
// Wait for final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getBattChargeStateImpl() {
|
||||||
|
thisModem().sendAT(GF("+CBC"));
|
||||||
|
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; }
|
||||||
|
// Read battery charge status
|
||||||
|
int8_t res = thisModem().streamGetIntBefore(',');
|
||||||
|
// Wait for final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
|
uint16_t& milliVolts) {
|
||||||
|
thisModem().sendAT(GF("+CBC"));
|
||||||
|
if (thisModem().waitResponse(GF("+CBC:")) != 1) { return false; }
|
||||||
|
chargeState = thisModem().streamGetIntBefore(',');
|
||||||
|
percent = thisModem().streamGetIntBefore(',');
|
||||||
|
milliVolts = thisModem().streamGetIntBefore('\n');
|
||||||
|
// Wait for final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMBATTERY_H_
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmCalling.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMCALLING_H_
|
||||||
|
#define SRC_TINYGSMCALLING_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_CALLING
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmCalling {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Phone Call functions
|
||||||
|
*/
|
||||||
|
bool callAnswer() {
|
||||||
|
return thisModem().callAnswerImpl();
|
||||||
|
}
|
||||||
|
bool callNumber(const String& number) {
|
||||||
|
return thisModem().callNumberImpl(number);
|
||||||
|
}
|
||||||
|
bool callHangup() {
|
||||||
|
return thisModem().callHangupImpl();
|
||||||
|
}
|
||||||
|
bool dtmfSend(char cmd, int duration_ms = 100) {
|
||||||
|
return thisModem().dtmfSendImpl(cmd, duration_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phone Call functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
bool callAnswerImpl() {
|
||||||
|
thisModem().sendAT(GF("A"));
|
||||||
|
return thisModem().waitResponse() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true on pick-up, false on error/busy
|
||||||
|
bool callNumberImpl(const String& number) {
|
||||||
|
if (number == GF("last")) {
|
||||||
|
thisModem().sendAT(GF("DL"));
|
||||||
|
} else {
|
||||||
|
thisModem().sendAT(GF("D"), number, ";");
|
||||||
|
}
|
||||||
|
int8_t status = thisModem().waitResponse(60000L, GF("OK"), GF("BUSY"),
|
||||||
|
GF("NO ANSWER"), GF("NO CARRIER"));
|
||||||
|
switch (status) {
|
||||||
|
case 1: return true;
|
||||||
|
case 2:
|
||||||
|
case 3: return false;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool callHangupImpl() {
|
||||||
|
thisModem().sendAT(GF("H"));
|
||||||
|
return thisModem().waitResponse() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0-9,*,#,A,B,C,D
|
||||||
|
bool dtmfSendImpl(char cmd, int duration_ms = 100) {
|
||||||
|
duration_ms = constrain(duration_ms, 100, 1000);
|
||||||
|
|
||||||
|
thisModem().sendAT(GF("+VTD="),
|
||||||
|
duration_ms / 100); // VTD accepts in 1/10 of a second
|
||||||
|
thisModem().waitResponse();
|
||||||
|
|
||||||
|
thisModem().sendAT(GF("+VTS="), cmd);
|
||||||
|
return thisModem().waitResponse(10000L) == 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMCALLING_H_
|
||||||
+44
-69
@@ -6,129 +6,104 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClient_h
|
#ifndef SRC_TINYGSMCLIENT_H_
|
||||||
#define TinyGsmClient_h
|
#define SRC_TINYGSMCLIENT_H_
|
||||||
|
|
||||||
#if defined(TINY_GSM_MODEM_SIM800)
|
#if defined(TINY_GSM_MODEM_SIM800)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM800.h"
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
|
||||||
#include <TinyGsmClientSIM800.h>
|
|
||||||
typedef TinyGsmSim800 TinyGsm;
|
typedef TinyGsmSim800 TinyGsm;
|
||||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
|
||||||
typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
|
#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM808.h"
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
|
||||||
#include <TinyGsmClientSIM808.h>
|
|
||||||
typedef TinyGsmSim808 TinyGsm;
|
typedef TinyGsmSim808 TinyGsm;
|
||||||
typedef TinyGsmSim808::GsmClient TinyGsmClient;
|
typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient;
|
||||||
typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SIM900)
|
#elif defined(TINY_GSM_MODEM_SIM900)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM800.h"
|
||||||
#include <TinyGsmClientSIM800.h>
|
|
||||||
typedef TinyGsmSim800 TinyGsm;
|
typedef TinyGsmSim800 TinyGsm;
|
||||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SIM7000)
|
#elif defined(TINY_GSM_MODEM_SIM7000)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM7000.h"
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
|
||||||
#include <TinyGsmClientSIM7000.h>
|
|
||||||
typedef TinyGsmSim7000 TinyGsm;
|
typedef TinyGsmSim7000 TinyGsm;
|
||||||
typedef TinyGsmSim7000::GsmClient TinyGsmClient;
|
typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient;
|
||||||
// typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO!
|
// typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO!
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
|
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
|
||||||
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
|
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM5360.h"
|
||||||
#include <TinyGsmClientSIM5360.h>
|
|
||||||
typedef TinyGsmSim5360 TinyGsm;
|
typedef TinyGsmSim5360 TinyGsm;
|
||||||
typedef TinyGsmSim5360::GsmClient TinyGsmClient;
|
typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \
|
#elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \
|
||||||
defined(TINY_GSM_MODEM_SIM7500)
|
defined(TINY_GSM_MODEM_SIM7500)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSIM7600.h"
|
||||||
#include <TinyGsmClientSIM7600.h>
|
|
||||||
typedef TinyGsmSim7600 TinyGsm;
|
typedef TinyGsmSim7600 TinyGsm;
|
||||||
typedef TinyGsmSim7600::GsmClient TinyGsmClient;
|
typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_UBLOX)
|
#elif defined(TINY_GSM_MODEM_UBLOX)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientUBLOX.h"
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
|
||||||
#include <TinyGsmClientUBLOX.h>
|
|
||||||
typedef TinyGsmUBLOX TinyGsm;
|
typedef TinyGsmUBLOX TinyGsm;
|
||||||
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
|
typedef TinyGsmUBLOX::GsmClientUBLOX TinyGsmClient;
|
||||||
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SARAR4)
|
#elif defined(TINY_GSM_MODEM_SARAR4)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSaraR4.h"
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
|
||||||
#include <TinyGsmClientSaraR4.h>
|
|
||||||
typedef TinyGsmSaraR4 TinyGsm;
|
typedef TinyGsmSaraR4 TinyGsm;
|
||||||
typedef TinyGsmSaraR4::GsmClient TinyGsmClient;
|
typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient;
|
||||||
typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_M95)
|
#elif defined(TINY_GSM_MODEM_M95)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientM95.h"
|
||||||
#include <TinyGsmClientM95.h>
|
|
||||||
typedef TinyGsmM95 TinyGsm;
|
typedef TinyGsmM95 TinyGsm;
|
||||||
typedef TinyGsmM95::GsmClient TinyGsmClient;
|
typedef TinyGsmM95::GsmClientM95 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_BG96)
|
#elif defined(TINY_GSM_MODEM_BG96)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientBG96.h"
|
||||||
#include <TinyGsmClientBG96.h>
|
|
||||||
typedef TinyGsmBG96 TinyGsm;
|
typedef TinyGsmBG96 TinyGsm;
|
||||||
typedef TinyGsmBG96::GsmClient TinyGsmClient;
|
typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
|
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientA6.h"
|
||||||
#include <TinyGsmClientA6.h>
|
|
||||||
typedef TinyGsmA6 TinyGsm;
|
typedef TinyGsmA6 TinyGsm;
|
||||||
typedef TinyGsmA6::GsmClient TinyGsmClient;
|
typedef TinyGsmA6::GsmClientA6 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_M590)
|
#elif defined(TINY_GSM_MODEM_M590)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientM590.h"
|
||||||
#include <TinyGsmClientM590.h>
|
|
||||||
typedef TinyGsmM590 TinyGsm;
|
typedef TinyGsmM590 TinyGsm;
|
||||||
typedef TinyGsmM590::GsmClient TinyGsmClient;
|
typedef TinyGsmM590::GsmClientM590 TinyGsmClient;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
|
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
|
||||||
#include <TinyGsmClientMC60.h>
|
#include "TinyGsmClientMC60.h"
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
|
||||||
typedef TinyGsmMC60 TinyGsm;
|
typedef TinyGsmMC60 TinyGsm;
|
||||||
typedef TinyGsmMC60::GsmClient TinyGsmClient;
|
typedef TinyGsmMC60::GsmClientMC60 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
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#include "TinyGsmClientESP8266.h"
|
||||||
#include <TinyGsmClientESP8266.h>
|
|
||||||
typedef TinyGsmESP8266 TinyGsm;
|
typedef TinyGsmESP8266 TinyGsm;
|
||||||
typedef TinyGsmESP8266::GsmClient TinyGsmClient;
|
typedef TinyGsmESP8266::GsmClientESP8266 TinyGsmClient;
|
||||||
typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_XBEE)
|
#elif defined(TINY_GSM_MODEM_XBEE)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
|
||||||
#define TINY_GSM_MODEM_HAS_WIFI
|
#define TINY_GSM_MODEM_HAS_WIFI
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#include "TinyGsmClientXBee.h"
|
||||||
#include <TinyGsmClientXBee.h>
|
|
||||||
typedef TinyGsmXBee TinyGsm;
|
typedef TinyGsmXBee TinyGsm;
|
||||||
typedef TinyGsmXBee::GsmClient TinyGsmClient;
|
typedef TinyGsmXBee::GsmClientXBee TinyGsmClient;
|
||||||
typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure;
|
||||||
|
|
||||||
#elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
|
#elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
|
||||||
#define TINY_GSM_MODEM_HAS_GPRS
|
#include "TinyGsmClientSequansMonarch.h"
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
|
||||||
#include <TinyGsmClientSequansMonarch.h>
|
|
||||||
typedef TinyGsmSequansMonarch TinyGsm;
|
typedef TinyGsmSequansMonarch TinyGsm;
|
||||||
typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient;
|
typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient;
|
||||||
typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure;
|
typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch
|
||||||
|
TinyGsmClientSecure;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "Please define GSM modem model"
|
#error "Please define GSM modem model"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENT_H_
|
||||||
|
|||||||
+219
-358
@@ -6,31 +6,32 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientA6_h
|
#ifndef SRC_TINYGSMCLIENTA6_H_
|
||||||
#define TinyGsmClientA6_h
|
#define SRC_TINYGSMCLIENTA6_H_
|
||||||
// #pragma message("TinyGSM: TinyGsmClientA6")
|
// #pragma message("TinyGSM: TinyGsmClientA6")
|
||||||
|
|
||||||
// #define TINY_GSM_DEBUG Serial
|
// #define TINY_GSM_DEBUG Serial
|
||||||
|
|
||||||
#if !defined(TINY_GSM_RX_BUFFER)
|
|
||||||
#define TINY_GSM_RX_BUFFER 256
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TINY_GSM_MUX_COUNT 8
|
#define TINY_GSM_MUX_COUNT 8
|
||||||
|
#define TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmBattery.tpp"
|
||||||
|
#include "TinyGsmCalling.tpp"
|
||||||
|
#include "TinyGsmGPRS.tpp"
|
||||||
|
#include "TinyGsmModem.tpp"
|
||||||
|
#include "TinyGsmSMS.tpp"
|
||||||
|
#include "TinyGsmTCP.tpp"
|
||||||
|
#include "TinyGsmTime.tpp"
|
||||||
|
|
||||||
#define GSM_NL "\r\n"
|
#define GSM_NL "\r\n"
|
||||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
enum SimStatus {
|
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
SIM_ERROR = 0,
|
#endif
|
||||||
SIM_READY = 1,
|
|
||||||
SIM_LOCKED = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RegStatus {
|
enum RegStatus {
|
||||||
|
REG_NO_RESULT = -1,
|
||||||
REG_UNREGISTERED = 0,
|
REG_UNREGISTERED = 0,
|
||||||
REG_SEARCHING = 2,
|
REG_SEARCHING = 2,
|
||||||
REG_DENIED = 3,
|
REG_DENIED = 3,
|
||||||
@@ -39,27 +40,36 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
|
||||||
|
public TinyGsmGPRS<TinyGsmA6>,
|
||||||
|
public TinyGsmTCP<TinyGsmA6, TINY_GSM_MUX_COUNT>,
|
||||||
|
public TinyGsmCalling<TinyGsmA6>,
|
||||||
|
public TinyGsmSMS<TinyGsmA6>,
|
||||||
|
public TinyGsmTime<TinyGsmA6>,
|
||||||
|
public TinyGsmBattery<TinyGsmA6> {
|
||||||
|
friend class TinyGsmModem<TinyGsmA6>;
|
||||||
|
friend class TinyGsmGPRS<TinyGsmA6>;
|
||||||
|
friend class TinyGsmTCP<TinyGsmA6, TINY_GSM_MUX_COUNT>;
|
||||||
|
friend class TinyGsmCalling<TinyGsmA6>;
|
||||||
|
friend class TinyGsmSMS<TinyGsmA6>;
|
||||||
|
friend class TinyGsmTime<TinyGsmA6>;
|
||||||
|
friend class TinyGsmBattery<TinyGsmA6>;
|
||||||
|
|
||||||
class TinyGsmA6
|
/*
|
||||||
{
|
* Inner Client
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
class GsmClientA6 : public GsmClient {
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmA6;
|
friend class TinyGsmA6;
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GsmClient() {}
|
GsmClientA6() {}
|
||||||
|
|
||||||
GsmClient(TinyGsmA6& modem) {
|
explicit GsmClientA6(TinyGsmA6& modem, uint8_t = 0) {
|
||||||
init(&modem);
|
init(&modem, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
bool init(TinyGsmA6* modem, uint8_t = 0) {
|
||||||
|
|
||||||
bool init(TinyGsmA6* modem) {
|
|
||||||
this->at = modem;
|
this->at = modem;
|
||||||
this->mux = -1;
|
this->mux = -1;
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
@@ -68,7 +78,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
stop();
|
stop();
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
rx.clear();
|
rx.clear();
|
||||||
@@ -80,70 +90,54 @@ public:
|
|||||||
}
|
}
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
at->waitResponse(maxWaitMs);
|
at->waitResponse(maxWaitMs);
|
||||||
rx.clear();
|
rx.clear();
|
||||||
}
|
}
|
||||||
|
void stop() override {
|
||||||
virtual void stop() { stop(1000L); }
|
stop(1000L);
|
||||||
|
}
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Extended API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
private:
|
|
||||||
TinyGsmA6* at;
|
|
||||||
uint8_t mux;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Doesn't support SSL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
explicit TinyGsmA6(Stream& stream) : stream(stream) {
|
||||||
TinyGsmA6(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TinyGsmA6() {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool begin(const char* pin = NULL) {
|
bool initImpl(const char* pin = NULL) {
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
|
||||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||||
|
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
|
// sendAT(GF("&FZ")); // Factory + Reset
|
||||||
if (waitResponse() != 1) {
|
// waitResponse();
|
||||||
return false;
|
|
||||||
}
|
sendAT(GF("E0")); // Echo Off
|
||||||
|
if (waitResponse() != 1) { return false; }
|
||||||
|
|
||||||
#ifdef TINY_GSM_DEBUG
|
#ifdef TINY_GSM_DEBUG
|
||||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
@@ -151,161 +145,86 @@ public:
|
|||||||
sendAT(GF("+CMEE=0")); // turn off error codes
|
sendAT(GF("+CMEE=0")); // turn off error codes
|
||||||
#endif
|
#endif
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination
|
sendAT(
|
||||||
|
GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
int ret = getSimStatus();
|
SimStatus ret = getSimStatus();
|
||||||
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
||||||
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||||
simUnlock(pin);
|
simUnlock(pin);
|
||||||
return (getSimStatus() == SIM_READY);
|
return (getSimStatus() == SIM_READY);
|
||||||
}
|
} else {
|
||||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
// if the sim is ready, or it's locked but no pin has been provided,
|
||||||
// true
|
// return true
|
||||||
else {
|
|
||||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
bool factoryDefaultImpl() {
|
||||||
#if defined(TINY_GSM_MODEM_A6)
|
|
||||||
return "AI-Thinker A6";
|
|
||||||
#elif defined(TINY_GSM_MODEM_A7)
|
|
||||||
return "AI-Thinker A7";
|
|
||||||
#endif
|
|
||||||
return "AI-Thinker A6";
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("&W")); // Write configuration
|
sendAT(GF("&W")); // Write configuration
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWifi() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasGPRS() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+RST=1"));
|
sendAT(GF("+RST=1"));
|
||||||
delay(3000);
|
delay(3000);
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+CPOF"));
|
sendAT(GF("+CPOF"));
|
||||||
|
// +CPOF: MS OFF OK
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SIM card functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+CCID"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
|
||||||
res.trim();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_IMEI_GSN()
|
|
||||||
|
|
||||||
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
|
||||||
sendAT(GF("+CPIN?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
|
||||||
delay(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
|
|
||||||
waitResponse();
|
|
||||||
switch (status) {
|
|
||||||
case 2:
|
|
||||||
case 3: return SIM_LOCKED;
|
|
||||||
case 1: return SIM_READY;
|
|
||||||
default: return SIM_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SIM_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
|
|
||||||
|
|
||||||
String getOperator() {
|
|
||||||
sendAT(GF("+COPS=3,0")); // Set format
|
|
||||||
waitResponse();
|
|
||||||
|
|
||||||
sendAT(GF("+COPS?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
streamSkipUntil('"'); // Skip mode and format
|
|
||||||
String res = stream.readStringUntil('"');
|
|
||||||
waitResponse();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||||
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
String getLocalIPImpl() {
|
||||||
|
sendAT(GF("+CIFSR"));
|
||||||
|
String res;
|
||||||
|
if (waitResponse(10000L, res) != 1) { return ""; }
|
||||||
|
res.replace(GSM_NL "OK" GSM_NL, "");
|
||||||
|
res.replace(GSM_NL, "");
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPRS functions
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
gprsDisconnect();
|
gprsDisconnect();
|
||||||
|
|
||||||
sendAT(GF("+CGATT=1"));
|
sendAT(GF("+CGATT=1"));
|
||||||
if (waitResponse(60000L) != 1)
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO: wait AT+CGATT?
|
// TODO(?): wait AT+CGATT?
|
||||||
|
|
||||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
@@ -313,117 +232,89 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
if (!user) user = "";
|
if (!user) user = "";
|
||||||
if (!pwd) pwd = "";
|
if (!pwd) pwd = "";
|
||||||
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||||
if (waitResponse(60000L) != 1) {
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("+CGACT=1,1"));
|
sendAT(GF("+CGACT=1,1"));
|
||||||
waitResponse(60000L);
|
waitResponse(60000L);
|
||||||
|
|
||||||
sendAT(GF("+CIPMUX=1"));
|
sendAT(GF("+CIPMUX=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
// Shut the TCP/IP connection
|
// Shut the TCP/IP connection
|
||||||
sendAT(GF("+CIPSHUT"));
|
sendAT(GF("+CIPSHUT"));
|
||||||
if (waitResponse(60000L) != 1)
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
sendAT(GF("+CGATT=0"));
|
sendAT(GF("+CGATT=0"));
|
||||||
if (waitResponse(5000L) == 1)
|
if (waitResponse(5000L) == 1) { return true; }
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isGprsConnected() {
|
String getOperatorImpl() {
|
||||||
sendAT(GF("+CGATT?"));
|
sendAT(GF("+COPS=3,0")); // Set format
|
||||||
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int res = stream.readStringUntil('\n').toInt();
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return (res == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
sendAT(GF("+COPS?"));
|
||||||
* IP Address functions
|
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
|
||||||
*/
|
streamSkipUntil('"'); // Skip mode and format
|
||||||
|
String res = stream.readStringUntil('"');
|
||||||
String getLocalIP() {
|
waitResponse();
|
||||||
sendAT(GF("+CIFSR"));
|
|
||||||
String res;
|
|
||||||
if (waitResponse(10000L, res) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
res.replace(GSM_NL "OK" GSM_NL, "");
|
|
||||||
res.replace(GSM_NL, "");
|
|
||||||
res.trim();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
/*
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
* SIM card functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
String getSimCCIDImpl() {
|
||||||
|
sendAT(GF("+CCID"));
|
||||||
|
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; }
|
||||||
|
String res = stream.readStringUntil('\n');
|
||||||
|
waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
bool callAnswer() {
|
|
||||||
sendAT(GF("A"));
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true on pick-up, false on error/busy
|
// Returns true on pick-up, false on error/busy
|
||||||
bool callNumber(const String& number) {
|
bool callNumberImpl(const String& number) {
|
||||||
if (number == GF("last")) {
|
if (number == GF("last")) {
|
||||||
sendAT(GF("DLST"));
|
sendAT(GF("DLST"));
|
||||||
} else {
|
} else {
|
||||||
sendAT(GF("D\""), number, "\";");
|
sendAT(GF("D\""), number, "\";");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitResponse(5000L) != 1) {
|
if (waitResponse(5000L) != 1) { return false; }
|
||||||
|
|
||||||
|
if (waitResponse(60000L, GF(GSM_NL "+CIEV: \"CALL\",1"),
|
||||||
|
GF(GSM_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitResponse(60000L,
|
int8_t rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",1"),
|
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",0"),
|
|
||||||
GFP(GSM_ERROR)) != 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rsp = waitResponse(60000L,
|
|
||||||
GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
||||||
|
|
||||||
int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL));
|
int8_t rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL),
|
||||||
|
GF(GSM_NL "NO ANSWER" GSM_NL));
|
||||||
|
|
||||||
return rsp == 1 && rsp2 == 0;
|
return rsp == 1 && rsp2 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool callHangup() {
|
|
||||||
sendAT(GF("H"));
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0-9,*,#,A,B,C,D
|
// 0-9,*,#,A,B,C,D
|
||||||
bool dtmfSend(char cmd, unsigned duration_ms = 100) {
|
bool dtmfSendImpl(char cmd, uint8_t duration_ms = 100) {
|
||||||
duration_ms = constrain(duration_ms, 100, 1000);
|
duration_ms = constrain(duration_ms, 100, 1000);
|
||||||
|
|
||||||
// The duration parameter is not working, so we simulate it using delay..
|
// The duration parameter is not working, so we simulate it using delay..
|
||||||
// TODO: Maybe there's another way...
|
// TODO(?): Maybe there's another way...
|
||||||
|
|
||||||
// sendAT(GF("+VTD="), duration_ms / 100);
|
// sendAT(GF("+VTD="), duration_ms / 100);
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
@@ -439,7 +330,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
/*
|
/*
|
||||||
* Audio functions
|
* Audio functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
bool audioSetHeadphones() {
|
bool audioSetHeadphones() {
|
||||||
sendAT(GF("+SNFS=0"));
|
sendAT(GF("+SNFS=0"));
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
@@ -458,23 +349,19 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
/*
|
/*
|
||||||
* Messaging functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String sendUSSD(const String& code) {
|
String sendUSSDImpl(const String& code) {
|
||||||
sendAT(GF("+CMGF=1"));
|
sendAT(GF("+CMGF=1"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+CSCS=\"HEX\""));
|
sendAT(GF("+CSCS=\"HEX\""));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
|
sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
|
||||||
if (waitResponse(10000L) != 1) {
|
if (waitResponse(10000L) != 1) { return ""; }
|
||||||
return "";
|
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; }
|
||||||
}
|
streamSkipUntil('"');
|
||||||
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
stream.readStringUntil('"');
|
|
||||||
String hex = stream.readStringUntil('"');
|
String hex = stream.readStringUntil('"');
|
||||||
stream.readStringUntil(',');
|
streamSkipUntil(',');
|
||||||
int dcs = stream.readStringUntil('\n').toInt();
|
int8_t dcs = streamGetIntBefore('\n');
|
||||||
|
|
||||||
if (dcs == 15) {
|
if (dcs == 15) {
|
||||||
return TinyGsmDecodeHex7bit(hex);
|
return TinyGsmDecodeHex7bit(hex);
|
||||||
@@ -485,96 +372,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendSMS(const String& number, const String& text) {
|
/*
|
||||||
sendAT(GF("+CMGF=1"));
|
* Time functions
|
||||||
waitResponse();
|
*/
|
||||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
protected:
|
||||||
if (waitResponse(GF(">")) != 1) {
|
// Can follow the standard CCLK function in the template
|
||||||
return false;
|
// Note - the clock probably has to be set manaually first
|
||||||
}
|
|
||||||
stream.print(text);
|
|
||||||
stream.write((char)0x1A);
|
|
||||||
stream.flush();
|
|
||||||
return waitResponse(60000L) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Battery functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
// Needs a '?' after CBC, unlike most
|
||||||
|
int8_t getBattPercentImpl() {
|
||||||
/*
|
|
||||||
* Battery & temperature functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
int8_t getBattPercent() {
|
|
||||||
sendAT(GF("+CBC?"));
|
sendAT(GF("+CBC?"));
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip battery charge status
|
streamSkipUntil(','); // Skip battery charge status
|
||||||
// Read battery charge level
|
// Read battery charge level
|
||||||
int res = stream.readStringUntil('\n').toInt();
|
int8_t res = streamGetIntBefore('\n');
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBattChargeState() {
|
// Needs a '?' after CBC, unlike most
|
||||||
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
|
uint16_t& milliVolts) {
|
||||||
sendAT(GF("+CBC?"));
|
sendAT(GF("+CBC?"));
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
|
||||||
return false;
|
chargeState = streamGetIntBefore(',');
|
||||||
}
|
percent = streamGetIntBefore('\n');
|
||||||
// Read battery charge status
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
|
||||||
// Wait for final OK
|
|
||||||
waitResponse();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
|
|
||||||
sendAT(GF("+CBC?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
chargeState = stream.readStringUntil(',').toInt();
|
|
||||||
percent = stream.readStringUntil('\n').toInt();
|
|
||||||
milliVolts = 0;
|
milliVolts = 0;
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client related functions
|
* 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, int timeout_s = 75) {
|
int timeout_s = 75) {
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
|
|
||||||
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
||||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) {
|
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
|
||||||
return false;
|
int8_t newMux = streamGetIntBefore('\n');
|
||||||
}
|
|
||||||
int newMux = stream.readStringUntil('\n').toInt();
|
|
||||||
|
|
||||||
int rsp = waitResponse((timeout_ms- (millis() - startMillis)),
|
int8_t rsp = waitResponse(
|
||||||
GF("CONNECT OK" GSM_NL),
|
(timeout_ms - (millis() - startMillis)), GF("CONNECT OK" GSM_NL),
|
||||||
GF("CONNECT FAIL" GSM_NL),
|
GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
|
||||||
GF("ALREADY CONNECT" GSM_NL));
|
if (waitResponse() != 1) { return false; }
|
||||||
if (waitResponse() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*mux = newMux;
|
*mux = newMux;
|
||||||
|
|
||||||
return (1 == rsp);
|
return (1 == rsp);
|
||||||
@@ -582,37 +434,35 @@ protected:
|
|||||||
|
|
||||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||||
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
||||||
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) {
|
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { return 0; }
|
||||||
return 0;
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
}
|
|
||||||
stream.write((uint8_t*)buff, len);
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) {
|
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modemGetConnected(uint8_t) {
|
bool modemGetConnected(uint8_t) {
|
||||||
sendAT(GF("+CIPSTATUS")); //TODO mux?
|
sendAT(GF("+CIPSTATUS")); // TODO(?) mux?
|
||||||
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
|
||||||
|
GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return 1 == res;
|
return 1 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||||
// TODO: Optimize this!
|
GsmConstStr r1 = GFP(GSM_OK),
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
#if defined TINY_GSM_DEBUG
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
/*String r1s(r1); r1s.trim();
|
/*String r1s(r1); r1s.trim();
|
||||||
String r2s(r2); r2s.trim();
|
String r2s(r2); r2s.trim();
|
||||||
String r3s(r3); r3s.trim();
|
String r3s(r3); r3s.trim();
|
||||||
@@ -620,15 +470,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r5s(r5); r5s.trim();
|
String r5s(r5); r5s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
uint8_t index = 0;
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
do {
|
do {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available() > 0) {
|
while (stream.available() > 0) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
int a = stream.read();
|
int8_t a = stream.read();
|
||||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||||
data += (char)a;
|
data += static_cast<char>(a);
|
||||||
if (r1 && data.endsWith(r1)) {
|
if (r1 && data.endsWith(r1)) {
|
||||||
index = 1;
|
index = 1;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -636,6 +486,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 2;
|
index = 2;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r3 && data.endsWith(r3)) {
|
} else if (r3 && data.endsWith(r3)) {
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
|
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||||
|
streamSkipUntil('\n'); // Read out the error
|
||||||
|
}
|
||||||
|
#endif
|
||||||
index = 3;
|
index = 3;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r4 && data.endsWith(r4)) {
|
} else if (r4 && data.endsWith(r4)) {
|
||||||
@@ -645,23 +500,23 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 5;
|
index = 5;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (data.endsWith(GF("+CIPRCV:"))) {
|
} else if (data.endsWith(GF("+CIPRCV:"))) {
|
||||||
int mux = stream.readStringUntil(',').toInt();
|
int8_t mux = streamGetIntBefore(',');
|
||||||
int len = stream.readStringUntil(',').toInt();
|
int16_t len = streamGetIntBefore(',');
|
||||||
int len_orig = len;
|
int16_t len_orig = len;
|
||||||
if (len > sockets[mux]->rx.free()) {
|
if (len > sockets[mux]->rx.free()) {
|
||||||
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
||||||
} else {
|
} else {
|
||||||
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
||||||
}
|
}
|
||||||
while (len--) {
|
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
// TODO(?) Deal with missing characters
|
||||||
}
|
if (len_orig > sockets[mux]->available()) {
|
||||||
if (len_orig > sockets[mux]->available()) { // TODO
|
DBG("### Fewer characters received than expected: ",
|
||||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
sockets[mux]->available(), " vs ", len_orig);
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
|
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
|
||||||
int mux = stream.readStringUntil('\n').toInt();
|
int8_t mux = streamGetIntBefore('\n');
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
||||||
sockets[mux]->sock_connected = false;
|
sockets[mux]->sock_connected = false;
|
||||||
}
|
}
|
||||||
@@ -673,9 +528,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
finish:
|
finish:
|
||||||
if (!index) {
|
if (!index) {
|
||||||
data.trim();
|
data.trim();
|
||||||
if (data.length()) {
|
if (data.length()) { DBG("### Unhandled:", data); }
|
||||||
DBG("### Unhandled:", data);
|
|
||||||
}
|
|
||||||
data = "";
|
data = "";
|
||||||
}
|
}
|
||||||
// data.replace(GSM_NL, "/");
|
// data.replace(GSM_NL, "/");
|
||||||
@@ -683,25 +536,33 @@ finish:
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
#if defined TINY_GSM_DEBUG
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
#if defined TINY_GSM_DEBUG
|
||||||
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Stream& stream;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
Stream& stream;
|
||||||
|
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
const char* gsmNL = GSM_NL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTA6_H_
|
||||||
|
|||||||
+423
-450
File diff suppressed because it is too large
Load Diff
+149
-235
@@ -6,24 +6,24 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientESP8266_h
|
#ifndef SRC_TINYGSMCLIENTESP8266_H_
|
||||||
#define TinyGsmClientESP8266_h
|
#define SRC_TINYGSMCLIENTESP8266_H_
|
||||||
// #pragma message("TinyGSM: TinyGsmClientESP8266")
|
// #pragma message("TinyGSM: TinyGsmClientESP8266")
|
||||||
|
|
||||||
// #define TINY_GSM_DEBUG Serial
|
// #define TINY_GSM_DEBUG Serial
|
||||||
|
|
||||||
#if !defined(TINY_GSM_RX_BUFFER)
|
|
||||||
#define TINY_GSM_RX_BUFFER 512
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TINY_GSM_MUX_COUNT 5
|
#define TINY_GSM_MUX_COUNT 5
|
||||||
|
#define TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmModem.tpp"
|
||||||
|
#include "TinyGsmSSL.tpp"
|
||||||
|
#include "TinyGsmTCP.tpp"
|
||||||
|
#include "TinyGsmWifi.tpp"
|
||||||
|
|
||||||
#define GSM_NL "\r\n"
|
#define GSM_NL "\r\n"
|
||||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
||||||
static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
|
static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120;
|
||||||
|
|
||||||
// <stat> status of ESP8266 station interface
|
// <stat> status of ESP8266 station interface
|
||||||
// 2 : ESP8266 station connected to an AP and has obtained IP
|
// 2 : ESP8266 station connected to an AP and has obtained IP
|
||||||
@@ -38,32 +38,39 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 6,
|
REG_UNKNOWN = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
|
||||||
|
public TinyGsmWifi<TinyGsmESP8266>,
|
||||||
|
public TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>,
|
||||||
|
public TinyGsmSSL<TinyGsmESP8266> {
|
||||||
|
friend class TinyGsmModem<TinyGsmESP8266>;
|
||||||
|
friend class TinyGsmWifi<TinyGsmESP8266>;
|
||||||
|
friend class TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>;
|
||||||
|
friend class TinyGsmSSL<TinyGsmESP8266>;
|
||||||
|
|
||||||
class TinyGsmESP8266
|
/*
|
||||||
{
|
* Inner Client
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
class GsmClientESP8266 : public GsmClient {
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmESP8266;
|
friend class TinyGsmESP8266;
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GsmClient() {}
|
GsmClientESP8266() {}
|
||||||
|
|
||||||
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 0) {
|
||||||
init(&modem, mux);
|
init(&modem, mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
bool init(TinyGsmESP8266* modem, uint8_t mux = 0) {
|
||||||
|
|
||||||
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
this->at = modem;
|
||||||
this->mux = mux;
|
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
if (mux < TINY_GSM_MUX_COUNT) {
|
||||||
|
this->mux = mux;
|
||||||
|
} else {
|
||||||
|
this->mux = (mux % TINY_GSM_MUX_COUNT);
|
||||||
|
}
|
||||||
|
at->sockets[this->mux] = this;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -76,194 +83,139 @@ public:
|
|||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
at->waitResponse(maxWaitMs);
|
at->waitResponse(maxWaitMs);
|
||||||
rx.clear();
|
rx.clear();
|
||||||
}
|
}
|
||||||
|
void stop() override {
|
||||||
virtual void stop() { stop(5000L); }
|
stop(5000L);
|
||||||
|
}
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Extended API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
private:
|
|
||||||
TinyGsmESP8266* at;
|
|
||||||
uint8_t mux;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
class GsmClientSecure : public GsmClient
|
* Inner Secure Client
|
||||||
{
|
*/
|
||||||
public:
|
public:
|
||||||
GsmClientSecure() {}
|
class GsmClientSecureESP8266 : public GsmClientESP8266 {
|
||||||
|
public:
|
||||||
|
GsmClientSecureESP8266() {}
|
||||||
|
|
||||||
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
|
explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 0)
|
||||||
: GsmClient(modem, mux)
|
: GsmClientESP8266(modem, mux) {}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual ~GsmClientSecure() {}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
int connect(const char* host, uint16_t port, int timeout_s) override {
|
||||||
stop();
|
stop();
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
rx.clear();
|
rx.clear();
|
||||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
|
||||||
TinyGsmESP8266(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TinyGsmESP8266() {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool begin(const char* pin = NULL) {
|
bool initImpl(const char* pin = NULL) {
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
|
||||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||||
if (!testAT()) {
|
|
||||||
return false;
|
if (!testAT()) { return false; }
|
||||||
}
|
|
||||||
if (pin && strlen(pin) > 0) {
|
if (pin && strlen(pin) > 0) {
|
||||||
DBG("ESP8266 modules do not use an unlock pin!");
|
DBG("ESP8266 modules do not use an unlock pin!");
|
||||||
}
|
}
|
||||||
sendAT(GF("E0")); // Echo Off
|
sendAT(GF("E0")); // Echo Off
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
|
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
|
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
String getModemNameImpl() {
|
||||||
return "ESP8266";
|
return "ESP8266";
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBaud(unsigned long baud) {
|
void setBaudImpl(uint32_t baud) {
|
||||||
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
|
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
bool factoryDefaultImpl() {
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("+RESTORE"));
|
sendAT(GF("+RESTORE"));
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemInfo() {
|
String getModemInfoImpl() {
|
||||||
sendAT(GF("+GMR"));
|
sendAT(GF("+GMR"));
|
||||||
String res;
|
String res;
|
||||||
if (waitResponse(1000L, res) != 1) {
|
if (waitResponse(1000L, res) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
res.replace(GSM_NL "OK" GSM_NL, "");
|
res.replace(GSM_NL "OK" GSM_NL, "");
|
||||||
res.replace(GSM_NL, " ");
|
res.replace(GSM_NL, " ");
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWifi() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasGPRS() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+RST"));
|
sendAT(GF("+RST"));
|
||||||
if (waitResponse(10000L) != 1) {
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
return false;
|
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
|
||||||
}
|
|
||||||
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
delay(500);
|
delay(500);
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
|
sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
/*
|
|
||||||
* SIM card functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
RegStatus getRegistrationStatus() {
|
|
||||||
sendAT(GF("+CIPSTATUS"));
|
|
||||||
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
|
|
||||||
int status =
|
|
||||||
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
|
|
||||||
waitResponse(); // Returns an OK after the status
|
|
||||||
return (RegStatus)status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
sendAT(GF("+CIPSTATUS"));
|
||||||
|
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
|
||||||
|
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
|
||||||
|
GF("5"));
|
||||||
|
waitResponse(); // Returns an OK after the status
|
||||||
|
return (RegStatus)status;
|
||||||
|
}
|
||||||
|
|
||||||
int16_t getSignalQuality() {
|
protected:
|
||||||
|
int8_t getSignalQualityImpl() {
|
||||||
sendAT(GF("+CWJAP_CUR?"));
|
sendAT(GF("+CWJAP_CUR?"));
|
||||||
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||||
if (res1 != 2) {
|
if (res1 != 2) {
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -271,38 +223,42 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|||||||
streamSkipUntil(','); // Skip SSID
|
streamSkipUntil(','); // Skip SSID
|
||||||
streamSkipUntil(','); // Skip BSSID/MAC address
|
streamSkipUntil(','); // Skip BSSID/MAC address
|
||||||
streamSkipUntil(','); // Skip Chanel number
|
streamSkipUntil(','); // Skip Chanel number
|
||||||
int res2 = stream.parseInt(); // Read RSSI
|
int8_t res2 = stream.parseInt(); // Read RSSI
|
||||||
waitResponse(); // Returns an OK after the value
|
waitResponse(); // Returns an OK after the value
|
||||||
return res2;
|
return res2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNetworkConnected() {
|
bool isNetworkConnectedImpl() {
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
if (s == REG_OK_IP || s == REG_OK_TCP) {
|
if (s == REG_OK_IP || s == REG_OK_TCP) {
|
||||||
// with these, we're definitely connected
|
// with these, we're definitely connected
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (s == REG_OK_NO_TCP) {
|
||||||
else if (s == REG_OK_NO_TCP) {
|
|
||||||
// with this, we may or may not be connected
|
// with this, we may or may not be connected
|
||||||
if (getLocalIP() == "") {
|
if (getLocalIP() == "") {
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
String getLocalIPImpl() {
|
||||||
|
sendAT(GF("+CIPSTA_CUR?"));
|
||||||
|
int8_t res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
||||||
|
if (res1 != 2) { return ""; }
|
||||||
|
String res2 = stream.readStringUntil('"');
|
||||||
|
waitResponse();
|
||||||
|
return res2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WiFi functions
|
* WiFi functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool networkConnect(const char* ssid, const char* pwd) {
|
bool networkConnectImpl(const char* ssid, const char* pwd) {
|
||||||
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
|
||||||
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
|
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -311,86 +267,49 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool networkDisconnect() {
|
bool networkDisconnectImpl() {
|
||||||
sendAT(GF("+CWQAP"));
|
sendAT(GF("+CWQAP"));
|
||||||
bool retVal = waitResponse(10000L) == 1;
|
bool retVal = waitResponse(10000L) == 1;
|
||||||
waitResponse(GF("WIFI DISCONNECT"));
|
waitResponse(GF("WIFI DISCONNECT"));
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* IP Address functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
String getLocalIP() {
|
|
||||||
sendAT(GF("+CIPSTA_CUR??"));
|
|
||||||
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
|
||||||
if (res1 != 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res2 = stream.readStringUntil('"');
|
|
||||||
waitResponse();
|
|
||||||
return res2;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Battery & temperature functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client related functions
|
* 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,
|
||||||
bool ssl = false, int timeout_s = 75)
|
bool ssl = false, int timeout_s = 75) {
|
||||||
{
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
sendAT(GF("+CIPSSLSIZE=4096"));
|
sendAT(GF("+CIPSSLSIZE=4096"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
|
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
|
||||||
GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
|
GF("\",\""), host, GF("\","), port, GF(","),
|
||||||
// TODO: Check mux
|
TINY_GSM_TCP_KEEP_ALIVE);
|
||||||
int rsp = waitResponse(timeout_ms,
|
// TODO(?): Check mux
|
||||||
GFP(GSM_OK),
|
int8_t rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR),
|
||||||
GFP(GSM_ERROR),
|
|
||||||
GF("ALREADY CONNECT"));
|
GF("ALREADY CONNECT"));
|
||||||
// if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
|
// if (rsp == 3) waitResponse();
|
||||||
|
// May return "ERROR" after the "ALREADY CONNECT"
|
||||||
return (1 == rsp);
|
return (1 == rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||||
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
||||||
if (waitResponse(GF(">")) != 1) {
|
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||||
return 0;
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
}
|
|
||||||
stream.write((uint8_t*)buff, len);
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
|
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modemGetConnected(uint8_t mux) {
|
bool modemGetConnected(uint8_t mux) {
|
||||||
sendAT(GF("+CIPSTATUS"));
|
sendAT(GF("+CIPSTATUS"));
|
||||||
if (waitResponse(3000, GF("STATUS:")) != 1) return false;
|
if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
|
||||||
int status =
|
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
|
||||||
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
|
GF("5"));
|
||||||
if (status != 3) {
|
if (status != 3) {
|
||||||
// if the status is anything but 3, there are no connections open
|
// if the status is anything but 3, there are no connections open
|
||||||
waitResponse(); // Returns an OK after the status
|
waitResponse(); // Returns an OK after the status
|
||||||
@@ -401,9 +320,10 @@ protected:
|
|||||||
}
|
}
|
||||||
bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
|
bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
|
||||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||||
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK),
|
||||||
|
GFP(GSM_ERROR));
|
||||||
if (has_status == 1) {
|
if (has_status == 1) {
|
||||||
int returned_mux = stream.readStringUntil(',').toInt();
|
int8_t returned_mux = streamGetIntBefore(',');
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
streamSkipUntil(','); // Skip type
|
streamSkipUntil(','); // Skip type
|
||||||
streamSkipUntil(','); // Skip remote IP
|
streamSkipUntil(','); // Skip remote IP
|
||||||
@@ -420,19 +340,15 @@ protected:
|
|||||||
return verified_connections[mux];
|
return verified_connections[mux];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||||
// TODO: Optimize this!
|
GsmConstStr r1 = GFP(GSM_OK),
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
|
||||||
{
|
|
||||||
/*String r1s(r1); r1s.trim();
|
/*String r1s(r1); r1s.trim();
|
||||||
String r2s(r2); r2s.trim();
|
String r2s(r2); r2s.trim();
|
||||||
String r3s(r3); r3s.trim();
|
String r3s(r3); r3s.trim();
|
||||||
@@ -440,15 +356,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r5s(r5); r5s.trim();
|
String r5s(r5); r5s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
uint8_t index = 0;
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
do {
|
do {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available() > 0) {
|
while (stream.available() > 0) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
int a = stream.read();
|
int8_t a = stream.read();
|
||||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||||
data += (char)a;
|
data += static_cast<char>(a);
|
||||||
if (r1 && data.endsWith(r1)) {
|
if (r1 && data.endsWith(r1)) {
|
||||||
index = 1;
|
index = 1;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -465,25 +381,27 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 5;
|
index = 5;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (data.endsWith(GF("+IPD,"))) {
|
} else if (data.endsWith(GF("+IPD,"))) {
|
||||||
int mux = stream.readStringUntil(',').toInt();
|
int8_t mux = streamGetIntBefore(',');
|
||||||
int len = stream.readStringUntil(':').toInt();
|
int16_t len = streamGetIntBefore(':');
|
||||||
int len_orig = len;
|
int16_t len_orig = len;
|
||||||
if (len > sockets[mux]->rx.free()) {
|
if (len > sockets[mux]->rx.free()) {
|
||||||
DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available");
|
DBG("### Buffer overflow: ", len, "received vs",
|
||||||
|
sockets[mux]->rx.free(), "available");
|
||||||
} else {
|
} else {
|
||||||
DBG("### Got Data: ", len, "on", mux);
|
// DBG("### Got Data: ", len, "on", mux);
|
||||||
}
|
}
|
||||||
while (len--) {
|
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
// TODO(SRGDamia1): deal with buffer overflow/missed characters
|
||||||
}
|
if (len_orig > sockets[mux]->available()) {
|
||||||
if (len_orig > sockets[mux]->available()) { // TODO
|
DBG("### Fewer characters received than expected: ",
|
||||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
sockets[mux]->available(), " vs ", len_orig);
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
} else if (data.endsWith(GF("CLOSED"))) {
|
} else if (data.endsWith(GF("CLOSED"))) {
|
||||||
int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
|
int8_t muxStart =
|
||||||
int coma = data.indexOf(',', muxStart);
|
TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
|
||||||
int mux = data.substring(muxStart, coma).toInt();
|
int8_t coma = data.indexOf(',', muxStart);
|
||||||
|
int8_t mux = data.substring(muxStart, coma).toInt();
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||||
sockets[mux]->sock_connected = false;
|
sockets[mux]->sock_connected = false;
|
||||||
}
|
}
|
||||||
@@ -495,9 +413,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
finish:
|
finish:
|
||||||
if (!index) {
|
if (!index) {
|
||||||
data.trim();
|
data.trim();
|
||||||
if (data.length()) {
|
if (data.length()) { DBG("### Unhandled:", data); }
|
||||||
DBG("### Unhandled:", data);
|
|
||||||
}
|
|
||||||
data = "";
|
data = "";
|
||||||
}
|
}
|
||||||
// data.replace(GSM_NL, "/");
|
// data.replace(GSM_NL, "/");
|
||||||
@@ -505,25 +421,23 @@ finish:
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
{
|
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||||
{
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Stream& stream;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
Stream& stream;
|
||||||
|
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
const char* gsmNL = GSM_NL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTESP8266_H_
|
||||||
|
|||||||
+163
-302
@@ -6,31 +6,30 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientM590_h
|
#ifndef SRC_TINYGSMCLIENTM590_H_
|
||||||
#define TinyGsmClientM590_h
|
#define SRC_TINYGSMCLIENTM590_H_
|
||||||
// #pragma message("TinyGSM: TinyGsmClientM590")
|
// #pragma message("TinyGSM: TinyGsmClientM590")
|
||||||
|
|
||||||
// #define TINY_GSM_DEBUG Serial
|
// #define TINY_GSM_DEBUG Serial
|
||||||
|
|
||||||
#if !defined(TINY_GSM_RX_BUFFER)
|
|
||||||
#define TINY_GSM_RX_BUFFER 256
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TINY_GSM_MUX_COUNT 2
|
#define TINY_GSM_MUX_COUNT 2
|
||||||
|
#define TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmGPRS.tpp"
|
||||||
|
#include "TinyGsmModem.tpp"
|
||||||
|
#include "TinyGsmSMS.tpp"
|
||||||
|
#include "TinyGsmTCP.tpp"
|
||||||
|
#include "TinyGsmTime.tpp"
|
||||||
|
|
||||||
#define GSM_NL "\r\n"
|
#define GSM_NL "\r\n"
|
||||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
enum SimStatus {
|
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
SIM_ERROR = 0,
|
#endif
|
||||||
SIM_READY = 1,
|
|
||||||
SIM_LOCKED = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RegStatus {
|
enum RegStatus {
|
||||||
|
REG_NO_RESULT = -1,
|
||||||
REG_UNREGISTERED = 0,
|
REG_UNREGISTERED = 0,
|
||||||
REG_SEARCHING = 3,
|
REG_SEARCHING = 3,
|
||||||
REG_DENIED = 2,
|
REG_DENIED = 2,
|
||||||
@@ -39,109 +38,92 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
|
||||||
|
public TinyGsmGPRS<TinyGsmM590>,
|
||||||
|
public TinyGsmTCP<TinyGsmM590, TINY_GSM_MUX_COUNT>,
|
||||||
|
public TinyGsmSMS<TinyGsmM590>,
|
||||||
|
public TinyGsmTime<TinyGsmM590> {
|
||||||
|
friend class TinyGsmModem<TinyGsmM590>;
|
||||||
|
friend class TinyGsmGPRS<TinyGsmM590>;
|
||||||
|
friend class TinyGsmTCP<TinyGsmM590, TINY_GSM_MUX_COUNT>;
|
||||||
|
friend class TinyGsmSMS<TinyGsmM590>;
|
||||||
|
friend class TinyGsmTime<TinyGsmM590>;
|
||||||
|
|
||||||
class TinyGsmM590
|
/*
|
||||||
{
|
* Inner Client
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
class GsmClientM590 : public GsmClient {
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmM590;
|
friend class TinyGsmM590;
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GsmClient() {}
|
GsmClientM590() {}
|
||||||
|
|
||||||
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) {
|
explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 0) {
|
||||||
init(&modem, mux);
|
init(&modem, mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
bool init(TinyGsmM590* modem, uint8_t mux = 0) {
|
||||||
|
|
||||||
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
this->at = modem;
|
||||||
this->mux = mux;
|
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
if (mux < TINY_GSM_MUX_COUNT) {
|
||||||
|
this->mux = mux;
|
||||||
|
} else {
|
||||||
|
this->mux = (mux % TINY_GSM_MUX_COUNT);
|
||||||
|
}
|
||||||
|
at->sockets[this->mux] = this;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
stop();
|
stop();
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
rx.clear();
|
rx.clear();
|
||||||
sock_connected = at->modemConnect(host, port, mux, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
at->sendAT(GF("+TCPCLOSE="), mux);
|
at->sendAT(GF("+TCPCLOSE="), mux);
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
at->waitResponse(maxWaitMs);
|
at->waitResponse(maxWaitMs);
|
||||||
rx.clear();
|
rx.clear();
|
||||||
}
|
}
|
||||||
|
void stop() override {
|
||||||
virtual void stop() { stop(1000L); }
|
stop(1000L);
|
||||||
|
}
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Extended API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
private:
|
|
||||||
TinyGsmM590* at;
|
|
||||||
uint8_t mux;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
explicit TinyGsmM590(Stream& stream) : stream(stream) {
|
||||||
TinyGsmM590(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TinyGsmM590() {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool begin(const char* pin = NULL) {
|
bool initImpl(const char* pin = NULL) {
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
|
||||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||||
|
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
|
sendAT(GF("E0")); // Echo Off
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TINY_GSM_DEBUG
|
#ifdef TINY_GSM_DEBUG
|
||||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
@@ -152,30 +134,25 @@ public:
|
|||||||
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
int ret = getSimStatus();
|
SimStatus ret = getSimStatus();
|
||||||
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
||||||
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||||
simUnlock(pin);
|
simUnlock(pin);
|
||||||
return (getSimStatus() == SIM_READY);
|
return (getSimStatus() == SIM_READY);
|
||||||
}
|
} else {
|
||||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
// if the sim is ready, or it's locked but no pin has been provided,
|
||||||
// true
|
// return true
|
||||||
else {
|
|
||||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
// Doesn't support CGMI
|
||||||
|
String getModemNameImpl() {
|
||||||
return "Neoway M590";
|
return "Neoway M590";
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
// Extra stuff here - pwr save, internal stack
|
||||||
|
bool factoryDefaultImpl() {
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
|
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
|
||||||
@@ -188,100 +165,59 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWifi() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasGPRS() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CFUN=15"));
|
sendAT(GF("+CFUN=15"));
|
||||||
if (waitResponse(10000L) != 1) {
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// MODEM:STARTUP
|
// MODEM:STARTUP
|
||||||
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
|
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+CPWROFF"));
|
sendAT(GF("+CPWROFF"));
|
||||||
return waitResponse(3000L) == 1;
|
return waitResponse(3000L) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) {
|
|
||||||
sendAT(GF("+ENPWRSAVE="), enable);
|
sendAT(GF("+ENPWRSAVE="), enable);
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* SIM card functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_SIMCCID_CCID()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_IMEI_GSN()
|
|
||||||
|
|
||||||
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
|
||||||
sendAT(GF("+CPIN?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
|
||||||
delay(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
|
|
||||||
waitResponse();
|
|
||||||
switch (status) {
|
|
||||||
case 2:
|
|
||||||
case 3: return SIM_LOCKED;
|
|
||||||
case 1: return SIM_READY;
|
|
||||||
default: return SIM_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SIM_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_OPERATOR_COPS()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||||
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
String getLocalIPImpl() {
|
||||||
|
sendAT(GF("+XIIC?"));
|
||||||
|
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; }
|
||||||
|
streamSkipUntil(',');
|
||||||
|
String res = stream.readStringUntil('\n');
|
||||||
|
waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPRS functions
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
gprsDisconnect();
|
gprsDisconnect();
|
||||||
|
|
||||||
sendAT(GF("+XISP=0"));
|
sendAT(GF("+XISP=0"));
|
||||||
@@ -298,8 +234,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
sendAT(GF("+XIIC=1"));
|
sendAT(GF("+XIIC=1"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
const unsigned long timeout_ms = 60000L;
|
const uint32_t timeout_ms = 60000L;
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||||
if (isGprsConnected()) {
|
if (isGprsConnected()) {
|
||||||
// goto set_dns; // TODO
|
// goto set_dns; // TODO
|
||||||
return true;
|
return true;
|
||||||
@@ -318,133 +254,51 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
// TODO: There is no command in AT command set
|
// TODO(?): There is no command in AT command set
|
||||||
// XIIC=0 does not work
|
// XIIC=0 does not work
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isGprsConnected() {
|
bool isGprsConnectedImpl() {
|
||||||
sendAT(GF("+XIIC?"));
|
sendAT(GF("+XIIC?"));
|
||||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; }
|
||||||
return false;
|
int8_t res = streamGetIntBefore(',');
|
||||||
}
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res == 1;
|
return res == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
// Able to follow all SIM card functions as inherited from the template
|
||||||
sendAT(GF("+XIIC?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
stream.readStringUntil(',');
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
|
||||||
res.trim();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Phone Call functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messaging functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String sendUSSD(const String& code) {
|
bool sendSMS_UTF16Impl(const String& number, const void* text,
|
||||||
sendAT(GF("+CMGF=1"));
|
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CSCS=\"HEX\""));
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("D"), code);
|
|
||||||
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
stream.readStringUntil('"');
|
|
||||||
String hex = stream.readStringUntil('"');
|
|
||||||
stream.readStringUntil(',');
|
|
||||||
int dcs = stream.readStringUntil('\n').toInt();
|
|
||||||
|
|
||||||
if (waitResponse() != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dcs == 15) {
|
|
||||||
return TinyGsmDecodeHex8bit(hex);
|
|
||||||
} else if (dcs == 72) {
|
|
||||||
return TinyGsmDecodeHex16bit(hex);
|
|
||||||
} else {
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendSMS(const String& number, const String& text) {
|
|
||||||
sendAT(GF("+CSCS=\"GSM\""));
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGF=1"));
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
|
||||||
if (waitResponse(GF(">")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
stream.print(text);
|
|
||||||
stream.write((char)0x1A);
|
|
||||||
stream.flush();
|
|
||||||
return waitResponse(60000L) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendSMS_UTF16(const String& number, const void* text, size_t len)
|
|
||||||
TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Time functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
|
||||||
* Battery & temperature functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client related functions
|
* Client related functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool,
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) {
|
int timeout_s = 75) {
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
for (int i=0; i<3; i++) { // TODO: no need for loop?
|
for (int i = 0; i < 3; i++) { // TODO(?): no need for loop?
|
||||||
String ip = dnsIpQuery(host);
|
String ip = dnsIpQuery(host);
|
||||||
|
|
||||||
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
|
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
|
||||||
int rsp = waitResponse(timeout_ms,
|
int8_t rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL),
|
||||||
GF(",OK" GSM_NL),
|
|
||||||
GF(",FAIL" GSM_NL),
|
GF(",FAIL" GSM_NL),
|
||||||
GF("+TCPSETUP:Error" GSM_NL));
|
GF("+TCPSETUP:Error" GSM_NL));
|
||||||
if (1 == rsp) {
|
if (1 == rsp) {
|
||||||
@@ -460,50 +314,46 @@ protected:
|
|||||||
|
|
||||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||||
sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len);
|
sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len);
|
||||||
if (waitResponse(GF(">")) != 1) {
|
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||||
return 0;
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
}
|
stream.write(static_cast<char>(0x0D));
|
||||||
stream.write((uint8_t*)buff, len);
|
|
||||||
stream.write((char)0x0D);
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) {
|
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; }
|
||||||
return 0;
|
streamSkipUntil('\n');
|
||||||
}
|
|
||||||
stream.readStringUntil('\n');
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modemGetConnected(uint8_t mux) {
|
bool modemGetConnected(uint8_t mux) {
|
||||||
sendAT(GF("+CIPSTATUS="), mux);
|
sendAT(GF("+CIPSTATUS="), mux);
|
||||||
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
|
||||||
|
GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return 1 == res;
|
return 1 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
String dnsIpQuery(const char* host) {
|
String dnsIpQuery(const char* host) {
|
||||||
sendAT(GF("+DNS=\""), host, GF("\""));
|
sendAT(GF("+DNS=\""), host, GF("\""));
|
||||||
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) {
|
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse(GF("+DNS:OK" GSM_NL));
|
waitResponse(GF("+DNS:OK" GSM_NL));
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||||
// TODO: Optimize this!
|
GsmConstStr r1 = GFP(GSM_OK),
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
#if defined TINY_GSM_DEBUG
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
/*String r1s(r1); r1s.trim();
|
/*String r1s(r1); r1s.trim();
|
||||||
String r2s(r2); r2s.trim();
|
String r2s(r2); r2s.trim();
|
||||||
String r3s(r3); r3s.trim();
|
String r3s(r3); r3s.trim();
|
||||||
@@ -511,15 +361,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r5s(r5); r5s.trim();
|
String r5s(r5); r5s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
uint8_t index = 0;
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
do {
|
do {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available() > 0) {
|
while (stream.available() > 0) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
int a = stream.read();
|
int8_t a = stream.read();
|
||||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||||
data += (char)a;
|
data += static_cast<char>(a);
|
||||||
if (r1 && data.endsWith(r1)) {
|
if (r1 && data.endsWith(r1)) {
|
||||||
index = 1;
|
index = 1;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -527,6 +377,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 2;
|
index = 2;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r3 && data.endsWith(r3)) {
|
} else if (r3 && data.endsWith(r3)) {
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
|
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||||
|
streamSkipUntil('\n'); // Read out the error
|
||||||
|
}
|
||||||
|
#endif
|
||||||
index = 3;
|
index = 3;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r4 && data.endsWith(r4)) {
|
} else if (r4 && data.endsWith(r4)) {
|
||||||
@@ -536,24 +391,24 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 5;
|
index = 5;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (data.endsWith(GF("+TCPRECV:"))) {
|
} else if (data.endsWith(GF("+TCPRECV:"))) {
|
||||||
int mux = stream.readStringUntil(',').toInt();
|
int8_t mux = streamGetIntBefore(',');
|
||||||
int len = stream.readStringUntil(',').toInt();
|
int16_t len = streamGetIntBefore(',');
|
||||||
int len_orig = len;
|
int16_t len_orig = len;
|
||||||
if (len > sockets[mux]->rx.free()) {
|
if (len > sockets[mux]->rx.free()) {
|
||||||
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
||||||
} else {
|
} else {
|
||||||
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
||||||
}
|
}
|
||||||
while (len--) {
|
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
// TODO(?): Handle lost characters
|
||||||
}
|
if (len_orig > sockets[mux]->available()) {
|
||||||
if (len_orig > sockets[mux]->available()) { // TODO
|
DBG("### Fewer characters received than expected: ",
|
||||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
sockets[mux]->available(), " vs ", len_orig);
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
|
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
|
||||||
int mux = stream.readStringUntil(',').toInt();
|
int8_t mux = streamGetIntBefore(',');
|
||||||
stream.readStringUntil('\n');
|
streamSkipUntil('\n');
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
||||||
sockets[mux]->sock_connected = false;
|
sockets[mux]->sock_connected = false;
|
||||||
}
|
}
|
||||||
@@ -565,9 +420,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
finish:
|
finish:
|
||||||
if (!index) {
|
if (!index) {
|
||||||
data.trim();
|
data.trim();
|
||||||
if (data.length()) {
|
if (data.length()) { DBG("### Unhandled:", data); }
|
||||||
DBG("### Unhandled:", data);
|
|
||||||
}
|
|
||||||
data = "";
|
data = "";
|
||||||
}
|
}
|
||||||
// data.replace(GSM_NL, "/");
|
// data.replace(GSM_NL, "/");
|
||||||
@@ -575,25 +428,33 @@ finish:
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
#if defined TINY_GSM_DEBUG
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
#if defined TINY_GSM_DEBUG
|
||||||
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Stream& stream;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
Stream& stream;
|
||||||
|
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
const char* gsmNL = GSM_NL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTM590_H_
|
||||||
|
|||||||
+247
-435
@@ -2,35 +2,38 @@
|
|||||||
* @file TinyGsmClientM95.h
|
* @file TinyGsmClientM95.h
|
||||||
* @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
|
* @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
|
||||||
* @license LGPL-3.0
|
* @license LGPL-3.0
|
||||||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com>
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd.
|
||||||
|
* <http://www.replicade.com>
|
||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientM95_h
|
#ifndef SRC_TINYGSMCLIENTM95_H_
|
||||||
#define TinyGsmClientM95_h
|
#define SRC_TINYGSMCLIENTM95_H_
|
||||||
// #pragma message("TinyGSM: TinyGsmClientM95")
|
// #pragma message("TinyGSM: TinyGsmClientM95")
|
||||||
|
|
||||||
// #define TINY_GSM_DEBUG Serial
|
// #define TINY_GSM_DEBUG Serial
|
||||||
|
|
||||||
#if !defined(TINY_GSM_RX_BUFFER)
|
|
||||||
#define TINY_GSM_RX_BUFFER 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TINY_GSM_MUX_COUNT 6
|
#define TINY_GSM_MUX_COUNT 6
|
||||||
|
#define TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmBattery.tpp"
|
||||||
|
#include "TinyGsmCalling.tpp"
|
||||||
|
#include "TinyGsmGPRS.tpp"
|
||||||
|
#include "TinyGsmModem.tpp"
|
||||||
|
#include "TinyGsmSMS.tpp"
|
||||||
|
#include "TinyGsmTCP.tpp"
|
||||||
|
#include "TinyGsmTemperature.tpp"
|
||||||
|
#include "TinyGsmTime.tpp"
|
||||||
|
|
||||||
#define GSM_NL "\r\n"
|
#define GSM_NL "\r\n"
|
||||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
enum SimStatus {
|
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
SIM_ERROR = 0,
|
#endif
|
||||||
SIM_READY = 1,
|
|
||||||
SIM_LOCKED = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RegStatus {
|
enum RegStatus {
|
||||||
|
REG_NO_RESULT = -1,
|
||||||
REG_UNREGISTERED = 0,
|
REG_UNREGISTERED = 0,
|
||||||
REG_SEARCHING = 2,
|
REG_SEARCHING = 2,
|
||||||
REG_DENIED = 3,
|
REG_DENIED = 3,
|
||||||
@@ -39,33 +42,48 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
|
||||||
|
public TinyGsmGPRS<TinyGsmM95>,
|
||||||
|
public TinyGsmTCP<TinyGsmM95, TINY_GSM_MUX_COUNT>,
|
||||||
|
public TinyGsmCalling<TinyGsmM95>,
|
||||||
|
public TinyGsmSMS<TinyGsmM95>,
|
||||||
|
public TinyGsmTime<TinyGsmM95>,
|
||||||
|
public TinyGsmBattery<TinyGsmM95>,
|
||||||
|
public TinyGsmTemperature<TinyGsmM95> {
|
||||||
|
friend class TinyGsmModem<TinyGsmM95>;
|
||||||
|
friend class TinyGsmGPRS<TinyGsmM95>;
|
||||||
|
friend class TinyGsmTCP<TinyGsmM95, TINY_GSM_MUX_COUNT>;
|
||||||
|
friend class TinyGsmCalling<TinyGsmM95>;
|
||||||
|
friend class TinyGsmSMS<TinyGsmM95>;
|
||||||
|
friend class TinyGsmTime<TinyGsmM95>;
|
||||||
|
friend class TinyGsmBattery<TinyGsmM95>;
|
||||||
|
friend class TinyGsmTemperature<TinyGsmM95>;
|
||||||
|
|
||||||
class TinyGsmM95
|
/*
|
||||||
{
|
* Inner Client
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
class GsmClientM95 : public GsmClient {
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmM95;
|
friend class TinyGsmM95;
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GsmClient() {}
|
GsmClientM95() {}
|
||||||
|
|
||||||
GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
|
explicit GsmClientM95(TinyGsmM95& modem, uint8_t mux = 0) {
|
||||||
init(&modem, mux);
|
init(&modem, mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
bool init(TinyGsmM95* modem, uint8_t mux = 0) {
|
||||||
|
|
||||||
bool init(TinyGsmM95* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
this->at = modem;
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
sock_available = 0;
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
if (mux < TINY_GSM_MUX_COUNT) {
|
||||||
|
this->mux = mux;
|
||||||
|
} else {
|
||||||
|
this->mux = (mux % TINY_GSM_MUX_COUNT);
|
||||||
|
}
|
||||||
|
at->sockets[this->mux] = this;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -78,92 +96,76 @@ public:
|
|||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
dumpModemBuffer(maxWaitMs);
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+QICLOSE="), mux);
|
at->sendAT(GF("+QICLOSE="), mux);
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
|
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
|
||||||
|
GF("CLOSE OK"), GF("ERROR"));
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(75000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void stop() { stop(75000L); }
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Extended API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
private:
|
|
||||||
TinyGsmM95* at;
|
|
||||||
uint8_t mux;
|
|
||||||
uint16_t sock_available;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
|
*/
|
||||||
|
|
||||||
// class GsmClientSecure : public GsmClient
|
/*
|
||||||
// {
|
class GsmClientSecureM95 : public GsmClientM95
|
||||||
// public:
|
{
|
||||||
// GsmClientSecure() {}
|
public:
|
||||||
//
|
GsmClientSecure() {}
|
||||||
// GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
|
|
||||||
// : GsmClient(modem, mux)
|
GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 0)
|
||||||
// {}
|
: GsmClient(modem, mux)
|
||||||
//
|
{}
|
||||||
// virtual ~GsmClientSecure() {}
|
|
||||||
//
|
|
||||||
// public:
|
|
||||||
// virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
// stop();
|
|
||||||
// TINY_GSM_YIELD();
|
|
||||||
// rx.clear();
|
|
||||||
// sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
|
||||||
// return sock_connected;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) override {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
TinyGsmM95(Stream& stream)
|
/*
|
||||||
: stream(stream)
|
* Constructor
|
||||||
{
|
*/
|
||||||
|
public:
|
||||||
|
explicit TinyGsmM95(Stream& stream) : stream(stream) {
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TinyGsmM95() {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool begin(const char* pin = NULL) {
|
bool initImpl(const char* pin = NULL) {
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
|
||||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||||
|
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
|
// sendAT(GF("&FZ")); // Factory + Reset
|
||||||
if (waitResponse() != 1) {
|
// waitResponse();
|
||||||
return false;
|
|
||||||
}
|
sendAT(GF("E0")); // Echo Off
|
||||||
|
if (waitResponse() != 1) { return false; }
|
||||||
|
|
||||||
#ifdef TINY_GSM_DEBUG
|
#ifdef TINY_GSM_DEBUG
|
||||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
@@ -174,62 +176,31 @@ public:
|
|||||||
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
int ret = getSimStatus();
|
// Enable network time synchronization
|
||||||
|
sendAT(GF("+QNITZ=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
|
SimStatus ret = getSimStatus();
|
||||||
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
||||||
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||||
simUnlock(pin);
|
simUnlock(pin);
|
||||||
return (getSimStatus() == SIM_READY);
|
return (getSimStatus() == SIM_READY);
|
||||||
}
|
} else {
|
||||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
// if the sim is ready, or it's locked but no pin has been provided,
|
||||||
// true
|
// return true
|
||||||
else {
|
|
||||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
|
||||||
return "Quectel M95";
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+IPR=0")); // Auto-baud
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("&W")); // Write configuration
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return false; // TODO: For now
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWifi() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasGPRS() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CFUN=0"));
|
sendAT(GF("+CFUN=0"));
|
||||||
if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) {
|
if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) ==
|
||||||
|
3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sendAT(GF("+CFUN=1"));
|
sendAT(GF("+CFUN=1"));
|
||||||
@@ -239,71 +210,31 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
|||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+QPOWD=1"));
|
sendAT(GF("+QPOWD=1"));
|
||||||
return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
|
return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() {
|
// When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
|
||||||
sendAT(GF("+CFUN=0"));
|
// is pulled up, the module can directly enter into sleep mode.If entering
|
||||||
if (waitResponse(10000L) != 1) {
|
// into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled
|
||||||
return false;
|
// down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first,
|
||||||
|
// and then the module can enter into sleep mode.
|
||||||
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
|
sendAT(GF("+QSCLK="), enable);
|
||||||
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
delay(3000);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SIM card functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+QCCID"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
|
||||||
res.trim();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_IMEI_GSN()
|
|
||||||
|
|
||||||
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
|
||||||
sendAT(GF("+CPIN?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
|
||||||
delay(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
|
|
||||||
waitResponse();
|
|
||||||
switch (status) {
|
|
||||||
case 2:
|
|
||||||
case 3: return SIM_LOCKED;
|
|
||||||
case 1: return SIM_READY;
|
|
||||||
default: return SIM_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SIM_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_OPERATOR_COPS()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||||
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
}
|
}
|
||||||
@@ -317,63 +248,55 @@ TINY_GSM_MODEM_GET_CSQ()
|
|||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
String getLocalIPImpl() {
|
||||||
|
sendAT(GF("+QILOCIP"));
|
||||||
|
streamSkipUntil('\n');
|
||||||
|
String res = stream.readStringUntil('\n');
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPRS functions
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
gprsDisconnect();
|
gprsDisconnect();
|
||||||
|
|
||||||
// select foreground context 0 = VIRTUAL_UART_1
|
// select foreground context 0 = VIRTUAL_UART_1
|
||||||
sendAT(GF("+QIFGCNT=0"));
|
sendAT(GF("+QIFGCNT=0"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select GPRS (=1) as the Bearer
|
// Select GPRS (=1) as the Bearer
|
||||||
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
|
||||||
if (waitResponse() != 1) {
|
GF("\""));
|
||||||
return false;
|
if (waitResponse() != 1) { return false; }
|
||||||
}
|
|
||||||
|
|
||||||
// Select TCP/IP transfer mode - NOT transparent mode
|
// Select TCP/IP transfer mode - NOT transparent mode
|
||||||
sendAT(GF("+QIMODE=0"));
|
sendAT(GF("+QIMODE=0"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable multiple TCP/IP connections
|
// Enable multiple TCP/IP connections
|
||||||
sendAT(GF("+QIMUX=1"));
|
sendAT(GF("+QIMUX=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start TCPIP Task and Set APN, User Name and Password
|
// Start TCPIP Task and Set APN, User Name and Password
|
||||||
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"");
|
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"");
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate GPRS/CSD Context
|
// Activate GPRS/CSD Context
|
||||||
sendAT(GF("+QIACT"));
|
sendAT(GF("+QIACT"));
|
||||||
if (waitResponse(60000L) != 1) {
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we have a local IP address
|
// Check that we have a local IP address
|
||||||
if (localIP() == IPAddress(0,0,0,0)) {
|
if (localIP() == IPAddress(0, 0, 0, 0)) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Method to Handle Received TCP/IP Data
|
// Set Method to Handle Received TCP/IP Data
|
||||||
// Mode = 1 - Output a notification when data is received
|
// Mode = 1 - Output a notification when data is received
|
||||||
// “+QIRDI: <id>,<sc>,<sid>”
|
// +QIRDI: <id>,<sc>,<sid>
|
||||||
sendAT(GF("+QINDI=1"));
|
sendAT(GF("+QINDI=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Request an IP header for received data
|
// // Request an IP header for received data
|
||||||
// // "IPD(data length):"
|
// // "IPD(data length):"
|
||||||
@@ -389,7 +312,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Do NOT show the protocol type at the end of the header for received data
|
// // Do NOT show the protocol type at the end of the header for received
|
||||||
|
// data
|
||||||
// // IPD(data length)(TCP/UDP):
|
// // IPD(data length)(TCP/UDP):
|
||||||
// sendAT(GF("+QISHOWPT=0"));
|
// sendAT(GF("+QISHOWPT=0"));
|
||||||
// if (waitResponse() != 1) {
|
// if (waitResponse() != 1) {
|
||||||
@@ -406,103 +330,37 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
sendAT(GF("+QIDEACT"));
|
sendAT(GF("+QIDEACT")); // Deactivate the bearer context
|
||||||
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
|
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getSimCCIDImpl() {
|
||||||
sendAT(GF("+QILOCIP"));
|
sendAT(GF("+QCCID"));
|
||||||
stream.readStringUntil('\n');
|
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
/*
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
* Phone Call functions
|
||||||
}
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow all of the phone call functions from the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messaging functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow all template functions
|
||||||
|
|
||||||
String sendUSSD(const String& code) {
|
public:
|
||||||
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 */
|
/** Delete all SMS */
|
||||||
bool deleteAllSMS() {
|
bool deleteAllSMS() {
|
||||||
sendAT(GF("+QMGDA=6"));
|
sendAT(GF("+QMGDA=6"));
|
||||||
@@ -513,87 +371,30 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Time functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
// Can follow the standard CCLK function in the template
|
||||||
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
|
* Battery functions
|
||||||
*/
|
*/
|
||||||
|
// Can follow the battery functions in the template
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
float getTemperatureImpl() {
|
||||||
uint16_t getBattVoltage() {
|
|
||||||
sendAT(GF("+CBC"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip battery charge status
|
|
||||||
streamSkipUntil(','); // Skip battery charge level
|
|
||||||
// return voltage in mV
|
|
||||||
uint16_t res = stream.readStringUntil(',').toInt();
|
|
||||||
// Wait for final OK
|
|
||||||
waitResponse();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t getBattPercent() {
|
|
||||||
sendAT(GF("+CBC"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip battery charge status
|
|
||||||
// Read battery charge level
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
|
||||||
// Wait for final OK
|
|
||||||
waitResponse();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t getBattChargeState() {
|
|
||||||
sendAT(GF("+CBC?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Read battery charge status
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
|
||||||
// Wait for final OK
|
|
||||||
waitResponse();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
|
|
||||||
sendAT(GF("+CBC?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
chargeState = stream.readStringUntil(',').toInt();
|
|
||||||
percent = stream.readStringUntil(',').toInt();
|
|
||||||
milliVolts = stream.readStringUntil('\n').toInt();
|
|
||||||
// Wait for final OK
|
|
||||||
waitResponse();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getTemperature() {
|
|
||||||
sendAT(GF("+QTEMP"));
|
sendAT(GF("+QTEMP"));
|
||||||
if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) {
|
||||||
return (float)-9999;
|
return static_cast<float>(-9999);
|
||||||
}
|
}
|
||||||
streamSkipUntil(','); // Skip mode
|
streamSkipUntil(','); // Skip mode
|
||||||
// Read charge of thermistor
|
// Read charge of thermistor
|
||||||
// milliVolts = stream.readStringUntil(',').toInt();
|
// milliVolts = streamGetIntBefore(',');
|
||||||
streamSkipUntil(','); // Skip thermistor charge
|
streamSkipUntil(','); // Skip thermistor charge
|
||||||
float temp = stream.readStringUntil('\n').toFloat();
|
float temp = streamGetFloatBefore('\n');
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return temp;
|
return temp;
|
||||||
@@ -602,18 +403,14 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|||||||
/*
|
/*
|
||||||
* Client related functions
|
* 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,
|
||||||
bool ssl = false, int timeout_s = 75) {
|
bool ssl = false, int timeout_s = 75) {
|
||||||
if (ssl) {
|
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||||
DBG("SSL not yet supported on this module!");
|
|
||||||
}
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port);
|
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
|
||||||
int rsp = waitResponse(timeout_ms,
|
GF("\","), port);
|
||||||
GF("CONNECT OK" GSM_NL),
|
int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
|
||||||
GF("CONNECT FAIL" GSM_NL),
|
GF("CONNECT FAIL" GSM_NL),
|
||||||
GF("ALREADY CONNECT" GSM_NL));
|
GF("ALREADY CONNECT" GSM_NL));
|
||||||
return (1 == rsp);
|
return (1 == rsp);
|
||||||
@@ -621,14 +418,10 @@ protected:
|
|||||||
|
|
||||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||||
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
|
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
|
||||||
if (waitResponse(GF(">")) != 1) {
|
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||||
return 0;
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
}
|
|
||||||
stream.write((uint8_t*)buff, len);
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
|
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool allAcknowledged = false;
|
// bool allAcknowledged = false;
|
||||||
// // bool failed = false;
|
// // bool failed = false;
|
||||||
@@ -640,18 +433,18 @@ protected:
|
|||||||
// streamSkipUntil(','); // Skip total length sent on connection
|
// streamSkipUntil(','); // Skip total length sent on connection
|
||||||
// streamSkipUntil(','); // Skip length already acknowledged by remote
|
// streamSkipUntil(','); // Skip length already acknowledged by remote
|
||||||
// // Make sure the total length un-acknowledged is 0
|
// // Make sure the total length un-acknowledged is 0
|
||||||
// if ( stream.readStringUntil('\n').toInt() == 0 ) {
|
// if ( streamGetIntBefore('\n') == 0 ) {
|
||||||
// allAcknowledged = true;
|
// allAcknowledged = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// waitResponse(5000L);
|
// waitResponse(5000L);
|
||||||
|
|
||||||
return len; // TODO
|
return len; // TODO(?): get len/ack properly
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t modemRead(size_t size, uint8_t mux) {
|
size_t modemRead(size_t size, uint8_t mux) {
|
||||||
// TODO: Does this work????
|
// TODO(?): Does this work????
|
||||||
// AT+QIRD=<id>,<sc>,<sid>,<len>
|
// AT+QIRD=<id>,<sc>,<sid>,<len>
|
||||||
// id = GPRS context number = 0, set in GPRS connect
|
// id = GPRS context number = 0, set in GPRS connect
|
||||||
// sc = role in connection = 1, client of connection
|
// sc = role in connection = 1, client of connection
|
||||||
@@ -660,27 +453,27 @@ protected:
|
|||||||
sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size);
|
sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size);
|
||||||
// If it replies only OK for the write command, it means there is no
|
// If it replies only OK for the write command, it means there is no
|
||||||
// received data in the buffer of the connection.
|
// received data in the buffer of the connection.
|
||||||
int res = waitResponse(GF("+QIRD:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
int8_t res = waitResponse(GF("+QIRD:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
||||||
if (res == 1) {
|
if (res == 1) {
|
||||||
streamSkipUntil(':'); // skip IP address
|
streamSkipUntil(':'); // skip IP address
|
||||||
streamSkipUntil(','); // skip port
|
streamSkipUntil(','); // skip port
|
||||||
streamSkipUntil(','); // skip connection type (TCP/UDP)
|
streamSkipUntil(','); // skip connection type (TCP/UDP)
|
||||||
// read the real length of the retrieved data
|
// read the real length of the retrieved data
|
||||||
uint16_t len = stream.readStringUntil('\n').toInt();
|
uint16_t len = streamGetIntBefore('\n');
|
||||||
// We have no way of knowing in advance how much data will be in the buffer
|
// We have no way of knowing in advance how much data will be in the
|
||||||
// so when data is received we always assume the buffer is completely full.
|
// buffer so when data is received we always assume the buffer is
|
||||||
// Chances are, this is not true and there's really not that much there.
|
// completely full. Chances are, this is not true and there's really not
|
||||||
// In that case, make sure we make sure we re-set the amount of data available.
|
// that much there. In that case, make sure we make sure we re-set the
|
||||||
if (len < size) {
|
// amount of data available.
|
||||||
sockets[mux]->sock_available = len;
|
if (len < size) { sockets[mux]->sock_available = len; }
|
||||||
}
|
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
moveCharFromStreamToFifo(mux);
|
||||||
sockets[mux]->sock_available--;
|
sockets[mux]->sock_available--;
|
||||||
// ^^ One less character available after moving from modem's FIFO to our FIFO
|
// ^^ One less character available after moving from modem's FIFO to our
|
||||||
|
// FIFO
|
||||||
}
|
}
|
||||||
waitResponse(); // ends with an OK
|
waitResponse(); // ends with an OK
|
||||||
DBG("### READ:", len, "from", mux);
|
// DBG("### READ:", len, "from", mux);
|
||||||
return len;
|
return len;
|
||||||
} else {
|
} else {
|
||||||
sockets[mux]->sock_available = 0;
|
sockets[mux]->sock_available = 0;
|
||||||
@@ -688,19 +481,22 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t modemGetAvailable(uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool modemGetConnected(uint8_t mux) {
|
bool modemGetConnected(uint8_t mux) {
|
||||||
sendAT(GF("+QISTATE=1,"), mux);
|
sendAT(GF("+QISTATE=1,"), mux);
|
||||||
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
|
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
|
||||||
|
|
||||||
if (waitResponse(GF("+QISTATE:")))
|
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
streamSkipUntil(','); // Skip socket type
|
streamSkipUntil(','); // Skip socket type
|
||||||
streamSkipUntil(','); // Skip remote ip
|
streamSkipUntil(','); // Skip remote ip
|
||||||
streamSkipUntil(','); // Skip remote port
|
streamSkipUntil(','); // Skip remote port
|
||||||
streamSkipUntil(','); // Skip local port
|
streamSkipUntil(','); // Skip local port
|
||||||
int res = stream.readStringUntil(',').toInt(); // socket state
|
int8_t res = streamGetIntBefore(','); // socket state
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -708,19 +504,20 @@ protected:
|
|||||||
return 2 == res;
|
return 2 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||||
// TODO: Optimize this!
|
GsmConstStr r1 = GFP(GSM_OK),
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
#if defined TINY_GSM_DEBUG
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
/*String r1s(r1); r1s.trim();
|
/*String r1s(r1); r1s.trim();
|
||||||
String r2s(r2); r2s.trim();
|
String r2s(r2); r2s.trim();
|
||||||
String r3s(r3); r3s.trim();
|
String r3s(r3); r3s.trim();
|
||||||
@@ -728,15 +525,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r5s(r5); r5s.trim();
|
String r5s(r5); r5s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
uint8_t index = 0;
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
do {
|
do {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available() > 0) {
|
while (stream.available() > 0) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
int a = stream.read();
|
int8_t a = stream.read();
|
||||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||||
data += (char)a;
|
data += static_cast<char>(a);
|
||||||
if (r1 && data.endsWith(r1)) {
|
if (r1 && data.endsWith(r1)) {
|
||||||
index = 1;
|
index = 1;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -744,6 +541,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 2;
|
index = 2;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r3 && data.endsWith(r3)) {
|
} else if (r3 && data.endsWith(r3)) {
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
|
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||||
|
streamSkipUntil('\n'); // Read out the error
|
||||||
|
}
|
||||||
|
#endif
|
||||||
index = 3;
|
index = 3;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r4 && data.endsWith(r4)) {
|
} else if (r4 && data.endsWith(r4)) {
|
||||||
@@ -755,8 +557,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
} else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) {
|
} else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) {
|
||||||
streamSkipUntil(','); // Skip the context
|
streamSkipUntil(','); // Skip the context
|
||||||
streamSkipUntil(','); // Skip the role
|
streamSkipUntil(','); // Skip the role
|
||||||
int mux = stream.readStringUntil('\n').toInt();
|
int8_t mux = streamGetIntBefore('\n');
|
||||||
DBG("### Got Data:", mux);
|
// DBG("### Got Data:", mux);
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||||
// We have no way of knowing how much data actually came in, so
|
// We have no way of knowing how much data actually came in, so
|
||||||
// we set the value to 1500, the maximum possible size.
|
// we set the value to 1500, the maximum possible size.
|
||||||
@@ -764,23 +566,25 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
|
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
|
||||||
int nl = data.lastIndexOf(GSM_NL, data.length()-8);
|
int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
|
||||||
int coma = data.indexOf(',', nl+2);
|
int8_t coma = data.indexOf(',', nl + 2);
|
||||||
int mux = data.substring(nl+2, coma).toInt();
|
int8_t mux = data.substring(nl + 2, coma).toInt();
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||||
sockets[mux]->sock_connected = false;
|
sockets[mux]->sock_connected = false;
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
DBG("### Closed: ", mux);
|
DBG("### Closed: ", mux);
|
||||||
|
} else if (data.endsWith(GF("+QNITZ:"))) {
|
||||||
|
streamSkipUntil('\n'); // URC for time sync
|
||||||
|
data = "";
|
||||||
|
DBG("### Network time updated.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (millis() - startMillis < timeout_ms);
|
} while (millis() - startMillis < timeout_ms);
|
||||||
finish:
|
finish:
|
||||||
if (!index) {
|
if (!index) {
|
||||||
data.trim();
|
data.trim();
|
||||||
if (data.length()) {
|
if (data.length()) { DBG("### Unhandled:", data); }
|
||||||
DBG("### Unhandled:", data);
|
|
||||||
}
|
|
||||||
data = "";
|
data = "";
|
||||||
}
|
}
|
||||||
// data.replace(GSM_NL, "/");
|
// data.replace(GSM_NL, "/");
|
||||||
@@ -788,25 +592,33 @@ finish:
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
#if defined TINY_GSM_DEBUG
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
#if defined TINY_GSM_DEBUG
|
||||||
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Stream& stream;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
Stream& stream;
|
||||||
|
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
const char* gsmNL = GSM_NL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTM95_H_
|
||||||
|
|||||||
+294
-491
File diff suppressed because it is too large
Load Diff
+277
-447
File diff suppressed because it is too large
Load Diff
+338
-607
File diff suppressed because it is too large
Load Diff
+364
-440
File diff suppressed because it is too large
Load Diff
+296
-572
File diff suppressed because it is too large
Load Diff
+86
-106
@@ -6,58 +6,42 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientSIM808_h
|
#ifndef SRC_TINYGSMCLIENTSIM808_H_
|
||||||
#define TinyGsmClientSIM808_h
|
#define SRC_TINYGSMCLIENTSIM808_H_
|
||||||
// #pragma message("TinyGSM: TinyGsmClientSIM808")
|
// #pragma message("TinyGSM: TinyGsmClientSIM808")
|
||||||
|
|
||||||
#include <TinyGsmClientSIM800.h>
|
#include "TinyGsmClientSIM800.h"
|
||||||
|
#include "TinyGsmGPS.tpp"
|
||||||
|
|
||||||
|
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
|
||||||
class TinyGsmSim808: public TinyGsmSim800
|
friend class TinyGsmGPS<TinyGsmSim808>;
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
|
||||||
|
|
||||||
TinyGsmSim808(Stream& stream)
|
|
||||||
: TinyGsmSim800(stream)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual ~TinyGsmSim808(){}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPS location functions
|
* GPS/GNSS/GLONASS location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
// enable GPS
|
// enable GPS
|
||||||
bool enableGPS() {
|
bool enableGPSImpl() {
|
||||||
// uint16_t state;
|
|
||||||
|
|
||||||
sendAT(GF("+CGNSPWR=1"));
|
sendAT(GF("+CGNSPWR=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disableGPS() {
|
bool disableGPSImpl() {
|
||||||
// uint16_t state;
|
|
||||||
|
|
||||||
sendAT(GF("+CGNSPWR=0"));
|
sendAT(GF("+CGNSPWR=0"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the RAW GPS output
|
// get the RAW GPS output
|
||||||
// works only with ans SIM808 V2
|
// works only with ans SIM808 V2
|
||||||
String getGPSraw() {
|
String getGPSrawImpl() {
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
@@ -66,87 +50,83 @@ public:
|
|||||||
|
|
||||||
// get GPS informations
|
// get GPS informations
|
||||||
// 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 getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
|
||||||
//String buffer = "";
|
int* vsat = 0, int* usat = 0, float* accuracy = 0,
|
||||||
// char chr_buffer[12];
|
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
|
||||||
bool fix = false;
|
int* minute = 0, int* second = 0) {
|
||||||
|
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.readStringUntil(','); // mode
|
streamSkipUntil(','); // GNSS run status
|
||||||
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true;
|
if (streamGetIntBefore(',') == 1) { // fix status
|
||||||
stream.readStringUntil(','); //utctime
|
// init variables
|
||||||
*lat = stream.readStringUntil(',').toFloat(); //lat
|
float ilat = 0;
|
||||||
*lon = stream.readStringUntil(',').toFloat(); //lon
|
float ilon = 0;
|
||||||
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon
|
float ispeed = 0;
|
||||||
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed
|
float ialt = 0;
|
||||||
stream.readStringUntil(',');
|
int ivsat = 0;
|
||||||
stream.readStringUntil(',');
|
int iusat = 0;
|
||||||
stream.readStringUntil(',');
|
float iaccuracy = 0;
|
||||||
stream.readStringUntil(',');
|
int iyear = 0;
|
||||||
stream.readStringUntil(',');
|
int imonth = 0;
|
||||||
stream.readStringUntil(',');
|
int iday = 0;
|
||||||
stream.readStringUntil(',');
|
int ihour = 0;
|
||||||
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
|
int imin = 0;
|
||||||
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites
|
float secondWithSS = 0;
|
||||||
stream.readStringUntil('\n');
|
|
||||||
|
// UTC date & Time
|
||||||
|
iyear = streamGetIntLength(4); // Four digit year
|
||||||
|
imonth = streamGetIntLength(2); // Two digit month
|
||||||
|
iday = streamGetIntLength(2); // Two digit day
|
||||||
|
ihour = streamGetIntLength(2); // Two digit hour
|
||||||
|
imin = streamGetIntLength(2); // Two digit minute
|
||||||
|
secondWithSS =
|
||||||
|
streamGetFloatBefore(','); // 6 digit second with subseconds
|
||||||
|
|
||||||
|
ilat = streamGetFloatBefore(','); // Latitude
|
||||||
|
ilon = streamGetFloatBefore(','); // Longitude
|
||||||
|
ialt = streamGetFloatBefore(','); // MSL Altitude. Unit is meters
|
||||||
|
ispeed = streamGetFloatBefore(','); // Speed Over Ground. Unit is knots.
|
||||||
|
streamSkipUntil(','); // Course Over Ground. Degrees.
|
||||||
|
streamSkipUntil(','); // Fix Mode
|
||||||
|
streamSkipUntil(','); // Reserved1
|
||||||
|
iaccuracy =
|
||||||
|
streamGetFloatBefore(','); // Horizontal Dilution Of Precision
|
||||||
|
streamSkipUntil(','); // Position Dilution Of Precision
|
||||||
|
streamSkipUntil(','); // Vertical Dilution Of Precision
|
||||||
|
streamSkipUntil(','); // Reserved2
|
||||||
|
ivsat = streamGetIntBefore(','); // GNSS Satellites in View
|
||||||
|
iusat = streamGetIntBefore(','); // GNSS Satellites Used
|
||||||
|
streamSkipUntil(','); // GLONASS Satellites Used
|
||||||
|
streamSkipUntil(','); // Reserved3
|
||||||
|
streamSkipUntil(','); // C/N0 max
|
||||||
|
streamSkipUntil(','); // HPA
|
||||||
|
streamSkipUntil('\n'); // VPA
|
||||||
|
|
||||||
|
// Set pointers
|
||||||
|
if (lat != NULL) *lat = ilat;
|
||||||
|
if (lon != NULL) *lon = ilon;
|
||||||
|
if (speed != NULL) *speed = ispeed;
|
||||||
|
if (alt != NULL) *alt = ialt;
|
||||||
|
if (vsat != NULL) *vsat = ivsat;
|
||||||
|
if (usat != NULL) *usat = iusat;
|
||||||
|
if (accuracy != NULL) *accuracy = iaccuracy;
|
||||||
|
if (iyear < 2000) iyear += 2000;
|
||||||
|
if (year != NULL) *year = iyear;
|
||||||
|
if (month != NULL) *month = imonth;
|
||||||
|
if (day != NULL) *day = iday;
|
||||||
|
if (hour != NULL) *hour = ihour;
|
||||||
|
if (minute != NULL) *minute = imin;
|
||||||
|
if (second != NULL) *second = static_cast<int>(secondWithSS);
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
return fix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get GPS time
|
|
||||||
// works only with SIM808 V2
|
|
||||||
bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) {
|
|
||||||
bool fix = false;
|
|
||||||
char chr_buffer[12];
|
|
||||||
sendAT(GF("+CGNSINF"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
String buffer = stream.readStringUntil(',');
|
|
||||||
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
//mode
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
//fixstatus
|
|
||||||
if ( buffer.toInt() == 1 ) {
|
|
||||||
fix = buffer.toInt();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
*year = buffer.substring(0,4).toInt();
|
|
||||||
*month = buffer.substring(4,6).toInt();
|
|
||||||
*day = buffer.substring(6,8).toInt();
|
|
||||||
*hour = buffer.substring(8,10).toInt();
|
|
||||||
*minute = buffer.substring(10,12).toInt();
|
|
||||||
*second = buffer.substring(12,14).toInt();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// if nothing else matches, do the default
|
|
||||||
// default is optional
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
|
||||||
|
|
||||||
if (fix) {
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
streamSkipUntil('\n'); // toss the row of commas
|
||||||
|
waitResponse();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTSIM808_H_
|
||||||
|
|||||||
+477
-364
File diff suppressed because it is too large
Load Diff
+278
-351
@@ -6,30 +6,32 @@
|
|||||||
* @date Jan 2019
|
* @date Jan 2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientSequansMonarch_h
|
#ifndef SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||||
#define TinyGsmClientSequansMonarch_h
|
#define SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||||
|
|
||||||
// #define TINY_GSM_DEBUG Serial
|
// #define TINY_GSM_DEBUG Serial
|
||||||
|
|
||||||
#if !defined(TINY_GSM_RX_BUFFER)
|
|
||||||
#define TINY_GSM_RX_BUFFER 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TINY_GSM_MUX_COUNT 6
|
#define TINY_GSM_MUX_COUNT 6
|
||||||
|
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCalling.tpp"
|
||||||
|
#include "TinyGsmGPRS.tpp"
|
||||||
|
#include "TinyGsmModem.tpp"
|
||||||
|
#include "TinyGsmSMS.tpp"
|
||||||
|
#include "TinyGsmSSL.tpp"
|
||||||
|
#include "TinyGsmTCP.tpp"
|
||||||
|
#include "TinyGsmTemperature.tpp"
|
||||||
|
#include "TinyGsmTime.tpp"
|
||||||
|
|
||||||
#define GSM_NL "\r\n"
|
#define GSM_NL "\r\n"
|
||||||
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
|
||||||
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
enum SimStatus {
|
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
SIM_ERROR = 0,
|
#endif
|
||||||
SIM_READY = 1,
|
|
||||||
SIM_LOCKED = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RegStatus {
|
enum RegStatus {
|
||||||
|
REG_NO_RESULT = -1,
|
||||||
REG_UNREGISTERED = 0,
|
REG_UNREGISTERED = 0,
|
||||||
REG_SEARCHING = 2,
|
REG_SEARCHING = 2,
|
||||||
REG_DENIED = 3,
|
REG_DENIED = 3,
|
||||||
@@ -48,29 +50,41 @@ enum SocketStatus {
|
|||||||
SOCK_OPENING = 6,
|
SOCK_OPENING = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmSequansMonarch
|
class TinyGsmSequansMonarch
|
||||||
{
|
: public TinyGsmModem<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmGPRS<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>,
|
||||||
|
public TinyGsmSSL<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmCalling<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmSMS<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmTime<TinyGsmSequansMonarch>,
|
||||||
|
public TinyGsmTemperature<TinyGsmSequansMonarch> {
|
||||||
|
friend class TinyGsmModem<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmGPRS<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>;
|
||||||
|
friend class TinyGsmSSL<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmCalling<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmSMS<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmTime<TinyGsmSequansMonarch>;
|
||||||
|
friend class TinyGsmTemperature<TinyGsmSequansMonarch>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Client
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
class GsmClientSequansMonarch : public GsmClient {
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmSequansMonarch;
|
friend class TinyGsmSequansMonarch;
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GsmClient() {}
|
GsmClientSequansMonarch() {}
|
||||||
|
|
||||||
GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) {
|
explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||||
|
uint8_t mux = 1) {
|
||||||
init(&modem, mux);
|
init(&modem, mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
|
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
|
||||||
this->at = modem;
|
this->at = modem;
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
sock_available = 0;
|
||||||
prev_check = 0;
|
prev_check = 0;
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
@@ -78,6 +92,11 @@ public:
|
|||||||
|
|
||||||
// adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
|
// adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
|
||||||
// using modulus will force 6 back to 0
|
// using modulus will force 6 back to 0
|
||||||
|
if (mux >= 1 && mux <= TINY_GSM_MUX_COUNT) {
|
||||||
|
this->mux = mux;
|
||||||
|
} else {
|
||||||
|
this->mux = (mux % TINY_GSM_MUX_COUNT) + 1;
|
||||||
|
}
|
||||||
at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
|
at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -91,59 +110,42 @@ public:
|
|||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+SQNSH="), mux);
|
at->sendAT(GF("+SQNSH="), mux);
|
||||||
sock_connected = false;
|
sock_connected = false;
|
||||||
at->waitResponse();
|
at->waitResponse();
|
||||||
}
|
}
|
||||||
|
void stop() override {
|
||||||
virtual void stop() { stop(15000L); }
|
stop(15000L);
|
||||||
|
}
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Extended API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
private:
|
|
||||||
TinyGsmSequansMonarch* at;
|
|
||||||
uint8_t mux;
|
|
||||||
uint16_t sock_available;
|
|
||||||
uint32_t prev_check;
|
|
||||||
bool sock_connected;
|
|
||||||
bool got_data;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
class GsmClientSecure : public GsmClient
|
* Inner Secure Client
|
||||||
{
|
*/
|
||||||
public:
|
public:
|
||||||
GsmClientSecure() {}
|
class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch {
|
||||||
|
public:
|
||||||
|
GsmClientSecureSequansMonarch() {}
|
||||||
|
|
||||||
GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1)
|
explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||||
: GsmClient(modem, mux)
|
uint8_t mux = 1)
|
||||||
{}
|
: GsmClientSequansMonarch(modem, mux) {}
|
||||||
|
|
||||||
virtual ~GsmClientSecure(){}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool strictSSL = false;
|
bool strictSSL = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
int connect(const char* host, uint16_t port, int timeout_s) override {
|
||||||
stop();
|
stop();
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
rx.clear();
|
rx.clear();
|
||||||
@@ -152,7 +154,8 @@ public:
|
|||||||
if (strictSSL) {
|
if (strictSSL) {
|
||||||
// require minimum of TLS 1.2 (3)
|
// require minimum of TLS 1.2 (3)
|
||||||
// only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
|
// only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
|
||||||
// verify server certificate against imported CA certs 0 and enforce validity period (3)
|
// verify server certificate against imported CA certs 0 and enforce
|
||||||
|
// validity period (3)
|
||||||
at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
|
at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
|
||||||
} else {
|
} else {
|
||||||
// use TLS 1.0 or higher (1)
|
// use TLS 1.0 or higher (1)
|
||||||
@@ -168,69 +171,102 @@ public:
|
|||||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
return sock_connected;
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||||
|
|
||||||
void setStrictSSL(bool strict) {
|
void setStrictSSL(bool strict) {
|
||||||
strictSSL = strict;
|
strictSSL = strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
public:
|
public:
|
||||||
|
explicit TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
|
||||||
TinyGsmSequansMonarch(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TinyGsmSequansMonarch() {}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool begin(const char* pin = NULL) {
|
bool initImpl(const char* pin = NULL) {
|
||||||
return init(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init(const char* pin = NULL) {
|
|
||||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||||
|
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("E0")); // Echo Off
|
sendAT(GF("E0")); // Echo Off
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
#ifdef TINY_GSM_DEBUG
|
||||||
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
|
#else
|
||||||
|
sendAT(GF("+CMEE=0")); // turn off error codes
|
||||||
|
#endif
|
||||||
|
waitResponse();
|
||||||
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
int ret = getSimStatus();
|
// Make sure the module is enabled. Unlike others, the VZN20Q powers on
|
||||||
|
// with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full
|
||||||
|
// functionality The module cannot even detect the sim card if the cellular
|
||||||
|
// functionality is disabled so unless we explicitly enable the
|
||||||
|
// functionality the init will fail.
|
||||||
|
sendAT(GF("+CFUN=1"));
|
||||||
|
waitResponse();
|
||||||
|
|
||||||
|
// Disable time and time zone URC's
|
||||||
|
sendAT(GF("+CTZR=0"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
|
// Enable automatic time zome update
|
||||||
|
sendAT(GF("+CTZU=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
|
SimStatus ret = getSimStatus();
|
||||||
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
||||||
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||||
simUnlock(pin);
|
simUnlock(pin);
|
||||||
return (getSimStatus() == SIM_READY);
|
return (getSimStatus() == SIM_READY);
|
||||||
}
|
} else {
|
||||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
// if the sim is ready, or it's locked but no pin has been provided,
|
||||||
// true
|
// return true
|
||||||
else {
|
|
||||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
String getModemNameImpl() {
|
||||||
return "Sequans Monarch";
|
sendAT(GF("+CGMI"));
|
||||||
|
String res1;
|
||||||
|
if (waitResponse(1000L, res1) != 1) { return "unknown"; }
|
||||||
|
res1.replace("\r\nOK\r\n", "");
|
||||||
|
res1.replace("\rOK\r", "");
|
||||||
|
res1.trim();
|
||||||
|
|
||||||
|
sendAT(GF("+CGMM"));
|
||||||
|
String res2;
|
||||||
|
if (waitResponse(1000L, res2) != 1) { return "unknown"; }
|
||||||
|
res2.replace("\r\nOK\r\n", "");
|
||||||
|
res2.replace("\rOK\r", "");
|
||||||
|
res2.trim();
|
||||||
|
|
||||||
|
String name = res1 + String(' ') + res2;
|
||||||
|
DBG("### Modem:", name);
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
bool factoryDefaultImpl() {
|
||||||
|
sendAT(GF("&F0")); // Factory
|
||||||
|
waitResponse();
|
||||||
|
sendAT(GF("Z")); // default configuration
|
||||||
|
waitResponse();
|
||||||
|
sendAT(GF("+IPR=0")); // Auto-baud
|
||||||
|
return waitResponse() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
void maintainImpl() {
|
||||||
|
|
||||||
void maintain() {
|
|
||||||
for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) {
|
for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) {
|
||||||
GsmClient* sock = sockets[mux % TINY_GSM_MUX_COUNT];
|
GsmClientSequansMonarch* sock = sockets[mux % TINY_GSM_MUX_COUNT];
|
||||||
if (sock && sock->got_data) {
|
if (sock && sock->got_data) {
|
||||||
sock->got_data = false;
|
sock->got_data = false;
|
||||||
sock->sock_available = modemGetAvailable(mux);
|
sock->sock_available = modemGetAvailable(mux);
|
||||||
@@ -238,147 +274,73 @@ TINY_GSM_MODEM_TEST_AT()
|
|||||||
modemGetConnected();
|
modemGetConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (stream.available()) {
|
while (stream.available()) { waitResponse(15, NULL, NULL); }
|
||||||
waitResponse(15, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+IPR=0")); // Auto-baud
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+IFC=0,0")); // No Flow Control
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CSCLK=0")); // Disable Slow Clock
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("&W")); // Write configuration
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("+CFUN=0"));
|
sendAT(GF("+CFUN=0"));
|
||||||
int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ;
|
int8_t res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR),
|
||||||
if (res != 1 && res != 3) {
|
GF("+SYSSTART"));
|
||||||
return false;
|
if (res != 1 && res != 3) { return false; }
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("+CFUN=1,1"));
|
sendAT(GF("+CFUN=1,1"));
|
||||||
res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR));
|
res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR));
|
||||||
if (res != 1 && res != 3) {
|
if (res != 1 && res != 3) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
|
// NOTE: The only way to turn the modem back on after this shutdown is with
|
||||||
|
// a hard reset
|
||||||
sendAT(GF("+SQNSSHDN"));
|
sendAT(GF("+SQNSSHDN"));
|
||||||
return waitResponse();
|
return waitResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() {
|
// When power saving is enabled, UART0 interface is activated with sleep mode
|
||||||
sendAT(GF("+CFUN=0"));
|
// support. Module power state is controlled by RTS0 line. When no activity
|
||||||
if (waitResponse(10000L) != 1) {
|
// on UART, CTS line will be set to OFF state (driven high level) <timeout>
|
||||||
return false;
|
// milliseconds (100ms to 10s, default 5s) after the last sent character,
|
||||||
}
|
// then module will go to sleep mode as soon as DTE set RTS line to OFF state
|
||||||
delay(3000);
|
// (driver high level).
|
||||||
return true;
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
When power saving is enabled, UART0 interface is activated with sleep mode support.
|
|
||||||
Module power state is controlled by RTS0 line. When no activity on UART, CTS line
|
|
||||||
will be set to OFF state (driven high level) <timeout> milliseconds (100ms to 10s,
|
|
||||||
default 5s) after the last sent character, then module will go to sleep mode as soon
|
|
||||||
as DTE set RTS line to OFF state (driver high level).
|
|
||||||
*/
|
|
||||||
bool sleepEnable(bool enable = true) {
|
|
||||||
sendAT(GF("+SQNIPSCFG="), enable);
|
sendAT(GF("+SQNIPSCFG="), enable);
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* SIM card functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+SQNCCID"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
|
||||||
res.trim();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_IMEI_GSN()
|
|
||||||
|
|
||||||
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
|
||||||
sendAT(GF("+CPIN?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
|
||||||
delay(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
|
|
||||||
waitResponse();
|
|
||||||
switch (status) {
|
|
||||||
case 2:
|
|
||||||
case 3: return SIM_LOCKED;
|
|
||||||
case 1: return SIM_READY;
|
|
||||||
default: return SIM_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SIM_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CEREG)
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_OPERATOR_COPS()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CEREG");
|
||||||
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
RegStatus s = getRegistrationStatus();
|
||||||
if (s == REG_OK_HOME || s == REG_OK_ROAMING) {
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
// DBG(F("connected with status:"), s);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
String getLocalIPImpl() {
|
||||||
|
sendAT(GF("+CGPADDR=3"));
|
||||||
|
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; }
|
||||||
|
String res = stream.readStringUntil('\"');
|
||||||
|
waitResponse();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPRS functions
|
* GPRS functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
gprsDisconnect();
|
gprsDisconnect();
|
||||||
|
|
||||||
// Define the PDP context (This uses context #3!)
|
// Define the PDP context (This uses context #3!)
|
||||||
@@ -397,123 +359,71 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
|
|
||||||
// Attach to GPRS
|
// Attach to GPRS
|
||||||
sendAT(GF("+CGATT=1"));
|
sendAT(GF("+CGATT=1"));
|
||||||
if (waitResponse(60000L) != 1)
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
sendAT(GF("+CGATT=0"));
|
sendAT(GF("+CGATT=0"));
|
||||||
if (waitResponse(60000L) != 1)
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isGprsConnected() {
|
|
||||||
sendAT(GF("+CGATT?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int res = stream.readStringUntil('\n').toInt();
|
|
||||||
waitResponse();
|
|
||||||
if (res != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getSimCCIDImpl() {
|
||||||
sendAT(GF("+CGPADDR=3"));
|
sendAT(GF("+SQNCCID"));
|
||||||
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) {
|
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; }
|
||||||
return "";
|
String res = stream.readStringUntil('\n');
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\"');
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool dtmfSendImpl(char cmd,
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
bool sendSMS(const String& number, const String& text) {
|
|
||||||
sendAT(GF("+CMGF=1"));
|
|
||||||
waitResponse();
|
|
||||||
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
|
|
||||||
sendAT(GF("+CSCS=\"GSM\""));
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
|
||||||
if (waitResponse(GF(">")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
stream.print(text);
|
|
||||||
stream.write((char)0x1A);
|
|
||||||
stream.flush();
|
|
||||||
return waitResponse(60000L) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
// Follows all messaging functions per template
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Time functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
* Temperature functions
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
*/
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
protected:
|
||||||
|
float getTemperatureImpl() {
|
||||||
float getTemperature() {
|
|
||||||
sendAT(GF("+SMDTH"));
|
sendAT(GF("+SMDTH"));
|
||||||
if (waitResponse(10000L, GF("+SMDTH: ")) != 1) {
|
if (waitResponse(10000L, GF("+SMDTH: ")) != 1) {
|
||||||
return (float)-9999;
|
return static_cast<float>(-9999);
|
||||||
}
|
}
|
||||||
String res;
|
String res;
|
||||||
if (waitResponse(1000L, res) != 1) {
|
if (waitResponse(1000L, res) != 1) { return static_cast<float>(-9999); }
|
||||||
return (float)-9999;
|
if (res.indexOf("ERROR") >= 0) { return static_cast<float>(-9999); }
|
||||||
}
|
|
||||||
if (res.indexOf("ERROR") >=0) {
|
|
||||||
return (float)-9999;
|
|
||||||
}
|
|
||||||
return res.toFloat();
|
return res.toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||||
bool ssl = false, int timeout_s = 75)
|
bool ssl = false, int timeout_s = 75) {
|
||||||
{
|
int8_t rsp;
|
||||||
int rsp;
|
uint32_t startMillis = millis();
|
||||||
unsigned long startMillis = millis();
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
|
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
@@ -529,22 +439,26 @@ protected:
|
|||||||
// Socket configuration
|
// Socket configuration
|
||||||
// AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
|
// AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
|
||||||
// <connId1> = Connection ID = mux
|
// <connId1> = Connection ID = mux
|
||||||
// <cid1> = PDP context ID = 3 - this is number set up above in the GprsConnect function
|
// <cid1> = PDP context ID = 3 - this is number set up above in the
|
||||||
|
// GprsConnect function
|
||||||
// <pktSz1> = Packet Size, used for online data mode only = 300 (default)
|
// <pktSz1> = Packet Size, used for online data mode only = 300 (default)
|
||||||
// <maxTo1> = Max timeout in seconds = 90 (default)
|
// <maxTo1> = Max timeout in seconds = 90 (default)
|
||||||
// <connTo1> = Connection timeout in hundreds of milliseconds = 600 (default)
|
// <connTo1> = Connection timeout in hundreds of milliseconds
|
||||||
// <txTo1> = Data sending timeout in hundreds of milliseconds, used for online data mode only = 50 (default)
|
// = 600 (default)
|
||||||
|
// <txTo1> = Data sending timeout in hundreds of milliseconds,
|
||||||
|
// used for online data mode only = 50 (default)
|
||||||
sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50"));
|
sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50"));
|
||||||
waitResponse(5000L);
|
waitResponse(5000L);
|
||||||
|
|
||||||
// Socket configuration extended
|
// Socket configuration extended
|
||||||
//AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>, <listenAutoRsp1>, <sendDataMode1>
|
// AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>,
|
||||||
|
// <listenAutoRsp1>, <sendDataMode1>
|
||||||
// <connId1> = Connection ID = mux
|
// <connId1> = Connection ID = mux
|
||||||
// <srMode1> = Send/Receive URC model = 1 - data amount mode
|
// <srMode1> = Send/Receive URC model = 1 - data amount mode
|
||||||
// <recvDataMode1> = Receive data mode = 0 - data as text (1 would be as hex)
|
// <recvDataMode1> = Receive data mode = 0 - data as text (1 for hex)
|
||||||
// <keepalive1> = unused = 0
|
// <keepalive1> = unused = 0
|
||||||
// <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated
|
// <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated
|
||||||
// <sendDataMode1> = Send data mode = 0 - data as text (1 would be as hex)
|
// <sendDataMode1> = Send data mode = 0 - data as text (1 for hex)
|
||||||
sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0"));
|
sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0"));
|
||||||
waitResponse(5000L);
|
waitResponse(5000L);
|
||||||
|
|
||||||
@@ -553,20 +467,20 @@ protected:
|
|||||||
// <connId> = Connection ID = mux
|
// <connId> = Connection ID = mux
|
||||||
// <txProt> = Transmission protocol = 0 - TCP (1 for UDP)
|
// <txProt> = Transmission protocol = 0 - TCP (1 for UDP)
|
||||||
// <rPort> = Remote host port to contact
|
// <rPort> = Remote host port to contact
|
||||||
// <IPaddr> = Any valid IP address in the format “xxx.xxx.xxx.xxx” or any host name solved with a DNS query
|
// <IPaddr> = Any valid IP address in the format xxx.xxx.xxx.xxx or any
|
||||||
// <closureType> = Socket closure behaviour for TCP, has no effect for UDP = 0 - local port closes when remote does (default)
|
// host name solved with a DNS query
|
||||||
|
// <closureType> = Socket closure behaviour for TCP, has no effect for UDP
|
||||||
|
// = 0 - local port closes when remote does (default)
|
||||||
// <lPort> = UDP connection local port, has no effect for TCP connections.
|
// <lPort> = UDP connection local port, has no effect for TCP connections.
|
||||||
// <connMode> = Connection mode = 1 - command mode connection
|
// <connMode> = Connection mode = 1 - command mode connection
|
||||||
// <acceptAnyRemote> = Applies to UDP only
|
// <acceptAnyRemote> = Applies to UDP only
|
||||||
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), ",0,0,1");
|
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""),
|
||||||
rsp = waitResponse((timeout_ms - (millis() - startMillis)),
|
",0,0,1");
|
||||||
GFP(GSM_OK),
|
rsp = waitResponse((timeout_ms - (millis() - startMillis)), GFP(GSM_OK),
|
||||||
GFP(GSM_ERROR),
|
GFP(GSM_ERROR), GF("NO CARRIER" GSM_NL));
|
||||||
GF("NO CARRIER" GSM_NL)
|
|
||||||
);
|
|
||||||
|
|
||||||
// creation of socket failed immediately.
|
// creation of socket failed immediately.
|
||||||
if (rsp != 1) return false;
|
if (rsp != 1) { return false; }
|
||||||
|
|
||||||
// wait until we get a good status
|
// wait until we get a good status
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
@@ -577,7 +491,6 @@ protected:
|
|||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int modemSend(const void* buff, size_t len, uint8_t mux) {
|
int modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||||
if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) {
|
if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) {
|
||||||
DBG("### Sock closed, cannot send data!");
|
DBG("### Sock closed, cannot send data!");
|
||||||
@@ -586,7 +499,7 @@ protected:
|
|||||||
|
|
||||||
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
|
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
|
||||||
waitResponse(10000L, GF(GSM_NL "> "));
|
waitResponse(10000L, GF(GSM_NL "> "));
|
||||||
stream.write((uint8_t*)buff, len);
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) {
|
||||||
DBG("### no OK after send");
|
DBG("### no OK after send");
|
||||||
@@ -605,8 +518,8 @@ protected:
|
|||||||
// delay(50);
|
// delay(50);
|
||||||
// }
|
// }
|
||||||
// if (gotPrompt) {
|
// if (gotPrompt) {
|
||||||
// stream.write((uint8_t*)buff, len);
|
// stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
// stream.write((char)0x1A);
|
// stream.write(reinterpret_cast<char>0x1A);
|
||||||
// stream.flush();
|
// stream.flush();
|
||||||
// if (waitResponse() != 1) {
|
// if (waitResponse() != 1) {
|
||||||
// DBG("### no OK after send");
|
// DBG("### no OK after send");
|
||||||
@@ -617,21 +530,22 @@ protected:
|
|||||||
// return 0;
|
// return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t modemRead(size_t size, uint8_t mux) {
|
size_t modemRead(size_t size, uint8_t mux) {
|
||||||
sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size);
|
sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size);
|
||||||
if (waitResponse(GF("+SQNSRECV: ")) != 1) {
|
if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
int len = stream.readStringUntil('\n').toInt();
|
int16_t len = streamGetIntBefore('\n');
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
uint32_t startMillis = millis(); \
|
uint32_t startMillis = millis();
|
||||||
while (!stream.available() && ((millis() - startMillis) < sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) { TINY_GSM_YIELD(); } \
|
while (!stream.available() &&
|
||||||
char c = stream.read(); \
|
((millis() - startMillis) <
|
||||||
|
sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
}
|
||||||
|
char c = stream.read();
|
||||||
sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c);
|
sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c);
|
||||||
}
|
}
|
||||||
DBG("### Read:", len, "from", mux);
|
// DBG("### READ:", len, "from", mux);
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = modemGetAvailable(mux);
|
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = modemGetAvailable(mux);
|
||||||
return len;
|
return len;
|
||||||
@@ -644,10 +558,10 @@ protected:
|
|||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
streamSkipUntil(','); // Skip total sent
|
streamSkipUntil(','); // Skip total sent
|
||||||
streamSkipUntil(','); // Skip total received
|
streamSkipUntil(','); // Skip total received
|
||||||
result = stream.readStringUntil(',').toInt(); // keep data not yet read
|
result = streamGetIntBefore(','); // keep data not yet read
|
||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
DBG("### Available:", result, "on", mux);
|
// DBG("### Available:", result, "on", mux);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,11 +570,9 @@ protected:
|
|||||||
// six possible sockets.
|
// six possible sockets.
|
||||||
sendAT(GF("+SQNSS"));
|
sendAT(GF("+SQNSS"));
|
||||||
for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
|
for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
|
||||||
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) {
|
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; }
|
||||||
break;
|
|
||||||
};
|
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
// if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no
|
// if (streamGetIntBefore(',') != muxNo) { // check the mux no
|
||||||
// DBG("### Warning: misaligned mux numbers!");
|
// DBG("### Warning: misaligned mux numbers!");
|
||||||
// }
|
// }
|
||||||
streamSkipUntil(','); // skip mux [use muxNo]
|
streamSkipUntil(','); // skip mux [use muxNo]
|
||||||
@@ -675,26 +587,28 @@ protected:
|
|||||||
// SOCK_LISTENING = 4,
|
// SOCK_LISTENING = 4,
|
||||||
// SOCK_INCOMING = 5,
|
// SOCK_INCOMING = 5,
|
||||||
// SOCK_OPENING = 6,
|
// SOCK_OPENING = 6,
|
||||||
sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \
|
sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected =
|
||||||
((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING));
|
((status != SOCK_CLOSED) && (status != SOCK_INCOMING) &&
|
||||||
|
(status != SOCK_OPENING));
|
||||||
}
|
}
|
||||||
waitResponse(); // Should be an OK at the end
|
waitResponse(); // Should be an OK at the end
|
||||||
return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected;
|
return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||||
// TODO: Optimize this!
|
GsmConstStr r1 = GFP(GSM_OK),
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
#if defined TINY_GSM_DEBUG
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
/*String r1s(r1); r1s.trim();
|
/*String r1s(r1); r1s.trim();
|
||||||
String r2s(r2); r2s.trim();
|
String r2s(r2); r2s.trim();
|
||||||
String r3s(r3); r3s.trim();
|
String r3s(r3); r3s.trim();
|
||||||
@@ -702,15 +616,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r5s(r5); r5s.trim();
|
String r5s(r5); r5s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
uint8_t index = 0;
|
||||||
unsigned long startMillis = millis();
|
uint32_t startMillis = millis();
|
||||||
do {
|
do {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
while (stream.available() > 0) {
|
while (stream.available() > 0) {
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
int a = stream.read();
|
int8_t a = stream.read();
|
||||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||||
data += (char)a;
|
data += static_cast<char>(a);
|
||||||
if (r1 && data.endsWith(r1)) {
|
if (r1 && data.endsWith(r1)) {
|
||||||
index = 1;
|
index = 1;
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -718,6 +632,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 2;
|
index = 2;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r3 && data.endsWith(r3)) {
|
} else if (r3 && data.endsWith(r3)) {
|
||||||
|
#if defined TINY_GSM_DEBUG
|
||||||
|
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||||
|
streamSkipUntil('\n'); // Read out the error
|
||||||
|
}
|
||||||
|
#endif
|
||||||
index = 3;
|
index = 3;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (r4 && data.endsWith(r4)) {
|
} else if (r4 && data.endsWith(r4)) {
|
||||||
@@ -727,17 +646,19 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
index = 5;
|
index = 5;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) {
|
} else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) {
|
||||||
int mux = stream.readStringUntil(',').toInt();
|
int8_t mux = streamGetIntBefore(',');
|
||||||
int len = stream.readStringUntil('\n').toInt();
|
int16_t len = streamGetIntBefore('\n');
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
|
||||||
|
sockets[mux % TINY_GSM_MUX_COUNT]) {
|
||||||
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
|
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
|
||||||
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
|
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
DBG("### URC Data Received:", len, "on", mux);
|
DBG("### URC Data Received:", len, "on", mux);
|
||||||
} else if (data.endsWith(GF("SQNSH: "))) {
|
} else if (data.endsWith(GF("SQNSH: "))) {
|
||||||
int mux = stream.readStringUntil('\n').toInt();
|
int8_t mux = streamGetIntBefore('\n');
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
|
||||||
|
sockets[mux % TINY_GSM_MUX_COUNT]) {
|
||||||
sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
|
sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
@@ -748,9 +669,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
finish:
|
finish:
|
||||||
if (!index) {
|
if (!index) {
|
||||||
data.trim();
|
data.trim();
|
||||||
if (data.length()) {
|
if (data.length()) { DBG("### Unhandled:", data); }
|
||||||
DBG("### Unhandled:", data);
|
|
||||||
}
|
|
||||||
data = "";
|
data = "";
|
||||||
}
|
}
|
||||||
// data.replace(GSM_NL, "/");
|
// data.replace(GSM_NL, "/");
|
||||||
@@ -758,25 +677,33 @@ finish:
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
#if defined TINY_GSM_DEBUG
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
#if defined TINY_GSM_DEBUG
|
||||||
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
|
#else
|
||||||
|
GsmConstStr r3 = NULL,
|
||||||
|
#endif
|
||||||
|
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Stream& stream;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
Stream& stream;
|
||||||
|
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
|
||||||
|
const char* gsmNL = GSM_NL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||||
|
|||||||
+401
-351
File diff suppressed because it is too large
Load Diff
+391
-342
File diff suppressed because it is too large
Load Diff
+18
-547
@@ -6,11 +6,11 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmCommon_h
|
#ifndef SRC_TINYGSMCOMMON_H_
|
||||||
#define TinyGsmCommon_h
|
#define SRC_TINYGSMCOMMON_H_
|
||||||
|
|
||||||
// The current library version number
|
// The current library version number
|
||||||
#define TINYGSM_VERSION "0.9.17"
|
#define TINYGSM_VERSION "0.10.0"
|
||||||
|
|
||||||
#if defined(SPARK) || defined(PARTICLE)
|
#if defined(SPARK) || defined(PARTICLE)
|
||||||
#include "Particle.h"
|
#include "Particle.h"
|
||||||
@@ -28,17 +28,17 @@
|
|||||||
#include <Client.h>
|
#include <Client.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <TinyGsmFifo.h>
|
|
||||||
|
|
||||||
#ifndef TINY_GSM_YIELD_MS
|
#ifndef TINY_GSM_YIELD_MS
|
||||||
#define TINY_GSM_YIELD_MS 0
|
#define TINY_GSM_YIELD_MS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TINY_GSM_YIELD
|
#ifndef TINY_GSM_YIELD
|
||||||
#define TINY_GSM_YIELD() { delay(TINY_GSM_YIELD_MS); }
|
#define TINY_GSM_YIELD() \
|
||||||
|
{ delay(TINY_GSM_YIELD_MS); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type")))
|
#define TINY_GSM_ATTR_NOT_AVAILABLE \
|
||||||
|
__attribute__((error("Not available on this modem type")))
|
||||||
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
|
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
|
||||||
|
|
||||||
#if defined(__AVR__)
|
#if defined(__AVR__)
|
||||||
@@ -74,37 +74,36 @@ namespace {
|
|||||||
TINY_GSM_DEBUG.print(GF("] "));
|
TINY_GSM_DEBUG.print(GF("] "));
|
||||||
DBG_PLAIN(args...);
|
DBG_PLAIN(args...);
|
||||||
}
|
}
|
||||||
}
|
} // namespace
|
||||||
#else
|
#else
|
||||||
#define DBG_PLAIN(...)
|
#define DBG_PLAIN(...)
|
||||||
#define DBG(...)
|
#define DBG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const T& TinyGsmMin(const T& a, const T& b)
|
const T& TinyGsmMin(const T& a, const T& b) {
|
||||||
{
|
|
||||||
return (b < a) ? b : a;
|
return (b < a) ? b : a;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const T& TinyGsmMax(const T& a, const T& b)
|
const T& TinyGsmMax(const T& a, const T& b) {
|
||||||
{
|
|
||||||
return (b < a) ? a : b;
|
return (b < a) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200)
|
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600,
|
||||||
{
|
uint32_t maximum = 115200) {
|
||||||
static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 };
|
static uint32_t rates[] = {115200, 57600, 38400, 19200, 9600, 74400, 74880,
|
||||||
|
230400, 460800, 2400, 4800, 14400, 28800};
|
||||||
|
|
||||||
for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) {
|
for (uint8_t i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
|
||||||
uint32_t rate = rates[i];
|
uint32_t rate = rates[i];
|
||||||
if (rate < minimum || rate > maximum) continue;
|
if (rate < minimum || rate > maximum) continue;
|
||||||
|
|
||||||
DBG("Trying baud rate", rate, "...");
|
DBG("Trying baud rate", rate, "...");
|
||||||
SerialAT.begin(rate);
|
SerialAT.begin(rate);
|
||||||
delay(10);
|
delay(10);
|
||||||
for (int i=0; i<10; i++) {
|
for (int j = 0; j < 10; j++) {
|
||||||
SerialAT.print("AT\r\n");
|
SerialAT.print("AT\r\n");
|
||||||
String input = SerialAT.readString();
|
String input = SerialAT.readString();
|
||||||
if (input.indexOf("OK") >= 0) {
|
if (input.indexOf("OK") >= 0) {
|
||||||
@@ -113,536 +112,8 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SerialAT.begin(minimum);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
#endif // SRC_TINYGSMCOMMON_H_
|
||||||
IPAddress TinyGsmIpFromString(const String& strIP) {
|
|
||||||
int Parts[4] = {0, };
|
|
||||||
int Part = 0;
|
|
||||||
for (uint8_t i=0; i<strIP.length(); i++) {
|
|
||||||
char c = strIP[i];
|
|
||||||
if (c == '.') {
|
|
||||||
Part++;
|
|
||||||
if (Part > 3) {
|
|
||||||
return IPAddress(0,0,0,0);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (c >= '0' && c <= '9') {
|
|
||||||
Parts[Part] *= 10;
|
|
||||||
Parts[Part] += c - '0';
|
|
||||||
} else {
|
|
||||||
if (Part == 3) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
String TinyGsmDecodeHex7bit(String &instr) {
|
|
||||||
String result;
|
|
||||||
byte reminder = 0;
|
|
||||||
int bitstate = 7;
|
|
||||||
for (unsigned i=0; i<instr.length(); i+=2) {
|
|
||||||
char buf[4] = { 0, };
|
|
||||||
buf[0] = instr[i];
|
|
||||||
buf[1] = instr[i+1];
|
|
||||||
byte b = strtol(buf, NULL, 16);
|
|
||||||
|
|
||||||
byte bb = b << (7 - bitstate);
|
|
||||||
char c = (bb + reminder) & 0x7F;
|
|
||||||
result += c;
|
|
||||||
reminder = b >> bitstate;
|
|
||||||
bitstate--;
|
|
||||||
if (bitstate == 0) {
|
|
||||||
char c = reminder;
|
|
||||||
result += c;
|
|
||||||
reminder = 0;
|
|
||||||
bitstate = 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
String TinyGsmDecodeHex8bit(String &instr) {
|
|
||||||
String result;
|
|
||||||
for (unsigned i=0; i<instr.length(); i+=2) {
|
|
||||||
char buf[4] = { 0, };
|
|
||||||
buf[0] = instr[i];
|
|
||||||
buf[1] = instr[i+1];
|
|
||||||
char b = strtol(buf, NULL, 16);
|
|
||||||
result += b;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
String TinyGsmDecodeHex16bit(String &instr) {
|
|
||||||
String result;
|
|
||||||
for (unsigned i=0; i<instr.length(); i+=4) {
|
|
||||||
char buf[4] = { 0, };
|
|
||||||
buf[0] = instr[i];
|
|
||||||
buf[1] = instr[i+1];
|
|
||||||
char b = strtol(buf, NULL, 16);
|
|
||||||
if (b) { // If high byte is non-zero, we can't handle it ;(
|
|
||||||
#if defined(TINY_GSM_UNICODE_TO_HEX)
|
|
||||||
result += "\\x";
|
|
||||||
result += instr.substring(i, i+4);
|
|
||||||
#else
|
|
||||||
result += "?";
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
buf[0] = instr[i+2];
|
|
||||||
buf[1] = instr[i+3];
|
|
||||||
b = strtol(buf, NULL, 16);
|
|
||||||
result += b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Connect to a IP address given as an IPAddress object by
|
|
||||||
// converting said IP address to text
|
|
||||||
#define TINY_GSM_CLIENT_CONNECT_OVERLOADS() \
|
|
||||||
virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { \
|
|
||||||
String host; host.reserve(16); \
|
|
||||||
host += ip[0]; \
|
|
||||||
host += "."; \
|
|
||||||
host += ip[1]; \
|
|
||||||
host += "."; \
|
|
||||||
host += ip[2]; \
|
|
||||||
host += "."; \
|
|
||||||
host += ip[3]; \
|
|
||||||
return connect(host.c_str(), port, timeout_s); \
|
|
||||||
} \
|
|
||||||
virtual int connect(const char *host, uint16_t port) { \
|
|
||||||
return connect(host, port, 75); \
|
|
||||||
} \
|
|
||||||
virtual int connect(IPAddress ip, uint16_t port) { \
|
|
||||||
return connect(ip, port, 75); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Writes data out on the client using the modem send functionality
|
|
||||||
#define TINY_GSM_CLIENT_WRITE() \
|
|
||||||
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)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the combined number of characters available in the TinyGSM fifo
|
|
||||||
// and the modem chips internal fifo, doing an extra check-in with the
|
|
||||||
// modem to see if anything has arrived without a UURC.
|
|
||||||
#define TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() \
|
|
||||||
virtual int available() { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
if (!rx.size()) { \
|
|
||||||
/* Workaround: sometimes module forgets to notify about data arrival.
|
|
||||||
TODO: Currently we ping the module periodically,
|
|
||||||
but maybe there's a better indicator that we need to poll */ \
|
|
||||||
if (millis() - prev_check > 500) { \
|
|
||||||
got_data = true; \
|
|
||||||
prev_check = millis(); \
|
|
||||||
} \
|
|
||||||
at->maintain(); \
|
|
||||||
} \
|
|
||||||
return rx.size() + sock_available; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the combined number of characters available in the TinyGSM fifo and
|
|
||||||
// the modem chips internal fifo. Use this if you don't expect to miss any URC's.
|
|
||||||
#define TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() \
|
|
||||||
virtual int available() { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
if (!rx.size()) { \
|
|
||||||
at->maintain(); \
|
|
||||||
} \
|
|
||||||
return rx.size() + sock_available; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the number of characters available in the TinyGSM fifo
|
|
||||||
// Assumes the modem chip has no internal fifo
|
|
||||||
#define TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() \
|
|
||||||
virtual int available() { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
if (!rx.size() && sock_connected) { \
|
|
||||||
at->maintain(); \
|
|
||||||
} \
|
|
||||||
return rx.size(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define TINY_GSM_CLIENT_READ_OVERLOAD() \
|
|
||||||
virtual int read() { \
|
|
||||||
uint8_t c; \
|
|
||||||
if (read(&c, 1) == 1) { \
|
|
||||||
return c; \
|
|
||||||
} \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads characters out of the TinyGSM fifo, and from the modem chips internal
|
|
||||||
// fifo if avaiable, also double checking with the modem if data has arrived
|
|
||||||
// without issuing a UURC.
|
|
||||||
#define TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() \
|
|
||||||
virtual int read(uint8_t *buf, size_t size) { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
at->maintain(); \
|
|
||||||
size_t cnt = 0; \
|
|
||||||
while (cnt < size) { \
|
|
||||||
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
|
|
||||||
if (chunk > 0) { \
|
|
||||||
rx.get(buf, chunk); \
|
|
||||||
buf += chunk; \
|
|
||||||
cnt += chunk; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
/* Workaround: sometimes module forgets to notify about data arrival.
|
|
||||||
TODO: Currently we ping the module periodically,
|
|
||||||
but maybe there's a better indicator that we need to poll */ \
|
|
||||||
if (millis() - prev_check > 500) { \
|
|
||||||
got_data = true; \
|
|
||||||
prev_check = millis(); \
|
|
||||||
} \
|
|
||||||
/* TODO: Read directly into user buffer? */ \
|
|
||||||
at->maintain(); \
|
|
||||||
if (sock_available > 0) { \
|
|
||||||
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
|
|
||||||
if (n == 0) break; \
|
|
||||||
} else { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return cnt; \
|
|
||||||
} \
|
|
||||||
TINY_GSM_CLIENT_READ_OVERLOAD()
|
|
||||||
|
|
||||||
|
|
||||||
// Reads characters out of the TinyGSM fifo, and from the modem chips internal
|
|
||||||
// fifo if avaiable. Use this if you don't expect to miss any URC's.
|
|
||||||
#define TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() \
|
|
||||||
virtual int read(uint8_t *buf, size_t size) { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
at->maintain(); \
|
|
||||||
size_t cnt = 0; \
|
|
||||||
while (cnt < size) { \
|
|
||||||
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
|
|
||||||
if (chunk > 0) { \
|
|
||||||
rx.get(buf, chunk); \
|
|
||||||
buf += chunk; \
|
|
||||||
cnt += chunk; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
/* TODO: Read directly into user buffer? */ \
|
|
||||||
at->maintain(); \
|
|
||||||
if (sock_available > 0) { \
|
|
||||||
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
|
|
||||||
if (n == 0) break; \
|
|
||||||
} else { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return cnt; \
|
|
||||||
} \
|
|
||||||
TINY_GSM_CLIENT_READ_OVERLOAD()
|
|
||||||
|
|
||||||
|
|
||||||
// Reads characters out of the TinyGSM fifo, waiting for any URC's from the
|
|
||||||
// modem for new data if there's nothing in the fifo. This assumes the
|
|
||||||
//modem chip itself has no fifo.
|
|
||||||
#define TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() \
|
|
||||||
virtual int read(uint8_t *buf, size_t size) { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
size_t cnt = 0; \
|
|
||||||
uint32_t _startMillis = millis(); \
|
|
||||||
while (cnt < size && millis() - _startMillis < _timeout) { \
|
|
||||||
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
|
|
||||||
if (chunk > 0) { \
|
|
||||||
rx.get(buf, chunk); \
|
|
||||||
buf += chunk; \
|
|
||||||
cnt += chunk; \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
/* TODO: Read directly into user buffer? */ \
|
|
||||||
if (!rx.size() && sock_connected) { \
|
|
||||||
at->maintain(); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return cnt; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
virtual int read() { \
|
|
||||||
uint8_t c; \
|
|
||||||
if (read(&c, 1) == 1) { \
|
|
||||||
return c; \
|
|
||||||
} \
|
|
||||||
return -1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Read and dump anything remaining in the modem's internal buffer.
|
|
||||||
// Using this in the client stop() function.
|
|
||||||
// The socket will appear open in response to connected() even after it
|
|
||||||
// closes until all data is read from the buffer.
|
|
||||||
// Doing it this way allows the external mcu to find and get all of the data
|
|
||||||
// that it wants from the socket even if it was closed externally.
|
|
||||||
#define TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
rx.clear(); \
|
|
||||||
at->maintain(); \
|
|
||||||
unsigned long startMillis = millis(); \
|
|
||||||
while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { \
|
|
||||||
at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
|
|
||||||
rx.clear(); \
|
|
||||||
at->maintain(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// The peek, flush, and connected functions
|
|
||||||
#define TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() \
|
|
||||||
virtual int peek() { return -1; } /* TODO */ \
|
|
||||||
\
|
|
||||||
virtual void flush() { at->stream.flush(); } \
|
|
||||||
\
|
|
||||||
virtual uint8_t connected() { \
|
|
||||||
if (available()) { \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
return sock_connected; \
|
|
||||||
} \
|
|
||||||
virtual operator bool() { return connected(); }
|
|
||||||
|
|
||||||
|
|
||||||
// Set baud rate via the V.25TER standard IPR command
|
|
||||||
#define TINY_GSM_MODEM_SET_BAUD_IPR() \
|
|
||||||
void setBaud(unsigned long baud) { \
|
|
||||||
sendAT(GF("+IPR="), baud); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Test response to AT commands
|
|
||||||
#define TINY_GSM_MODEM_TEST_AT() \
|
|
||||||
bool testAT(unsigned long timeout_ms = 10000L) { \
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \
|
|
||||||
sendAT(GF("")); \
|
|
||||||
if (waitResponse(200) == 1) return true; \
|
|
||||||
delay(100); \
|
|
||||||
} \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Keeps listening for modem URC's and iterates through sockets
|
|
||||||
// to see if any data is avaiable
|
|
||||||
#define TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() \
|
|
||||||
void maintain() { \
|
|
||||||
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { \
|
|
||||||
GsmClient* sock = sockets[mux]; \
|
|
||||||
if (sock && sock->got_data) { \
|
|
||||||
sock->got_data = false; \
|
|
||||||
sock->sock_available = modemGetAvailable(mux); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
while (stream.available()) { \
|
|
||||||
waitResponse(15, NULL, NULL); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Keeps listening for modem URC's - doesn't check socks because
|
|
||||||
// modem has no internal fifo
|
|
||||||
#define TINY_GSM_MODEM_MAINTAIN_LISTEN() \
|
|
||||||
void maintain() { \
|
|
||||||
waitResponse(100, NULL, NULL); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Asks for modem information via the V.25TER standard ATI command
|
|
||||||
// NOTE: The actual value and style of the response is quite varied
|
|
||||||
#define TINY_GSM_MODEM_GET_INFO_ATI() \
|
|
||||||
String getModemInfo() { \
|
|
||||||
sendAT(GF("I")); \
|
|
||||||
String res; \
|
|
||||||
if (waitResponse(1000L, res) != 1) { \
|
|
||||||
return ""; \
|
|
||||||
} \
|
|
||||||
res.replace(GSM_NL "OK" GSM_NL, ""); \
|
|
||||||
res.replace(GSM_NL, " "); \
|
|
||||||
res.trim(); \
|
|
||||||
return res; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Unlocks a sim via the 3GPP TS command AT+CPIN
|
|
||||||
#define TINY_GSM_MODEM_SIM_UNLOCK_CPIN() \
|
|
||||||
bool simUnlock(const char *pin) { \
|
|
||||||
if (pin && strlen(pin) > 0) { \
|
|
||||||
sendAT(GF("+CPIN=\""), pin, GF("\"")); \
|
|
||||||
return waitResponse() == 1; \
|
|
||||||
} \
|
|
||||||
return true; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets the CCID of a sim card via AT+CCID
|
|
||||||
#define TINY_GSM_MODEM_GET_SIMCCID_CCID() \
|
|
||||||
String getSimCCID() { \
|
|
||||||
sendAT(GF("+CCID")); \
|
|
||||||
if (waitResponse(GF(GSM_NL "+CCID:")) != 1) { \
|
|
||||||
return ""; \
|
|
||||||
} \
|
|
||||||
String res = stream.readStringUntil('\n'); \
|
|
||||||
waitResponse(); \
|
|
||||||
res.trim(); \
|
|
||||||
return res; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Asks for TA Serial Number Identification (IMEI) via the V.25TER standard AT+GSN command
|
|
||||||
#define TINY_GSM_MODEM_GET_IMEI_GSN() \
|
|
||||||
String getIMEI() { \
|
|
||||||
sendAT(GF("+GSN")); \
|
|
||||||
if (waitResponse(GF(GSM_NL)) != 1) { \
|
|
||||||
return ""; \
|
|
||||||
} \
|
|
||||||
String res = stream.readStringUntil('\n'); \
|
|
||||||
waitResponse(); \
|
|
||||||
res.trim(); \
|
|
||||||
return res; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets the modem's registration status via CREG/CGREG/CEREG
|
|
||||||
// CREG = Generic network registration
|
|
||||||
// CGREG = GPRS service registration
|
|
||||||
// CEREG = EPS registration for LTE modules
|
|
||||||
#define TINY_GSM_MODEM_GET_REGISTRATION_XREG(regCommand) \
|
|
||||||
RegStatus getRegistrationStatus() { \
|
|
||||||
sendAT(GF("+" #regCommand "?")); \
|
|
||||||
if (waitResponse(GF(GSM_NL "+" #regCommand ":")) != 1) { \
|
|
||||||
return REG_UNKNOWN; \
|
|
||||||
} \
|
|
||||||
streamSkipUntil(','); /* Skip format (0) */ \
|
|
||||||
int status = stream.readStringUntil('\n').toInt(); \
|
|
||||||
waitResponse(); \
|
|
||||||
return (RegStatus)status; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets the current network operator via the 3GPP TS command AT+COPS
|
|
||||||
#define TINY_GSM_MODEM_GET_OPERATOR_COPS() \
|
|
||||||
String getOperator() { \
|
|
||||||
sendAT(GF("+COPS?")); \
|
|
||||||
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { \
|
|
||||||
return ""; \
|
|
||||||
} \
|
|
||||||
streamSkipUntil('"'); /* Skip mode and format */ \
|
|
||||||
String res = stream.readStringUntil('"'); \
|
|
||||||
waitResponse(); \
|
|
||||||
return res; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Waits for network attachment
|
|
||||||
#define TINY_GSM_MODEM_WAIT_FOR_NETWORK() \
|
|
||||||
bool waitForNetwork(unsigned long timeout_ms = 60000L) { \
|
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \
|
|
||||||
if (isNetworkConnected()) { \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
delay(250); \
|
|
||||||
} \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Checks if current attached to GPRS/EPS service
|
|
||||||
#define TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() \
|
|
||||||
bool isGprsConnected() { \
|
|
||||||
sendAT(GF("+CGATT?")); \
|
|
||||||
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { \
|
|
||||||
return false; \
|
|
||||||
} \
|
|
||||||
int res = stream.readStringUntil('\n').toInt(); \
|
|
||||||
waitResponse(); \
|
|
||||||
if (res != 1) \
|
|
||||||
return false; \
|
|
||||||
\
|
|
||||||
return localIP() != IPAddress(0,0,0,0); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets signal quality report according to 3GPP TS command AT+CSQ
|
|
||||||
#define TINY_GSM_MODEM_GET_CSQ() \
|
|
||||||
int16_t getSignalQuality() { \
|
|
||||||
sendAT(GF("+CSQ")); \
|
|
||||||
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { \
|
|
||||||
return 99; \
|
|
||||||
} \
|
|
||||||
int res = stream.readStringUntil(',').toInt(); \
|
|
||||||
waitResponse(); \
|
|
||||||
return res; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Yields up to a time-out period and then reads a character from the stream into the mux FIFO
|
|
||||||
// TODO: Do we need to wait two _timeout periods for no character return? Will wait once in the first
|
|
||||||
// "while !stream.available()" and then will wait again in the stream.read() function.
|
|
||||||
#define TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT \
|
|
||||||
uint32_t startMillis = millis(); \
|
|
||||||
while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } \
|
|
||||||
char c = stream.read(); \
|
|
||||||
sockets[mux]->rx.put(c);
|
|
||||||
|
|
||||||
|
|
||||||
// Utility templates for writing/skipping characters on a stream
|
|
||||||
#define TINY_GSM_MODEM_STREAM_UTILITIES() \
|
|
||||||
template<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...); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
template<typename... Args> \
|
|
||||||
void sendAT(Args... cmd) { \
|
|
||||||
streamWrite("AT", cmd..., GSM_NL); \
|
|
||||||
stream.flush(); \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
/* DBG("### AT:", cmd...); */ \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
bool streamSkipUntil(const char c, const unsigned long timeout_ms = 1000L) { \
|
|
||||||
unsigned long startMillis = millis(); \
|
|
||||||
while (millis() - startMillis < timeout_ms) { \
|
|
||||||
while (millis() - startMillis < timeout_ms && !stream.available()) { \
|
|
||||||
TINY_GSM_YIELD(); \
|
|
||||||
} \
|
|
||||||
if (stream.read() == c) { \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmGPRS.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMGPRS_H_
|
||||||
|
#define SRC_TINYGSMGPRS_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
|
|
||||||
|
enum SimStatus {
|
||||||
|
SIM_ERROR = 0,
|
||||||
|
SIM_READY = 1,
|
||||||
|
SIM_LOCKED = 2,
|
||||||
|
SIM_ANTITHEFT_LOCKED = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmGPRS {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* SIM card functions
|
||||||
|
*/
|
||||||
|
// Unlocks the SIM
|
||||||
|
bool simUnlock(const char* pin) {
|
||||||
|
return thisModem().simUnlockImpl(pin);
|
||||||
|
}
|
||||||
|
// Gets the CCID of a sim card via AT+CCID
|
||||||
|
String getSimCCID() {
|
||||||
|
return thisModem().getSimCCIDImpl();
|
||||||
|
}
|
||||||
|
// Asks for TA Serial Number Identification (IMEI)
|
||||||
|
String getIMEI() {
|
||||||
|
return thisModem().getIMEIImpl();
|
||||||
|
}
|
||||||
|
// Asks for International Mobile Subscriber Identity IMSI
|
||||||
|
String getIMSI() {
|
||||||
|
return thisModem().getIMSIImpl();
|
||||||
|
}
|
||||||
|
SimStatus getSimStatus(uint32_t timeout_ms = 10000L) {
|
||||||
|
return thisModem().getSimStatusImpl(timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPRS functions
|
||||||
|
*/
|
||||||
|
bool gprsConnect(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
|
return thisModem().gprsConnectImpl(apn, user, pwd);
|
||||||
|
}
|
||||||
|
bool gprsDisconnect() {
|
||||||
|
return thisModem().gprsDisconnectImpl();
|
||||||
|
}
|
||||||
|
// Checks if current attached to GPRS/EPS service
|
||||||
|
bool isGprsConnected() {
|
||||||
|
return thisModem().isGprsConnectedImpl();
|
||||||
|
}
|
||||||
|
// Gets the current network operator
|
||||||
|
String getOperator() {
|
||||||
|
return thisModem().getOperatorImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIM card functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Unlocks a sim via the 3GPP TS command AT+CPIN
|
||||||
|
bool simUnlockImpl(const char* pin) {
|
||||||
|
if (pin && strlen(pin) > 0) {
|
||||||
|
thisModem().sendAT(GF("+CPIN=\""), pin, GF("\""));
|
||||||
|
return thisModem().waitResponse() == 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the CCID of a sim card via AT+CCID
|
||||||
|
String getSimCCIDImpl() {
|
||||||
|
thisModem().sendAT(GF("+CCID"));
|
||||||
|
if (thisModem().waitResponse(GF("+CCID:")) != 1) { return ""; }
|
||||||
|
String res = thisModem().stream.readStringUntil('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asks for TA Serial Number Identification (IMEI) via the V.25TER standard
|
||||||
|
// AT+GSN command
|
||||||
|
String getIMEIImpl() {
|
||||||
|
thisModem().sendAT(GF("+GSN"));
|
||||||
|
thisModem().streamSkipUntil('\n'); // skip first newline
|
||||||
|
String res = thisModem().stream.readStringUntil('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asks for International Mobile Subscriber Identity IMSI via the AT+CIMI
|
||||||
|
// command
|
||||||
|
String getIMSIImpl() {
|
||||||
|
thisModem().sendAT(GF("+CIMI"));
|
||||||
|
thisModem().streamSkipUntil('\n'); // skip first newline
|
||||||
|
String res = thisModem().stream.readStringUntil('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) {
|
||||||
|
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||||
|
thisModem().sendAT(GF("+CPIN?"));
|
||||||
|
if (thisModem().waitResponse(GF("+CPIN:")) != 1) {
|
||||||
|
delay(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int8_t status =
|
||||||
|
thisModem().waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"),
|
||||||
|
GF("NOT INSERTED"), GF("NOT READY"));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
switch (status) {
|
||||||
|
case 2:
|
||||||
|
case 3: return SIM_LOCKED;
|
||||||
|
case 1: return SIM_READY;
|
||||||
|
default: return SIM_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SIM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPRS functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Checks if current attached to GPRS/EPS service
|
||||||
|
bool isGprsConnectedImpl() {
|
||||||
|
thisModem().sendAT(GF("+CGATT?"));
|
||||||
|
if (thisModem().waitResponse(GF("+CGATT:")) != 1) { return false; }
|
||||||
|
int8_t res = thisModem().streamGetIntBefore('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
if (res != 1) { return false; }
|
||||||
|
|
||||||
|
return thisModem().localIP() != IPAddress(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the current network operator via the 3GPP TS command AT+COPS
|
||||||
|
String getOperatorImpl() {
|
||||||
|
thisModem().sendAT(GF("+COPS?"));
|
||||||
|
if (thisModem().waitResponse(GF("+COPS:")) != 1) { return ""; }
|
||||||
|
thisModem().streamSkipUntil('"'); /* Skip mode and format */
|
||||||
|
String res = thisModem().stream.readStringUntil('"');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMGPRS_H_
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmGPS.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMGPS_H_
|
||||||
|
#define SRC_TINYGSMGPS_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_GPS
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmGPS {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* GPS/GNSS/GLONASS location functions
|
||||||
|
*/
|
||||||
|
bool enableGPS() {
|
||||||
|
return thisModem().enableGPSImpl();
|
||||||
|
}
|
||||||
|
bool disableGPS() {
|
||||||
|
return thisModem().disableGPSImpl();
|
||||||
|
}
|
||||||
|
String getGPSraw() {
|
||||||
|
return thisModem().getGPSrawImpl();
|
||||||
|
}
|
||||||
|
bool getGPS(float* lat, float* lon, float* speed = 0, float* alt = 0,
|
||||||
|
int* vsat = 0, int* usat = 0, float* accuracy = 0, int* year = 0,
|
||||||
|
int* month = 0, int* day = 0, int* hour = 0, int* minute = 0,
|
||||||
|
int* second = 0) {
|
||||||
|
return thisModem().getGPSImpl(lat, lon, speed, alt, vsat, usat, accuracy,
|
||||||
|
year, month, day, hour, minute, second);
|
||||||
|
}
|
||||||
|
bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute,
|
||||||
|
int* second) {
|
||||||
|
float lat = 0;
|
||||||
|
float lon = 0;
|
||||||
|
return thisModem().getGPSImpl(lat, lon, 0, 0, 0, 0, 0, year, month, day,
|
||||||
|
hour, minute, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPS/GNSS/GLONASS location functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool enableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
bool disableGPSImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
String getGPSrawImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
|
||||||
|
int* vsat = 0, int* usat = 0, float* accuracy = 0,
|
||||||
|
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
|
||||||
|
int* minute = 0,
|
||||||
|
int* second = 0) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMGPS_H_
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmGSMLocation.h
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMGSMLOCATION_H_
|
||||||
|
#define SRC_TINYGSMGSMLOCATION_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_GSM_LOCATION
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmGSMLocation {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* GSM Location functions
|
||||||
|
*/
|
||||||
|
String getGsmLocationRaw() {
|
||||||
|
return thisModem().getGsmLocationRawImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getGsmLocation() {
|
||||||
|
return thisModem().getGsmLocationRawImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getGsmLocation(float* lat, float* lon, float* accuracy = 0,
|
||||||
|
int* year = 0, int* month = 0, int* day = 0,
|
||||||
|
int* hour = 0, int* minute = 0, int* second = 0) {
|
||||||
|
return thisModem().getGsmLocationImpl(lat, lon, accuracy, year, month, day,
|
||||||
|
hour, minute, second);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool getGsmLocationTime(int* year, int* month, int* day, int* hour,
|
||||||
|
int* minute, int* second) {
|
||||||
|
float lat = 0;
|
||||||
|
float lon = 0;
|
||||||
|
float accuracy = 0;
|
||||||
|
return thisModem().getGsmLocation(&lat, &lon, &accuracy, year, month, day,
|
||||||
|
hour, minute, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GSM Location functions
|
||||||
|
* Template is based on SIMCOM commands
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// String getGsmLocationImpl() {
|
||||||
|
// thisModem().sendAT(GF("+CIPGSMLOC=1,1"));
|
||||||
|
// if (thisModem().waitResponse(10000L, GF("+CIPGSMLOC:")) != 1) { return
|
||||||
|
// ""; } String res = thisModem().stream.readStringUntil('\n');
|
||||||
|
// thisModem().waitResponse();
|
||||||
|
// res.trim();
|
||||||
|
// return res;
|
||||||
|
// }
|
||||||
|
|
||||||
|
String getGsmLocationRawImpl() {
|
||||||
|
// AT+CLBS=<type>,<cid>
|
||||||
|
// <type> 1 = location using 3 cell's information
|
||||||
|
// 3 = get number of times location has been accessed
|
||||||
|
// 4 = Get longitude latitude and date time
|
||||||
|
thisModem().sendAT(GF("+CLBS=1,1"));
|
||||||
|
// Should get a location code of "0" indicating success
|
||||||
|
if (thisModem().waitResponse(120000L, GF("+CLBS: ")) != 1) { return ""; }
|
||||||
|
int8_t locationCode = thisModem().streamGetIntLength(2);
|
||||||
|
// 0 = success, else, error
|
||||||
|
if (locationCode != 0) {
|
||||||
|
thisModem().waitResponse(); // should be an ok after the error
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String res = thisModem().stream.readStringUntil('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getGsmLocationImpl(float* lat, float* lon, float* accuracy = 0,
|
||||||
|
int* year = 0, int* month = 0, int* day = 0,
|
||||||
|
int* hour = 0, int* minute = 0, int* second = 0) {
|
||||||
|
// AT+CLBS=<type>,<cid>
|
||||||
|
// <type> 1 = location using 3 cell's information
|
||||||
|
// 3 = get number of times location has been accessed
|
||||||
|
// 4 = Get longitude latitude and date time
|
||||||
|
thisModem().sendAT(GF("+CLBS=4,1"));
|
||||||
|
// Should get a location code of "0" indicating success
|
||||||
|
if (thisModem().waitResponse(120000L, GF("+CLBS: ")) != 1) { return false; }
|
||||||
|
int8_t locationCode = thisModem().streamGetIntLength(2);
|
||||||
|
// 0 = success, else, error
|
||||||
|
if (locationCode != 0) {
|
||||||
|
thisModem().waitResponse(); // should be an ok after the error
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init variables
|
||||||
|
float ilat = 0;
|
||||||
|
float ilon = 0;
|
||||||
|
float iaccuracy = 0;
|
||||||
|
int iyear = 0;
|
||||||
|
int imonth = 0;
|
||||||
|
int iday = 0;
|
||||||
|
int ihour = 0;
|
||||||
|
int imin = 0;
|
||||||
|
int isec = 0;
|
||||||
|
|
||||||
|
ilat = thisModem().streamGetFloatBefore(','); // Latitude
|
||||||
|
ilon = thisModem().streamGetFloatBefore(','); // Longitude
|
||||||
|
iaccuracy = thisModem().streamGetIntBefore(','); // Positioning accuracy
|
||||||
|
|
||||||
|
// Date & Time
|
||||||
|
iyear = thisModem().streamGetIntBefore('/');
|
||||||
|
imonth = thisModem().streamGetIntBefore('/');
|
||||||
|
iday = thisModem().streamGetIntBefore(',');
|
||||||
|
ihour = thisModem().streamGetIntBefore(':');
|
||||||
|
imin = thisModem().streamGetIntBefore(':');
|
||||||
|
isec = thisModem().streamGetIntBefore('\n');
|
||||||
|
|
||||||
|
// Set pointers
|
||||||
|
if (lat != NULL) *lat = ilat;
|
||||||
|
if (lon != NULL) *lon = ilon;
|
||||||
|
if (accuracy != NULL) *accuracy = iaccuracy;
|
||||||
|
if (iyear < 2000) iyear += 2000;
|
||||||
|
if (year != NULL) *year = iyear;
|
||||||
|
if (month != NULL) *month = imonth;
|
||||||
|
if (day != NULL) *day = iday;
|
||||||
|
if (hour != NULL) *hour = ihour;
|
||||||
|
if (minute != NULL) *minute = imin;
|
||||||
|
if (second != NULL) *second = isec;
|
||||||
|
|
||||||
|
// Final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMGSMLOCATION_H_
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmModem.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMMODEM_H_
|
||||||
|
#define SRC_TINYGSMMODEM_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmModem {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Basic functions
|
||||||
|
*/
|
||||||
|
bool begin(const char* pin = NULL) {
|
||||||
|
return thisModem().initImpl(pin);
|
||||||
|
}
|
||||||
|
bool init(const char* pin = NULL) {
|
||||||
|
return thisModem().initImpl(pin);
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
inline void sendAT(Args... cmd) {
|
||||||
|
thisModem().streamWrite("AT", cmd..., thisModem().gsmNL);
|
||||||
|
thisModem().stream.flush();
|
||||||
|
TINY_GSM_YIELD(); /* DBG("### AT:", cmd...); */
|
||||||
|
}
|
||||||
|
void setBaud(uint32_t baud) {
|
||||||
|
thisModem().setBaudImpl(baud);
|
||||||
|
}
|
||||||
|
// Test response to AT commands
|
||||||
|
bool testAT(uint32_t timeout_ms = 10000L) {
|
||||||
|
return thisModem().testATImpl(timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asks for modem information via the V.25TER standard ATI command
|
||||||
|
// NOTE: The actual value and style of the response is quite varied
|
||||||
|
String getModemInfo() {
|
||||||
|
return thisModem().getModemInfoImpl();
|
||||||
|
}
|
||||||
|
// Gets the modem name (as it calls itself)
|
||||||
|
String getModemName() {
|
||||||
|
return thisModem().getModemNameImpl();
|
||||||
|
}
|
||||||
|
bool factoryDefault() {
|
||||||
|
return thisModem().factoryDefaultImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power functions
|
||||||
|
*/
|
||||||
|
bool restart() {
|
||||||
|
return thisModem().restartImpl();
|
||||||
|
}
|
||||||
|
bool poweroff() {
|
||||||
|
return thisModem().powerOffImpl();
|
||||||
|
}
|
||||||
|
bool radioOff() {
|
||||||
|
return thisModem().radioOffImpl();
|
||||||
|
}
|
||||||
|
bool sleepEnable(bool enable = true) {
|
||||||
|
return thisModem().sleepEnableImpl(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic network functions
|
||||||
|
*/
|
||||||
|
// RegStatus getRegistrationStatus() {}
|
||||||
|
bool isNetworkConnected() {
|
||||||
|
return thisModem().isNetworkConnectedImpl();
|
||||||
|
}
|
||||||
|
// Waits for network attachment
|
||||||
|
bool waitForNetwork(uint32_t timeout_ms = 60000L) {
|
||||||
|
return thisModem().waitForNetworkImpl(timeout_ms);
|
||||||
|
}
|
||||||
|
// Gets signal quality report
|
||||||
|
int16_t getSignalQuality() {
|
||||||
|
return thisModem().getSignalQualityImpl();
|
||||||
|
}
|
||||||
|
String getLocalIP() {
|
||||||
|
return thisModem().getLocalIPImpl();
|
||||||
|
}
|
||||||
|
IPAddress localIP() {
|
||||||
|
return thisModem().TinyGsmIpFromString(thisModem().getLocalIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
void setBaudImpl(uint32_t baud) {
|
||||||
|
thisModem().sendAT(GF("+IPR="), baud);
|
||||||
|
thisModem().waitResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool testATImpl(uint32_t timeout_ms = 10000L) {
|
||||||
|
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||||
|
thisModem().sendAT(GF(""));
|
||||||
|
if (thisModem().waitResponse(200) == 1) { return true; }
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getModemInfoImpl() {
|
||||||
|
thisModem().sendAT(GF("I"));
|
||||||
|
String res;
|
||||||
|
if (thisModem().waitResponse(1000L, res) != 1) { return ""; }
|
||||||
|
// Do the replaces twice so we cover both \r and \r\n type endings
|
||||||
|
res.replace("\r\nOK\r\n", "");
|
||||||
|
res.replace("\rOK\r", "");
|
||||||
|
res.replace("\r\n", " ");
|
||||||
|
res.replace("\r", " ");
|
||||||
|
res.trim();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getModemNameImpl() {
|
||||||
|
thisModem().sendAT(GF("+CGMI"));
|
||||||
|
String res1;
|
||||||
|
if (thisModem().waitResponse(1000L, res1) != 1) { return "unknown"; }
|
||||||
|
res1.replace("\r\nOK\r\n", "");
|
||||||
|
res1.replace("\rOK\r", "");
|
||||||
|
res1.trim();
|
||||||
|
|
||||||
|
thisModem().sendAT(GF("+GMM"));
|
||||||
|
String res2;
|
||||||
|
if (thisModem().waitResponse(1000L, res2) != 1) { return "unknown"; }
|
||||||
|
res2.replace("\r\nOK\r\n", "");
|
||||||
|
res2.replace("\rOK\r", "");
|
||||||
|
res2.trim();
|
||||||
|
|
||||||
|
String name = res1 + String(' ') + res2;
|
||||||
|
DBG("### Modem:", name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool factoryDefaultImpl() {
|
||||||
|
thisModem().sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
||||||
|
thisModem().waitResponse();
|
||||||
|
thisModem().sendAT(GF("+IPR=0")); // Auto-baud
|
||||||
|
thisModem().waitResponse();
|
||||||
|
thisModem().sendAT(GF("&W")); // Write configuration
|
||||||
|
return thisModem().waitResponse() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
bool radioOffImpl() {
|
||||||
|
thisModem().sendAT(GF("+CFUN=0"));
|
||||||
|
if (thisModem().waitResponse(10000L) != 1) { return false; }
|
||||||
|
delay(3000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic network functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Gets the modem's registration status via CREG/CGREG/CEREG
|
||||||
|
// CREG = Generic network registration
|
||||||
|
// CGREG = GPRS service registration
|
||||||
|
// CEREG = EPS registration for LTE modules
|
||||||
|
int8_t getRegistrationStatusXREG(const char* regCommand) {
|
||||||
|
thisModem().sendAT('+', regCommand, '?');
|
||||||
|
// check for any of the three for simplicity
|
||||||
|
int8_t resp = thisModem().waitResponse(GF("+CREG:"), GF("+CGREG:"),
|
||||||
|
GF("+CEREG:"));
|
||||||
|
if (resp != 1 && resp != 2 && resp != 3) { return -1; }
|
||||||
|
thisModem().streamSkipUntil(','); /* Skip format (0) */
|
||||||
|
int status = thisModem().streamGetIntBefore('\n');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitForNetworkImpl(uint32_t timeout_ms = 60000L) {
|
||||||
|
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||||
|
if (thisModem().isNetworkConnected()) { return true; }
|
||||||
|
delay(250);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets signal quality report according to 3GPP TS command AT+CSQ
|
||||||
|
int8_t getSignalQualityImpl() {
|
||||||
|
thisModem().sendAT(GF("+CSQ"));
|
||||||
|
if (thisModem().waitResponse(GF("+CSQ:")) != 1) { return 99; }
|
||||||
|
int8_t res = thisModem().streamGetIntBefore(',');
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLocalIPImpl() {
|
||||||
|
thisModem().sendAT(GF("+CGPADDR=1"));
|
||||||
|
if (thisModem().waitResponse(GF("+CGPADDR:")) != 1) { return ""; }
|
||||||
|
thisModem().streamSkipUntil(','); // Skip context id
|
||||||
|
String res = thisModem().stream.readStringUntil('\r');
|
||||||
|
if (thisModem().waitResponse() != 1) { return ""; }
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline IPAddress TinyGsmIpFromString(const String& strIP) {
|
||||||
|
int Parts[4] = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
int Part = 0;
|
||||||
|
for (uint8_t i = 0; i < strIP.length(); i++) {
|
||||||
|
char c = strIP[i];
|
||||||
|
if (c == '.') {
|
||||||
|
Part++;
|
||||||
|
if (Part > 3) { return IPAddress(0, 0, 0, 0); }
|
||||||
|
continue;
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
Parts[Part] *= 10;
|
||||||
|
Parts[Part] += c - '0';
|
||||||
|
} else {
|
||||||
|
if (Part == 3) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Utilities
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// Utility templates for writing/skipping characters on a stream
|
||||||
|
template <typename T>
|
||||||
|
inline void streamWrite(T last) {
|
||||||
|
thisModem().stream.print(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
inline void streamWrite(T head, Args... tail) {
|
||||||
|
thisModem().stream.print(head);
|
||||||
|
thisModem().streamWrite(tail...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void streamClear() {
|
||||||
|
while (thisModem().stream.available()) {
|
||||||
|
thisModem().waitResponse(50, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline int16_t streamGetIntLength(int8_t numChars) {
|
||||||
|
char buf[6];
|
||||||
|
size_t bytesRead = thisModem().stream.readBytes(buf, numChars);
|
||||||
|
if (bytesRead) {
|
||||||
|
buf[numChars] = '\0';
|
||||||
|
int16_t res = atoi(buf);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return -9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int16_t streamGetIntBefore(char lastChar) {
|
||||||
|
char buf[7];
|
||||||
|
size_t bytesRead = thisModem().stream.readBytesUntil(
|
||||||
|
lastChar, buf, static_cast<size_t>(7));
|
||||||
|
// if we read 7 or more bytes, it's an overflow
|
||||||
|
if (bytesRead && bytesRead < 7) {
|
||||||
|
buf[bytesRead] = '\0';
|
||||||
|
int16_t res = atoi(buf);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return -9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float streamGetFloatLength(int8_t numChars) {
|
||||||
|
char buf[16];
|
||||||
|
size_t bytesRead = thisModem().stream.readBytes(buf, numChars);
|
||||||
|
DBG("### bytesRead:", bytesRead);
|
||||||
|
if (bytesRead) {
|
||||||
|
buf[numChars] = '\0';
|
||||||
|
int16_t res = atof(buf);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return static_cast<float>(-9999);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float streamGetFloatBefore(char lastChar) {
|
||||||
|
char buf[16];
|
||||||
|
size_t bytesRead = thisModem().stream.readBytesUntil(
|
||||||
|
lastChar, buf, static_cast<size_t>(16));
|
||||||
|
if (bytesRead) {
|
||||||
|
buf[bytesRead] = '\0';
|
||||||
|
float res = atof(buf);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return static_cast<float>(-9999);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool streamSkipUntil(const char c, const uint32_t timeout_ms = 1000L) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
while (millis() - startMillis < timeout_ms) {
|
||||||
|
while (millis() - startMillis < timeout_ms &&
|
||||||
|
!thisModem().stream.available()) {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
}
|
||||||
|
if (thisModem().stream.read() == c) { return true; }
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMMODEM_H_
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmSMS.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMSMS_H_
|
||||||
|
#define SRC_TINYGSMSMS_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_SMS
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmSMS {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Messaging functions
|
||||||
|
*/
|
||||||
|
String sendUSSD(const String& code) {
|
||||||
|
return thisModem().sendUSSDImpl(code);
|
||||||
|
}
|
||||||
|
bool sendSMS(const String& number, const String& text) {
|
||||||
|
return thisModem().sendSMSImpl(number, text);
|
||||||
|
}
|
||||||
|
bool sendSMS_UTF16(const char* const number, const void* text, size_t len) {
|
||||||
|
return thisModem().sendSMS_UTF16Impl(number, text, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Messaging functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
static inline String TinyGsmDecodeHex7bit(String& instr) {
|
||||||
|
String result;
|
||||||
|
byte reminder = 0;
|
||||||
|
int8_t bitstate = 7;
|
||||||
|
for (uint8_t i = 0; i < instr.length(); i += 2) {
|
||||||
|
char buf[4] = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
buf[0] = instr[i];
|
||||||
|
buf[1] = instr[i + 1];
|
||||||
|
byte b = strtol(buf, NULL, 16);
|
||||||
|
|
||||||
|
byte bb = b << (7 - bitstate);
|
||||||
|
char c = (bb + reminder) & 0x7F;
|
||||||
|
result += c;
|
||||||
|
reminder = b >> bitstate;
|
||||||
|
bitstate--;
|
||||||
|
if (bitstate == 0) {
|
||||||
|
char cc = reminder;
|
||||||
|
result += cc;
|
||||||
|
reminder = 0;
|
||||||
|
bitstate = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline String TinyGsmDecodeHex8bit(String& instr) {
|
||||||
|
String result;
|
||||||
|
for (uint8_t i = 0; i < instr.length(); i += 2) {
|
||||||
|
char buf[4] = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
buf[0] = instr[i];
|
||||||
|
buf[1] = instr[i + 1];
|
||||||
|
char b = strtol(buf, NULL, 16);
|
||||||
|
result += b;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline String TinyGsmDecodeHex16bit(String& instr) {
|
||||||
|
String result;
|
||||||
|
for (uint8_t i = 0; i < instr.length(); i += 4) {
|
||||||
|
char buf[4] = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
buf[0] = instr[i];
|
||||||
|
buf[1] = instr[i + 1];
|
||||||
|
char b = strtol(buf, NULL, 16);
|
||||||
|
if (b) { // If high byte is non-zero, we can't handle it ;(
|
||||||
|
#if defined(TINY_GSM_UNICODE_TO_HEX)
|
||||||
|
result += "\\x";
|
||||||
|
result += instr.substring(i, i + 4);
|
||||||
|
#else
|
||||||
|
result += "?";
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
buf[0] = instr[i + 2];
|
||||||
|
buf[1] = instr[i + 3];
|
||||||
|
b = strtol(buf, NULL, 16);
|
||||||
|
result += b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sendUSSDImpl(const String& code) {
|
||||||
|
// Set preferred message format to text mode
|
||||||
|
thisModem().sendAT(GF("+CMGF=1"));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
// Set 8-bit hexadecimal alphabet (3GPP TS 23.038)
|
||||||
|
thisModem().sendAT(GF("+CSCS=\"HEX\""));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
// Send the message
|
||||||
|
thisModem().sendAT(GF("+CUSD=1,\""), code, GF("\""));
|
||||||
|
if (thisModem().waitResponse() != 1) { return ""; }
|
||||||
|
if (thisModem().waitResponse(10000L, GF("+CUSD:")) != 1) { return ""; }
|
||||||
|
thisModem().stream.readStringUntil('"');
|
||||||
|
String hex = thisModem().stream.readStringUntil('"');
|
||||||
|
thisModem().stream.readStringUntil(',');
|
||||||
|
int8_t dcs = thisModem().streamGetIntBefore('\n');
|
||||||
|
|
||||||
|
if (dcs == 15) {
|
||||||
|
return TinyGsmDecodeHex8bit(hex);
|
||||||
|
} else if (dcs == 72) {
|
||||||
|
return TinyGsmDecodeHex16bit(hex);
|
||||||
|
} else {
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sendSMSImpl(const String& number, const String& text) {
|
||||||
|
// Set preferred message format to text mode
|
||||||
|
thisModem().sendAT(GF("+CMGF=1"));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
// Set GSM 7 bit default alphabet (3GPP TS 23.038)
|
||||||
|
thisModem().sendAT(GF("+CSCS=\"GSM\""));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
thisModem().sendAT(GF("+CMGS=\""), number, GF("\""));
|
||||||
|
if (thisModem().waitResponse(GF(">")) != 1) { return false; }
|
||||||
|
thisModem().stream.print(text); // Actually send the message
|
||||||
|
thisModem().stream.write(static_cast<char>(0x1A)); // Terminate the message
|
||||||
|
thisModem().stream.flush();
|
||||||
|
return thisModem().waitResponse(60000L) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common methods for UTF8/UTF16 SMS.
|
||||||
|
// Supported by: BG96, M95, MC60, SIM5360, SIM7000, SIM7600, SIM800
|
||||||
|
class UTF8Print : public Print {
|
||||||
|
public:
|
||||||
|
explicit UTF8Print(Print& p) : p(p) {}
|
||||||
|
size_t write(const uint8_t c) override {
|
||||||
|
if (prv < 0xC0) {
|
||||||
|
if (c < 0xC0) printHex(c);
|
||||||
|
prv = c;
|
||||||
|
} else {
|
||||||
|
uint16_t v = uint16_t(prv) << 8 | c;
|
||||||
|
v -= (v >> 8 == 0xD0) ? 0xCC80 : 0xCD40;
|
||||||
|
printHex(v);
|
||||||
|
prv = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Print& p;
|
||||||
|
uint8_t prv = 0;
|
||||||
|
void printHex(const uint16_t v) {
|
||||||
|
uint8_t c = v >> 8;
|
||||||
|
if (c < 0x10) p.print('0');
|
||||||
|
p.print(c, HEX);
|
||||||
|
c = v & 0xFF;
|
||||||
|
if (c < 0x10) p.print('0');
|
||||||
|
p.print(c, HEX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool sendSMS_UTF8_begin(const char* const number) {
|
||||||
|
thisModem().sendAT(GF("+CMGF=1"));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
thisModem().sendAT(GF("+CSCS=\"HEX\""));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
thisModem().sendAT(GF("+CSMP=17,167,0,8"));
|
||||||
|
thisModem().waitResponse();
|
||||||
|
|
||||||
|
thisModem().sendAT(GF("+CMGS=\""), number, GF("\""));
|
||||||
|
return thisModem().waitResponse(GF(">")) == 1;
|
||||||
|
}
|
||||||
|
bool sendSMS_UTF8_end() {
|
||||||
|
thisModem().stream.write(static_cast<char>(0x1A));
|
||||||
|
thisModem().stream.flush();
|
||||||
|
return thisModem().waitResponse(60000L) == 1;
|
||||||
|
}
|
||||||
|
UTF8Print sendSMS_UTF8_stream() {
|
||||||
|
return UTF8Print(thisModem().stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sendSMS_UTF16Impl(const char* const number, const void* text,
|
||||||
|
size_t len) {
|
||||||
|
if (!sendSMS_UTF8_begin(number)) { return false; }
|
||||||
|
|
||||||
|
uint16_t* t =
|
||||||
|
const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(text));
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint8_t c = t[i] >> 8;
|
||||||
|
if (c < 0x10) { thisModem().stream.print('0'); }
|
||||||
|
thisModem().stream.print(c, HEX);
|
||||||
|
c = t[i] & 0xFF;
|
||||||
|
if (c < 0x10) { thisModem().stream.print('0'); }
|
||||||
|
thisModem().stream.print(c, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendSMS_UTF8_end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMSMS_H_
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmSSL.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMSSL_H_
|
||||||
|
#define SRC_TINYGSMSSL_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
|
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmSSL {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* SSL functions
|
||||||
|
*/
|
||||||
|
bool addCertificate(const char* filename) {
|
||||||
|
return thisModem().addCertificateImpl(filename);
|
||||||
|
}
|
||||||
|
bool deleteCertificate() {
|
||||||
|
return thisModem().deleteCertificateImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
public:
|
||||||
|
class GsmClientSecure : public GsmClient {
|
||||||
|
public:
|
||||||
|
GsmClientSecureSim800() {}
|
||||||
|
|
||||||
|
explicit GsmClientSecureSim800(TinyGsmSim800& modem, uint8_t mux = 0)
|
||||||
|
: GsmClientSim800(modem, mux) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) overide {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
};*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSL functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
bool addCertificateImpl(const char* filename) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
bool deleteCertificateImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMSSL_H_
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmTCP.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMTCP_H_
|
||||||
|
#define SRC_TINYGSMTCP_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_TCP
|
||||||
|
|
||||||
|
#include "TinyGsmFifo.h"
|
||||||
|
|
||||||
|
#if !defined(TINY_GSM_RX_BUFFER)
|
||||||
|
#define TINY_GSM_RX_BUFFER 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Because of the ordering of resolution of overrides in templates, these need
|
||||||
|
// to be written out every time. This macro is to shorten that.
|
||||||
|
#define TINY_GSM_CLIENT_CONNECT_OVERRIDES \
|
||||||
|
int connect(IPAddress ip, uint16_t port, int timeout_s) { \
|
||||||
|
return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); \
|
||||||
|
} \
|
||||||
|
int connect(const char* host, uint16_t port) override { \
|
||||||
|
return connect(host, port, 75); \
|
||||||
|
} \
|
||||||
|
int connect(IPAddress ip, uint16_t port) override { \
|
||||||
|
return connect(ip, port, 75); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// // For modules that do not store incoming data in any sort of buffer
|
||||||
|
// #define TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
// // Data is stored in a buffer, but we can only read from the buffer,
|
||||||
|
// // not check how much data is stored in it
|
||||||
|
// #define TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
// // Data is stored in a buffer and we can both read and check the size
|
||||||
|
// // of the buffer
|
||||||
|
// #define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||||
|
|
||||||
|
template <class modemType, uint8_t muxCount>
|
||||||
|
class TinyGsmTCP {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Basic functions
|
||||||
|
*/
|
||||||
|
void maintain() {
|
||||||
|
return thisModem().maintainImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClient : public Client {
|
||||||
|
// Make all classes created from the modem template friends
|
||||||
|
friend class TinyGsmTCP<modemType, muxCount>;
|
||||||
|
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// bool init(modemType* modem, uint8_t);
|
||||||
|
// int connect(const char* host, uint16_t port, int timeout_s);
|
||||||
|
|
||||||
|
// Connect to a IP address given as an IPAddress object by
|
||||||
|
// converting said IP address to text
|
||||||
|
// virtual int connect(IPAddress ip,uint16_t port, int timeout_s) {
|
||||||
|
// return connect(TinyGsmStringFromIp(ip).c_str(), port,
|
||||||
|
// timeout_s);
|
||||||
|
// }
|
||||||
|
// int connect(const char* host, uint16_t port) override {
|
||||||
|
// return connect(host, port, 75);
|
||||||
|
// }
|
||||||
|
// int connect(IPAddress ip,uint16_t port) override {
|
||||||
|
// return connect(ip, port, 75);
|
||||||
|
// }
|
||||||
|
|
||||||
|
static inline String TinyGsmStringFromIp(IPAddress ip) {
|
||||||
|
String host;
|
||||||
|
host.reserve(16);
|
||||||
|
host += ip[0];
|
||||||
|
host += ".";
|
||||||
|
host += ip[1];
|
||||||
|
host += ".";
|
||||||
|
host += ip[2];
|
||||||
|
host += ".";
|
||||||
|
host += ip[3];
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void stop(uint32_t maxWaitMs);
|
||||||
|
// void stop() override {
|
||||||
|
// stop(15000L);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Writes data out on the client using the modem send functionality
|
||||||
|
size_t write(const uint8_t* buf, size_t size) override {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
at->maintain();
|
||||||
|
return at->modemSend(buf, size, mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(uint8_t c) override {
|
||||||
|
return write(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const char* str) {
|
||||||
|
if (str == NULL) return 0;
|
||||||
|
return write((const uint8_t*)str, strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
int available() override {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
#if defined TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
// Returns the number of characters available in the TinyGSM fifo
|
||||||
|
if (!rx.size() && sock_connected) { at->maintain(); }
|
||||||
|
return rx.size();
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
// Returns the combined number of characters available in the TinyGSM
|
||||||
|
// fifo and the modem chips internal fifo.
|
||||||
|
if (!rx.size()) { at->maintain(); }
|
||||||
|
return rx.size() + sock_available;
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||||
|
// Returns the combined number of characters available in the TinyGSM
|
||||||
|
// fifo and the modem chips internal fifo, doing an extra check-in
|
||||||
|
// with the modem to see if anything has arrived without a UURC.
|
||||||
|
if (!rx.size()) {
|
||||||
|
if (millis() - prev_check > 500) {
|
||||||
|
got_data = true;
|
||||||
|
prev_check = millis();
|
||||||
|
}
|
||||||
|
at->maintain();
|
||||||
|
}
|
||||||
|
return rx.size() + sock_available;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Modem client has been incorrectly created
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int read(uint8_t* buf, size_t size) override {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
size_t cnt = 0;
|
||||||
|
|
||||||
|
#if defined TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
// Reads characters out of the TinyGSM fifo, waiting for any URC's
|
||||||
|
// from the modem for new data if there's nothing in the fifo.
|
||||||
|
uint32_t _startMillis = millis();
|
||||||
|
while (cnt < size && millis() - _startMillis < _timeout) {
|
||||||
|
size_t chunk = TinyGsmMin(size - cnt, rx.size());
|
||||||
|
if (chunk > 0) {
|
||||||
|
rx.get(buf, chunk);
|
||||||
|
buf += chunk;
|
||||||
|
cnt += chunk;
|
||||||
|
continue;
|
||||||
|
} /* TODO: Read directly into user buffer? */
|
||||||
|
if (!rx.size() && sock_connected) { at->maintain(); }
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
// Reads characters out of the TinyGSM fifo, and from the modem chip's
|
||||||
|
// internal fifo if avaiable.
|
||||||
|
at->maintain();
|
||||||
|
while (cnt < size) {
|
||||||
|
size_t chunk = TinyGsmMin(size - cnt, rx.size());
|
||||||
|
if (chunk > 0) {
|
||||||
|
rx.get(buf, chunk);
|
||||||
|
buf += chunk;
|
||||||
|
cnt += chunk;
|
||||||
|
continue;
|
||||||
|
} /* TODO: Read directly into user buffer? */
|
||||||
|
at->maintain();
|
||||||
|
if (sock_available > 0) {
|
||||||
|
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available),
|
||||||
|
mux);
|
||||||
|
if (n == 0) break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||||
|
// Reads characters out of the TinyGSM fifo, and from the modem chips
|
||||||
|
// internal fifo if avaiable, also double checking with the modem if
|
||||||
|
// data has arrived without issuing a UURC.
|
||||||
|
at->maintain();
|
||||||
|
while (cnt < size) {
|
||||||
|
size_t chunk = TinyGsmMin(size - cnt, rx.size());
|
||||||
|
if (chunk > 0) {
|
||||||
|
rx.get(buf, chunk);
|
||||||
|
buf += chunk;
|
||||||
|
cnt += chunk;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Workaround: Some modules "forget" to notify about data arrival
|
||||||
|
if (millis() - prev_check > 500) {
|
||||||
|
got_data = true;
|
||||||
|
prev_check = millis();
|
||||||
|
}
|
||||||
|
// TODO(vshymanskyy): Read directly into user buffer?
|
||||||
|
at->maintain();
|
||||||
|
if (sock_available > 0) {
|
||||||
|
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available),
|
||||||
|
mux);
|
||||||
|
if (n == 0) break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Modem client has been incorrectly created
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int read() override {
|
||||||
|
uint8_t c;
|
||||||
|
if (read(&c, 1) == 1) { return c; }
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(SRGDamia1): Implement peek
|
||||||
|
int peek() override {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush() override {
|
||||||
|
at->stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t connected() override {
|
||||||
|
if (available()) { return true; }
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
operator bool() override {
|
||||||
|
return connected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Read and dump anything remaining in the modem's internal buffer.
|
||||||
|
// Using this in the client stop() function.
|
||||||
|
// The socket will appear open in response to connected() even after it
|
||||||
|
// closes until all data is read from the buffer.
|
||||||
|
// Doing it this way allows the external mcu to find and get all of the
|
||||||
|
// data that it wants from the socket even if it was closed externally.
|
||||||
|
inline void dumpModemBuffer(uint32_t maxWaitMs) {
|
||||||
|
#if defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE || \
|
||||||
|
defined TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) {
|
||||||
|
rx.clear();
|
||||||
|
at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux);
|
||||||
|
}
|
||||||
|
rx.clear();
|
||||||
|
at->streamClear();
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_NO_MODEM_BUFFER
|
||||||
|
rx.clear();
|
||||||
|
at->streamClear();
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Modem client has been incorrectly created
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
modemType* at;
|
||||||
|
uint8_t mux;
|
||||||
|
uint16_t sock_available;
|
||||||
|
uint32_t prev_check;
|
||||||
|
bool sock_connected;
|
||||||
|
bool got_data;
|
||||||
|
RxFifo rx;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
void maintainImpl() {
|
||||||
|
#if defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
|
||||||
|
// Keep listening for modem URC's and proactively iterate through
|
||||||
|
// sockets asking if any data is avaiable
|
||||||
|
for (int mux = 0; mux < muxCount; mux++) {
|
||||||
|
GsmClient* sock = thisModem().sockets[mux];
|
||||||
|
if (sock && sock->got_data) {
|
||||||
|
sock->got_data = false;
|
||||||
|
sock->sock_available = thisModem().modemGetAvailable(mux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (thisModem().stream.available()) {
|
||||||
|
thisModem().waitResponse(15, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined TINY_GSM_NO_MODEM_BUFFER || defined TINY_GSM_BUFFER_READ_NO_CHECK
|
||||||
|
// Just listen for any URC's
|
||||||
|
thisModem().waitResponse(100, NULL, NULL);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Modem client has been incorrectly created
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yields up to a time-out period and then reads a character from the stream
|
||||||
|
// into the mux FIFO
|
||||||
|
// TODO(SRGDamia1): Do we need to wait two _timeout periods for no
|
||||||
|
// character return? Will wait once in the first "while
|
||||||
|
// !stream.available()" and then will wait again in the stream.read()
|
||||||
|
// function.
|
||||||
|
inline void moveCharFromStreamToFifo(uint8_t mux) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
while (!thisModem().stream.available() &&
|
||||||
|
(millis() - startMillis < thisModem().sockets[mux]->_timeout)) {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
}
|
||||||
|
char c = thisModem().stream.read();
|
||||||
|
thisModem().sockets[mux]->rx.put(c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMTCP_H_
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmTemperature.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMTEMPERATURE_H_
|
||||||
|
#define SRC_TINYGSMTEMPERATURE_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_TEMPERATURE
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmTemperature {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Temperature functions
|
||||||
|
*/
|
||||||
|
float getTemperature() {
|
||||||
|
return thisModem().getTemperatureImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMTEMPERATURE_H_
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmTime.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMTIME_H_
|
||||||
|
#define SRC_TINYGSMTIME_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_TIME
|
||||||
|
|
||||||
|
enum TinyGSMDateTimeFormat { DATE_FULL = 0, DATE_TIME = 1, DATE_DATE = 2 };
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmTime {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
String getGSMDateTime(TinyGSMDateTimeFormat format) {
|
||||||
|
return thisModem().getGSMDateTimeImpl(format);
|
||||||
|
}
|
||||||
|
bool getNetworkTime(int* year, int* month, int* day, int* hour, int* minute,
|
||||||
|
int* second, float* timezone) {
|
||||||
|
return thisModem().getNetworkTimeImpl(year, month, day, hour, minute,
|
||||||
|
second, timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
String getGSMDateTimeImpl(TinyGSMDateTimeFormat format) {
|
||||||
|
thisModem().sendAT(GF("+CCLK?"));
|
||||||
|
if (thisModem().waitResponse(2000L, GF("+CCLK: \"")) != 1) { return ""; }
|
||||||
|
|
||||||
|
String res;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case DATE_FULL: res = thisModem().stream.readStringUntil('"'); break;
|
||||||
|
case DATE_TIME:
|
||||||
|
thisModem().streamSkipUntil(',');
|
||||||
|
res = thisModem().stream.readStringUntil('"');
|
||||||
|
break;
|
||||||
|
case DATE_DATE: res = thisModem().stream.readStringUntil(','); break;
|
||||||
|
}
|
||||||
|
thisModem().waitResponse(); // Ends with OK
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getNetworkTimeImpl(int* year, int* month, int* day, int* hour,
|
||||||
|
int* minute, int* second, float* timezone) {
|
||||||
|
thisModem().sendAT(GF("+CCLK?"));
|
||||||
|
if (thisModem().waitResponse(2000L, GF("+CCLK: \"")) != 1) { return false; }
|
||||||
|
|
||||||
|
int iyear = 0;
|
||||||
|
int imonth = 0;
|
||||||
|
int iday = 0;
|
||||||
|
int ihour = 0;
|
||||||
|
int imin = 0;
|
||||||
|
int isec = 0;
|
||||||
|
int itimezone = 0;
|
||||||
|
|
||||||
|
// Date & Time
|
||||||
|
iyear = thisModem().streamGetIntBefore('/');
|
||||||
|
imonth = thisModem().streamGetIntBefore('/');
|
||||||
|
iday = thisModem().streamGetIntBefore(',');
|
||||||
|
ihour = thisModem().streamGetIntBefore(':');
|
||||||
|
imin = thisModem().streamGetIntBefore(':');
|
||||||
|
isec = thisModem().streamGetIntLength(2);
|
||||||
|
char tzSign = thisModem().stream.read();
|
||||||
|
itimezone = thisModem().streamGetIntBefore('\n');
|
||||||
|
if (tzSign == '-') { itimezone = itimezone * -1; }
|
||||||
|
|
||||||
|
// Set pointers
|
||||||
|
if (iyear < 2000) iyear += 2000;
|
||||||
|
if (year != NULL) *year = iyear;
|
||||||
|
if (month != NULL) *month = imonth;
|
||||||
|
if (day != NULL) *day = iday;
|
||||||
|
if (hour != NULL) *hour = ihour;
|
||||||
|
if (minute != NULL) *minute = imin;
|
||||||
|
if (second != NULL) *second = isec;
|
||||||
|
if (timezone != NULL) *timezone = static_cast<float>(itimezone) / 4.0;
|
||||||
|
|
||||||
|
// Final OK
|
||||||
|
thisModem().waitResponse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMTIME_H_
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @file TinyGsmWifi.tpp
|
||||||
|
* @author Volodymyr Shymanskyy
|
||||||
|
* @license LGPL-3.0
|
||||||
|
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
|
||||||
|
* @date Nov 2016
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_TINYGSMWIFI_H_
|
||||||
|
#define SRC_TINYGSMWIFI_H_
|
||||||
|
|
||||||
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
|
#define TINY_GSM_MODEM_HAS_WIFI
|
||||||
|
|
||||||
|
template <class modemType>
|
||||||
|
class TinyGsmWifi {
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* WiFi functions
|
||||||
|
*/
|
||||||
|
bool networkConnect(const char* ssid, const char* pwd) {
|
||||||
|
return thisModem().networkConnectImpl(ssid, pwd);
|
||||||
|
}
|
||||||
|
bool networkDisconnect() {
|
||||||
|
return thisModem().networkDisconnectImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRTP Helper
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
inline const modemType& thisModem() const {
|
||||||
|
return static_cast<const modemType&>(*this);
|
||||||
|
}
|
||||||
|
inline modemType& thisModem() {
|
||||||
|
return static_cast<modemType&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WiFi functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool networkConnectImpl(const char* ssid,
|
||||||
|
const char* pwd) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
bool networkDisconnectImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_TINYGSMWIFI_H_
|
||||||
@@ -45,7 +45,9 @@
|
|||||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||||
// need enough space in the buffer for the entire response
|
// need enough space in the buffer for the entire response
|
||||||
// else data will be lost (and the http library will fail).
|
// else data will be lost (and the http library will fail).
|
||||||
|
#ifndef TINY_GSM_RX_BUFFER
|
||||||
#define TINY_GSM_RX_BUFFER 1024
|
#define TINY_GSM_RX_BUFFER 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
// #define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
@@ -106,7 +108,7 @@ const char resource[] = "/TinyGSM/logo.txt";
|
|||||||
TinyGsm modem(SerialAT);
|
TinyGsm modem(SerialAT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||||
TinyGsmClientSecure client(modem);
|
TinyGsmClientSecure client(modem);
|
||||||
const int port = 443;
|
const int port = 443;
|
||||||
#else
|
#else
|
||||||
@@ -127,7 +129,7 @@ void setup() {
|
|||||||
|
|
||||||
// Set GSM module baud rate
|
// Set GSM module baud rate
|
||||||
// TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
// TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
||||||
SerialAT.begin(115200);
|
SerialAT.begin(9600);
|
||||||
delay(3000);
|
delay(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +238,8 @@ void loop() {
|
|||||||
client.find("\r\n\r\n");
|
client.find("\r\n\r\n");
|
||||||
|
|
||||||
// Read data
|
// Read data
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
unsigned long bytesReceived = 0;
|
uint32_t bytesReceived = 0;
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
char c = client.read();
|
char c = client.read();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ void setup() {
|
|||||||
delay(10);
|
delay(10);
|
||||||
|
|
||||||
// Set GSM module baud rate
|
// Set GSM module baud rate
|
||||||
SerialAT.begin(115200);
|
SerialAT.begin(9600);
|
||||||
delay(3000);
|
delay(3000);
|
||||||
|
|
||||||
if (!modem.init()) {
|
if (!modem.init()) {
|
||||||
|
|||||||
+166
-32
@@ -1,59 +1,78 @@
|
|||||||
/**************************************************************
|
/**************************************************************
|
||||||
*
|
*
|
||||||
* DO NOT USE THIS - this is just a compilation test!
|
* DO NOT USE THIS - this is just a compilation test!
|
||||||
|
* This is NOT an example for use of this library!
|
||||||
*
|
*
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
// #define TINY_GSM_MODEM_SIM800
|
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
|
|
||||||
TinyGsm modem(Serial);
|
TinyGsm modem(Serial);
|
||||||
TinyGsmClient client(modem);
|
|
||||||
|
|
||||||
#if defined(TINY_GSM_MODEM_HAS_SSL)
|
|
||||||
TinyGsmClientSecure client_secure(modem);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char server[] = "somewhere";
|
|
||||||
char resource[] = "something";
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
delay(3000);
|
delay(3000);
|
||||||
modem.restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
// Test the basic functions
|
||||||
// Test the start/restart functions
|
|
||||||
modem.restart();
|
|
||||||
modem.begin();
|
modem.begin();
|
||||||
|
modem.begin("1234");
|
||||||
|
modem.init();
|
||||||
|
modem.init("1234");
|
||||||
|
modem.setBaud(115200);
|
||||||
modem.testAT();
|
modem.testAT();
|
||||||
|
|
||||||
|
modem.getModemInfo();
|
||||||
|
modem.getModemName();
|
||||||
modem.factoryDefault();
|
modem.factoryDefault();
|
||||||
|
|
||||||
// Test the SIM card functions
|
// Test Power functions
|
||||||
|
modem.restart();
|
||||||
|
// modem.sleepEnable(); // Not available for all modems
|
||||||
|
// modem.radioOff(); // Not available for all modems
|
||||||
|
modem.poweroff();
|
||||||
|
|
||||||
|
// Test generic network functions
|
||||||
|
modem.getRegistrationStatus();
|
||||||
|
modem.isNetworkConnected();
|
||||||
|
modem.waitForNetwork();
|
||||||
|
modem.waitForNetwork(15000L);
|
||||||
|
modem.getSignalQuality();
|
||||||
|
modem.getLocalIP();
|
||||||
|
modem.localIP();
|
||||||
|
|
||||||
|
// Test the GPRS and SIM card functions
|
||||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||||
|
modem.simUnlock("1234");
|
||||||
modem.getSimCCID();
|
modem.getSimCCID();
|
||||||
modem.getIMEI();
|
modem.getIMEI();
|
||||||
|
modem.getIMSI();
|
||||||
modem.getSimStatus();
|
modem.getSimStatus();
|
||||||
modem.getRegistrationStatus();
|
|
||||||
|
modem.gprsConnect("myAPN");
|
||||||
|
modem.gprsConnect("myAPN", "myUser");
|
||||||
|
modem.gprsConnect("myAPN", "myAPNUser", "myAPNPass");
|
||||||
|
modem.gprsDisconnect();
|
||||||
modem.getOperator();
|
modem.getOperator();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Test WiFi Functions
|
||||||
// Test the Networking functions
|
|
||||||
modem.getSignalQuality();
|
|
||||||
modem.localIP();
|
|
||||||
|
|
||||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
|
||||||
modem.waitForNetwork();
|
|
||||||
modem.gprsConnect("YourAPN", "", "");
|
|
||||||
#endif
|
|
||||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
||||||
modem.networkConnect("YourSSID", "YourPWD");
|
modem.networkConnect("mySSID", "mySSIDPassword");
|
||||||
modem.waitForNetwork();
|
modem.networkDisconnect();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Test TCP functions
|
||||||
|
modem.maintain();
|
||||||
|
TinyGsmClient client;
|
||||||
|
TinyGsmClient client2(modem);
|
||||||
|
TinyGsmClient client3(modem, 1);
|
||||||
|
client.init(&modem);
|
||||||
|
client.init(&modem, 1);
|
||||||
|
|
||||||
|
char server[] = "somewhere";
|
||||||
|
char resource[] = "something";
|
||||||
|
|
||||||
client.connect(server, 80);
|
client.connect(server, 80);
|
||||||
|
|
||||||
// Make a HTTP GET request:
|
// Make a HTTP GET request:
|
||||||
@@ -61,7 +80,7 @@ void loop() {
|
|||||||
client.print(String("Host: ") + server + "\r\n");
|
client.print(String("Host: ") + server + "\r\n");
|
||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
client.read();
|
client.read();
|
||||||
@@ -71,10 +90,125 @@ void loop() {
|
|||||||
|
|
||||||
client.stop();
|
client.stop();
|
||||||
|
|
||||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
#if defined(TINY_GSM_MODEM_HAS_SSL)
|
||||||
modem.gprsDisconnect();
|
// modem.addCertificate(); // not yet impemented
|
||||||
|
// modem.deleteCertificate(); // not yet impemented
|
||||||
|
TinyGsmClientSecure client_secure(modem);
|
||||||
|
TinyGsmClientSecure client_secure2(modem);
|
||||||
|
TinyGsmClientSecure client_secure3(modem, 1);
|
||||||
|
client_secure.init(&modem);
|
||||||
|
client_secure.init(&modem, 1);
|
||||||
|
|
||||||
|
client_secure.connect(server, 443);
|
||||||
|
|
||||||
|
// Make a HTTP GET request:
|
||||||
|
client_secure.print(String("GET ") + resource + " HTTP/1.0\r\n");
|
||||||
|
client_secure.print(String("Host: ") + server + "\r\n");
|
||||||
|
client_secure.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
timeout = millis();
|
||||||
|
while (client_secure.connected() && millis() - timeout < 10000L) {
|
||||||
|
while (client_secure.available()) {
|
||||||
|
client_secure.read();
|
||||||
|
timeout = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client_secure.stop();
|
||||||
#endif
|
#endif
|
||||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
|
||||||
modem.networkDisconnect();
|
// Test the calling functions
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_CALLING)
|
||||||
|
modem.callNumber(String("+380000000000"));
|
||||||
|
modem.callHangup();
|
||||||
|
|
||||||
|
#if not defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
|
||||||
|
modem.callAnswer();
|
||||||
|
modem.dtmfSend('A', 1000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test the SMS functions
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_SMS)
|
||||||
|
modem.sendSMS(String("+380000000000"), String("Hello from "));
|
||||||
|
|
||||||
|
#if not defined(TINY_GSM_MODEM_XBEE) && not defined(TINY_GSM_MODEM_SARAR4)
|
||||||
|
modem.sendUSSD("*111#");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if not defined(TINY_GSM_MODEM_XBEE) && not defined(TINY_GSM_MODEM_M590) && \
|
||||||
|
not defined(TINY_GSM_MODEM_SARAR4)
|
||||||
|
modem.sendSMS_UTF16("+380000000000", "Hello", 5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test the GSM location functions
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION)
|
||||||
|
modem.getGsmLocationRaw();
|
||||||
|
modem.getGsmLocation();
|
||||||
|
float glatitude = -9999;
|
||||||
|
float glongitude = -9999;
|
||||||
|
float gacc = 0;
|
||||||
|
int gyear = 0;
|
||||||
|
int gmonth = 0;
|
||||||
|
int gday = 0;
|
||||||
|
int ghour = 0;
|
||||||
|
int gmin = 0;
|
||||||
|
int gsec = 0;
|
||||||
|
modem.getGsmLocation(&glatitude, &glongitude);
|
||||||
|
modem.getGsmLocation(&glatitude, &glongitude, &gacc, &gyear, &gmonth, &gday,
|
||||||
|
&ghour, &gmin, &gsec);
|
||||||
|
modem.getGsmLocationTime(&gyear, &gmonth, &gday, &ghour, &gmin, &gsec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test the GPS functions
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_GPS)
|
||||||
|
modem.enableGPS();
|
||||||
|
modem.getGPSraw();
|
||||||
|
float latitude = -9999;
|
||||||
|
float longitude = -9999;
|
||||||
|
float speed = 0;
|
||||||
|
float alt = 0;
|
||||||
|
int vsat = 0;
|
||||||
|
int usat = 0;
|
||||||
|
float acc = 0;
|
||||||
|
int year = 0;
|
||||||
|
int month = 0;
|
||||||
|
int day = 0;
|
||||||
|
int hour = 0;
|
||||||
|
int minute = 0;
|
||||||
|
int second = 0;
|
||||||
|
modem.getGPS(&latitude, &longitude);
|
||||||
|
modem.getGPS(&latitude, &longitude, &speed, &alt, &vsat, &usat, &acc, &year,
|
||||||
|
&month, &day, &hour, &minute, &second);
|
||||||
|
modem.disableGPS();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test the Network time function
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_TIME)
|
||||||
|
modem.getGSMDateTime(DATE_FULL);
|
||||||
|
int year3 = 0;
|
||||||
|
int month3 = 0;
|
||||||
|
int day3 = 0;
|
||||||
|
int hour3 = 0;
|
||||||
|
int min3 = 0;
|
||||||
|
int sec3 = 0;
|
||||||
|
float timezone = 0;
|
||||||
|
modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3, &timezone);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test Battery functions
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_BATTERY)
|
||||||
|
uint8_t chargeState = 0;
|
||||||
|
int8_t chargePercent = 0;
|
||||||
|
uint16_t milliVolts = 0;
|
||||||
|
modem.getBattStats(chargeState, chargePercent, milliVolts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test the temperature function
|
||||||
|
#if defined(TINY_GSM_MODEM_HAS_TEMPERATURE)
|
||||||
|
modem.getTemperature();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user