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 -->
|
||||
Modem: <!-- Brand, model, variant, firmware version -->
|
||||
TinyGSM version: <!-- always try to use the latest (0.9.19) -->
|
||||
TinyGSM version: <!-- always try to use the latest (0.10.0) -->
|
||||
Code: <!-- Example name or paste in your code -->
|
||||
|
||||
### Scenario, steps to reproduce
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
platformio.ini
|
||||
extra_envs.ini
|
||||
lib/readme.txt
|
||||
include/readme.txt
|
||||
.atomrc.cson
|
||||
|
||||
@@ -47,7 +47,7 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
|
||||
- Neoway M590
|
||||
- u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
|
||||
- u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_)
|
||||
- Sequans Monarch LTE Cat M1/NB1
|
||||
- Sequans Monarch LTE Cat M1/NB1 (VZM20Q)
|
||||
- Quectel BG96
|
||||
- Quectel M95
|
||||
- Quectel MC60 ***(alpha)***
|
||||
@@ -83,26 +83,29 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
- SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
|
||||
- Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
|
||||
- Not yet supported on:
|
||||
- Quectel modems, SIM7000, SIM5360/5320/7100/7500/7600
|
||||
- Quectel modems, SIM7000, SIM5360/5320, SIM7100/7500/7600
|
||||
- Not possible on:
|
||||
- SIM900, A6/A7, M560, XBee _WiFi_
|
||||
- SIM900, A6/A7, Neoway M590, XBee _WiFi_
|
||||
|
||||
**USSD**
|
||||
- Sending USSD requests and decoding 7,8,16-bit responses
|
||||
- Supported on:
|
||||
- SIM800/SIM900, SIM7000
|
||||
- Not yet supported on:
|
||||
- Quectel modems, SIM5360/5320/7100/7500/7600, XBee
|
||||
- All SIMCom modems, Quectel modems, most u-blox
|
||||
- Not possible on:
|
||||
- XBee, u-blox SARA R4/N4, ESP8266 (obviously)
|
||||
|
||||
**SMS**
|
||||
- Only _sending_ SMS is supported, not receiving
|
||||
- Supported on:
|
||||
- SIM800/SIM900, SIM7000, XBee
|
||||
- Not yet supported on:
|
||||
- Quectel modems, SIM5360/5320/7100/7500/7600
|
||||
- Supported on all cellular modules
|
||||
|
||||
**Voice Calls**
|
||||
- Only Supported on SIM800 and A6/A7/A20
|
||||
- Supported on:
|
||||
- SIM800/SIM900, A6/A7, Quectel modems, u-blox
|
||||
- Not yet supported on:
|
||||
- SIM7000, SIM5360/5320/7100, SIM7500/7600/7800, VZM20Q (Monarch)
|
||||
- Not possible on:
|
||||
- XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously)
|
||||
- Functions:
|
||||
- Dial, hangup
|
||||
- Receiving calls
|
||||
- Incoming event (RING)
|
||||
@@ -111,9 +114,9 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
|
||||
|
||||
**Location**
|
||||
- GPS/GNSS
|
||||
- SIM808 and SIM7000 only
|
||||
- SIM808, SIM7000, SIM7500/7600/7800 only
|
||||
- GSM location service
|
||||
- SIM800, SIM and SIM7000 only
|
||||
- SIM800, SIM7000, Quectel, u-blox
|
||||
|
||||
**Credits**
|
||||
- Primary Authors/Contributors:
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Allow references to be used to change values
|
||||
filter=-runtime/references
|
||||
filter=-build/namespaces
|
||||
@@ -39,28 +39,33 @@
|
||||
|
||||
// or Software Serial on Uno, Nano
|
||||
//#include <SoftwareSerial.h>
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
// SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
|
||||
// Range to attempt to autobaud
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 38400
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
/*
|
||||
* Tests enabled
|
||||
*/
|
||||
#define TINY_GSM_TEST_GPRS true
|
||||
#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_SMS true
|
||||
#define TINY_GSM_TEST_USSD 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
|
||||
#define TINY_GSM_POWERDOWN false
|
||||
|
||||
@@ -68,30 +73,28 @@
|
||||
#define GSM_PIN ""
|
||||
|
||||
// Set phone numbers, if you want to test SMS and Calls
|
||||
//#define SMS_TARGET "+380xxxxxxxxx"
|
||||
//#define CALL_TARGET "+380xxxxxxxxx"
|
||||
// #define SMS_TARGET "+380xxxxxxxxx"
|
||||
// #define CALL_TARGET "+380xxxxxxxxx"
|
||||
|
||||
// Your GPRS credentials, if any
|
||||
const char apn[] = "YourAPN";
|
||||
const char apn[] = "YourAPN";
|
||||
const char gprsUser[] = "";
|
||||
const char gprsPass[] = "";
|
||||
|
||||
// Your WiFi connection credentials, if applicable
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiSSID[] = "YourSSID";
|
||||
const char wifiPass[] = "YourWiFiPass";
|
||||
|
||||
// Server details to test TCP/SSL
|
||||
const char server[] = "vsh.pp.ua";
|
||||
const char resource[] = "/TinyGSM/logo.txt";
|
||||
|
||||
#include <TinyGsmClient.h>
|
||||
|
||||
#if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
|
||||
#undef TINY_GSM_TEST_GPRS
|
||||
#undef TINY_GSM_TEST_CALL
|
||||
#undef TINY_GSM_TEST_SMS
|
||||
#undef TINY_GSM_TEST_USSD
|
||||
#undef TINY_GSM_TEST_WIFI
|
||||
#define TINY_GSM_TEST_GPRS false
|
||||
#define TINY_GSM_TEST_CALL false
|
||||
#define TINY_GSM_TEST_SMS false
|
||||
#define TINY_GSM_TEST_USSD false
|
||||
#define TINY_GSM_TEST_WIFI true
|
||||
#endif
|
||||
#if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
|
||||
@@ -100,10 +103,6 @@ const char wifiPass[] = "YourWiFiPass";
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
#endif
|
||||
#if TINY_GSM_TEST_GPS && not defined TINY_GSM_MODEM_HAS_GPS
|
||||
#undef TINY_GSM_TEST_GPS
|
||||
#define TINY_GSM_TEST_GPS false
|
||||
#endif
|
||||
|
||||
#ifdef DUMP_AT_COMMANDS
|
||||
#include <StreamDebugger.h>
|
||||
@@ -120,28 +119,28 @@ void setup() {
|
||||
|
||||
// !!!!!!!!!!!
|
||||
// Set your reset, enable, power pins here
|
||||
pinMode(23, OUTPUT);
|
||||
digitalWrite(23, HIGH);
|
||||
// !!!!!!!!!!!
|
||||
|
||||
DBG("Wait...");
|
||||
delay(6000);
|
||||
|
||||
// Set GSM module baud rate
|
||||
TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
||||
//SerialAT.begin(9600);
|
||||
delay(3000);
|
||||
TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
|
||||
// SerialAT.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Restart takes quite some time
|
||||
// To skip it, call init() instead of restart()
|
||||
DBG("Initializing modem...");
|
||||
if (!modem.restart()) {
|
||||
// if (!modem.init()) {
|
||||
// if (!modem.init()) {
|
||||
DBG("Failed to restart modem, delaying 10s and retrying");
|
||||
delay(3000);
|
||||
delay(10000L);
|
||||
// restart autobaud in case GSM just rebooted
|
||||
TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
||||
delay(10000);
|
||||
// TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -153,7 +152,7 @@ void loop() {
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
// Unlock your SIM card with a PIN if needed
|
||||
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
|
||||
if (GSM_PIN && modem.getSimStatus() != 3) {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
#endif
|
||||
@@ -174,7 +173,7 @@ void loop() {
|
||||
#endif
|
||||
|
||||
DBG("Waiting for network...");
|
||||
if (!modem.waitForNetwork()) {
|
||||
if (!modem.waitForNetwork(600000L)) {
|
||||
delay(10000);
|
||||
return;
|
||||
}
|
||||
@@ -199,6 +198,9 @@ void loop() {
|
||||
String imei = modem.getIMEI();
|
||||
DBG("IMEI:", imei);
|
||||
|
||||
String imsi = modem.getIMSI();
|
||||
DBG("IMSI:", imsi);
|
||||
|
||||
String cop = modem.getOperator();
|
||||
DBG("Operator:", cop);
|
||||
|
||||
@@ -207,19 +209,9 @@ void loop() {
|
||||
|
||||
int csq = modem.getSignalQuality();
|
||||
DBG("Signal quality:", csq);
|
||||
|
||||
// This is only supported on SIMxxx series
|
||||
// String gsmLoc = modem.getGsmLocation();
|
||||
// DBG("GSM location:", gsmLoc);
|
||||
|
||||
// This is only supported on SIMxxx series
|
||||
// String gsmTime = modem.getGSMDateTime(DATE_TIME);
|
||||
// DBG("GSM Time:", gsmTime);
|
||||
// String gsmDate = modem.getGSMDateTime(DATE_DATE);
|
||||
// DBG("GSM Date:", gsmDate);
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_USSD
|
||||
#if TINY_GSM_TEST_USSD && defined TINY_GSM_MODEM_HAS_SMS
|
||||
String ussd_balance = modem.sendUSSD("*111#");
|
||||
DBG("Balance (USSD):", ussd_balance);
|
||||
|
||||
@@ -227,23 +219,70 @@ void loop() {
|
||||
DBG("Phone number (USSD):", ussd_phone_num);
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_GPS
|
||||
modem.enableGPS();
|
||||
String gps_raw = modem.getGPSraw();
|
||||
modem.disableGPS();
|
||||
DBG("GPS raw data:", gps_raw);
|
||||
#if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP
|
||||
TinyGsmClient client(modem, 0);
|
||||
const int port = 80;
|
||||
DBG("Connecting to ", server);
|
||||
if (!client.connect(server, port)) {
|
||||
DBG("... failed");
|
||||
} else {
|
||||
// Make a HTTP GET request:
|
||||
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
|
||||
client.print(String("Host: ") + server + "\r\n");
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
|
||||
// Wait for data to arrive
|
||||
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
|
||||
|
||||
#if TINY_GSM_TEST_SMS && defined(SMS_TARGET)
|
||||
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
||||
DBG("SMS:", res ? "OK" : "fail");
|
||||
#if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||
TinyGsmClientSecure secureClient(modem, 1);
|
||||
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
|
||||
res = modem.sendSMS_UTF16(SMS_TARGET, u"Привіііт!", 9);
|
||||
DBG("UTF16 SMS:", res ? "OK" : "fail");
|
||||
// Wait for data to arrive
|
||||
uint32_t startS = millis();
|
||||
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
|
||||
|
||||
#if TINY_GSM_TEST_CALL && defined(CALL_TARGET)
|
||||
#if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
|
||||
defined CALL_TARGET
|
||||
DBG("Calling:", CALL_TARGET);
|
||||
|
||||
// This is NOT supported on M590
|
||||
@@ -257,7 +296,7 @@ void loop() {
|
||||
modem.dtmfSend('A', 1000);
|
||||
|
||||
// Play DTMF 0..4, default duration (100ms)
|
||||
for (char tone='0'; tone<='4'; tone++) {
|
||||
for (char tone = '0'; tone <= '4'; tone++) {
|
||||
modem.dtmfSend(tone);
|
||||
}
|
||||
|
||||
@@ -268,21 +307,120 @@ void loop() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINY_GSM_TEST_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);
|
||||
#if TINY_GSM_TEST_SMS && defined TINY_GSM_MODEM_HAS_SMS && defined SMS_TARGET
|
||||
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
|
||||
DBG("SMS:", res ? "OK" : "fail");
|
||||
|
||||
float temp = modem.getTemperature();
|
||||
DBG("Chip temperature:", temp);
|
||||
// This is only supported on SIMxxx series
|
||||
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
|
||||
|
||||
#if TINY_GSM_TEST_GPRS
|
||||
modem.gprsDisconnect();
|
||||
delay(5000L);
|
||||
if (!modem.isGprsConnected()) {
|
||||
DBG("GPRS disconnected");
|
||||
} else {
|
||||
@@ -295,6 +433,21 @@ void loop() {
|
||||
DBG("WiFi disconnected");
|
||||
#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
|
||||
// Try to power-off (modem may decide to restart automatically)
|
||||
// To turn off modem completely, please use Reset/Enable pins
|
||||
@@ -302,6 +455,8 @@ void loop() {
|
||||
DBG("Poweroff.");
|
||||
#endif
|
||||
|
||||
DBG("End of tests.");
|
||||
|
||||
// Do nothing forevermore
|
||||
while (true) {
|
||||
modem.maintain();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
// Default heartbeat interval for GSM is 60
|
||||
// If you want override this value, uncomment and set this option:
|
||||
//#define BLYNK_HEARTBEAT 30
|
||||
// #define BLYNK_HEARTBEAT 30
|
||||
|
||||
// Select your modem:
|
||||
#define TINY_GSM_MODEM_SIM800
|
||||
|
||||
@@ -49,17 +49,19 @@
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
// need enough space in the buffer for the entire response
|
||||
// else data will be lost (and the http library will fail).
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 1024
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
//#define LOGGING // <- Logging is for the HTTP library
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
@@ -217,7 +219,7 @@ void loop() {
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
|
||||
// Let's see what the entire elapsed time is, from after we send the request.
|
||||
unsigned long timeElapsed = millis();
|
||||
uint32_t timeElapsed = millis();
|
||||
|
||||
SerialMon.println(F("Waiting for response header"));
|
||||
|
||||
@@ -246,7 +248,7 @@ void loop() {
|
||||
// SerialMon.print(c, HEX);
|
||||
// SerialMon.print(' ');
|
||||
// if (isprint(c))
|
||||
// SerialMon.print((char) c);
|
||||
// SerialMon.print(reinterpret_cast<char> c);
|
||||
// else
|
||||
// SerialMon.print('*');
|
||||
// SerialMon.print(' ');
|
||||
@@ -301,7 +303,7 @@ void loop() {
|
||||
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
|
||||
while (client.available()) {
|
||||
uint8_t c = client.read();
|
||||
//SerialMon.print((char)c); // Uncomment this to show data
|
||||
//SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show data
|
||||
crc.update(c);
|
||||
readLength++;
|
||||
if (readLength % (contentLength / 13) == 0) {
|
||||
|
||||
@@ -54,21 +54,23 @@
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
// need enough space in the buffer for the entire response
|
||||
// else data will be lost (and the http library will fail).
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 650
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
//#define LOGGING // <- Logging is for the HTTP library
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Range to attempt to autobaud
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
|
||||
@@ -46,21 +46,23 @@
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
// need enough space in the buffer for the entire response
|
||||
// else data will be lost (and the http library will fail).
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 650
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
//#define LOGGING // <- Logging is for the HTTP library
|
||||
// #define LOGGING // <- Logging is for the HTTP library
|
||||
|
||||
// Range to attempt to autobaud
|
||||
#define GSM_AUTOBAUD_MIN 9600
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
@@ -143,11 +145,6 @@ void setup() {
|
||||
modem.simUnlock(GSM_PIN);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!modem.hasSSL()) {
|
||||
SerialMon.println(F("SSL is not supported by this modem"));
|
||||
while(true) { delay(1000); }
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
@@ -70,7 +70,7 @@
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
@@ -125,7 +125,7 @@ PubSubClient mqtt(client);
|
||||
#define LED_PIN 13
|
||||
int ledStatus = LOW;
|
||||
|
||||
long lastReconnectAttempt = 0;
|
||||
uint32_t lastReconnectAttempt = 0;
|
||||
|
||||
void mqttCallback(char* topic, byte* payload, unsigned int len) {
|
||||
SerialMon.print("Message arrived [");
|
||||
@@ -252,7 +252,7 @@ void loop() {
|
||||
if (!mqtt.connected()) {
|
||||
SerialMon.println("=== MQTT NOT CONNECTED ===");
|
||||
// Reconnect every 10 seconds
|
||||
unsigned long t = millis();
|
||||
uint32_t t = millis();
|
||||
if (t - lastReconnectAttempt > 10000L) {
|
||||
lastReconnectAttempt = t;
|
||||
if (mqttConnect()) {
|
||||
|
||||
@@ -44,10 +44,12 @@
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
// need enough space in the buffer for the entire response
|
||||
// else data will be lost (and the http library will fail).
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 650
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
@@ -57,10 +59,10 @@
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
//#define USE_SSL
|
||||
// #define USE_SSL
|
||||
|
||||
// Define how you're planning to connect to the internet
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
@@ -210,7 +212,7 @@ void loop() {
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
client.println();
|
||||
|
||||
unsigned long timeout = millis();
|
||||
uint32_t timeout = millis();
|
||||
while (client.connected() && millis() - timeout < 10000L) {
|
||||
// Print available data
|
||||
while (client.available()) {
|
||||
|
||||
@@ -12,15 +12,17 @@
|
||||
#define TINY_GSM_MODEM_UBLOX
|
||||
|
||||
// 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>
|
||||
|
||||
// Uncomment this if you want to see all AT commands
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
//#define USE_SSL
|
||||
// #define USE_SSL
|
||||
|
||||
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
||||
#define SerialMon Serial
|
||||
@@ -108,7 +110,7 @@ void loop() {
|
||||
client.print(String("Host: ") + server + "\r\n");
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timeout = millis();
|
||||
uint32_t timeout = millis();
|
||||
while (client.connected() && millis() - timeout < 10000L) {
|
||||
// Print available data
|
||||
while (client.available()) {
|
||||
|
||||
@@ -18,16 +18,18 @@
|
||||
#define TINY_GSM_MODEM_SIM800
|
||||
|
||||
// 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 <ArduinoHttpClient.h>
|
||||
|
||||
// Uncomment this if you want to see all AT commands
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
//#define USE_SSL
|
||||
// #define USE_SSL
|
||||
|
||||
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
||||
#define SerialMon SerialUSB
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define SerialAT Serial1
|
||||
|
||||
// Uncomment this if you want to see all AT commands
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
|
||||
#ifdef DUMP_AT_COMMANDS
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TinyGSM",
|
||||
"version": "0.9.19",
|
||||
"version": "0.10.0",
|
||||
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.",
|
||||
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
|
||||
"authors":
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name=TinyGSM
|
||||
version=0.9.19
|
||||
version=0.10.0
|
||||
author=Volodymyr Shymanskyy
|
||||
maintainer=Volodymyr Shymanskyy
|
||||
sentence=A small Arduino library for GPRS modules, that just works.
|
||||
|
||||
@@ -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_
|
||||
+64
-89
@@ -6,129 +6,104 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClient_h
|
||||
#define TinyGsmClient_h
|
||||
#ifndef SRC_TINYGSMCLIENT_H_
|
||||
#define SRC_TINYGSMCLIENT_H_
|
||||
|
||||
#if defined(TINY_GSM_MODEM_SIM800)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientSIM800.h>
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure;
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
|
||||
typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#define TINY_GSM_MODEM_HAS_GPS
|
||||
#include <TinyGsmClientSIM808.h>
|
||||
typedef TinyGsmSim808 TinyGsm;
|
||||
typedef TinyGsmSim808::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure;
|
||||
#include "TinyGsmClientSIM808.h"
|
||||
typedef TinyGsmSim808 TinyGsm;
|
||||
typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient;
|
||||
typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM900)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientSIM800.h>
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM7000)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_GPS
|
||||
#include <TinyGsmClientSIM7000.h>
|
||||
typedef TinyGsmSim7000 TinyGsm;
|
||||
typedef TinyGsmSim7000::GsmClient TinyGsmClient;
|
||||
// typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO!
|
||||
#include "TinyGsmClientSIM7000.h"
|
||||
typedef TinyGsmSim7000 TinyGsm;
|
||||
typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient;
|
||||
// typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO!
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
|
||||
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientSIM5360.h>
|
||||
typedef TinyGsmSim5360 TinyGsm;
|
||||
typedef TinyGsmSim5360::GsmClient TinyGsmClient;
|
||||
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
|
||||
#include "TinyGsmClientSIM5360.h"
|
||||
typedef TinyGsmSim5360 TinyGsm;
|
||||
typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \
|
||||
defined(TINY_GSM_MODEM_SIM7500)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientSIM7600.h>
|
||||
typedef TinyGsmSim7600 TinyGsm;
|
||||
typedef TinyGsmSim7600::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientSIM7600.h"
|
||||
typedef TinyGsmSim7600 TinyGsm;
|
||||
typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_UBLOX)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientUBLOX.h>
|
||||
typedef TinyGsmUBLOX TinyGsm;
|
||||
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
|
||||
#include "TinyGsmClientUBLOX.h"
|
||||
typedef TinyGsmUBLOX TinyGsm;
|
||||
typedef TinyGsmUBLOX::GsmClientUBLOX TinyGsmClient;
|
||||
typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SARAR4)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientSaraR4.h>
|
||||
typedef TinyGsmSaraR4 TinyGsm;
|
||||
typedef TinyGsmSaraR4::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure;
|
||||
#include "TinyGsmClientSaraR4.h"
|
||||
typedef TinyGsmSaraR4 TinyGsm;
|
||||
typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient;
|
||||
typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_M95)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientM95.h>
|
||||
typedef TinyGsmM95 TinyGsm;
|
||||
typedef TinyGsmM95::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientM95.h"
|
||||
typedef TinyGsmM95 TinyGsm;
|
||||
typedef TinyGsmM95::GsmClientM95 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_BG96)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientBG96.h>
|
||||
typedef TinyGsmBG96 TinyGsm;
|
||||
typedef TinyGsmBG96::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientBG96.h"
|
||||
typedef TinyGsmBG96 TinyGsm;
|
||||
typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientA6.h>
|
||||
typedef TinyGsmA6 TinyGsm;
|
||||
typedef TinyGsmA6::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientA6.h"
|
||||
typedef TinyGsmA6 TinyGsm;
|
||||
typedef TinyGsmA6::GsmClientA6 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_M590)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientM590.h>
|
||||
typedef TinyGsmM590 TinyGsm;
|
||||
typedef TinyGsmM590::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientM590.h"
|
||||
typedef TinyGsmM590 TinyGsm;
|
||||
typedef TinyGsmM590::GsmClientM590 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
|
||||
#include <TinyGsmClientMC60.h>
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_GPS
|
||||
typedef TinyGsmMC60 TinyGsm;
|
||||
typedef TinyGsmMC60::GsmClient TinyGsmClient;
|
||||
#include "TinyGsmClientMC60.h"
|
||||
typedef TinyGsmMC60 TinyGsm;
|
||||
typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_ESP8266)
|
||||
#define TINY_GSM_MODEM_HAS_WIFI
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientESP8266.h>
|
||||
typedef TinyGsmESP8266 TinyGsm;
|
||||
typedef TinyGsmESP8266::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure;
|
||||
#define TINY_GSM_MODEM_HAS_WIFI
|
||||
#include "TinyGsmClientESP8266.h"
|
||||
typedef TinyGsmESP8266 TinyGsm;
|
||||
typedef TinyGsmESP8266::GsmClientESP8266 TinyGsmClient;
|
||||
typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_XBEE)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_WIFI
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientXBee.h>
|
||||
typedef TinyGsmXBee TinyGsm;
|
||||
typedef TinyGsmXBee::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure;
|
||||
#define TINY_GSM_MODEM_HAS_WIFI
|
||||
#include "TinyGsmClientXBee.h"
|
||||
typedef TinyGsmXBee TinyGsm;
|
||||
typedef TinyGsmXBee::GsmClientXBee TinyGsmClient;
|
||||
typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_SSL
|
||||
#include <TinyGsmClientSequansMonarch.h>
|
||||
typedef TinyGsmSequansMonarch TinyGsm;
|
||||
typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure;
|
||||
|
||||
#include "TinyGsmClientSequansMonarch.h"
|
||||
typedef TinyGsmSequansMonarch TinyGsm;
|
||||
typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient;
|
||||
typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch
|
||||
TinyGsmClientSecure;
|
||||
|
||||
#else
|
||||
#error "Please define GSM modem model"
|
||||
#error "Please define GSM modem model"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENT_H_
|
||||
|
||||
+302
-444
@@ -6,31 +6,32 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientA6_h
|
||||
#define TinyGsmClientA6_h
|
||||
//#pragma message("TinyGSM: TinyGsmClientA6")
|
||||
#ifndef SRC_TINYGSMCLIENTA6_H_
|
||||
#define SRC_TINYGSMCLIENTA6_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientA6")
|
||||
|
||||
//#define TINY_GSM_DEBUG Serial
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 256
|
||||
#endif
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 8
|
||||
#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"
|
||||
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;
|
||||
|
||||
enum SimStatus {
|
||||
SIM_ERROR = 0,
|
||||
SIM_READY = 1,
|
||||
SIM_LOCKED = 2,
|
||||
};
|
||||
#if defined TINY_GSM_DEBUG
|
||||
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||
#endif
|
||||
|
||||
enum RegStatus {
|
||||
REG_NO_RESULT = -1,
|
||||
REG_UNREGISTERED = 0,
|
||||
REG_SEARCHING = 2,
|
||||
REG_DENIED = 3,
|
||||
@@ -39,114 +40,104 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmA6
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
friend class TinyGsmA6;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
|
||||
GsmClient(TinyGsmA6& modem) {
|
||||
init(&modem);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmA6* modem) {
|
||||
this->at = modem;
|
||||
this->mux = -1;
|
||||
sock_connected = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
uint8_t newMux = -1;
|
||||
sock_connected = at->modemConnect(host, port, &newMux, timeout_s);
|
||||
if (sock_connected) {
|
||||
mux = newMux;
|
||||
at->sockets[mux] = this;
|
||||
}
|
||||
return sock_connected;
|
||||
}
|
||||
|
||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { 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()
|
||||
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>;
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientA6 : public GsmClient {
|
||||
friend class TinyGsmA6;
|
||||
|
||||
public:
|
||||
GsmClientA6() {}
|
||||
|
||||
explicit GsmClientA6(TinyGsmA6& modem, uint8_t = 0) {
|
||||
init(&modem, -1);
|
||||
}
|
||||
|
||||
bool init(TinyGsmA6* modem, uint8_t = 0) {
|
||||
this->at = modem;
|
||||
this->mux = -1;
|
||||
sock_connected = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
uint8_t newMux = -1;
|
||||
sock_connected = at->modemConnect(host, port, &newMux, timeout_s);
|
||||
if (sock_connected) {
|
||||
mux = newMux;
|
||||
at->sockets[mux] = this;
|
||||
}
|
||||
return sock_connected;
|
||||
}
|
||||
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
void stop() override {
|
||||
stop(1000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
// Doesn't support SSL
|
||||
|
||||
private:
|
||||
TinyGsmA6* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
TinyGsmA6(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmA6(Stream& stream) : stream(stream) {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
virtual ~TinyGsmA6() {}
|
||||
|
||||
/*
|
||||
* Basic functions
|
||||
*/
|
||||
|
||||
bool begin(const char* pin = NULL) {
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool init(const char* pin = NULL) {
|
||||
protected:
|
||||
bool initImpl(const char* pin = NULL) {
|
||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
if (!testAT()) { return false; }
|
||||
|
||||
// sendAT(GF("&FZ")); // Factory + Reset
|
||||
// waitResponse();
|
||||
|
||||
sendAT(GF("E0")); // Echo Off
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
#ifdef TINY_GSM_DEBUG
|
||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||
@@ -154,282 +145,179 @@ public:
|
||||
sendAT(GF("+CMEE=0")); // turn off error codes
|
||||
#endif
|
||||
waitResponse();
|
||||
sendAT(GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination
|
||||
sendAT(
|
||||
GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination
|
||||
waitResponse();
|
||||
|
||||
DBG(GF("### Modem:"), getModemName());
|
||||
|
||||
int ret = getSimStatus();
|
||||
SimStatus ret = getSimStatus();
|
||||
// if the sim isn't ready and a pin has been provided, try to unlock the sim
|
||||
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||
simUnlock(pin);
|
||||
return (getSimStatus() == SIM_READY);
|
||||
}
|
||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
||||
// true
|
||||
else {
|
||||
} else {
|
||||
// if the sim is ready, or it's locked but no pin has been provided,
|
||||
// return true
|
||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
String getModemName() {
|
||||
#if defined(TINY_GSM_MODEM_A6)
|
||||
return "AI-Thinker A6";
|
||||
#elif defined(TINY_GSM_MODEM_A7)
|
||||
return "AI-Thinker A7";
|
||||
#endif
|
||||
return "AI-Thinker A6";
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
||||
|
||||
TINY_GSM_MODEM_TEST_AT()
|
||||
|
||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
|
||||
bool factoryDefault() {
|
||||
bool factoryDefaultImpl() {
|
||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
||||
waitResponse();
|
||||
sendAT(GF("&W")); // Write configuration
|
||||
sendAT(GF("&W")); // Write configuration
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
|
||||
bool hasSSL() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasWifi() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasGPRS() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
|
||||
bool restart() {
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+RST=1"));
|
||||
delay(3000);
|
||||
return init();
|
||||
}
|
||||
|
||||
bool poweroff() {
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+CPOF"));
|
||||
// +CPOF: MS OFF OK
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_CSQ()
|
||||
|
||||
bool isNetworkConnected() {
|
||||
protected:
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
|
||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1)
|
||||
return false;
|
||||
|
||||
// TODO: wait AT+CGATT?
|
||||
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
if (!user) user = "";
|
||||
if (!pwd) pwd = "";
|
||||
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||
if (waitResponse(60000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sendAT(GF("+CGACT=1,1"));
|
||||
waitResponse(60000L);
|
||||
|
||||
sendAT(GF("+CIPMUX=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnect() {
|
||||
// Shut the TCP/IP connection
|
||||
sendAT(GF("+CIPSHUT"));
|
||||
if (waitResponse(60000L) != 1)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i<3; i++) {
|
||||
sendAT(GF("+CGATT=0"));
|
||||
if (waitResponse(5000L) == 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isGprsConnected() {
|
||||
sendAT(GF("+CGATT?"));
|
||||
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
int res = stream.readStringUntil('\n').toInt();
|
||||
waitResponse();
|
||||
return (res == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* IP Address functions
|
||||
*/
|
||||
|
||||
String getLocalIP() {
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+CIFSR"));
|
||||
String res;
|
||||
if (waitResponse(10000L, res) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(10000L, res) != 1) { return ""; }
|
||||
res.replace(GSM_NL "OK" GSM_NL, "");
|
||||
res.replace(GSM_NL, "");
|
||||
res.trim();
|
||||
return res;
|
||||
}
|
||||
|
||||
IPAddress localIP() {
|
||||
return TinyGsmIpFromString(getLocalIP());
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
sendAT(GF("+CGATT=1"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
// TODO(?): wait AT+CGATT?
|
||||
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
waitResponse();
|
||||
|
||||
if (!user) user = "";
|
||||
if (!pwd) pwd = "";
|
||||
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
sendAT(GF("+CGACT=1,1"));
|
||||
waitResponse(60000L);
|
||||
|
||||
sendAT(GF("+CIPMUX=1"));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
// Shut the TCP/IP connection
|
||||
sendAT(GF("+CIPSHUT"));
|
||||
if (waitResponse(60000L) != 1) { return false; }
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
sendAT(GF("+CGATT=0"));
|
||||
if (waitResponse(5000L) == 1) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String getOperatorImpl() {
|
||||
sendAT(GF("+COPS=3,0")); // Set format
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+COPS?"));
|
||||
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
|
||||
streamSkipUntil('"'); // Skip mode and format
|
||||
String res = stream.readStringUntil('"');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
bool callAnswer() {
|
||||
sendAT(GF("A"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Returns true on pick-up, false on error/busy
|
||||
bool callNumber(const String& number) {
|
||||
bool callNumberImpl(const String& number) {
|
||||
if (number == GF("last")) {
|
||||
sendAT(GF("DLST"));
|
||||
} else {
|
||||
sendAT(GF("D\""), number, "\";");
|
||||
}
|
||||
|
||||
if (waitResponse(5000L) != 1) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (waitResponse(60000L,
|
||||
GF(GSM_NL "+CIEV: \"CALL\",1"),
|
||||
GF(GSM_NL "+CIEV: \"CALL\",0"),
|
||||
GFP(GSM_ERROR)) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int8_t rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
||||
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
||||
|
||||
int rsp = waitResponse(60000L,
|
||||
GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
||||
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
||||
|
||||
int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL));
|
||||
int8_t rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL),
|
||||
GF(GSM_NL "NO ANSWER" GSM_NL));
|
||||
|
||||
return rsp == 1 && rsp2 == 0;
|
||||
}
|
||||
|
||||
bool callHangup() {
|
||||
sendAT(GF("H"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
// 0-9,*,#,A,B,C,D
|
||||
bool dtmfSend(char cmd, unsigned duration_ms = 100) {
|
||||
bool dtmfSendImpl(char cmd, uint8_t duration_ms = 100) {
|
||||
duration_ms = constrain(duration_ms, 100, 1000);
|
||||
|
||||
// The duration parameter is not working, so we simulate it using delay..
|
||||
// TODO: Maybe there's another way...
|
||||
// TODO(?): Maybe there's another way...
|
||||
|
||||
//sendAT(GF("+VTD="), duration_ms / 100);
|
||||
//waitResponse();
|
||||
// sendAT(GF("+VTD="), duration_ms / 100);
|
||||
// waitResponse();
|
||||
|
||||
sendAT(GF("+VTS="), cmd);
|
||||
if (waitResponse(10000L) == 1) {
|
||||
@@ -442,7 +330,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* Audio functions
|
||||
*/
|
||||
|
||||
public:
|
||||
bool audioSetHeadphones() {
|
||||
sendAT(GF("+SNFS=0"));
|
||||
return waitResponse() == 1;
|
||||
@@ -461,23 +349,19 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
|
||||
String sendUSSD(const String& code) {
|
||||
protected:
|
||||
String sendUSSDImpl(const String& code) {
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
sendAT(GF("+CSCS=\"HEX\""));
|
||||
waitResponse();
|
||||
sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
stream.readStringUntil('"');
|
||||
if (waitResponse(10000L) != 1) { return ""; }
|
||||
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; }
|
||||
streamSkipUntil('"');
|
||||
String hex = stream.readStringUntil('"');
|
||||
stream.readStringUntil(',');
|
||||
int dcs = stream.readStringUntil('\n').toInt();
|
||||
streamSkipUntil(',');
|
||||
int8_t dcs = streamGetIntBefore('\n');
|
||||
|
||||
if (dcs == 15) {
|
||||
return TinyGsmDecodeHex7bit(hex);
|
||||
@@ -488,96 +372,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
}
|
||||
}
|
||||
|
||||
bool sendSMS(const String& number, const String& text) {
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
||||
if (waitResponse(GF(">")) != 1) {
|
||||
return false;
|
||||
}
|
||||
stream.print(text);
|
||||
stream.write((char)0x1A);
|
||||
stream.flush();
|
||||
return waitResponse(60000L) == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
// Note - the clock probably has to be set manaually first
|
||||
|
||||
/*
|
||||
* Location functions
|
||||
* Battery functions
|
||||
*/
|
||||
protected:
|
||||
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
|
||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
int8_t getBattPercent() {
|
||||
// Needs a '?' after CBC, unlike most
|
||||
int8_t getBattPercentImpl() {
|
||||
sendAT(GF("+CBC?"));
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
streamSkipUntil(','); // Skip battery charge status
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
|
||||
streamSkipUntil(','); // Skip battery charge status
|
||||
// Read battery charge level
|
||||
int res = stream.readStringUntil('\n').toInt();
|
||||
int8_t res = streamGetIntBefore('\n');
|
||||
// Wait for final OK
|
||||
waitResponse();
|
||||
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?"));
|
||||
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('\n').toInt();
|
||||
milliVolts = 0;
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
|
||||
chargeState = streamGetIntBefore(',');
|
||||
percent = streamGetIntBefore('\n');
|
||||
milliVolts = 0;
|
||||
// Wait for final OK
|
||||
waitResponse();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Client related functions
|
||||
*/
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
|
||||
int timeout_s = 75) {
|
||||
uint32_t startMillis = millis();
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
||||
protected:
|
||||
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
|
||||
int8_t newMux = streamGetIntBefore('\n');
|
||||
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, int timeout_s = 75) {
|
||||
unsigned long startMillis = millis();
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
||||
|
||||
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
int newMux = stream.readStringUntil('\n').toInt();
|
||||
|
||||
int rsp = waitResponse((timeout_ms- (millis() - startMillis)),
|
||||
GF("CONNECT OK" GSM_NL),
|
||||
GF("CONNECT FAIL" GSM_NL),
|
||||
GF("ALREADY CONNECT" GSM_NL));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
int8_t rsp = waitResponse(
|
||||
(timeout_ms - (millis() - startMillis)), GF("CONNECT OK" GSM_NL),
|
||||
GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
*mux = newMux;
|
||||
|
||||
return (1 == rsp);
|
||||
@@ -585,37 +434,35 @@ protected:
|
||||
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
||||
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
stream.write((uint8_t*)buff, len);
|
||||
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { return 0; }
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
stream.flush();
|
||||
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { return 0; }
|
||||
return len;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t) {
|
||||
sendAT(GF("+CIPSTATUS")); //TODO mux?
|
||||
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
||||
sendAT(GF("+CIPSTATUS")); // TODO(?) mux?
|
||||
int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
|
||||
GF(",\"CLOSING\""), GF(",\"INITIAL\""));
|
||||
waitResponse();
|
||||
return 1 == res;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
Utilities
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
|
||||
// TODO: Optimize this!
|
||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
public:
|
||||
// TODO(vshymanskyy): Optimize this!
|
||||
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||
#if defined TINY_GSM_DEBUG
|
||||
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||
#else
|
||||
GsmConstStr r3 = NULL,
|
||||
#endif
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
/*String r1s(r1); r1s.trim();
|
||||
String r2s(r2); r2s.trim();
|
||||
String r3s(r3); r3s.trim();
|
||||
@@ -623,15 +470,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
String r5s(r5); r5s.trim();
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
uint8_t index = 0;
|
||||
uint32_t startMillis = millis();
|
||||
do {
|
||||
TINY_GSM_YIELD();
|
||||
while (stream.available() > 0) {
|
||||
TINY_GSM_YIELD();
|
||||
int a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += (char)a;
|
||||
int8_t a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += static_cast<char>(a);
|
||||
if (r1 && data.endsWith(r1)) {
|
||||
index = 1;
|
||||
goto finish;
|
||||
@@ -639,6 +486,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
index = 2;
|
||||
goto finish;
|
||||
} else if (r3 && data.endsWith(r3)) {
|
||||
#if defined TINY_GSM_DEBUG
|
||||
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||
streamSkipUntil('\n'); // Read out the error
|
||||
}
|
||||
#endif
|
||||
index = 3;
|
||||
goto finish;
|
||||
} else if (r4 && data.endsWith(r4)) {
|
||||
@@ -648,23 +500,23 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
index = 5;
|
||||
goto finish;
|
||||
} else if (data.endsWith(GF("+CIPRCV:"))) {
|
||||
int mux = stream.readStringUntil(',').toInt();
|
||||
int len = stream.readStringUntil(',').toInt();
|
||||
int len_orig = len;
|
||||
int8_t mux = streamGetIntBefore(',');
|
||||
int16_t len = streamGetIntBefore(',');
|
||||
int16_t len_orig = len;
|
||||
if (len > sockets[mux]->rx.free()) {
|
||||
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
||||
} else {
|
||||
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
||||
}
|
||||
while (len--) {
|
||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
||||
}
|
||||
if (len_orig > sockets[mux]->available()) { // TODO
|
||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
||||
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||
// TODO(?) Deal with missing characters
|
||||
if (len_orig > sockets[mux]->available()) {
|
||||
DBG("### Fewer characters received than expected: ",
|
||||
sockets[mux]->available(), " vs ", len_orig);
|
||||
}
|
||||
data = "";
|
||||
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
|
||||
int mux = stream.readStringUntil('\n').toInt();
|
||||
int8_t mux = streamGetIntBefore('\n');
|
||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
||||
sockets[mux]->sock_connected = false;
|
||||
}
|
||||
@@ -673,38 +525,44 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
finish:
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
//data.replace(GSM_NL, "/");
|
||||
//DBG('<', index, '>', data);
|
||||
// data.replace(GSM_NL, "/");
|
||||
// DBG('<', index, '>', data);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t waitResponse(uint32_t timeout_ms,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||
#if defined TINY_GSM_DEBUG
|
||||
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||
#else
|
||||
GsmConstStr r3 = NULL,
|
||||
#endif
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
String data;
|
||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||
}
|
||||
|
||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
Stream& stream;
|
||||
|
||||
protected:
|
||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
||||
protected:
|
||||
Stream& stream;
|
||||
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTA6_H_
|
||||
|
||||
+481
-514
File diff suppressed because it is too large
Load Diff
+209
-295
@@ -6,24 +6,24 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientESP8266_h
|
||||
#define TinyGsmClientESP8266_h
|
||||
//#pragma message("TinyGSM: TinyGsmClientESP8266")
|
||||
#ifndef SRC_TINYGSMCLIENTESP8266_H_
|
||||
#define SRC_TINYGSMCLIENTESP8266_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientESP8266")
|
||||
|
||||
//#define TINY_GSM_DEBUG Serial
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 512
|
||||
#endif
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 5
|
||||
#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"
|
||||
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 unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
|
||||
static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120;
|
||||
|
||||
// <stat> status of ESP8266 station interface
|
||||
// 2 : ESP8266 station connected to an AP and has obtained IP
|
||||
@@ -38,271 +38,227 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 6,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmESP8266
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
friend class TinyGsmESP8266;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
|
||||
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
sock_connected = false;
|
||||
|
||||
at->sockets[mux] = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
|
||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { 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()
|
||||
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>;
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientESP8266 : public GsmClient {
|
||||
friend class TinyGsmESP8266;
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
public:
|
||||
GsmClientESP8266() {}
|
||||
|
||||
private:
|
||||
TinyGsmESP8266* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
bool init(TinyGsmESP8266* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
sock_connected = false;
|
||||
|
||||
class GsmClientSecure : public GsmClient
|
||||
{
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
if (mux < TINY_GSM_MUX_COUNT) {
|
||||
this->mux = mux;
|
||||
} else {
|
||||
this->mux = (mux % TINY_GSM_MUX_COUNT);
|
||||
}
|
||||
at->sockets[this->mux] = this;
|
||||
|
||||
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
return true;
|
||||
}
|
||||
|
||||
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, false, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
void stop() override {
|
||||
stop(5000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
public:
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
TinyGsmESP8266(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientSecureESP8266 : public GsmClientESP8266 {
|
||||
public:
|
||||
GsmClientSecureESP8266() {}
|
||||
|
||||
explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 0)
|
||||
: GsmClientESP8266(modem, mux) {}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
virtual ~TinyGsmESP8266() {}
|
||||
|
||||
/*
|
||||
* Basic functions
|
||||
*/
|
||||
|
||||
bool begin(const char* pin = NULL) {
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool init(const char* pin = NULL) {
|
||||
protected:
|
||||
bool initImpl(const char* pin = NULL) {
|
||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!testAT()) { return false; }
|
||||
if (pin && strlen(pin) > 0) {
|
||||
DBG("ESP8266 modules do not use an unlock pin!");
|
||||
}
|
||||
sendAT(GF("E0")); // Echo Off
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
sendAT(GF("E0")); // Echo Off
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
DBG(GF("### Modem:"), getModemName());
|
||||
return true;
|
||||
}
|
||||
|
||||
String getModemName() {
|
||||
String getModemNameImpl() {
|
||||
return "ESP8266";
|
||||
}
|
||||
|
||||
void setBaud(unsigned long baud) {
|
||||
void setBaudImpl(uint32_t baud) {
|
||||
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_TEST_AT()
|
||||
|
||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
|
||||
bool factoryDefault() {
|
||||
bool factoryDefaultImpl() {
|
||||
sendAT(GF("+RESTORE"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
String getModemInfo() {
|
||||
String getModemInfoImpl() {
|
||||
sendAT(GF("+GMR"));
|
||||
String res;
|
||||
if (waitResponse(1000L, res) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(1000L, res) != 1) { return ""; }
|
||||
res.replace(GSM_NL "OK" GSM_NL, "");
|
||||
res.replace(GSM_NL, " ");
|
||||
res.trim();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool hasSSL() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasWifi() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasGPRS() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
|
||||
bool restart() {
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+RST"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
|
||||
delay(500);
|
||||
return init();
|
||||
}
|
||||
|
||||
bool poweroff() {
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* 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?"));
|
||||
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||
int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||
if (res1 != 2) {
|
||||
waitResponse();
|
||||
return 0;
|
||||
}
|
||||
streamSkipUntil(','); // Skip SSID
|
||||
streamSkipUntil(','); // Skip BSSID/MAC address
|
||||
streamSkipUntil(','); // Skip Chanel number
|
||||
int res2 = stream.parseInt(); // Read RSSI
|
||||
waitResponse(); // Returns an OK after the value
|
||||
streamSkipUntil(','); // Skip SSID
|
||||
streamSkipUntil(','); // Skip BSSID/MAC address
|
||||
streamSkipUntil(','); // Skip Chanel number
|
||||
int8_t res2 = stream.parseInt(); // Read RSSI
|
||||
waitResponse(); // Returns an OK after the value
|
||||
return res2;
|
||||
}
|
||||
|
||||
bool isNetworkConnected() {
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
if (s == REG_OK_IP || s == REG_OK_TCP) {
|
||||
// with these, we're definitely connected
|
||||
return true;
|
||||
}
|
||||
else if (s == REG_OK_NO_TCP) {
|
||||
} else if (s == REG_OK_NO_TCP) {
|
||||
// with this, we may or may not be connected
|
||||
if (getLocalIP() == "") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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
|
||||
*/
|
||||
|
||||
bool networkConnect(const char* ssid, const char* pwd) {
|
||||
protected:
|
||||
bool networkConnectImpl(const char* ssid, const char* pwd) {
|
||||
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
|
||||
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
|
||||
return false;
|
||||
@@ -311,86 +267,49 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool networkDisconnect() {
|
||||
bool networkDisconnectImpl() {
|
||||
sendAT(GF("+CWQAP"));
|
||||
bool retVal = waitResponse(10000L) == 1;
|
||||
waitResponse(GF("WIFI DISCONNECT"));
|
||||
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
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 75)
|
||||
{
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
||||
bool ssl = false, int timeout_s = 75) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
if (ssl) {
|
||||
sendAT(GF("+CIPSSLSIZE=4096"));
|
||||
waitResponse();
|
||||
}
|
||||
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
|
||||
GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
|
||||
// TODO: Check mux
|
||||
int rsp = waitResponse(timeout_ms,
|
||||
GFP(GSM_OK),
|
||||
GFP(GSM_ERROR),
|
||||
GF("ALREADY CONNECT"));
|
||||
// if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
|
||||
GF("\",\""), host, GF("\","), port, GF(","),
|
||||
TINY_GSM_TCP_KEEP_ALIVE);
|
||||
// TODO(?): Check mux
|
||||
int8_t rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR),
|
||||
GF("ALREADY CONNECT"));
|
||||
// if (rsp == 3) waitResponse();
|
||||
// May return "ERROR" after the "ALREADY CONNECT"
|
||||
return (1 == rsp);
|
||||
}
|
||||
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
|
||||
if (waitResponse(GF(">")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
stream.write((uint8_t*)buff, len);
|
||||
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
stream.flush();
|
||||
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
|
||||
return len;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t mux) {
|
||||
sendAT(GF("+CIPSTATUS"));
|
||||
if (waitResponse(3000, GF("STATUS:")) != 1) return false;
|
||||
int status =
|
||||
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
|
||||
if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
|
||||
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
|
||||
GF("5"));
|
||||
if (status != 3) {
|
||||
// if the status is anything but 3, there are no connections open
|
||||
waitResponse(); // Returns an OK after the status
|
||||
@@ -401,14 +320,15 @@ protected:
|
||||
}
|
||||
bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR));
|
||||
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK),
|
||||
GFP(GSM_ERROR));
|
||||
if (has_status == 1) {
|
||||
int returned_mux = stream.readStringUntil(',').toInt();
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip type
|
||||
streamSkipUntil(','); // Skip remote IP
|
||||
streamSkipUntil(','); // Skip remote port
|
||||
streamSkipUntil(','); // Skip local port
|
||||
int8_t returned_mux = streamGetIntBefore(',');
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip type
|
||||
streamSkipUntil(','); // Skip remote IP
|
||||
streamSkipUntil(','); // Skip remote port
|
||||
streamSkipUntil(','); // Skip local port
|
||||
streamSkipUntil('\n'); // Skip client/server type
|
||||
verified_connections[returned_mux] = 1;
|
||||
}
|
||||
@@ -420,19 +340,15 @@ protected:
|
||||
return verified_connections[mux];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
Utilities
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
|
||||
// TODO: Optimize this!
|
||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
public:
|
||||
// TODO(vshymanskyy): Optimize this!
|
||||
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
/*String r1s(r1); r1s.trim();
|
||||
String r2s(r2); r2s.trim();
|
||||
String r3s(r3); r3s.trim();
|
||||
@@ -440,15 +356,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
String r5s(r5); r5s.trim();
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
uint8_t index = 0;
|
||||
uint32_t startMillis = millis();
|
||||
do {
|
||||
TINY_GSM_YIELD();
|
||||
while (stream.available() > 0) {
|
||||
TINY_GSM_YIELD();
|
||||
int a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += (char)a;
|
||||
int8_t a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += static_cast<char>(a);
|
||||
if (r1 && data.endsWith(r1)) {
|
||||
index = 1;
|
||||
goto finish;
|
||||
@@ -465,25 +381,27 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
index = 5;
|
||||
goto finish;
|
||||
} else if (data.endsWith(GF("+IPD,"))) {
|
||||
int mux = stream.readStringUntil(',').toInt();
|
||||
int len = stream.readStringUntil(':').toInt();
|
||||
int len_orig = len;
|
||||
int8_t mux = streamGetIntBefore(',');
|
||||
int16_t len = streamGetIntBefore(':');
|
||||
int16_t len_orig = len;
|
||||
if (len > sockets[mux]->rx.free()) {
|
||||
DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available");
|
||||
DBG("### Buffer overflow: ", len, "received vs",
|
||||
sockets[mux]->rx.free(), "available");
|
||||
} else {
|
||||
DBG("### Got Data: ", len, "on", mux);
|
||||
// DBG("### Got Data: ", len, "on", mux);
|
||||
}
|
||||
while (len--) {
|
||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
||||
}
|
||||
if (len_orig > sockets[mux]->available()) { // TODO
|
||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
||||
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||
// TODO(SRGDamia1): deal with buffer overflow/missed characters
|
||||
if (len_orig > sockets[mux]->available()) {
|
||||
DBG("### Fewer characters received than expected: ",
|
||||
sockets[mux]->available(), " vs ", len_orig);
|
||||
}
|
||||
data = "";
|
||||
} else if (data.endsWith(GF("CLOSED"))) {
|
||||
int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
|
||||
int coma = data.indexOf(',', muxStart);
|
||||
int mux = data.substring(muxStart, coma).toInt();
|
||||
int8_t muxStart =
|
||||
TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
|
||||
int8_t coma = data.indexOf(',', muxStart);
|
||||
int8_t mux = data.substring(muxStart, coma).toInt();
|
||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||
sockets[mux]->sock_connected = false;
|
||||
}
|
||||
@@ -492,38 +410,34 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
finish:
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
//data.replace(GSM_NL, "/");
|
||||
//DBG('<', index, '>', data);
|
||||
// data.replace(GSM_NL, "/");
|
||||
// DBG('<', index, '>', data);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t waitResponse(uint32_t timeout_ms,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
String data;
|
||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||
}
|
||||
|
||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||
}
|
||||
|
||||
public:
|
||||
Stream& stream;
|
||||
|
||||
protected:
|
||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
||||
protected:
|
||||
Stream& stream;
|
||||
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTESP8266_H_
|
||||
|
||||
+216
-358
@@ -6,31 +6,30 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientM590_h
|
||||
#define TinyGsmClientM590_h
|
||||
//#pragma message("TinyGSM: TinyGsmClientM590")
|
||||
#ifndef SRC_TINYGSMCLIENTM590_H_
|
||||
#define SRC_TINYGSMCLIENTM590_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientM590")
|
||||
|
||||
//#define TINY_GSM_DEBUG Serial
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 256
|
||||
#endif
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 2
|
||||
#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"
|
||||
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;
|
||||
|
||||
enum SimStatus {
|
||||
SIM_ERROR = 0,
|
||||
SIM_READY = 1,
|
||||
SIM_LOCKED = 2,
|
||||
};
|
||||
#if defined TINY_GSM_DEBUG
|
||||
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||
#endif
|
||||
|
||||
enum RegStatus {
|
||||
REG_NO_RESULT = -1,
|
||||
REG_UNREGISTERED = 0,
|
||||
REG_SEARCHING = 3,
|
||||
REG_DENIED = 2,
|
||||
@@ -39,112 +38,92 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmM590
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
friend class TinyGsmM590;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
|
||||
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
sock_connected = false;
|
||||
|
||||
at->sockets[mux] = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, timeout_s);
|
||||
|
||||
return sock_connected;
|
||||
}
|
||||
|
||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+TCPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { 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()
|
||||
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>;
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
class GsmClientM590 : public GsmClient {
|
||||
friend class TinyGsmM590;
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
public:
|
||||
GsmClientM590() {}
|
||||
|
||||
private:
|
||||
TinyGsmM590* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
bool init(TinyGsmM590* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
sock_connected = false;
|
||||
|
||||
public:
|
||||
if (mux < TINY_GSM_MUX_COUNT) {
|
||||
this->mux = mux;
|
||||
} else {
|
||||
this->mux = (mux % TINY_GSM_MUX_COUNT);
|
||||
}
|
||||
at->sockets[this->mux] = this;
|
||||
|
||||
TinyGsmM590(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
TINY_GSM_CLIENT_CONNECT_OVERRIDES
|
||||
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+TCPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
void stop() override {
|
||||
stop(1000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmM590(Stream& stream) : stream(stream) {
|
||||
memset(sockets, 0, sizeof(sockets));
|
||||
}
|
||||
|
||||
virtual ~TinyGsmM590() {}
|
||||
|
||||
/*
|
||||
* Basic functions
|
||||
*/
|
||||
|
||||
bool begin(const char* pin = NULL) {
|
||||
return init(pin);
|
||||
}
|
||||
|
||||
bool init(const char* pin = NULL) {
|
||||
protected:
|
||||
bool initImpl(const char* pin = NULL) {
|
||||
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
|
||||
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sendAT(GF("&FZ")); // Factory + Reset
|
||||
// waitResponse();
|
||||
if (!testAT()) { return false; }
|
||||
|
||||
sendAT(GF("E0")); // Echo Off
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
#ifdef TINY_GSM_DEBUG
|
||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||
@@ -155,136 +134,90 @@ public:
|
||||
|
||||
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 (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
|
||||
simUnlock(pin);
|
||||
return (getSimStatus() == SIM_READY);
|
||||
}
|
||||
// if the sim is ready, or it's locked but no pin has been provided, return
|
||||
// true
|
||||
else {
|
||||
} else {
|
||||
// if the sim is ready, or it's locked but no pin has been provided,
|
||||
// return true
|
||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
String getModemName() {
|
||||
// Doesn't support CGMI
|
||||
String getModemNameImpl() {
|
||||
return "Neoway M590";
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
||||
|
||||
TINY_GSM_MODEM_TEST_AT()
|
||||
|
||||
TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
|
||||
bool factoryDefault() {
|
||||
// Extra stuff here - pwr save, internal stack
|
||||
bool factoryDefaultImpl() {
|
||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
||||
waitResponse();
|
||||
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
|
||||
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
|
||||
waitResponse();
|
||||
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
|
||||
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
|
||||
waitResponse();
|
||||
sendAT(GF("+XISP=0")); // Use internal stack
|
||||
waitResponse();
|
||||
sendAT(GF("&W")); // Write configuration
|
||||
sendAT(GF("&W")); // Write configuration
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
|
||||
bool hasSSL() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasWifi() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasGPRS() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Power functions
|
||||
*/
|
||||
|
||||
bool restart() {
|
||||
if (!testAT()) {
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
bool restartImpl() {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+CFUN=15"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
//MODEM:STARTUP
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
// MODEM:STARTUP
|
||||
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
|
||||
return init();
|
||||
}
|
||||
|
||||
bool poweroff() {
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+CPWROFF"));
|
||||
return waitResponse(3000L) == 1;
|
||||
}
|
||||
|
||||
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
bool sleepEnable(bool enable = true) {
|
||||
bool sleepEnableImpl(bool enable = true) {
|
||||
sendAT(GF("+ENPWRSAVE="), enable);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_CSQ()
|
||||
|
||||
bool isNetworkConnected() {
|
||||
protected:
|
||||
bool isNetworkConnectedImpl() {
|
||||
RegStatus s = getRegistrationStatus();
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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
|
||||
*/
|
||||
|
||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect();
|
||||
|
||||
sendAT(GF("+XISP=0"));
|
||||
@@ -294,162 +227,80 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
waitResponse();
|
||||
|
||||
if (!user) user = "";
|
||||
if (!pwd) pwd = "";
|
||||
if (!pwd) pwd = "";
|
||||
sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+XIIC=1"));
|
||||
waitResponse();
|
||||
|
||||
const unsigned long timeout_ms = 60000L;
|
||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
||||
const uint32_t timeout_ms = 60000L;
|
||||
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||
if (isGprsConnected()) {
|
||||
//goto set_dns; // TODO
|
||||
// goto set_dns; // TODO
|
||||
return true;
|
||||
}
|
||||
delay(500);
|
||||
}
|
||||
return false;
|
||||
|
||||
// set_dns: // TODO
|
||||
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
|
||||
// waitResponse();
|
||||
//
|
||||
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
|
||||
// waitResponse();
|
||||
// set_dns: // TODO
|
||||
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
|
||||
// waitResponse();
|
||||
//
|
||||
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
|
||||
// waitResponse();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnect() {
|
||||
// TODO: There is no command in AT command set
|
||||
bool gprsDisconnectImpl() {
|
||||
// TODO(?): There is no command in AT command set
|
||||
// XIIC=0 does not work
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isGprsConnected() {
|
||||
bool isGprsConnectedImpl() {
|
||||
sendAT(GF("+XIIC?"));
|
||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
int res = stream.readStringUntil(',').toInt();
|
||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; }
|
||||
int8_t res = streamGetIntBefore(',');
|
||||
waitResponse();
|
||||
return res == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* IP Address functions
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
String getLocalIP() {
|
||||
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;
|
||||
protected:
|
||||
// Able to follow all SIM card functions as inherited from the template
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
|
||||
String sendUSSD(const String& code) {
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
sendAT(GF("+CSCS=\"HEX\""));
|
||||
waitResponse();
|
||||
sendAT(GF("D"), code);
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
stream.readStringUntil('"');
|
||||
String hex = stream.readStringUntil('"');
|
||||
stream.readStringUntil(',');
|
||||
int dcs = stream.readStringUntil('\n').toInt();
|
||||
|
||||
if (waitResponse() != 1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (dcs == 15) {
|
||||
return TinyGsmDecodeHex8bit(hex);
|
||||
} else if (dcs == 72) {
|
||||
return TinyGsmDecodeHex16bit(hex);
|
||||
} else {
|
||||
return hex;
|
||||
}
|
||||
}
|
||||
|
||||
bool sendSMS(const String& number, const String& text) {
|
||||
sendAT(GF("+CSCS=\"GSM\""));
|
||||
waitResponse();
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
||||
if (waitResponse(GF(">")) != 1) {
|
||||
return false;
|
||||
}
|
||||
stream.print(text);
|
||||
stream.write((char)0x1A);
|
||||
stream.flush();
|
||||
return waitResponse(60000L) == 1;
|
||||
}
|
||||
|
||||
bool sendSMS_UTF16(const String& number, const void* text, size_t len)
|
||||
TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
protected:
|
||||
bool sendSMS_UTF16Impl(const String& number, const void* text,
|
||||
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Location functions
|
||||
* Time functions
|
||||
*/
|
||||
|
||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
|
||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* Client related functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
||||
for (int i=0; i<3; i++) { // TODO: no need for loop?
|
||||
protected:
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool,
|
||||
int timeout_s = 75) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
for (int i = 0; i < 3; i++) { // TODO(?): no need for loop?
|
||||
String ip = dnsIpQuery(host);
|
||||
|
||||
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
|
||||
int rsp = waitResponse(timeout_ms,
|
||||
GF(",OK" GSM_NL),
|
||||
GF(",FAIL" GSM_NL),
|
||||
GF("+TCPSETUP:Error" GSM_NL));
|
||||
int8_t rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL),
|
||||
GF(",FAIL" GSM_NL),
|
||||
GF("+TCPSETUP:Error" GSM_NL));
|
||||
if (1 == rsp) {
|
||||
return true;
|
||||
} else if (3 == rsp) {
|
||||
@@ -463,50 +314,46 @@ protected:
|
||||
|
||||
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
|
||||
sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len);
|
||||
if (waitResponse(GF(">")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
stream.write((uint8_t*)buff, len);
|
||||
stream.write((char)0x0D);
|
||||
if (waitResponse(GF(">")) != 1) { return 0; }
|
||||
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||
stream.write(static_cast<char>(0x0D));
|
||||
stream.flush();
|
||||
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
stream.readStringUntil('\n');
|
||||
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; }
|
||||
streamSkipUntil('\n');
|
||||
return len;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t 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();
|
||||
return 1 == res;
|
||||
}
|
||||
|
||||
String dnsIpQuery(const char* host) {
|
||||
sendAT(GF("+DNS=\""), host, GF("\""));
|
||||
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse(GF("+DNS:OK" GSM_NL));
|
||||
res.trim();
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
Utilities
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
|
||||
// TODO: Optimize this!
|
||||
uint8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
public:
|
||||
// TODO(vshymanskyy): Optimize this!
|
||||
int8_t waitResponse(uint32_t timeout_ms, String& data,
|
||||
GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||
#if defined TINY_GSM_DEBUG
|
||||
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||
#else
|
||||
GsmConstStr r3 = NULL,
|
||||
#endif
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
/*String r1s(r1); r1s.trim();
|
||||
String r2s(r2); r2s.trim();
|
||||
String r3s(r3); r3s.trim();
|
||||
@@ -514,15 +361,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
String r5s(r5); r5s.trim();
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
uint8_t index = 0;
|
||||
uint32_t startMillis = millis();
|
||||
do {
|
||||
TINY_GSM_YIELD();
|
||||
while (stream.available() > 0) {
|
||||
TINY_GSM_YIELD();
|
||||
int a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += (char)a;
|
||||
int8_t a = stream.read();
|
||||
if (a <= 0) continue; // Skip 0x00 bytes, just in case
|
||||
data += static_cast<char>(a);
|
||||
if (r1 && data.endsWith(r1)) {
|
||||
index = 1;
|
||||
goto finish;
|
||||
@@ -530,6 +377,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
index = 2;
|
||||
goto finish;
|
||||
} else if (r3 && data.endsWith(r3)) {
|
||||
#if defined TINY_GSM_DEBUG
|
||||
if (r3 == GFP(GSM_CME_ERROR)) {
|
||||
streamSkipUntil('\n'); // Read out the error
|
||||
}
|
||||
#endif
|
||||
index = 3;
|
||||
goto finish;
|
||||
} else if (r4 && data.endsWith(r4)) {
|
||||
@@ -539,24 +391,24 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
index = 5;
|
||||
goto finish;
|
||||
} else if (data.endsWith(GF("+TCPRECV:"))) {
|
||||
int mux = stream.readStringUntil(',').toInt();
|
||||
int len = stream.readStringUntil(',').toInt();
|
||||
int len_orig = len;
|
||||
int8_t mux = streamGetIntBefore(',');
|
||||
int16_t len = streamGetIntBefore(',');
|
||||
int16_t len_orig = len;
|
||||
if (len > sockets[mux]->rx.free()) {
|
||||
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
|
||||
} else {
|
||||
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
|
||||
}
|
||||
while (len--) {
|
||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
||||
}
|
||||
if (len_orig > sockets[mux]->available()) { // TODO
|
||||
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
|
||||
while (len--) { moveCharFromStreamToFifo(mux); }
|
||||
// TODO(?): Handle lost characters
|
||||
if (len_orig > sockets[mux]->available()) {
|
||||
DBG("### Fewer characters received than expected: ",
|
||||
sockets[mux]->available(), " vs ", len_orig);
|
||||
}
|
||||
data = "";
|
||||
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
|
||||
int mux = stream.readStringUntil(',').toInt();
|
||||
stream.readStringUntil('\n');
|
||||
int8_t mux = streamGetIntBefore(',');
|
||||
streamSkipUntil('\n');
|
||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
|
||||
sockets[mux]->sock_connected = false;
|
||||
}
|
||||
@@ -565,38 +417,44 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
}
|
||||
}
|
||||
} while (millis() - startMillis < timeout_ms);
|
||||
finish:
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
//data.replace(GSM_NL, "/");
|
||||
//DBG('<', index, '>', data);
|
||||
// data.replace(GSM_NL, "/");
|
||||
// DBG('<', index, '>', data);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t waitResponse(uint32_t timeout_ms,
|
||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||
#if defined TINY_GSM_DEBUG
|
||||
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||
#else
|
||||
GsmConstStr r3 = NULL,
|
||||
#endif
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
String data;
|
||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
|
||||
}
|
||||
|
||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
||||
{
|
||||
int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
Stream& stream;
|
||||
|
||||
protected:
|
||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
||||
protected:
|
||||
Stream& stream;
|
||||
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTM590_H_
|
||||
|
||||
+309
-500
File diff suppressed because it is too large
Load Diff
+332
-529
File diff suppressed because it is too large
Load Diff
+338
-508
File diff suppressed because it is too large
Load Diff
+413
-682
File diff suppressed because it is too large
Load Diff
+436
-512
File diff suppressed because it is too large
Load Diff
+372
-652
File diff suppressed because it is too large
Load Diff
+86
-106
@@ -6,58 +6,42 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientSIM808_h
|
||||
#define TinyGsmClientSIM808_h
|
||||
//#pragma message("TinyGSM: TinyGsmClientSIM808")
|
||||
#ifndef SRC_TINYGSMCLIENTSIM808_H_
|
||||
#define SRC_TINYGSMCLIENTSIM808_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientSIM808")
|
||||
|
||||
#include <TinyGsmClientSIM800.h>
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
#include "TinyGsmGPS.tpp"
|
||||
|
||||
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
|
||||
friend class TinyGsmGPS<TinyGsmSim808>;
|
||||
|
||||
class TinyGsmSim808: public TinyGsmSim800
|
||||
{
|
||||
public:
|
||||
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
|
||||
|
||||
public:
|
||||
|
||||
TinyGsmSim808(Stream& stream)
|
||||
: TinyGsmSim800(stream)
|
||||
{}
|
||||
|
||||
virtual ~TinyGsmSim808(){}
|
||||
|
||||
/*
|
||||
* GPS location functions
|
||||
* GPS/GNSS/GLONASS location functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
// enable GPS
|
||||
bool enableGPS() {
|
||||
// uint16_t state;
|
||||
|
||||
bool enableGPSImpl() {
|
||||
sendAT(GF("+CGNSPWR=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disableGPS() {
|
||||
// uint16_t state;
|
||||
|
||||
bool disableGPSImpl() {
|
||||
sendAT(GF("+CGNSPWR=0"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the RAW GPS output
|
||||
// works only with ans SIM808 V2
|
||||
String getGPSraw() {
|
||||
String getGPSrawImpl() {
|
||||
sendAT(GF("+CGNSINF"));
|
||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
res.trim();
|
||||
@@ -66,87 +50,83 @@ public:
|
||||
|
||||
// get GPS informations
|
||||
// works only with ans SIM808 V2
|
||||
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
|
||||
//String buffer = "";
|
||||
// char chr_buffer[12];
|
||||
bool fix = false;
|
||||
|
||||
bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
|
||||
int* vsat = 0, int* usat = 0, float* accuracy = 0,
|
||||
int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
|
||||
int* minute = 0, int* second = 0) {
|
||||
sendAT(GF("+CGNSINF"));
|
||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||
|
||||
stream.readStringUntil(','); // mode
|
||||
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true;
|
||||
stream.readStringUntil(','); //utctime
|
||||
*lat = stream.readStringUntil(',').toFloat(); //lat
|
||||
*lon = stream.readStringUntil(',').toFloat(); //lon
|
||||
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon
|
||||
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
stream.readStringUntil(',');
|
||||
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
|
||||
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites
|
||||
stream.readStringUntil('\n');
|
||||
streamSkipUntil(','); // GNSS run status
|
||||
if (streamGetIntBefore(',') == 1) { // fix status
|
||||
// init variables
|
||||
float ilat = 0;
|
||||
float ilon = 0;
|
||||
float ispeed = 0;
|
||||
float ialt = 0;
|
||||
int ivsat = 0;
|
||||
int iusat = 0;
|
||||
float iaccuracy = 0;
|
||||
int iyear = 0;
|
||||
int imonth = 0;
|
||||
int iday = 0;
|
||||
int ihour = 0;
|
||||
int imin = 0;
|
||||
float secondWithSS = 0;
|
||||
|
||||
waitResponse();
|
||||
// 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
|
||||
|
||||
return fix;
|
||||
}
|
||||
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
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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);
|
||||
|
||||
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) {
|
||||
waitResponse();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
streamSkipUntil('\n'); // toss the row of commas
|
||||
waitResponse();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTSIM808_H_
|
||||
|
||||
+492
-481
File diff suppressed because it is too large
Load Diff
+325
-430
File diff suppressed because it is too large
Load Diff
+480
-430
File diff suppressed because it is too large
Load Diff
+597
-548
File diff suppressed because it is too large
Load Diff
+60
-603
@@ -6,105 +6,104 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmCommon_h
|
||||
#define TinyGsmCommon_h
|
||||
#ifndef SRC_TINYGSMCOMMON_H_
|
||||
#define SRC_TINYGSMCOMMON_H_
|
||||
|
||||
// The current library version number
|
||||
#define TINYGSM_VERSION "0.9.19"
|
||||
#define TINYGSM_VERSION "0.10.0"
|
||||
|
||||
#if defined(SPARK) || defined(PARTICLE)
|
||||
#include "Particle.h"
|
||||
#include "Particle.h"
|
||||
#elif defined(ARDUINO)
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_DASH)
|
||||
#include <ArduinoCompat/Client.h>
|
||||
#include <ArduinoCompat/Client.h>
|
||||
#else
|
||||
#include <Client.h>
|
||||
#include <Client.h>
|
||||
#endif
|
||||
|
||||
#include <TinyGsmFifo.h>
|
||||
|
||||
#ifndef TINY_GSM_YIELD_MS
|
||||
#define TINY_GSM_YIELD_MS 0
|
||||
#define TINY_GSM_YIELD_MS 0
|
||||
#endif
|
||||
|
||||
#ifndef TINY_GSM_YIELD
|
||||
#define TINY_GSM_YIELD() { delay(TINY_GSM_YIELD_MS); }
|
||||
#define TINY_GSM_YIELD() \
|
||||
{ delay(TINY_GSM_YIELD_MS); }
|
||||
#endif
|
||||
|
||||
#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type")))
|
||||
#define TINY_GSM_ATTR_NOT_AVAILABLE \
|
||||
__attribute__((error("Not available on this modem type")))
|
||||
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define TINY_GSM_PROGMEM PROGMEM
|
||||
typedef const __FlashStringHelper* GsmConstStr;
|
||||
#define GFP(x) (reinterpret_cast<GsmConstStr>(x))
|
||||
#define GF(x) F(x)
|
||||
#define TINY_GSM_PROGMEM PROGMEM
|
||||
typedef const __FlashStringHelper* GsmConstStr;
|
||||
#define GFP(x) (reinterpret_cast<GsmConstStr>(x))
|
||||
#define GF(x) F(x)
|
||||
#else
|
||||
#define TINY_GSM_PROGMEM
|
||||
typedef const char* GsmConstStr;
|
||||
#define GFP(x) x
|
||||
#define GF(x) x
|
||||
#define TINY_GSM_PROGMEM
|
||||
typedef const char* GsmConstStr;
|
||||
#define GFP(x) x
|
||||
#define GF(x) x
|
||||
#endif
|
||||
|
||||
#ifdef TINY_GSM_DEBUG
|
||||
namespace {
|
||||
template<typename T>
|
||||
static void DBG_PLAIN(T last) {
|
||||
TINY_GSM_DEBUG.println(last);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
static void DBG_PLAIN(T head, Args... tail) {
|
||||
TINY_GSM_DEBUG.print(head);
|
||||
TINY_GSM_DEBUG.print(' ');
|
||||
DBG_PLAIN(tail...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static void DBG(Args... args) {
|
||||
TINY_GSM_DEBUG.print(GF("["));
|
||||
TINY_GSM_DEBUG.print(millis());
|
||||
TINY_GSM_DEBUG.print(GF("] "));
|
||||
DBG_PLAIN(args...);
|
||||
}
|
||||
template <typename T>
|
||||
static void DBG_PLAIN(T last) {
|
||||
TINY_GSM_DEBUG.println(last);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static void DBG_PLAIN(T head, Args... tail) {
|
||||
TINY_GSM_DEBUG.print(head);
|
||||
TINY_GSM_DEBUG.print(' ');
|
||||
DBG_PLAIN(tail...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static void DBG(Args... args) {
|
||||
TINY_GSM_DEBUG.print(GF("["));
|
||||
TINY_GSM_DEBUG.print(millis());
|
||||
TINY_GSM_DEBUG.print(GF("] "));
|
||||
DBG_PLAIN(args...);
|
||||
}
|
||||
} // namespace
|
||||
#else
|
||||
#define DBG_PLAIN(...)
|
||||
#define DBG(...)
|
||||
#define DBG_PLAIN(...)
|
||||
#define DBG(...)
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
const T& TinyGsmMin(const T& a, const T& b)
|
||||
{
|
||||
return (b < a) ? b : a;
|
||||
template <class T>
|
||||
const T& TinyGsmMin(const T& a, const T& b) {
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T& TinyGsmMax(const T& a, const T& b)
|
||||
{
|
||||
return (b < a) ? a : b;
|
||||
template <class T>
|
||||
const T& TinyGsmMax(const T& a, const T& b) {
|
||||
return (b < a) ? a : b;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200)
|
||||
{
|
||||
static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 };
|
||||
template <class T>
|
||||
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600,
|
||||
uint32_t maximum = 115200) {
|
||||
static uint32_t rates[] = {115200, 57600, 38400, 19200, 9600, 74400, 74880,
|
||||
230400, 460800, 2400, 4800, 14400, 28800};
|
||||
|
||||
for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) {
|
||||
for (uint8_t i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
|
||||
uint32_t rate = rates[i];
|
||||
if (rate < minimum || rate > maximum) continue;
|
||||
|
||||
DBG("Trying baud rate", rate, "...");
|
||||
SerialAT.begin(rate);
|
||||
delay(10);
|
||||
for (int i=0; i<10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
SerialAT.print("AT\r\n");
|
||||
String input = SerialAT.readString();
|
||||
if (input.indexOf("OK") >= 0) {
|
||||
@@ -113,550 +112,8 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum
|
||||
}
|
||||
}
|
||||
}
|
||||
SerialAT.begin(minimum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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; \
|
||||
}
|
||||
|
||||
|
||||
// Asks for International Mobile Subscriber Identity IMSI via the AT+CIMI command
|
||||
#define TINY_GSM_MODEM_GET_IMSI_CIMI() \
|
||||
String getIMSI() { \
|
||||
sendAT(GF("+CIMI")); \
|
||||
if (waitResponse(GF(GSM_NL)) != 1) { \
|
||||
return ""; \
|
||||
} \
|
||||
String res = stream.readStringUntil('\n'); \
|
||||
waitResponse(); \
|
||||
res.trim(); \
|
||||
return res; \
|
||||
}
|
||||
|
||||
|
||||
// Gets the modem's registration status via CREG/CGREG/CEREG
|
||||
// CREG = Generic network registration
|
||||
// CGREG = GPRS service registration
|
||||
// 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
|
||||
#endif // SRC_TINYGSMCOMMON_H_
|
||||
|
||||
@@ -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,10 +45,12 @@
|
||||
// Chips without internal buffering (A6/A7, ESP8266, M590)
|
||||
// need enough space in the buffer for the entire response
|
||||
// else data will be lost (and the http library will fail).
|
||||
#ifndef TINY_GSM_RX_BUFFER
|
||||
#define TINY_GSM_RX_BUFFER 1024
|
||||
#endif
|
||||
|
||||
// See all AT commands, if wanted
|
||||
//#define DUMP_AT_COMMANDS
|
||||
// #define DUMP_AT_COMMANDS
|
||||
|
||||
// Define the serial console for debug prints, if needed
|
||||
#define TINY_GSM_DEBUG SerialMon
|
||||
@@ -58,10 +60,10 @@
|
||||
#define GSM_AUTOBAUD_MAX 115200
|
||||
|
||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||
//#define TINY_GSM_YIELD() { delay(2); }
|
||||
// #define TINY_GSM_YIELD() { delay(2); }
|
||||
|
||||
// Uncomment this if you want to use SSL
|
||||
//#define USE_SSL
|
||||
// #define USE_SSL
|
||||
|
||||
#define TINY_GSM_USE_GPRS true
|
||||
#define TINY_GSM_USE_WIFI false
|
||||
@@ -106,7 +108,7 @@ const char resource[] = "/TinyGSM/logo.txt";
|
||||
TinyGsm modem(SerialAT);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
#ifdef USE_SSL && defined TINY_GSM_MODEM_HAS_SSL
|
||||
TinyGsmClientSecure client(modem);
|
||||
const int port = 443;
|
||||
#else
|
||||
@@ -127,7 +129,7 @@ void setup() {
|
||||
|
||||
// Set GSM module baud rate
|
||||
// TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
|
||||
SerialAT.begin(115200);
|
||||
SerialAT.begin(9600);
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
@@ -236,8 +238,8 @@ void loop() {
|
||||
client.find("\r\n\r\n");
|
||||
|
||||
// Read data
|
||||
unsigned long timeout = millis();
|
||||
unsigned long bytesReceived = 0;
|
||||
uint32_t timeout = millis();
|
||||
uint32_t bytesReceived = 0;
|
||||
while (client.connected() && millis() - timeout < 10000L) {
|
||||
while (client.available()) {
|
||||
char c = client.read();
|
||||
|
||||
@@ -48,7 +48,7 @@ void setup() {
|
||||
delay(10);
|
||||
|
||||
// Set GSM module baud rate
|
||||
SerialAT.begin(115200);
|
||||
SerialAT.begin(9600);
|
||||
delay(3000);
|
||||
|
||||
if (!modem.init()) {
|
||||
|
||||
+173
-39
@@ -1,58 +1,77 @@
|
||||
/**************************************************************
|
||||
*
|
||||
* 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>
|
||||
|
||||
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() {
|
||||
Serial.begin(115200);
|
||||
delay(3000);
|
||||
modem.restart();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Test the start/restart functions
|
||||
modem.restart();
|
||||
// Test the basic functions
|
||||
modem.begin();
|
||||
modem.begin("1234");
|
||||
modem.init();
|
||||
modem.init("1234");
|
||||
modem.setBaud(115200);
|
||||
modem.testAT();
|
||||
|
||||
modem.getModemInfo();
|
||||
modem.getModemName();
|
||||
modem.factoryDefault();
|
||||
|
||||
// Test the SIM card functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||
modem.getSimCCID();
|
||||
modem.getIMEI();
|
||||
modem.getSimStatus();
|
||||
// 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.getOperator();
|
||||
#endif
|
||||
|
||||
|
||||
// Test the Networking functions
|
||||
modem.isNetworkConnected();
|
||||
modem.waitForNetwork();
|
||||
modem.waitForNetwork(15000L);
|
||||
modem.getSignalQuality();
|
||||
modem.getLocalIP();
|
||||
modem.localIP();
|
||||
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||
modem.waitForNetwork();
|
||||
modem.gprsConnect("YourAPN", "", "");
|
||||
#endif
|
||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
||||
modem.networkConnect("YourSSID", "YourPWD");
|
||||
modem.waitForNetwork();
|
||||
#endif
|
||||
// Test the GPRS and SIM card functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||
modem.simUnlock("1234");
|
||||
modem.getSimCCID();
|
||||
modem.getIMEI();
|
||||
modem.getIMSI();
|
||||
modem.getSimStatus();
|
||||
|
||||
modem.gprsConnect("myAPN");
|
||||
modem.gprsConnect("myAPN", "myUser");
|
||||
modem.gprsConnect("myAPN", "myAPNUser", "myAPNPass");
|
||||
modem.gprsDisconnect();
|
||||
modem.getOperator();
|
||||
#endif
|
||||
|
||||
// Test WiFi Functions
|
||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
||||
modem.networkConnect("mySSID", "mySSIDPassword");
|
||||
modem.networkDisconnect();
|
||||
#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);
|
||||
|
||||
@@ -61,7 +80,7 @@ void loop() {
|
||||
client.print(String("Host: ") + server + "\r\n");
|
||||
client.print("Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timeout = millis();
|
||||
uint32_t timeout = millis();
|
||||
while (client.connected() && millis() - timeout < 10000L) {
|
||||
while (client.available()) {
|
||||
client.read();
|
||||
@@ -71,10 +90,125 @@ void loop() {
|
||||
|
||||
client.stop();
|
||||
|
||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||
modem.gprsDisconnect();
|
||||
#endif
|
||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
||||
modem.networkDisconnect();
|
||||
#endif
|
||||
#if defined(TINY_GSM_MODEM_HAS_SSL)
|
||||
// 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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user