Merge pull request #365 from EnviroDIY/master

CRTP
This commit is contained in:
Sara Damiano
2020-03-02 08:33:12 -05:00
committed by GitHub
49 changed files with 7959 additions and 7799 deletions

112
.clang-format Normal file
View File

@@ -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
---

View File

@@ -22,7 +22,7 @@ with your board before submitting any issues.
Main processor board: <!-- Uno, Zero, ESP32, Particle, etc --> Main processor board: <!-- Uno, Zero, ESP32, Particle, etc -->
Modem: <!-- Brand, model, variant, firmware version --> Modem: <!-- Brand, model, variant, firmware version -->
TinyGSM version: <!-- always try to use the latest (0.9.17) --> TinyGSM version: <!-- always try to use the latest (0.10.0) -->
Code: <!-- Example name or paste in your code --> Code: <!-- Example name or paste in your code -->
### Scenario, steps to reproduce ### Scenario, steps to reproduce

1
.gitignore vendored
View File

@@ -20,6 +20,7 @@
.clang_complete .clang_complete
.gcc-flags.json .gcc-flags.json
platformio.ini platformio.ini
extra_envs.ini
lib/readme.txt lib/readme.txt
include/readme.txt include/readme.txt
.atomrc.cson .atomrc.cson

View File

@@ -47,7 +47,7 @@ TinyGSM also pulls data gently from the modem (whenever possible), so it can ope
- Neoway M590 - Neoway M590
- u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx) - u-blox 2G, 3G, 4G, and LTE Cat1 Cellular Modems (many modules including LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
- u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_) - u-blox LTE-M Modems (SARA-R4xx, SARA-N4xx, _but NOT SARA-N2xx_)
- Sequans Monarch LTE Cat M1/NB1 - Sequans Monarch LTE Cat M1/NB1 (VZM20Q)
- Quectel BG96 - Quectel BG96
- Quectel M95 - Quectel M95
- Quectel MC60 ***(alpha)*** - Quectel MC60 ***(alpha)***
@@ -83,26 +83,29 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
- SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch - SIM800, u-Blox, XBee _cellular_, ESP8266, and Sequans Monarch
- Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.) - Note: only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
- Not yet supported on: - Not yet supported on:
- Quectel modems, SIM7000, SIM5360/5320/7100/7500/7600 - Quectel modems, SIM7000, SIM5360/5320, SIM7100/7500/7600
- Not possible on: - Not possible on:
- SIM900, A6/A7, M560, XBee _WiFi_ - SIM900, A6/A7, Neoway M590, XBee _WiFi_
**USSD** **USSD**
- Sending USSD requests and decoding 7,8,16-bit responses - Sending USSD requests and decoding 7,8,16-bit responses
- Supported on: - Supported on:
- SIM800/SIM900, SIM7000 - All SIMCom modems, Quectel modems, most u-blox
- Not yet supported on: - Not possible on:
- Quectel modems, SIM5360/5320/7100/7500/7600, XBee - XBee, u-blox SARA R4/N4, ESP8266 (obviously)
**SMS** **SMS**
- Only _sending_ SMS is supported, not receiving - Only _sending_ SMS is supported, not receiving
- Supported on: - Supported on all cellular modules
- SIM800/SIM900, SIM7000, XBee
- Not yet supported on:
- Quectel modems, SIM5360/5320/7100/7500/7600
**Voice Calls** **Voice Calls**
- Only Supported on SIM800 and A6/A7/A20 - Supported on:
- SIM800/SIM900, A6/A7, Quectel modems, u-blox
- Not yet supported on:
- SIM7000, SIM5360/5320/7100, SIM7500/7600/7800, VZM20Q (Monarch)
- Not possible on:
- XBee (any type), u-blox SARA R4/N4, Neoway M590, ESP8266 (obviously)
- Functions:
- Dial, hangup - Dial, hangup
- Receiving calls - Receiving calls
- Incoming event (RING) - Incoming event (RING)
@@ -111,9 +114,9 @@ Watch this repo for new updates! And of course, contributions are welcome ;)
**Location** **Location**
- GPS/GNSS - GPS/GNSS
- SIM808 and SIM7000 only - SIM808, SIM7000, SIM7500/7600/7800 only
- GSM location service - GSM location service
- SIM800, SIM and SIM7000 only - SIM800, SIM7000, Quectel, u-blox
**Credits** **Credits**
- Primary Authors/Contributors: - Primary Authors/Contributors:

3
cpplint.cfg Normal file
View File

@@ -0,0 +1,3 @@
# Allow references to be used to change values
filter=-runtime/references
filter=-build/namespaces

View File

@@ -49,18 +49,23 @@
// Range to attempt to autobaud // Range to attempt to autobaud
#define GSM_AUTOBAUD_MIN 9600 #define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 38400 #define GSM_AUTOBAUD_MAX 115200
/* /*
* Tests enabled * Tests enabled
*/ */
#define TINY_GSM_TEST_GPRS true #define TINY_GSM_TEST_GPRS true
#define TINY_GSM_TEST_WIFI false #define TINY_GSM_TEST_WIFI false
#define TINY_GSM_TEST_TCP true
#define TINY_GSM_TEST_SSL true
#define TINY_GSM_TEST_CALL true #define TINY_GSM_TEST_CALL true
#define TINY_GSM_TEST_SMS true #define TINY_GSM_TEST_SMS true
#define TINY_GSM_TEST_USSD true #define TINY_GSM_TEST_USSD true
#define TINY_GSM_TEST_BATTERY true #define TINY_GSM_TEST_BATTERY true
#define TINY_GSM_TEST_GPS false #define TINY_GSM_TEST_TEMPERATURE true
#define TINY_GSM_TEST_GSM_LOCATION true
#define TINY_GSM_TEST_TIME true
#define TINY_GSM_TEST_GPS true
// powerdown modem after tests // powerdown modem after tests
#define TINY_GSM_POWERDOWN false #define TINY_GSM_POWERDOWN false
@@ -80,18 +85,16 @@ const char gprsPass[] = "";
const char wifiSSID[] = "YourSSID"; const char wifiSSID[] = "YourSSID";
const char wifiPass[] = "YourWiFiPass"; const char wifiPass[] = "YourWiFiPass";
// Server details to test TCP/SSL
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
#include <TinyGsmClient.h> #include <TinyGsmClient.h>
#if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS #if TINY_GSM_TEST_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
#undef TINY_GSM_TEST_GPRS #undef TINY_GSM_TEST_GPRS
#undef TINY_GSM_TEST_CALL
#undef TINY_GSM_TEST_SMS
#undef TINY_GSM_TEST_USSD
#undef TINY_GSM_TEST_WIFI #undef TINY_GSM_TEST_WIFI
#define TINY_GSM_TEST_GPRS false #define TINY_GSM_TEST_GPRS false
#define TINY_GSM_TEST_CALL false
#define TINY_GSM_TEST_SMS false
#define TINY_GSM_TEST_USSD false
#define TINY_GSM_TEST_WIFI true #define TINY_GSM_TEST_WIFI true
#endif #endif
#if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI #if TINY_GSM_TEST_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
@@ -100,10 +103,6 @@ const char wifiPass[] = "YourWiFiPass";
#define TINY_GSM_USE_GPRS true #define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false #define TINY_GSM_USE_WIFI false
#endif #endif
#if TINY_GSM_TEST_GPS && not defined TINY_GSM_MODEM_HAS_GPS
#undef TINY_GSM_TEST_GPS
#define TINY_GSM_TEST_GPS false
#endif
#ifdef DUMP_AT_COMMANDS #ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h> #include <StreamDebugger.h>
@@ -120,28 +119,28 @@ void setup() {
// !!!!!!!!!!! // !!!!!!!!!!!
// Set your reset, enable, power pins here // Set your reset, enable, power pins here
pinMode(23, OUTPUT);
digitalWrite(23, HIGH);
// !!!!!!!!!!! // !!!!!!!!!!!
DBG("Wait..."); DBG("Wait...");
delay(6000);
// Set GSM module baud rate // Set GSM module baud rate
TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX); TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
// SerialAT.begin(9600); // SerialAT.begin(9600);
delay(3000);
} }
void loop() { void loop() {
// Restart takes quite some time // Restart takes quite some time
// To skip it, call init() instead of restart() // To skip it, call init() instead of restart()
DBG("Initializing modem..."); DBG("Initializing modem...");
if (!modem.restart()) { if (!modem.restart()) {
// if (!modem.init()) { // if (!modem.init()) {
DBG("Failed to restart modem, delaying 10s and retrying"); DBG("Failed to restart modem, delaying 10s and retrying");
delay(3000); delay(10000L);
// restart autobaud in case GSM just rebooted // restart autobaud in case GSM just rebooted
TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); // TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
delay(10000);
return; return;
} }
@@ -174,7 +173,7 @@ void loop() {
#endif #endif
DBG("Waiting for network..."); DBG("Waiting for network...");
if (!modem.waitForNetwork()) { if (!modem.waitForNetwork(600000L)) {
delay(10000); delay(10000);
return; return;
} }
@@ -199,6 +198,9 @@ void loop() {
String imei = modem.getIMEI(); String imei = modem.getIMEI();
DBG("IMEI:", imei); DBG("IMEI:", imei);
String imsi = modem.getIMSI();
DBG("IMSI:", imsi);
String cop = modem.getOperator(); String cop = modem.getOperator();
DBG("Operator:", cop); DBG("Operator:", cop);
@@ -207,19 +209,9 @@ void loop() {
int csq = modem.getSignalQuality(); int csq = modem.getSignalQuality();
DBG("Signal quality:", csq); DBG("Signal quality:", csq);
// This is only supported on SIMxxx series
// String gsmLoc = modem.getGsmLocation();
// DBG("GSM location:", gsmLoc);
// This is only supported on SIMxxx series
// String gsmTime = modem.getGSMDateTime(DATE_TIME);
// DBG("GSM Time:", gsmTime);
// String gsmDate = modem.getGSMDateTime(DATE_DATE);
// DBG("GSM Date:", gsmDate);
#endif #endif
#if TINY_GSM_TEST_USSD #if TINY_GSM_TEST_USSD && defined TINY_GSM_MODEM_HAS_SMS
String ussd_balance = modem.sendUSSD("*111#"); String ussd_balance = modem.sendUSSD("*111#");
DBG("Balance (USSD):", ussd_balance); DBG("Balance (USSD):", ussd_balance);
@@ -227,23 +219,70 @@ void loop() {
DBG("Phone number (USSD):", ussd_phone_num); DBG("Phone number (USSD):", ussd_phone_num);
#endif #endif
#if TINY_GSM_TEST_GPS #if TINY_GSM_TEST_TCP && defined TINY_GSM_MODEM_HAS_TCP
modem.enableGPS(); TinyGsmClient client(modem, 0);
String gps_raw = modem.getGPSraw(); const int port = 80;
modem.disableGPS(); DBG("Connecting to ", server);
DBG("GPS raw data:", gps_raw); if (!client.connect(server, port)) {
DBG("... failed");
} else {
// Make a HTTP GET request:
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
// Wait for data to arrive
uint32_t start = millis();
while (client.connected() && !client.available() &&
millis() - start < 30000L) {
delay(100);
};
// Read data
start = millis();
while (client.connected() && millis() - start < 5000L) {
while (client.available()) {
SerialMon.write(client.read());
start = millis();
}
}
client.stop();
}
#endif #endif
#if TINY_GSM_TEST_SMS && defined(SMS_TARGET) #if TINY_GSM_TEST_SSL && defined TINY_GSM_MODEM_HAS_SSL
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei); TinyGsmClientSecure secureClient(modem, 1);
DBG("SMS:", res ? "OK" : "fail"); const int securePort = 443;
DBG("Connecting to ", server);
if (!secureClient.connect(server, securePort)) {
DBG("... failed");
} else {
// Make a HTTP GET request:
secureClient.print(String("GET ") + resource + " HTTP/1.0\r\n");
secureClient.print(String("Host: ") + server + "\r\n");
secureClient.print("Connection: close\r\n\r\n");
// This is only supported on SIMxxx series // Wait for data to arrive
res = modem.sendSMS_UTF16(SMS_TARGET, u"Привіііт!", 9); uint32_t startS = millis();
DBG("UTF16 SMS:", res ? "OK" : "fail"); while (secureClient.connected() && !secureClient.available() &&
millis() - startS < 30000L) {
delay(100);
};
// Read data
startS = millis();
while (secureClient.connected() && millis() - startS < 5000L) {
while (secureClient.available()) {
SerialMon.write(secureClient.read());
startS = millis();
}
}
secureClient.stop();
}
#endif #endif
#if TINY_GSM_TEST_CALL && defined(CALL_TARGET) #if TINY_GSM_TEST_CALL && defined TINY_GSM_MODEM_HAS_CALLING && \
defined CALL_TARGET
DBG("Calling:", CALL_TARGET); DBG("Calling:", CALL_TARGET);
// This is NOT supported on M590 // This is NOT supported on M590
@@ -268,21 +307,120 @@ void loop() {
} }
#endif #endif
#if TINY_GSM_TEST_BATTERY #if TINY_GSM_TEST_SMS && defined TINY_GSM_MODEM_HAS_SMS && defined SMS_TARGET
uint8_t chargeState = -99; res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
int8_t percent = -99; DBG("SMS:", res ? "OK" : "fail");
uint16_t milliVolts = -9999;
modem.getBattStats(chargeState, percent, milliVolts);
DBG("Battery charge state:", chargeState);
DBG("Battery charge 'percent':", percent);
DBG("Battery voltage:", milliVolts / 1000.0F);
float temp = modem.getTemperature(); // This is only supported on SIMxxx series
DBG("Chip temperature:", temp); res = modem.sendSMS_UTF8_begin(SMS_TARGET);
if (res) {
auto stream = modem.sendSMS_UTF8_stream();
stream.print(F("Привіііт! Print number: "));
stream.print(595);
res = modem.sendSMS_UTF8_end();
}
DBG("UTF8 SMS:", res ? "OK" : "fail");
#endif
#if TINY_GSM_TEST_GSM_LOCATION && defined TINY_GSM_MODEM_HAS_GSM_LOCATION
float lat = 0;
float lon = 0;
float accuracy = 0;
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int min = 0;
int sec = 0;
for (int8_t i = 15; i; i--) {
DBG("Requesting current GSM location");
if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
&min, &sec)) {
DBG("Latitude:", String(lat, 8), "\tLongitude:", String(lon, 8));
DBG("Accuracy:", accuracy);
DBG("Year:", year, "\tMonth:", month, "\tDay:", day);
DBG("Hour:", hour, "\tMinute:", min, "\tSecond:", sec);
break;
} else {
DBG("Couldn't get GSM location, retrying in 15s.");
delay(15000L);
}
}
DBG("Retrieving GSM location again as a string");
String location = modem.getGsmLocation();
DBG("GSM Based Location String:", location);
#endif
#if TINY_GSM_TEST_GPS && defined TINY_GSM_MODEM_HAS_GPS
DBG("Enabling GPS/GNSS/GLONASS and waiting 15s for warm-up");
modem.enableGPS();
delay(15000L);
float lat2 = 0;
float lon2 = 0;
float speed2 = 0;
float alt2 = 0;
int vsat2 = 0;
int usat2 = 0;
float accuracy2 = 0;
int year2 = 0;
int month2 = 0;
int day2 = 0;
int hour2 = 0;
int min2 = 0;
int sec2 = 0;
for (int8_t i = 15; i; i--) {
DBG("Requesting current GPS/GNSS/GLONASS location");
if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2, &accuracy2,
&year2, &month2, &day2, &hour2, &min2, &sec2)) {
DBG("Latitude:", String(lat2, 8), "\tLongitude:", String(lon2, 8));
DBG("Speed:", speed2, "\tAltitude:", alt2);
DBG("Visible Satellites:", vsat2, "\tUsed Satellites:", usat2);
DBG("Accuracy:", accuracy2);
DBG("Year:", year2, "\tMonth:", month2, "\tDay:", day2);
DBG("Hour:", hour2, "\tMinute:", min2, "\tSecond:", sec2);
break;
} else {
DBG("Couldn't get GPS/GNSS/GLONASS location, retrying in 15s.");
delay(15000L);
}
}
DBG("Retrieving GPS/GNSS/GLONASS location again as a string");
String gps_raw = modem.getGPSraw();
DBG("GPS/GNSS Based Location String:", gps_raw);
DBG("Disabling GPS");
modem.disableGPS();
#endif
#if TINY_GSM_TEST_TIME && defined TINY_GSM_MODEM_HAS_TIME
int year3 = 0;
int month3 = 0;
int day3 = 0;
int hour3 = 0;
int min3 = 0;
int sec3 = 0;
float timezone = 0;
for (int8_t i = 5; i; i--) {
DBG("Requesting current network time");
if (modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3,
&timezone)) {
DBG("Year:", year3, "\tMonth:", month3, "\tDay:", day3);
DBG("Hour:", hour3, "\tMinute:", min3, "\tSecond:", sec3);
DBG("Timezone:", timezone);
break;
} else {
DBG("Couldn't get network time, retrying in 15s.");
delay(15000L);
}
}
DBG("Retrieving time again as a string");
String time = modem.getGSMDateTime(DATE_FULL);
DBG("Current Network Time:", time);
#endif #endif
#if TINY_GSM_TEST_GPRS #if TINY_GSM_TEST_GPRS
modem.gprsDisconnect(); modem.gprsDisconnect();
delay(5000L);
if (!modem.isGprsConnected()) { if (!modem.isGprsConnected()) {
DBG("GPRS disconnected"); DBG("GPRS disconnected");
} else { } else {
@@ -295,6 +433,21 @@ void loop() {
DBG("WiFi disconnected"); DBG("WiFi disconnected");
#endif #endif
#if TINY_GSM_TEST_BATTERY && defined TINY_GSM_MODEM_HAS_BATTERY
uint8_t chargeState = -99;
int8_t percent = -99;
uint16_t milliVolts = -9999;
modem.getBattStats(chargeState, percent, milliVolts);
DBG("Battery charge state:", chargeState);
DBG("Battery charge 'percent':", percent);
DBG("Battery voltage:", milliVolts / 1000.0F);
#endif
#if TINY_GSM_TEST_TEMPERATURE && defined TINY_GSM_MODEM_HAS_TEMPERATURE
float temp = modem.getTemperature();
DBG("Chip temperature:", temp);
#endif
#if TINY_GSM_POWERDOWN #if TINY_GSM_POWERDOWN
// Try to power-off (modem may decide to restart automatically) // Try to power-off (modem may decide to restart automatically)
// To turn off modem completely, please use Reset/Enable pins // To turn off modem completely, please use Reset/Enable pins
@@ -302,6 +455,8 @@ void loop() {
DBG("Poweroff."); DBG("Poweroff.");
#endif #endif
DBG("End of tests.");
// Do nothing forevermore // Do nothing forevermore
while (true) { while (true) {
modem.maintain(); modem.maintain();

View File

@@ -49,7 +49,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 1024 #define TINY_GSM_RX_BUFFER 1024
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS
@@ -217,7 +219,7 @@ void loop() {
client.print("Connection: close\r\n\r\n"); client.print("Connection: close\r\n\r\n");
// Let's see what the entire elapsed time is, from after we send the request. // Let's see what the entire elapsed time is, from after we send the request.
unsigned long timeElapsed = millis(); uint32_t timeElapsed = millis();
SerialMon.println(F("Waiting for response header")); SerialMon.println(F("Waiting for response header"));
@@ -246,7 +248,7 @@ void loop() {
// SerialMon.print(c, HEX); // SerialMon.print(c, HEX);
// SerialMon.print(' '); // SerialMon.print(' ');
// if (isprint(c)) // if (isprint(c))
// SerialMon.print((char) c); // SerialMon.print(reinterpret_cast<char> c);
// else // else
// SerialMon.print('*'); // SerialMon.print('*');
// SerialMon.print(' '); // SerialMon.print(' ');
@@ -301,7 +303,7 @@ void loop() {
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) { while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
while (client.available()) { while (client.available()) {
uint8_t c = client.read(); uint8_t c = client.read();
//SerialMon.print((char)c); // Uncomment this to show data //SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show data
crc.update(c); crc.update(c);
readLength++; readLength++;
if (readLength % (contentLength / 13) == 0) { if (readLength % (contentLength / 13) == 0) {

View File

@@ -54,7 +54,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 650 #define TINY_GSM_RX_BUFFER 650
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS

View File

@@ -46,7 +46,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 650 #define TINY_GSM_RX_BUFFER 650
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS
@@ -143,11 +145,6 @@ void setup() {
modem.simUnlock(GSM_PIN); modem.simUnlock(GSM_PIN);
} }
#endif #endif
if (!modem.hasSSL()) {
SerialMon.println(F("SSL is not supported by this modem"));
while(true) { delay(1000); }
}
} }
void loop() { void loop() {

View File

@@ -125,7 +125,7 @@ PubSubClient mqtt(client);
#define LED_PIN 13 #define LED_PIN 13
int ledStatus = LOW; int ledStatus = LOW;
long lastReconnectAttempt = 0; uint32_t lastReconnectAttempt = 0;
void mqttCallback(char* topic, byte* payload, unsigned int len) { void mqttCallback(char* topic, byte* payload, unsigned int len) {
SerialMon.print("Message arrived ["); SerialMon.print("Message arrived [");
@@ -252,7 +252,7 @@ void loop() {
if (!mqtt.connected()) { if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ==="); SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds // Reconnect every 10 seconds
unsigned long t = millis(); uint32_t t = millis();
if (t - lastReconnectAttempt > 10000L) { if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t; lastReconnectAttempt = t;
if (mqttConnect()) { if (mqttConnect()) {

View File

@@ -44,7 +44,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 650 #define TINY_GSM_RX_BUFFER 650
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS
@@ -210,7 +212,7 @@ void loop() {
client.print("Connection: close\r\n\r\n"); client.print("Connection: close\r\n\r\n");
client.println(); client.println();
unsigned long timeout = millis(); uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) { while (client.connected() && millis() - timeout < 10000L) {
// Print available data // Print available data
while (client.available()) { while (client.available()) {

View File

@@ -12,7 +12,9 @@
#define TINY_GSM_MODEM_UBLOX #define TINY_GSM_MODEM_UBLOX
// Increase RX buffer if needed // Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512 #if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 512
#endif
#include <TinyGsmClient.h> #include <TinyGsmClient.h>
@@ -108,7 +110,7 @@ void loop() {
client.print(String("Host: ") + server + "\r\n"); client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n"); client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis(); uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) { while (client.connected() && millis() - timeout < 10000L) {
// Print available data // Print available data
while (client.available()) { while (client.available()) {

View File

@@ -18,7 +18,9 @@
#define TINY_GSM_MODEM_SIM800 #define TINY_GSM_MODEM_SIM800
// Increase RX buffer if needed // Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512 #if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 512
#endif
#include <TinyGsmClient.h> #include <TinyGsmClient.h>
#include <ArduinoHttpClient.h> #include <ArduinoHttpClient.h>

View File

@@ -1,6 +1,6 @@
{ {
"name": "TinyGSM", "name": "TinyGSM",
"version": "0.9.17", "version": "0.10.0",
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.", "description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports many GSM, LTE, and WiFi modules with AT command interfaces.",
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M", "keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM7000, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968, M95, MC60, MC60E, BG96, ublox, Quectel, SIMCOM, AI Thinker, LTE, LTE-M",
"authors": "authors":

View File

@@ -1,5 +1,5 @@
name=TinyGSM name=TinyGSM
version=0.9.17 version=0.10.0
author=Volodymyr Shymanskyy author=Volodymyr Shymanskyy
maintainer=Volodymyr Shymanskyy maintainer=Volodymyr Shymanskyy
sentence=A small Arduino library for GPRS modules, that just works. sentence=A small Arduino library for GPRS modules, that just works.

98
src/TinyGsmBattery.tpp Normal file
View File

@@ -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_

90
src/TinyGsmCalling.tpp Normal file
View File

@@ -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_

View File

@@ -6,129 +6,104 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClient_h #ifndef SRC_TINYGSMCLIENT_H_
#define TinyGsmClient_h #define SRC_TINYGSMCLIENT_H_
#if defined(TINY_GSM_MODEM_SIM800) #if defined(TINY_GSM_MODEM_SIM800)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM800.h"
#define TINY_GSM_MODEM_HAS_SSL
#include <TinyGsmClientSIM800.h>
typedef TinyGsmSim800 TinyGsm; typedef TinyGsmSim800 TinyGsm;
typedef TinyGsmSim800::GsmClient TinyGsmClient; typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) #elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM808.h"
#define TINY_GSM_MODEM_HAS_SSL
#define TINY_GSM_MODEM_HAS_GPS
#include <TinyGsmClientSIM808.h>
typedef TinyGsmSim808 TinyGsm; typedef TinyGsmSim808 TinyGsm;
typedef TinyGsmSim808::GsmClient TinyGsmClient; typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient;
typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SIM900) #elif defined(TINY_GSM_MODEM_SIM900)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM800.h"
#include <TinyGsmClientSIM800.h>
typedef TinyGsmSim800 TinyGsm; typedef TinyGsmSim800 TinyGsm;
typedef TinyGsmSim800::GsmClient TinyGsmClient; typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_SIM7000) #elif defined(TINY_GSM_MODEM_SIM7000)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM7000.h"
#define TINY_GSM_MODEM_HAS_GPS
#include <TinyGsmClientSIM7000.h>
typedef TinyGsmSim7000 TinyGsm; typedef TinyGsmSim7000 TinyGsm;
typedef TinyGsmSim7000::GsmClient TinyGsmClient; typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient;
// typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO! // typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO!
#elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \
defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM5360.h"
#include <TinyGsmClientSIM5360.h>
typedef TinyGsmSim5360 TinyGsm; typedef TinyGsmSim5360 TinyGsm;
typedef TinyGsmSim5360::GsmClient TinyGsmClient; typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \ #elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \
defined(TINY_GSM_MODEM_SIM7500) defined(TINY_GSM_MODEM_SIM7500)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSIM7600.h"
#include <TinyGsmClientSIM7600.h>
typedef TinyGsmSim7600 TinyGsm; typedef TinyGsmSim7600 TinyGsm;
typedef TinyGsmSim7600::GsmClient TinyGsmClient; typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_UBLOX) #elif defined(TINY_GSM_MODEM_UBLOX)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientUBLOX.h"
#define TINY_GSM_MODEM_HAS_SSL
#include <TinyGsmClientUBLOX.h>
typedef TinyGsmUBLOX TinyGsm; typedef TinyGsmUBLOX TinyGsm;
typedef TinyGsmUBLOX::GsmClient TinyGsmClient; typedef TinyGsmUBLOX::GsmClientUBLOX TinyGsmClient;
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SARAR4) #elif defined(TINY_GSM_MODEM_SARAR4)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSaraR4.h"
#define TINY_GSM_MODEM_HAS_SSL
#include <TinyGsmClientSaraR4.h>
typedef TinyGsmSaraR4 TinyGsm; typedef TinyGsmSaraR4 TinyGsm;
typedef TinyGsmSaraR4::GsmClient TinyGsmClient; typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient;
typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_M95) #elif defined(TINY_GSM_MODEM_M95)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientM95.h"
#include <TinyGsmClientM95.h>
typedef TinyGsmM95 TinyGsm; typedef TinyGsmM95 TinyGsm;
typedef TinyGsmM95::GsmClient TinyGsmClient; typedef TinyGsmM95::GsmClientM95 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_BG96) #elif defined(TINY_GSM_MODEM_BG96)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientBG96.h"
#include <TinyGsmClientBG96.h>
typedef TinyGsmBG96 TinyGsm; typedef TinyGsmBG96 TinyGsm;
typedef TinyGsmBG96::GsmClient TinyGsmClient; typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) #elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientA6.h"
#include <TinyGsmClientA6.h>
typedef TinyGsmA6 TinyGsm; typedef TinyGsmA6 TinyGsm;
typedef TinyGsmA6::GsmClient TinyGsmClient; typedef TinyGsmA6::GsmClientA6 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_M590) #elif defined(TINY_GSM_MODEM_M590)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientM590.h"
#include <TinyGsmClientM590.h>
typedef TinyGsmM590 TinyGsm; typedef TinyGsmM590 TinyGsm;
typedef TinyGsmM590::GsmClient TinyGsmClient; typedef TinyGsmM590::GsmClientM590 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E) #elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
#include <TinyGsmClientMC60.h> #include "TinyGsmClientMC60.h"
#define TINY_GSM_MODEM_HAS_GPRS
#define TINY_GSM_MODEM_HAS_GPS
typedef TinyGsmMC60 TinyGsm; typedef TinyGsmMC60 TinyGsm;
typedef TinyGsmMC60::GsmClient TinyGsmClient; typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient;
#elif defined(TINY_GSM_MODEM_ESP8266) #elif defined(TINY_GSM_MODEM_ESP8266)
#define TINY_GSM_MODEM_HAS_WIFI #define TINY_GSM_MODEM_HAS_WIFI
#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientESP8266.h"
#include <TinyGsmClientESP8266.h>
typedef TinyGsmESP8266 TinyGsm; typedef TinyGsmESP8266 TinyGsm;
typedef TinyGsmESP8266::GsmClient TinyGsmClient; typedef TinyGsmESP8266::GsmClientESP8266 TinyGsmClient;
typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_XBEE) #elif defined(TINY_GSM_MODEM_XBEE)
#define TINY_GSM_MODEM_HAS_GPRS
#define TINY_GSM_MODEM_HAS_WIFI #define TINY_GSM_MODEM_HAS_WIFI
#define TINY_GSM_MODEM_HAS_SSL #include "TinyGsmClientXBee.h"
#include <TinyGsmClientXBee.h>
typedef TinyGsmXBee TinyGsm; typedef TinyGsmXBee TinyGsm;
typedef TinyGsmXBee::GsmClient TinyGsmClient; typedef TinyGsmXBee::GsmClientXBee TinyGsmClient;
typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH) #elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
#define TINY_GSM_MODEM_HAS_GPRS #include "TinyGsmClientSequansMonarch.h"
#define TINY_GSM_MODEM_HAS_SSL
#include <TinyGsmClientSequansMonarch.h>
typedef TinyGsmSequansMonarch TinyGsm; typedef TinyGsmSequansMonarch TinyGsm;
typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient; typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient;
typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure; typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch
TinyGsmClientSecure;
#else #else
#error "Please define GSM modem model" #error "Please define GSM modem model"
#endif #endif
#endif #endif // SRC_TINYGSMCLIENT_H_

View File

@@ -6,31 +6,32 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClientA6_h #ifndef SRC_TINYGSMCLIENTA6_H_
#define TinyGsmClientA6_h #define SRC_TINYGSMCLIENTA6_H_
// #pragma message("TinyGSM: TinyGsmClientA6") // #pragma message("TinyGSM: TinyGsmClientA6")
// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 256
#endif
#define TINY_GSM_MUX_COUNT 8 #define TINY_GSM_MUX_COUNT 8
#define TINY_GSM_NO_MODEM_BUFFER
#include <TinyGsmCommon.h> #include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n" #define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
enum SimStatus { static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
SIM_ERROR = 0, #endif
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus { enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0, REG_UNREGISTERED = 0,
REG_SEARCHING = 2, REG_SEARCHING = 2,
REG_DENIED = 3, REG_DENIED = 3,
@@ -39,27 +40,36 @@ enum RegStatus {
REG_UNKNOWN = 4, REG_UNKNOWN = 4,
}; };
class TinyGsmA6 : public TinyGsmModem<TinyGsmA6>,
public TinyGsmGPRS<TinyGsmA6>,
public TinyGsmTCP<TinyGsmA6, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmA6>,
public TinyGsmSMS<TinyGsmA6>,
public TinyGsmTime<TinyGsmA6>,
public TinyGsmBattery<TinyGsmA6> {
friend class TinyGsmModem<TinyGsmA6>;
friend class TinyGsmGPRS<TinyGsmA6>;
friend class TinyGsmTCP<TinyGsmA6, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmA6>;
friend class TinyGsmSMS<TinyGsmA6>;
friend class TinyGsmTime<TinyGsmA6>;
friend class TinyGsmBattery<TinyGsmA6>;
class TinyGsmA6 /*
{ * Inner Client
*/
public: public:
class GsmClientA6 : public GsmClient {
class GsmClient : public Client
{
friend class TinyGsmA6; friend class TinyGsmA6;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public: public:
GsmClient() {} GsmClientA6() {}
GsmClient(TinyGsmA6& modem) { explicit GsmClientA6(TinyGsmA6& modem, uint8_t = 0) {
init(&modem); init(&modem, -1);
} }
virtual ~GsmClient(){} bool init(TinyGsmA6* modem, uint8_t = 0) {
bool init(TinyGsmA6* modem) {
this->at = modem; this->at = modem;
this->mux = -1; this->mux = -1;
sock_connected = false; sock_connected = false;
@@ -68,7 +78,7 @@ public:
} }
public: public:
virtual int connect(const char *host, uint16_t port, int timeout_s) { int connect(const char* host, uint16_t port, int timeout_s) {
stop(); stop();
TINY_GSM_YIELD(); TINY_GSM_YIELD();
rx.clear(); rx.clear();
@@ -80,70 +90,54 @@ public:
} }
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_CONNECT_OVERLOADS() void stop(uint32_t maxWaitMs) {
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux); at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false; sock_connected = false;
at->waitResponse(maxWaitMs); at->waitResponse(maxWaitMs);
rx.clear(); rx.clear();
} }
void stop() override {
virtual void stop() { stop(1000L); } stop(1000L);
}
TINY_GSM_CLIENT_WRITE()
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
/* /*
* Extended API * Extended API
*/ */
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmA6* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
}; };
/*
* Inner Secure Client
*/
// Doesn't support SSL
/*
* Constructor
*/
public: public:
explicit TinyGsmA6(Stream& stream) : stream(stream) {
TinyGsmA6(Stream& stream)
: stream(stream)
{
memset(sockets, 0, sizeof(sockets)); memset(sockets, 0, sizeof(sockets));
} }
virtual ~TinyGsmA6() {}
/* /*
* Basic functions * Basic functions
*/ */
protected:
bool begin(const char* pin = NULL) { bool initImpl(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off // sendAT(GF("&FZ")); // Factory + Reset
if (waitResponse() != 1) { // waitResponse();
return false;
} sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG #ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes sendAT(GF("+CMEE=2")); // turn on verbose error codes
@@ -151,161 +145,86 @@ public:
sendAT(GF("+CMEE=0")); // turn off error codes sendAT(GF("+CMEE=0")); // turn off error codes
#endif #endif
waitResponse(); waitResponse();
sendAT(GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination sendAT(
GF("+CMER=3,0,0,2")); // Set unsolicited result code output destination
waitResponse(); waitResponse();
DBG(GF("### Modem:"), getModemName()); DBG(GF("### Modem:"), getModemName());
int ret = getSimStatus(); SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim // if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin); simUnlock(pin);
return (getSimStatus() == SIM_READY); return (getSimStatus() == SIM_READY);
} } else {
// if the sim is ready, or it's locked but no pin has been provided, return // if the sim is ready, or it's locked but no pin has been provided,
// true // return true
else {
return (ret == SIM_READY || ret == SIM_LOCKED); return (ret == SIM_READY || ret == SIM_LOCKED);
} }
} }
String getModemName() { bool factoryDefaultImpl() {
#if defined(TINY_GSM_MODEM_A6)
return "AI-Thinker A6";
#elif defined(TINY_GSM_MODEM_A7)
return "AI-Thinker A7";
#endif
return "AI-Thinker A6";
}
TINY_GSM_MODEM_SET_BAUD_IPR()
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse(); waitResponse();
sendAT(GF("&W")); // Write configuration sendAT(GF("&W")); // Write configuration
return waitResponse() == 1; return waitResponse() == 1;
} }
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
return false;
}
bool hasWifi() {
return false;
}
bool hasGPRS() {
return true;
}
/* /*
* Power functions * Power functions
*/ */
protected:
bool restart() { bool restartImpl() {
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("+RST=1")); sendAT(GF("+RST=1"));
delay(3000); delay(3000);
return init(); return init();
} }
bool poweroff() { bool powerOffImpl() {
sendAT(GF("+CPOF")); sendAT(GF("+CPOF"));
// +CPOF: MS OFF OK
return waitResponse() == 1; return waitResponse() == 1;
} }
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
String getOperator() {
sendAT(GF("+COPS=3,0")); // Set format
waitResponse();
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
return "";
}
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/* /*
* Generic network functions * Generic network functions
*/ */
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ() protected:
bool isNetworkConnectedImpl() {
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus(); RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING); return (s == REG_OK_HOME || s == REG_OK_ROAMING);
} }
TINY_GSM_MODEM_WAIT_FOR_NETWORK() String getLocalIPImpl() {
sendAT(GF("+CIFSR"));
String res;
if (waitResponse(10000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
return res;
}
/* /*
* GPRS functions * GPRS functions
*/ */
protected:
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect(); gprsDisconnect();
sendAT(GF("+CGATT=1")); sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) if (waitResponse(60000L) != 1) { return false; }
return false;
// TODO: wait AT+CGATT? // TODO(?): wait AT+CGATT?
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
waitResponse(); waitResponse();
@@ -313,117 +232,89 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
if (!user) user = ""; if (!user) user = "";
if (!pwd) pwd = ""; if (!pwd) pwd = "";
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse(60000L) != 1) { if (waitResponse(60000L) != 1) { return false; }
return false;
}
sendAT(GF("+CGACT=1,1")); sendAT(GF("+CGACT=1,1"));
waitResponse(60000L); waitResponse(60000L);
sendAT(GF("+CIPMUX=1")); sendAT(GF("+CIPMUX=1"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
return true; return true;
} }
bool gprsDisconnect() { bool gprsDisconnectImpl() {
// Shut the TCP/IP connection // Shut the TCP/IP connection
sendAT(GF("+CIPSHUT")); sendAT(GF("+CIPSHUT"));
if (waitResponse(60000L) != 1) if (waitResponse(60000L) != 1) { return false; }
return false;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
sendAT(GF("+CGATT=0")); sendAT(GF("+CGATT=0"));
if (waitResponse(5000L) == 1) if (waitResponse(5000L) == 1) { return true; }
return true;
} }
return false; return false;
} }
bool isGprsConnected() { String getOperatorImpl() {
sendAT(GF("+CGATT?")); sendAT(GF("+COPS=3,0")); // Set format
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
return false;
}
int res = stream.readStringUntil('\n').toInt();
waitResponse(); waitResponse();
return (res == 1);
}
/* sendAT(GF("+COPS?"));
* IP Address functions if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
*/ streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
String getLocalIP() { waitResponse();
sendAT(GF("+CIFSR"));
String res;
if (waitResponse(10000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
return res; return res;
} }
IPAddress localIP() { /*
return TinyGsmIpFromString(getLocalIP()); * SIM card functions
*/
protected:
String getSimCCIDImpl() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
} }
/* /*
* Phone Call functions * Phone Call functions
*/ */
protected:
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() {
sendAT(GF("A"));
return waitResponse() == 1;
}
// Returns true on pick-up, false on error/busy // Returns true on pick-up, false on error/busy
bool callNumber(const String& number) { bool callNumberImpl(const String& number) {
if (number == GF("last")) { if (number == GF("last")) {
sendAT(GF("DLST")); sendAT(GF("DLST"));
} else { } else {
sendAT(GF("D\""), number, "\";"); sendAT(GF("D\""), number, "\";");
} }
if (waitResponse(5000L) != 1) { if (waitResponse(5000L) != 1) { return false; }
if (waitResponse(60000L, GF(GSM_NL "+CIEV: \"CALL\",1"),
GF(GSM_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) {
return false; return false;
} }
if (waitResponse(60000L, int8_t rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
GF(GSM_NL "+CIEV: \"CALL\",1"),
GF(GSM_NL "+CIEV: \"CALL\",0"),
GFP(GSM_ERROR)) != 1)
{
return false;
}
int rsp = waitResponse(60000L,
GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
GF(GSM_NL "+CIEV: \"CALL\",0")); GF(GSM_NL "+CIEV: \"CALL\",0"));
int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL)); int8_t rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL),
GF(GSM_NL "NO ANSWER" GSM_NL));
return rsp == 1 && rsp2 == 0; return rsp == 1 && rsp2 == 0;
} }
bool callHangup() {
sendAT(GF("H"));
return waitResponse() == 1;
}
// 0-9,*,#,A,B,C,D // 0-9,*,#,A,B,C,D
bool dtmfSend(char cmd, unsigned duration_ms = 100) { bool dtmfSendImpl(char cmd, uint8_t duration_ms = 100) {
duration_ms = constrain(duration_ms, 100, 1000); duration_ms = constrain(duration_ms, 100, 1000);
// The duration parameter is not working, so we simulate it using delay.. // The duration parameter is not working, so we simulate it using delay..
// TODO: Maybe there's another way... // TODO(?): Maybe there's another way...
// sendAT(GF("+VTD="), duration_ms / 100); // sendAT(GF("+VTD="), duration_ms / 100);
// waitResponse(); // waitResponse();
@@ -439,7 +330,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/* /*
* Audio functions * Audio functions
*/ */
public:
bool audioSetHeadphones() { bool audioSetHeadphones() {
sendAT(GF("+SNFS=0")); sendAT(GF("+SNFS=0"));
return waitResponse() == 1; return waitResponse() == 1;
@@ -458,23 +349,19 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/* /*
* Messaging functions * Messaging functions
*/ */
protected:
String sendUSSD(const String& code) { String sendUSSDImpl(const String& code) {
sendAT(GF("+CMGF=1")); sendAT(GF("+CMGF=1"));
waitResponse(); waitResponse();
sendAT(GF("+CSCS=\"HEX\"")); sendAT(GF("+CSCS=\"HEX\""));
waitResponse(); waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\",15")); sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
if (waitResponse(10000L) != 1) { if (waitResponse(10000L) != 1) { return ""; }
return ""; if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; }
} streamSkipUntil('"');
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"'); String hex = stream.readStringUntil('"');
stream.readStringUntil(','); streamSkipUntil(',');
int dcs = stream.readStringUntil('\n').toInt(); int8_t dcs = streamGetIntBefore('\n');
if (dcs == 15) { if (dcs == 15) {
return TinyGsmDecodeHex7bit(hex); return TinyGsmDecodeHex7bit(hex);
@@ -485,96 +372,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
} }
} }
bool sendSMS(const String& number, const String& text) { /*
sendAT(GF("+CMGF=1")); * Time functions
waitResponse(); */
sendAT(GF("+CMGS=\""), number, GF("\"")); protected:
if (waitResponse(GF(">")) != 1) { // Can follow the standard CCLK function in the template
return false; // Note - the clock probably has to be set manaually first
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
/* /*
* Location functions * Battery functions
*/ */
protected:
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; // Needs a '?' after CBC, unlike most
int8_t getBattPercentImpl() {
/*
* Battery & temperature functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() {
sendAT(GF("+CBC?")); sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
return false;
}
streamSkipUntil(','); // Skip battery charge status streamSkipUntil(','); // Skip battery charge status
// Read battery charge level // Read battery charge level
int res = stream.readStringUntil('\n').toInt(); int8_t res = streamGetIntBefore('\n');
// Wait for final OK // Wait for final OK
waitResponse(); waitResponse();
return res; return res;
} }
uint8_t getBattChargeState() { // Needs a '?' after CBC, unlike most
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) {
sendAT(GF("+CBC?")); sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
return false; chargeState = streamGetIntBefore(',');
} percent = streamGetIntBefore('\n');
// Read battery charge status
int res = stream.readStringUntil(',').toInt();
// Wait for final OK
waitResponse();
return res;
}
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return false;
}
chargeState = stream.readStringUntil(',').toInt();
percent = stream.readStringUntil('\n').toInt();
milliVolts = 0; milliVolts = 0;
// Wait for final OK // Wait for final OK
waitResponse(); waitResponse();
return true; return true;
} }
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Client related functions * Client related functions
*/ */
protected: protected:
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, int timeout_s = 75) { int timeout_s = 75) {
unsigned long startMillis = millis(); uint32_t startMillis = millis();
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port); sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
return false; int8_t newMux = streamGetIntBefore('\n');
}
int newMux = stream.readStringUntil('\n').toInt();
int rsp = waitResponse((timeout_ms- (millis() - startMillis)), int8_t rsp = waitResponse(
GF("CONNECT OK" GSM_NL), (timeout_ms - (millis() - startMillis)), GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL), GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
GF("ALREADY CONNECT" GSM_NL)); if (waitResponse() != 1) { return false; }
if (waitResponse() != 1) {
return false;
}
*mux = newMux; *mux = newMux;
return (1 == rsp); return (1 == rsp);
@@ -582,37 +434,35 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) { int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { return 0; }
return 0; stream.write(reinterpret_cast<const uint8_t*>(buff), len);
}
stream.write((uint8_t*)buff, len);
stream.flush(); stream.flush();
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { return 0; }
return 0;
}
return len; return len;
} }
bool modemGetConnected(uint8_t) { bool modemGetConnected(uint8_t) {
sendAT(GF("+CIPSTATUS")); //TODO mux? sendAT(GF("+CIPSTATUS")); // TODO(?) mux?
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
GF(",\"CLOSING\""), GF(",\"INITIAL\""));
waitResponse(); waitResponse();
return 1 == res; return 1 == res;
} }
public:
/* /*
Utilities * Utilities
*/ */
public:
TINY_GSM_MODEM_STREAM_UTILITIES() // TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
// TODO: Optimize this! GsmConstStr r1 = GFP(GSM_OK),
uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), #if defined TINY_GSM_DEBUG
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r3 = GFP(GSM_CME_ERROR),
{ #else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim(); /*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim(); String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim(); String r3s(r3); r3s.trim();
@@ -620,15 +470,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim(); String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64); data.reserve(64);
int index = 0; uint8_t index = 0;
unsigned long startMillis = millis(); uint32_t startMillis = millis();
do { do {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
while (stream.available() > 0) { while (stream.available() > 0) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
int a = stream.read(); int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a; data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) { if (r1 && data.endsWith(r1)) {
index = 1; index = 1;
goto finish; goto finish;
@@ -636,6 +486,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 2; index = 2;
goto finish; goto finish;
} else if (r3 && data.endsWith(r3)) { } else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3; index = 3;
goto finish; goto finish;
} else if (r4 && data.endsWith(r4)) { } else if (r4 && data.endsWith(r4)) {
@@ -645,23 +500,23 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5; index = 5;
goto finish; goto finish;
} else if (data.endsWith(GF("+CIPRCV:"))) { } else if (data.endsWith(GF("+CIPRCV:"))) {
int mux = stream.readStringUntil(',').toInt(); int8_t mux = streamGetIntBefore(',');
int len = stream.readStringUntil(',').toInt(); int16_t len = streamGetIntBefore(',');
int len_orig = len; int16_t len_orig = len;
if (len > sockets[mux]->rx.free()) { if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else { } else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free()); DBG("### Got: ", len, "->", sockets[mux]->rx.free());
} }
while (len--) { while (len--) { moveCharFromStreamToFifo(mux); }
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT // TODO(?) Deal with missing characters
} if (len_orig > sockets[mux]->available()) {
if (len_orig > sockets[mux]->available()) { // TODO DBG("### Fewer characters received than expected: ",
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); sockets[mux]->available(), " vs ", len_orig);
} }
data = ""; data = "";
} else if (data.endsWith(GF("+TCPCLOSED:"))) { } else if (data.endsWith(GF("+TCPCLOSED:"))) {
int mux = stream.readStringUntil('\n').toInt(); int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
sockets[mux]->sock_connected = false; sockets[mux]->sock_connected = false;
} }
@@ -673,9 +528,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
finish: finish:
if (!index) { if (!index) {
data.trim(); data.trim();
if (data.length()) { if (data.length()) { DBG("### Unhandled:", data); }
DBG("### Unhandled:", data);
}
data = ""; data = "";
} }
// data.replace(GSM_NL, "/"); // data.replace(GSM_NL, "/");
@@ -683,25 +536,33 @@ finish:
return index; return index;
} }
uint8_t waitResponse(uint32_t timeout_ms, int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) #if defined TINY_GSM_DEBUG
{ GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data; String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
} }
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r2 = GFP(GSM_ERROR),
{ #if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5); return waitResponse(1000, r1, r2, r3, r4, r5);
} }
public:
Stream& stream;
protected: protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT]; Stream& stream;
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
}; };
#endif #endif // SRC_TINYGSMCLIENTA6_H_

File diff suppressed because it is too large Load Diff

View File

@@ -6,24 +6,24 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClientESP8266_h #ifndef SRC_TINYGSMCLIENTESP8266_H_
#define TinyGsmClientESP8266_h #define SRC_TINYGSMCLIENTESP8266_H_
// #pragma message("TinyGSM: TinyGsmClientESP8266") // #pragma message("TinyGSM: TinyGsmClientESP8266")
// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 512
#endif
#define TINY_GSM_MUX_COUNT 5 #define TINY_GSM_MUX_COUNT 5
#define TINY_GSM_NO_MODEM_BUFFER
#include <TinyGsmCommon.h> #include "TinyGsmModem.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmWifi.tpp"
#define GSM_NL "\r\n" #define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; static uint8_t TINY_GSM_TCP_KEEP_ALIVE = 120;
// <stat> status of ESP8266 station interface // <stat> status of ESP8266 station interface
// 2 : ESP8266 station connected to an AP and has obtained IP // 2 : ESP8266 station connected to an AP and has obtained IP
@@ -38,32 +38,39 @@ enum RegStatus {
REG_UNKNOWN = 6, REG_UNKNOWN = 6,
}; };
class TinyGsmESP8266 : public TinyGsmModem<TinyGsmESP8266>,
public TinyGsmWifi<TinyGsmESP8266>,
public TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmESP8266> {
friend class TinyGsmModem<TinyGsmESP8266>;
friend class TinyGsmWifi<TinyGsmESP8266>;
friend class TinyGsmTCP<TinyGsmESP8266, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmESP8266>;
class TinyGsmESP8266 /*
{ * Inner Client
*/
public: public:
class GsmClientESP8266 : public GsmClient {
class GsmClient : public Client
{
friend class TinyGsmESP8266; friend class TinyGsmESP8266;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public: public:
GsmClient() {} GsmClientESP8266() {}
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) { explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 0) {
init(&modem, mux); init(&modem, mux);
} }
virtual ~GsmClient(){} bool init(TinyGsmESP8266* modem, uint8_t mux = 0) {
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
this->at = modem; this->at = modem;
this->mux = mux;
sock_connected = false; sock_connected = false;
at->sockets[mux] = this; if (mux < TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT);
}
at->sockets[this->mux] = this;
return true; return true;
} }
@@ -76,194 +83,139 @@ public:
sock_connected = at->modemConnect(host, port, mux, false, timeout_s); sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_CONNECT_OVERLOADS() void stop(uint32_t maxWaitMs) {
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux); at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false; sock_connected = false;
at->waitResponse(maxWaitMs); at->waitResponse(maxWaitMs);
rx.clear(); rx.clear();
} }
void stop() override {
virtual void stop() { stop(5000L); } stop(5000L);
}
TINY_GSM_CLIENT_WRITE()
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
/* /*
* Extended API * Extended API
*/ */
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmESP8266* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
}; };
/*
class GsmClientSecure : public GsmClient * Inner Secure Client
{ */
public: public:
GsmClientSecure() {} class GsmClientSecureESP8266 : public GsmClientESP8266 {
public:
GsmClientSecureESP8266() {}
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1) explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 0)
: GsmClient(modem, mux) : GsmClientESP8266(modem, mux) {}
{}
virtual ~GsmClientSecure() {}
public: public:
virtual int connect(const char *host, uint16_t port, int timeout_s) { int connect(const char* host, uint16_t port, int timeout_s) override {
stop(); stop();
TINY_GSM_YIELD(); TINY_GSM_YIELD();
rx.clear(); rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s); sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
}; };
/*
* Constructor
*/
public: public:
explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
TinyGsmESP8266(Stream& stream)
: stream(stream)
{
memset(sockets, 0, sizeof(sockets)); memset(sockets, 0, sizeof(sockets));
} }
virtual ~TinyGsmESP8266() {}
/* /*
* Basic functions * Basic functions
*/ */
protected:
bool begin(const char* pin = NULL) { bool initImpl(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false; if (!testAT()) { return false; }
}
if (pin && strlen(pin) > 0) { if (pin && strlen(pin) > 0) {
DBG("ESP8266 modules do not use an unlock pin!"); DBG("ESP8266 modules do not use an unlock pin!");
} }
sendAT(GF("E0")); // Echo Off sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
DBG(GF("### Modem:"), getModemName()); DBG(GF("### Modem:"), getModemName());
return true; return true;
} }
String getModemName() { String getModemNameImpl() {
return "ESP8266"; return "ESP8266";
} }
void setBaud(unsigned long baud) { void setBaudImpl(uint32_t baud) {
sendAT(GF("+UART_CUR="), baud, "8,1,0,0"); sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
} }
TINY_GSM_MODEM_TEST_AT() bool factoryDefaultImpl() {
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
sendAT(GF("+RESTORE")); sendAT(GF("+RESTORE"));
return waitResponse() == 1; return waitResponse() == 1;
} }
String getModemInfo() { String getModemInfoImpl() {
sendAT(GF("+GMR")); sendAT(GF("+GMR"));
String res; String res;
if (waitResponse(1000L, res) != 1) { if (waitResponse(1000L, res) != 1) { return ""; }
return "";
}
res.replace(GSM_NL "OK" GSM_NL, ""); res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " "); res.replace(GSM_NL, " ");
res.trim(); res.trim();
return res; return res;
} }
bool hasSSL() {
return true;
}
bool hasWifi() {
return true;
}
bool hasGPRS() {
return false;
}
/* /*
* Power functions * Power functions
*/ */
protected:
bool restart() { bool restartImpl() {
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("+RST")); sendAT(GF("+RST"));
if (waitResponse(10000L) != 1) { if (waitResponse(10000L) != 1) { return false; }
return false; if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
}
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
return false;
}
delay(500); delay(500);
return init(); return init();
} }
bool poweroff() { bool powerOffImpl() {
sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset! sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
return waitResponse() == 1; return waitResponse() == 1;
} }
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* SIM card functions
*/
RegStatus getRegistrationStatus() {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
int status =
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
waitResponse(); // Returns an OK after the status
return (RegStatus)status;
}
/* /*
* Generic network functions * Generic network functions
*/ */
public:
RegStatus getRegistrationStatus() {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
GF("5"));
waitResponse(); // Returns an OK after the status
return (RegStatus)status;
}
int16_t getSignalQuality() { protected:
int8_t getSignalQualityImpl() {
sendAT(GF("+CWJAP_CUR?")); sendAT(GF("+CWJAP_CUR?"));
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); int8_t res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
if (res1 != 2) { if (res1 != 2) {
waitResponse(); waitResponse();
return 0; return 0;
@@ -271,38 +223,42 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
streamSkipUntil(','); // Skip SSID streamSkipUntil(','); // Skip SSID
streamSkipUntil(','); // Skip BSSID/MAC address streamSkipUntil(','); // Skip BSSID/MAC address
streamSkipUntil(','); // Skip Chanel number streamSkipUntil(','); // Skip Chanel number
int res2 = stream.parseInt(); // Read RSSI int8_t res2 = stream.parseInt(); // Read RSSI
waitResponse(); // Returns an OK after the value waitResponse(); // Returns an OK after the value
return res2; return res2;
} }
bool isNetworkConnected() { bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus(); RegStatus s = getRegistrationStatus();
if (s == REG_OK_IP || s == REG_OK_TCP) { if (s == REG_OK_IP || s == REG_OK_TCP) {
// with these, we're definitely connected // with these, we're definitely connected
return true; return true;
} } else if (s == REG_OK_NO_TCP) {
else if (s == REG_OK_NO_TCP) {
// with this, we may or may not be connected // with this, we may or may not be connected
if (getLocalIP() == "") { if (getLocalIP() == "") {
return false; return false;
} } else {
else {
return true; return true;
} }
} } else {
else {
return false; return false;
} }
} }
TINY_GSM_MODEM_WAIT_FOR_NETWORK() String getLocalIPImpl() {
sendAT(GF("+CIPSTA_CUR?"));
int8_t res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
if (res1 != 2) { return ""; }
String res2 = stream.readStringUntil('"');
waitResponse();
return res2;
}
/* /*
* WiFi functions * WiFi functions
*/ */
protected:
bool networkConnect(const char* ssid, const char* pwd) { bool networkConnectImpl(const char* ssid, const char* pwd) {
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\"")); sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) { if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
return false; return false;
@@ -311,86 +267,49 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
return true; return true;
} }
bool networkDisconnect() { bool networkDisconnectImpl() {
sendAT(GF("+CWQAP")); sendAT(GF("+CWQAP"));
bool retVal = waitResponse(10000L) == 1; bool retVal = waitResponse(10000L) == 1;
waitResponse(GF("WIFI DISCONNECT")); waitResponse(GF("WIFI DISCONNECT"));
return retVal; return retVal;
} }
/*
* IP Address functions
*/
String getLocalIP() {
sendAT(GF("+CIPSTA_CUR??"));
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
if (res1 != 2) {
return "";
}
String res2 = stream.readStringUntil('"');
waitResponse();
return res2;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Battery & temperature functions
*/
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Client related functions * Client related functions
*/ */
protected: protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) bool ssl = false, int timeout_s = 75) {
{
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
if (ssl) { if (ssl) {
sendAT(GF("+CIPSSLSIZE=4096")); sendAT(GF("+CIPSSLSIZE=4096"));
waitResponse(); waitResponse();
} }
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE); GF("\",\""), host, GF("\","), port, GF(","),
// TODO: Check mux TINY_GSM_TCP_KEEP_ALIVE);
int rsp = waitResponse(timeout_ms, // TODO(?): Check mux
GFP(GSM_OK), int8_t rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR),
GFP(GSM_ERROR),
GF("ALREADY CONNECT")); GF("ALREADY CONNECT"));
// if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT" // if (rsp == 3) waitResponse();
// May return "ERROR" after the "ALREADY CONNECT"
return (1 == rsp); return (1 == rsp);
} }
int16_t modemSend(const void* buff, size_t len, uint8_t mux) { int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) { if (waitResponse(GF(">")) != 1) { return 0; }
return 0; stream.write(reinterpret_cast<const uint8_t*>(buff), len);
}
stream.write((uint8_t*)buff, len);
stream.flush(); stream.flush();
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
return 0;
}
return len; return len;
} }
bool modemGetConnected(uint8_t mux) { bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS")); sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return false; if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
int status = int8_t status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"),
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); GF("5"));
if (status != 3) { if (status != 3) {
// if the status is anything but 3, there are no connections open // if the status is anything but 3, there are no connections open
waitResponse(); // Returns an OK after the status waitResponse(); // Returns an OK after the status
@@ -401,9 +320,10 @@ protected:
} }
bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0}; bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK),
GFP(GSM_ERROR));
if (has_status == 1) { if (has_status == 1) {
int returned_mux = stream.readStringUntil(',').toInt(); int8_t returned_mux = streamGetIntBefore(',');
streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type streamSkipUntil(','); // Skip type
streamSkipUntil(','); // Skip remote IP streamSkipUntil(','); // Skip remote IP
@@ -420,19 +340,15 @@ protected:
return verified_connections[mux]; return verified_connections[mux];
} }
public:
/* /*
Utilities * Utilities
*/ */
public:
TINY_GSM_MODEM_STREAM_UTILITIES() // TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
// TODO: Optimize this! GsmConstStr r1 = GFP(GSM_OK),
uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim(); /*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim(); String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim(); String r3s(r3); r3s.trim();
@@ -440,15 +356,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim(); String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64); data.reserve(64);
int index = 0; uint8_t index = 0;
unsigned long startMillis = millis(); uint32_t startMillis = millis();
do { do {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
while (stream.available() > 0) { while (stream.available() > 0) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
int a = stream.read(); int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a; data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) { if (r1 && data.endsWith(r1)) {
index = 1; index = 1;
goto finish; goto finish;
@@ -465,25 +381,27 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5; index = 5;
goto finish; goto finish;
} else if (data.endsWith(GF("+IPD,"))) { } else if (data.endsWith(GF("+IPD,"))) {
int mux = stream.readStringUntil(',').toInt(); int8_t mux = streamGetIntBefore(',');
int len = stream.readStringUntil(':').toInt(); int16_t len = streamGetIntBefore(':');
int len_orig = len; int16_t len_orig = len;
if (len > sockets[mux]->rx.free()) { if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available"); DBG("### Buffer overflow: ", len, "received vs",
sockets[mux]->rx.free(), "available");
} else { } else {
DBG("### Got Data: ", len, "on", mux); // DBG("### Got Data: ", len, "on", mux);
} }
while (len--) { while (len--) { moveCharFromStreamToFifo(mux); }
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT // TODO(SRGDamia1): deal with buffer overflow/missed characters
} if (len_orig > sockets[mux]->available()) {
if (len_orig > sockets[mux]->available()) { // TODO DBG("### Fewer characters received than expected: ",
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); sockets[mux]->available(), " vs ", len_orig);
} }
data = ""; data = "";
} else if (data.endsWith(GF("CLOSED"))) { } else if (data.endsWith(GF("CLOSED"))) {
int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8)); int8_t muxStart =
int coma = data.indexOf(',', muxStart); TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
int mux = data.substring(muxStart, coma).toInt(); int8_t coma = data.indexOf(',', muxStart);
int8_t mux = data.substring(muxStart, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false; sockets[mux]->sock_connected = false;
} }
@@ -495,9 +413,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
finish: finish:
if (!index) { if (!index) {
data.trim(); data.trim();
if (data.length()) { if (data.length()) { DBG("### Unhandled:", data); }
DBG("### Unhandled:", data);
}
data = ""; data = "";
} }
// data.replace(GSM_NL, "/"); // data.replace(GSM_NL, "/");
@@ -505,25 +421,23 @@ finish:
return index; return index;
} }
uint8_t waitResponse(uint32_t timeout_ms, int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
{
String data; String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
} }
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
{ GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5); return waitResponse(1000, r1, r2, r3, r4, r5);
} }
public:
Stream& stream;
protected: protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT]; Stream& stream;
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
}; };
#endif #endif // SRC_TINYGSMCLIENTESP8266_H_

View File

@@ -6,31 +6,30 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClientM590_h #ifndef SRC_TINYGSMCLIENTM590_H_
#define TinyGsmClientM590_h #define SRC_TINYGSMCLIENTM590_H_
// #pragma message("TinyGSM: TinyGsmClientM590") // #pragma message("TinyGSM: TinyGsmClientM590")
// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 256
#endif
#define TINY_GSM_MUX_COUNT 2 #define TINY_GSM_MUX_COUNT 2
#define TINY_GSM_NO_MODEM_BUFFER
#include <TinyGsmCommon.h> #include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n" #define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
enum SimStatus { static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
SIM_ERROR = 0, #endif
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus { enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0, REG_UNREGISTERED = 0,
REG_SEARCHING = 3, REG_SEARCHING = 3,
REG_DENIED = 2, REG_DENIED = 2,
@@ -39,109 +38,92 @@ enum RegStatus {
REG_UNKNOWN = 4, REG_UNKNOWN = 4,
}; };
class TinyGsmM590 : public TinyGsmModem<TinyGsmM590>,
public TinyGsmGPRS<TinyGsmM590>,
public TinyGsmTCP<TinyGsmM590, TINY_GSM_MUX_COUNT>,
public TinyGsmSMS<TinyGsmM590>,
public TinyGsmTime<TinyGsmM590> {
friend class TinyGsmModem<TinyGsmM590>;
friend class TinyGsmGPRS<TinyGsmM590>;
friend class TinyGsmTCP<TinyGsmM590, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSMS<TinyGsmM590>;
friend class TinyGsmTime<TinyGsmM590>;
class TinyGsmM590 /*
{ * Inner Client
*/
public: public:
class GsmClientM590 : public GsmClient {
class GsmClient : public Client
{
friend class TinyGsmM590; friend class TinyGsmM590;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public: public:
GsmClient() {} GsmClientM590() {}
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) { explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 0) {
init(&modem, mux); init(&modem, mux);
} }
virtual ~GsmClient(){} bool init(TinyGsmM590* modem, uint8_t mux = 0) {
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
this->at = modem; this->at = modem;
this->mux = mux;
sock_connected = false; sock_connected = false;
at->sockets[mux] = this; if (mux < TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT);
}
at->sockets[this->mux] = this;
return true; return true;
} }
public: public:
virtual int connect(const char *host, uint16_t port, int timeout_s) { int connect(const char* host, uint16_t port, int timeout_s) {
stop(); stop();
TINY_GSM_YIELD(); TINY_GSM_YIELD();
rx.clear(); rx.clear();
sock_connected = at->modemConnect(host, port, mux, timeout_s); sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_CONNECT_OVERLOADS() void stop(uint32_t maxWaitMs) {
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
at->sendAT(GF("+TCPCLOSE="), mux); at->sendAT(GF("+TCPCLOSE="), mux);
sock_connected = false; sock_connected = false;
at->waitResponse(maxWaitMs); at->waitResponse(maxWaitMs);
rx.clear(); rx.clear();
} }
void stop() override {
virtual void stop() { stop(1000L); } stop(1000L);
}
TINY_GSM_CLIENT_WRITE()
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
/* /*
* Extended API * Extended API
*/ */
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmM590* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
}; };
/*
* Constructor
*/
public: public:
explicit TinyGsmM590(Stream& stream) : stream(stream) {
TinyGsmM590(Stream& stream)
: stream(stream)
{
memset(sockets, 0, sizeof(sockets)); memset(sockets, 0, sizeof(sockets));
} }
virtual ~TinyGsmM590() {}
/* /*
* Basic functions * Basic functions
*/ */
protected:
bool begin(const char* pin = NULL) { bool initImpl(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
#ifdef TINY_GSM_DEBUG #ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes sendAT(GF("+CMEE=2")); // turn on verbose error codes
@@ -152,30 +134,25 @@ public:
DBG(GF("### Modem:"), getModemName()); DBG(GF("### Modem:"), getModemName());
int ret = getSimStatus(); SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim // if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin); simUnlock(pin);
return (getSimStatus() == SIM_READY); return (getSimStatus() == SIM_READY);
} } else {
// if the sim is ready, or it's locked but no pin has been provided, return // if the sim is ready, or it's locked but no pin has been provided,
// true // return true
else {
return (ret == SIM_READY || ret == SIM_LOCKED); return (ret == SIM_READY || ret == SIM_LOCKED);
} }
} }
String getModemName() { // Doesn't support CGMI
String getModemNameImpl() {
return "Neoway M590"; return "Neoway M590";
} }
TINY_GSM_MODEM_SET_BAUD_IPR() // Extra stuff here - pwr save, internal stack
bool factoryDefaultImpl() {
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse(); waitResponse();
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
@@ -188,100 +165,59 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
return waitResponse() == 1; return waitResponse() == 1;
} }
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
return false;
}
bool hasWifi() {
return false;
}
bool hasGPRS() {
return true;
}
/* /*
* Power functions * Power functions
*/ */
protected:
bool restart() { bool restartImpl() {
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("+CFUN=15")); sendAT(GF("+CFUN=15"));
if (waitResponse(10000L) != 1) { if (waitResponse(10000L) != 1) { return false; }
return false;
}
// MODEM:STARTUP // MODEM:STARTUP
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL)); waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
return init(); return init();
} }
bool poweroff() { bool powerOffImpl() {
sendAT(GF("+CPWROFF")); sendAT(GF("+CPWROFF"));
return waitResponse(3000L) == 1; return waitResponse(3000L) == 1;
} }
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; bool sleepEnableImpl(bool enable = true) {
bool sleepEnable(bool enable = true) {
sendAT(GF("+ENPWRSAVE="), enable); sendAT(GF("+ENPWRSAVE="), enable);
return waitResponse() == 1; return waitResponse() == 1;
} }
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
TINY_GSM_MODEM_GET_SIMCCID_CCID()
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/* /*
* Generic network functions * Generic network functions
*/ */
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ() protected:
bool isNetworkConnectedImpl() {
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus(); RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING); return (s == REG_OK_HOME || s == REG_OK_ROAMING);
} }
TINY_GSM_MODEM_WAIT_FOR_NETWORK() String getLocalIPImpl() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; }
streamSkipUntil(',');
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
/* /*
* GPRS functions * GPRS functions
*/ */
protected:
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect(); gprsDisconnect();
sendAT(GF("+XISP=0")); sendAT(GF("+XISP=0"));
@@ -298,8 +234,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
sendAT(GF("+XIIC=1")); sendAT(GF("+XIIC=1"));
waitResponse(); waitResponse();
const unsigned long timeout_ms = 60000L; const uint32_t timeout_ms = 60000L;
for (unsigned long start = millis(); millis() - start < timeout_ms; ) { for (uint32_t start = millis(); millis() - start < timeout_ms;) {
if (isGprsConnected()) { if (isGprsConnected()) {
// goto set_dns; // TODO // goto set_dns; // TODO
return true; return true;
@@ -318,133 +254,51 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
return true; return true;
} }
bool gprsDisconnect() { bool gprsDisconnectImpl() {
// TODO: There is no command in AT command set // TODO(?): There is no command in AT command set
// XIIC=0 does not work // XIIC=0 does not work
return true; return true;
} }
bool isGprsConnected() { bool isGprsConnectedImpl() {
sendAT(GF("+XIIC?")); sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; }
return false; int8_t res = streamGetIntBefore(',');
}
int res = stream.readStringUntil(',').toInt();
waitResponse(); waitResponse();
return res == 1; return res == 1;
} }
/* /*
* IP Address functions * SIM card functions
*/ */
protected:
String getLocalIP() { // Able to follow all SIM card functions as inherited from the template
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
return "";
}
stream.readStringUntil(',');
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Messaging functions * Messaging functions
*/ */
protected:
String sendUSSD(const String& code) { bool sendSMS_UTF16Impl(const String& number, const void* text,
sendAT(GF("+CMGF=1")); size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("D"), code);
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len)
TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Location functions * Time functions
*/ */
protected:
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; // Can follow the standard CCLK function in the template
/*
* Battery & temperature functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Client related functions * Client related functions
*/ */
protected: protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool,
bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) { int timeout_s = 75) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
for (int i=0; i<3; i++) { // TODO: no need for loop? for (int i = 0; i < 3; i++) { // TODO(?): no need for loop?
String ip = dnsIpQuery(host); String ip = dnsIpQuery(host);
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port); sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
int rsp = waitResponse(timeout_ms, int8_t rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL),
GF(",OK" GSM_NL),
GF(",FAIL" GSM_NL), GF(",FAIL" GSM_NL),
GF("+TCPSETUP:Error" GSM_NL)); GF("+TCPSETUP:Error" GSM_NL));
if (1 == rsp) { if (1 == rsp) {
@@ -460,50 +314,46 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) { int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len); sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) { if (waitResponse(GF(">")) != 1) { return 0; }
return 0; stream.write(reinterpret_cast<const uint8_t*>(buff), len);
} stream.write(static_cast<char>(0x0D));
stream.write((uint8_t*)buff, len);
stream.write((char)0x0D);
stream.flush(); stream.flush();
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; }
return 0; streamSkipUntil('\n');
}
stream.readStringUntil('\n');
return len; return len;
} }
bool modemGetConnected(uint8_t mux) { bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS="), mux); sendAT(GF("+CIPSTATUS="), mux);
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); int8_t res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""),
GF(",\"CLOSING\""), GF(",\"INITIAL\""));
waitResponse(); waitResponse();
return 1 == res; return 1 == res;
} }
String dnsIpQuery(const char* host) { String dnsIpQuery(const char* host) {
sendAT(GF("+DNS=\""), host, GF("\"")); sendAT(GF("+DNS=\""), host, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; }
return "";
}
String res = stream.readStringUntil('\n'); String res = stream.readStringUntil('\n');
waitResponse(GF("+DNS:OK" GSM_NL)); waitResponse(GF("+DNS:OK" GSM_NL));
res.trim(); res.trim();
return res; return res;
} }
public:
/* /*
Utilities * Utilities
*/ */
public:
TINY_GSM_MODEM_STREAM_UTILITIES() // TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
// TODO: Optimize this! GsmConstStr r1 = GFP(GSM_OK),
uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), #if defined TINY_GSM_DEBUG
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r3 = GFP(GSM_CME_ERROR),
{ #else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim(); /*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim(); String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim(); String r3s(r3); r3s.trim();
@@ -511,15 +361,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim(); String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64); data.reserve(64);
int index = 0; uint8_t index = 0;
unsigned long startMillis = millis(); uint32_t startMillis = millis();
do { do {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
while (stream.available() > 0) { while (stream.available() > 0) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
int a = stream.read(); int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a; data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) { if (r1 && data.endsWith(r1)) {
index = 1; index = 1;
goto finish; goto finish;
@@ -527,6 +377,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 2; index = 2;
goto finish; goto finish;
} else if (r3 && data.endsWith(r3)) { } else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3; index = 3;
goto finish; goto finish;
} else if (r4 && data.endsWith(r4)) { } else if (r4 && data.endsWith(r4)) {
@@ -536,24 +391,24 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5; index = 5;
goto finish; goto finish;
} else if (data.endsWith(GF("+TCPRECV:"))) { } else if (data.endsWith(GF("+TCPRECV:"))) {
int mux = stream.readStringUntil(',').toInt(); int8_t mux = streamGetIntBefore(',');
int len = stream.readStringUntil(',').toInt(); int16_t len = streamGetIntBefore(',');
int len_orig = len; int16_t len_orig = len;
if (len > sockets[mux]->rx.free()) { if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else { } else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free()); DBG("### Got: ", len, "->", sockets[mux]->rx.free());
} }
while (len--) { while (len--) { moveCharFromStreamToFifo(mux); }
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT // TODO(?): Handle lost characters
} if (len_orig > sockets[mux]->available()) {
if (len_orig > sockets[mux]->available()) { // TODO DBG("### Fewer characters received than expected: ",
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); sockets[mux]->available(), " vs ", len_orig);
} }
data = ""; data = "";
} else if (data.endsWith(GF("+TCPCLOSE:"))) { } else if (data.endsWith(GF("+TCPCLOSE:"))) {
int mux = stream.readStringUntil(',').toInt(); int8_t mux = streamGetIntBefore(',');
stream.readStringUntil('\n'); streamSkipUntil('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
sockets[mux]->sock_connected = false; sockets[mux]->sock_connected = false;
} }
@@ -565,9 +420,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
finish: finish:
if (!index) { if (!index) {
data.trim(); data.trim();
if (data.length()) { if (data.length()) { DBG("### Unhandled:", data); }
DBG("### Unhandled:", data);
}
data = ""; data = "";
} }
// data.replace(GSM_NL, "/"); // data.replace(GSM_NL, "/");
@@ -575,25 +428,33 @@ finish:
return index; return index;
} }
uint8_t waitResponse(uint32_t timeout_ms, int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) #if defined TINY_GSM_DEBUG
{ GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data; String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
} }
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r2 = GFP(GSM_ERROR),
{ #if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5); return waitResponse(1000, r1, r2, r3, r4, r5);
} }
public:
Stream& stream;
protected: protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT]; Stream& stream;
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
}; };
#endif #endif // SRC_TINYGSMCLIENTM590_H_

View File

@@ -2,35 +2,38 @@
* @file TinyGsmClientM95.h * @file TinyGsmClientM95.h
* @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd. * @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
* @license LGPL-3.0 * @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com> * @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd.
* <http://www.replicade.com>
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClientM95_h #ifndef SRC_TINYGSMCLIENTM95_H_
#define TinyGsmClientM95_h #define SRC_TINYGSMCLIENTM95_H_
// #pragma message("TinyGSM: TinyGsmClientM95") // #pragma message("TinyGSM: TinyGsmClientM95")
// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
#define TINY_GSM_MUX_COUNT 6 #define TINY_GSM_MUX_COUNT 6
#define TINY_GSM_BUFFER_READ_NO_CHECK
#include <TinyGsmCommon.h> #include "TinyGsmBattery.tpp"
#include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n" #define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
enum SimStatus { static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
SIM_ERROR = 0, #endif
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus { enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0, REG_UNREGISTERED = 0,
REG_SEARCHING = 2, REG_SEARCHING = 2,
REG_DENIED = 3, REG_DENIED = 3,
@@ -39,33 +42,48 @@ enum RegStatus {
REG_UNKNOWN = 4, REG_UNKNOWN = 4,
}; };
class TinyGsmM95 : public TinyGsmModem<TinyGsmM95>,
public TinyGsmGPRS<TinyGsmM95>,
public TinyGsmTCP<TinyGsmM95, TINY_GSM_MUX_COUNT>,
public TinyGsmCalling<TinyGsmM95>,
public TinyGsmSMS<TinyGsmM95>,
public TinyGsmTime<TinyGsmM95>,
public TinyGsmBattery<TinyGsmM95>,
public TinyGsmTemperature<TinyGsmM95> {
friend class TinyGsmModem<TinyGsmM95>;
friend class TinyGsmGPRS<TinyGsmM95>;
friend class TinyGsmTCP<TinyGsmM95, TINY_GSM_MUX_COUNT>;
friend class TinyGsmCalling<TinyGsmM95>;
friend class TinyGsmSMS<TinyGsmM95>;
friend class TinyGsmTime<TinyGsmM95>;
friend class TinyGsmBattery<TinyGsmM95>;
friend class TinyGsmTemperature<TinyGsmM95>;
class TinyGsmM95 /*
{ * Inner Client
*/
public: public:
class GsmClientM95 : public GsmClient {
class GsmClient : public Client
{
friend class TinyGsmM95; friend class TinyGsmM95;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public: public:
GsmClient() {} GsmClientM95() {}
GsmClient(TinyGsmM95& modem, uint8_t mux = 1) { explicit GsmClientM95(TinyGsmM95& modem, uint8_t mux = 0) {
init(&modem, mux); init(&modem, mux);
} }
virtual ~GsmClient(){} bool init(TinyGsmM95* modem, uint8_t mux = 0) {
bool init(TinyGsmM95* modem, uint8_t mux = 1) {
this->at = modem; this->at = modem;
this->mux = mux;
sock_available = 0; sock_available = 0;
sock_connected = false; sock_connected = false;
at->sockets[mux] = this; if (mux < TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT);
}
at->sockets[this->mux] = this;
return true; return true;
} }
@@ -78,92 +96,76 @@ public:
sock_connected = at->modemConnect(host, port, mux, false, timeout_s); sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_CONNECT_OVERLOADS() void stop(uint32_t maxWaitMs) {
uint32_t startMillis = millis();
virtual void stop(uint32_t maxWaitMs) { dumpModemBuffer(maxWaitMs);
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
at->sendAT(GF("+QICLOSE="), mux); at->sendAT(GF("+QICLOSE="), mux);
sock_connected = false; sock_connected = false;
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR")); at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
GF("CLOSE OK"), GF("ERROR"));
}
void stop() override {
stop(75000L);
} }
virtual void stop() { stop(75000L); }
TINY_GSM_CLIENT_WRITE()
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
/* /*
* Extended API * Extended API
*/ */
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmM95* at;
uint8_t mux;
uint16_t sock_available;
bool sock_connected;
RxFifo rx;
}; };
/*
* Inner Secure Client
*/
// class GsmClientSecure : public GsmClient /*
// { class GsmClientSecureM95 : public GsmClientM95
// public: {
// GsmClientSecure() {} public:
// GsmClientSecure() {}
// GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
// : GsmClient(modem, mux) GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 0)
// {} : GsmClient(modem, mux)
// {}
// virtual ~GsmClientSecure() {}
//
// public:
// virtual int connect(const char *host, uint16_t port, int timeout_s) {
// stop();
// TINY_GSM_YIELD();
// rx.clear();
// sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
// return sock_connected;
// }
// };
public: public:
int connect(const char* host, uint16_t port, int timeout_s) override {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
TINY_GSM_CLIENT_CONNECT_OVERRIDES
};
*/
TinyGsmM95(Stream& stream) /*
: stream(stream) * Constructor
{ */
public:
explicit TinyGsmM95(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets)); memset(sockets, 0, sizeof(sockets));
} }
virtual ~TinyGsmM95() {}
/* /*
* Basic functions * Basic functions
*/ */
protected:
bool begin(const char* pin = NULL) { bool initImpl(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off // sendAT(GF("&FZ")); // Factory + Reset
if (waitResponse() != 1) { // waitResponse();
return false;
} sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG #ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes sendAT(GF("+CMEE=2")); // turn on verbose error codes
@@ -174,62 +176,31 @@ public:
DBG(GF("### Modem:"), getModemName()); DBG(GF("### Modem:"), getModemName());
int ret = getSimStatus(); // Enable network time synchronization
sendAT(GF("+QNITZ=1"));
if (waitResponse(10000L) != 1) { return false; }
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim // if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin); simUnlock(pin);
return (getSimStatus() == SIM_READY); return (getSimStatus() == SIM_READY);
} } else {
// if the sim is ready, or it's locked but no pin has been provided, return // if the sim is ready, or it's locked but no pin has been provided,
// true // return true
else {
return (ret == SIM_READY || ret == SIM_LOCKED); return (ret == SIM_READY || ret == SIM_LOCKED);
} }
} }
String getModemName() {
return "Quectel M95";
}
TINY_GSM_MODEM_SET_BAUD_IPR()
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
return false; // TODO: For now
}
bool hasWifi() {
return false;
}
bool hasGPRS() {
return true;
}
/* /*
* Power functions * Power functions
*/ */
protected:
bool restart() { bool restartImpl() {
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("+CFUN=0")); sendAT(GF("+CFUN=0"));
if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) { if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) ==
3) {
return false; return false;
} }
sendAT(GF("+CFUN=1")); sendAT(GF("+CFUN=1"));
@@ -239,71 +210,31 @@ TINY_GSM_MODEM_GET_INFO_ATI()
return init(); return init();
} }
bool poweroff() { bool powerOffImpl() {
sendAT(GF("+QPOWD=1")); sendAT(GF("+QPOWD=1"));
return waitResponse(300, GF("NORMAL POWER DOWN")) == 1; return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
} }
bool radioOff() { // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
sendAT(GF("+CFUN=0")); // is pulled up, the module can directly enter into sleep mode.If entering
if (waitResponse(10000L) != 1) { // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled
return false; // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first,
// and then the module can enter into sleep mode.
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+QSCLK="), enable);
return waitResponse() == 1;
} }
delay(3000);
return true;
}
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
sendAT(GF("+QCCID"));
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/* /*
* Generic network functions * Generic network functions
*/ */
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ() protected:
bool isNetworkConnectedImpl() {
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus(); RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING); return (s == REG_OK_HOME || s == REG_OK_ROAMING);
} }
@@ -317,63 +248,55 @@ TINY_GSM_MODEM_GET_CSQ()
waitResponse(); waitResponse();
} }
TINY_GSM_MODEM_WAIT_FOR_NETWORK() String getLocalIPImpl() {
sendAT(GF("+QILOCIP"));
streamSkipUntil('\n');
String res = stream.readStringUntil('\n');
res.trim();
return res;
}
/* /*
* GPRS functions * GPRS functions
*/ */
protected:
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect(); gprsDisconnect();
// select foreground context 0 = VIRTUAL_UART_1 // select foreground context 0 = VIRTUAL_UART_1
sendAT(GF("+QIFGCNT=0")); sendAT(GF("+QIFGCNT=0"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
// Select GPRS (=1) as the Bearer // Select GPRS (=1) as the Bearer
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
if (waitResponse() != 1) { GF("\""));
return false; if (waitResponse() != 1) { return false; }
}
// Select TCP/IP transfer mode - NOT transparent mode // Select TCP/IP transfer mode - NOT transparent mode
sendAT(GF("+QIMODE=0")); sendAT(GF("+QIMODE=0"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
// Enable multiple TCP/IP connections // Enable multiple TCP/IP connections
sendAT(GF("+QIMUX=1")); sendAT(GF("+QIMUX=1"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
// Start TCPIP Task and Set APN, User Name and Password // Start TCPIP Task and Set APN, User Name and Password
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\""); sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"");
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
// Activate GPRS/CSD Context // Activate GPRS/CSD Context
sendAT(GF("+QIACT")); sendAT(GF("+QIACT"));
if (waitResponse(60000L) != 1) { if (waitResponse(60000L) != 1) { return false; }
return false;
}
// Check that we have a local IP address // Check that we have a local IP address
if (localIP() == IPAddress(0,0,0,0)) { if (localIP() == IPAddress(0, 0, 0, 0)) { return false; }
return false;
}
// Set Method to Handle Received TCP/IP Data // Set Method to Handle Received TCP/IP Data
// Mode = 1 - Output a notification when data is received // Mode = 1 - Output a notification when data is received
// +QIRDI: <id>,<sc>,<sid> // +QIRDI: <id>,<sc>,<sid>
sendAT(GF("+QINDI=1")); sendAT(GF("+QINDI=1"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
// // Request an IP header for received data // // Request an IP header for received data
// // "IPD(data length):" // // "IPD(data length):"
@@ -389,7 +312,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// return false; // return false;
// } // }
// //
// // Do NOT show the protocol type at the end of the header for received data // // Do NOT show the protocol type at the end of the header for received
// data
// // IPD(data length)(TCP/UDP): // // IPD(data length)(TCP/UDP):
// sendAT(GF("+QISHOWPT=0")); // sendAT(GF("+QISHOWPT=0"));
// if (waitResponse() != 1) { // if (waitResponse() != 1) {
@@ -406,103 +330,37 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
return true; return true;
} }
bool gprsDisconnect() { bool gprsDisconnectImpl() {
sendAT(GF("+QIDEACT")); sendAT(GF("+QIDEACT")); // Deactivate the bearer context
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1; return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
} }
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/* /*
* IP Address functions * SIM card functions
*/ */
protected:
String getLocalIP() { String getSimCCIDImpl() {
sendAT(GF("+QILOCIP")); sendAT(GF("+QCCID"));
stream.readStringUntil('\n'); if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n'); String res = stream.readStringUntil('\n');
waitResponse();
res.trim(); res.trim();
return res; return res;
} }
IPAddress localIP() { /*
return TinyGsmIpFromString(getLocalIP()); * Phone Call functions
} */
protected:
// Can follow all of the phone call functions from the template
/* /*
* Messaging functions * Messaging functions
*/ */
protected:
// Can follow all template functions
String sendUSSD(const String& code) { public:
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("+CSMP=17,167,0,8"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
uint16_t* t = (uint16_t*)text;
for (size_t i=0; i<len; i++) {
uint8_t c = t[i] >> 8;
if (c < 0x10) { stream.print('0'); }
stream.print(c, HEX);
c = t[i] & 0xFF;
if (c < 0x10) { stream.print('0'); }
stream.print(c, HEX);
}
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
/** Delete all SMS */ /** Delete all SMS */
bool deleteAllSMS() { bool deleteAllSMS() {
sendAT(GF("+QMGDA=6")); sendAT(GF("+QMGDA=6"));
@@ -513,87 +371,30 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
} }
/* /*
* Phone Call functions * Time functions
*/ */
protected:
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; // Can follow the standard CCLK function in the template
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Location functions * Battery functions
*/ */
// Can follow the battery functions in the template
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/* /*
* Battery & temperature functions * Temperature functions
*/ */
protected:
// Use: float vBatt = modem.getBattVoltage() / 1000.0; float getTemperatureImpl() {
uint16_t getBattVoltage() {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip battery charge status
streamSkipUntil(','); // Skip battery charge level
// return voltage in mV
uint16_t res = stream.readStringUntil(',').toInt();
// Wait for final OK
waitResponse();
return res;
}
int8_t getBattPercent() {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return false;
}
streamSkipUntil(','); // Skip battery charge status
// Read battery charge level
int res = stream.readStringUntil(',').toInt();
// Wait for final OK
waitResponse();
return res;
}
uint8_t getBattChargeState() {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return false;
}
// Read battery charge status
int res = stream.readStringUntil(',').toInt();
// Wait for final OK
waitResponse();
return res;
}
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return false;
}
chargeState = stream.readStringUntil(',').toInt();
percent = stream.readStringUntil(',').toInt();
milliVolts = stream.readStringUntil('\n').toInt();
// Wait for final OK
waitResponse();
return true;
}
float getTemperature() {
sendAT(GF("+QTEMP")); sendAT(GF("+QTEMP"));
if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) { if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) {
return (float)-9999; return static_cast<float>(-9999);
} }
streamSkipUntil(','); // Skip mode streamSkipUntil(','); // Skip mode
// Read charge of thermistor // Read charge of thermistor
// milliVolts = stream.readStringUntil(',').toInt(); // milliVolts = streamGetIntBefore(',');
streamSkipUntil(','); // Skip thermistor charge streamSkipUntil(','); // Skip thermistor charge
float temp = stream.readStringUntil('\n').toFloat(); float temp = streamGetFloatBefore('\n');
// Wait for final OK // Wait for final OK
waitResponse(); waitResponse();
return temp; return temp;
@@ -602,18 +403,14 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/* /*
* Client related functions * Client related functions
*/ */
protected: protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) { bool ssl = false, int timeout_s = 75) {
if (ssl) { if (ssl) { DBG("SSL not yet supported on this module!"); }
DBG("SSL not yet supported on this module!");
}
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
int rsp = waitResponse(timeout_ms, GF("\","), port);
GF("CONNECT OK" GSM_NL), int8_t rsp = waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL), GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL)); GF("ALREADY CONNECT" GSM_NL));
return (1 == rsp); return (1 == rsp);
@@ -621,14 +418,10 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) { int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) { if (waitResponse(GF(">")) != 1) { return 0; }
return 0; stream.write(reinterpret_cast<const uint8_t*>(buff), len);
}
stream.write((uint8_t*)buff, len);
stream.flush(); stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
return 0;
}
// bool allAcknowledged = false; // bool allAcknowledged = false;
// // bool failed = false; // // bool failed = false;
@@ -640,18 +433,18 @@ protected:
// streamSkipUntil(','); // Skip total length sent on connection // streamSkipUntil(','); // Skip total length sent on connection
// streamSkipUntil(','); // Skip length already acknowledged by remote // streamSkipUntil(','); // Skip length already acknowledged by remote
// // Make sure the total length un-acknowledged is 0 // // Make sure the total length un-acknowledged is 0
// if ( stream.readStringUntil('\n').toInt() == 0 ) { // if ( streamGetIntBefore('\n') == 0 ) {
// allAcknowledged = true; // allAcknowledged = true;
// } // }
// } // }
// } // }
// waitResponse(5000L); // waitResponse(5000L);
return len; // TODO return len; // TODO(?): get len/ack properly
} }
size_t modemRead(size_t size, uint8_t mux) { size_t modemRead(size_t size, uint8_t mux) {
// TODO: Does this work???? // TODO(?): Does this work????
// AT+QIRD=<id>,<sc>,<sid>,<len> // AT+QIRD=<id>,<sc>,<sid>,<len>
// id = GPRS context number = 0, set in GPRS connect // id = GPRS context number = 0, set in GPRS connect
// sc = role in connection = 1, client of connection // sc = role in connection = 1, client of connection
@@ -660,27 +453,27 @@ protected:
sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size); sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size);
// If it replies only OK for the write command, it means there is no // If it replies only OK for the write command, it means there is no
// received data in the buffer of the connection. // received data in the buffer of the connection.
int res = waitResponse(GF("+QIRD:"), GFP(GSM_OK), GFP(GSM_ERROR)); int8_t res = waitResponse(GF("+QIRD:"), GFP(GSM_OK), GFP(GSM_ERROR));
if (res == 1) { if (res == 1) {
streamSkipUntil(':'); // skip IP address streamSkipUntil(':'); // skip IP address
streamSkipUntil(','); // skip port streamSkipUntil(','); // skip port
streamSkipUntil(','); // skip connection type (TCP/UDP) streamSkipUntil(','); // skip connection type (TCP/UDP)
// read the real length of the retrieved data // read the real length of the retrieved data
uint16_t len = stream.readStringUntil('\n').toInt(); uint16_t len = streamGetIntBefore('\n');
// We have no way of knowing in advance how much data will be in the buffer // We have no way of knowing in advance how much data will be in the
// so when data is received we always assume the buffer is completely full. // buffer so when data is received we always assume the buffer is
// Chances are, this is not true and there's really not that much there. // completely full. Chances are, this is not true and there's really not
// In that case, make sure we make sure we re-set the amount of data available. // that much there. In that case, make sure we make sure we re-set the
if (len < size) { // amount of data available.
sockets[mux]->sock_available = len; if (len < size) { sockets[mux]->sock_available = len; }
}
for (uint16_t i = 0; i < len; i++) { for (uint16_t i = 0; i < len; i++) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT moveCharFromStreamToFifo(mux);
sockets[mux]->sock_available--; sockets[mux]->sock_available--;
// ^^ One less character available after moving from modem's FIFO to our FIFO // ^^ One less character available after moving from modem's FIFO to our
// FIFO
} }
waitResponse(); // ends with an OK waitResponse(); // ends with an OK
DBG("### READ:", len, "from", mux); // DBG("### READ:", len, "from", mux);
return len; return len;
} else { } else {
sockets[mux]->sock_available = 0; sockets[mux]->sock_available = 0;
@@ -688,19 +481,22 @@ protected:
} }
} }
size_t modemGetAvailable(uint8_t) {
return 0;
}
bool modemGetConnected(uint8_t mux) { bool modemGetConnected(uint8_t mux) {
sendAT(GF("+QISTATE=1,"), mux); sendAT(GF("+QISTATE=1,"), mux);
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
if (waitResponse(GF("+QISTATE:"))) if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
return false;
streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state int8_t res = streamGetIntBefore(','); // socket state
waitResponse(); waitResponse();
@@ -708,19 +504,20 @@ protected:
return 2 == res; return 2 == res;
} }
public:
/* /*
Utilities * Utilities
*/ */
public:
TINY_GSM_MODEM_STREAM_UTILITIES() // TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
// TODO: Optimize this! GsmConstStr r1 = GFP(GSM_OK),
uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), #if defined TINY_GSM_DEBUG
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r3 = GFP(GSM_CME_ERROR),
{ #else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim(); /*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim(); String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim(); String r3s(r3); r3s.trim();
@@ -728,15 +525,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim(); String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64); data.reserve(64);
int index = 0; uint8_t index = 0;
unsigned long startMillis = millis(); uint32_t startMillis = millis();
do { do {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
while (stream.available() > 0) { while (stream.available() > 0) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
int a = stream.read(); int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a; data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) { if (r1 && data.endsWith(r1)) {
index = 1; index = 1;
goto finish; goto finish;
@@ -744,6 +541,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 2; index = 2;
goto finish; goto finish;
} else if (r3 && data.endsWith(r3)) { } else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3; index = 3;
goto finish; goto finish;
} else if (r4 && data.endsWith(r4)) { } else if (r4 && data.endsWith(r4)) {
@@ -755,8 +557,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
} else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) { } else if (data.endsWith(GF(GSM_NL "+QIRDI:"))) {
streamSkipUntil(','); // Skip the context streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role streamSkipUntil(','); // Skip the role
int mux = stream.readStringUntil('\n').toInt(); int8_t mux = streamGetIntBefore('\n');
DBG("### Got Data:", mux); // DBG("### Got Data:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
// We have no way of knowing how much data actually came in, so // We have no way of knowing how much data actually came in, so
// we set the value to 1500, the maximum possible size. // we set the value to 1500, the maximum possible size.
@@ -764,23 +566,25 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
} }
data = ""; data = "";
} else if (data.endsWith(GF("CLOSED" GSM_NL))) { } else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int nl = data.lastIndexOf(GSM_NL, data.length()-8); int8_t nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int coma = data.indexOf(',', nl+2); int8_t coma = data.indexOf(',', nl + 2);
int mux = data.substring(nl+2, coma).toInt(); int8_t mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false; sockets[mux]->sock_connected = false;
} }
data = ""; data = "";
DBG("### Closed: ", mux); DBG("### Closed: ", mux);
} else if (data.endsWith(GF("+QNITZ:"))) {
streamSkipUntil('\n'); // URC for time sync
data = "";
DBG("### Network time updated.");
} }
} }
} while (millis() - startMillis < timeout_ms); } while (millis() - startMillis < timeout_ms);
finish: finish:
if (!index) { if (!index) {
data.trim(); data.trim();
if (data.length()) { if (data.length()) { DBG("### Unhandled:", data); }
DBG("### Unhandled:", data);
}
data = ""; data = "";
} }
// data.replace(GSM_NL, "/"); // data.replace(GSM_NL, "/");
@@ -788,25 +592,33 @@ finish:
return index; return index;
} }
uint8_t waitResponse(uint32_t timeout_ms, int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) #if defined TINY_GSM_DEBUG
{ GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data; String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
} }
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r2 = GFP(GSM_ERROR),
{ #if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5); return waitResponse(1000, r1, r2, r3, r4, r5);
} }
public:
Stream& stream;
protected: protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT]; Stream& stream;
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
}; };
#endif #endif // SRC_TINYGSMCLIENTM95_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,58 +6,42 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmClientSIM808_h #ifndef SRC_TINYGSMCLIENTSIM808_H_
#define TinyGsmClientSIM808_h #define SRC_TINYGSMCLIENTSIM808_H_
// #pragma message("TinyGSM: TinyGsmClientSIM808") // #pragma message("TinyGSM: TinyGsmClientSIM808")
#include <TinyGsmClientSIM800.h> #include "TinyGsmClientSIM800.h"
#include "TinyGsmGPS.tpp"
class TinyGsmSim808 : public TinyGsmSim800, public TinyGsmGPS<TinyGsmSim808> {
class TinyGsmSim808: public TinyGsmSim800 friend class TinyGsmGPS<TinyGsmSim808>;
{
public: public:
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
TinyGsmSim808(Stream& stream)
: TinyGsmSim800(stream)
{}
virtual ~TinyGsmSim808(){}
/* /*
* GPS location functions * GPS/GNSS/GLONASS location functions
*/ */
protected:
// enable GPS // enable GPS
bool enableGPS() { bool enableGPSImpl() {
// uint16_t state;
sendAT(GF("+CGNSPWR=1")); sendAT(GF("+CGNSPWR=1"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
return true; return true;
} }
bool disableGPS() { bool disableGPSImpl() {
// uint16_t state;
sendAT(GF("+CGNSPWR=0")); sendAT(GF("+CGNSPWR=0"));
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
}
return true; return true;
} }
// get the RAW GPS output // get the RAW GPS output
// works only with ans SIM808 V2 // works only with ans SIM808 V2
String getGPSraw() { String getGPSrawImpl() {
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
return "";
}
String res = stream.readStringUntil('\n'); String res = stream.readStringUntil('\n');
waitResponse(); waitResponse();
res.trim(); res.trim();
@@ -66,87 +50,83 @@ public:
// get GPS informations // get GPS informations
// works only with ans SIM808 V2 // works only with ans SIM808 V2
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) { bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
//String buffer = ""; int* vsat = 0, int* usat = 0, float* accuracy = 0,
// char chr_buffer[12]; int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
bool fix = false; int* minute = 0, int* second = 0) {
sendAT(GF("+CGNSINF")); sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { if (waitResponse(10000L, GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
return false;
}
stream.readStringUntil(','); // mode streamSkipUntil(','); // GNSS run status
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; if (streamGetIntBefore(',') == 1) { // fix status
stream.readStringUntil(','); //utctime // init variables
*lat = stream.readStringUntil(',').toFloat(); //lat float ilat = 0;
*lon = stream.readStringUntil(',').toFloat(); //lon float ilon = 0;
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon float ispeed = 0;
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed float ialt = 0;
stream.readStringUntil(','); int ivsat = 0;
stream.readStringUntil(','); int iusat = 0;
stream.readStringUntil(','); float iaccuracy = 0;
stream.readStringUntil(','); int iyear = 0;
stream.readStringUntil(','); int imonth = 0;
stream.readStringUntil(','); int iday = 0;
stream.readStringUntil(','); int ihour = 0;
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites int imin = 0;
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites float secondWithSS = 0;
stream.readStringUntil('\n');
// UTC date & Time
iyear = streamGetIntLength(4); // Four digit year
imonth = streamGetIntLength(2); // Two digit month
iday = streamGetIntLength(2); // Two digit day
ihour = streamGetIntLength(2); // Two digit hour
imin = streamGetIntLength(2); // Two digit minute
secondWithSS =
streamGetFloatBefore(','); // 6 digit second with subseconds
ilat = streamGetFloatBefore(','); // Latitude
ilon = streamGetFloatBefore(','); // Longitude
ialt = streamGetFloatBefore(','); // MSL Altitude. Unit is meters
ispeed = streamGetFloatBefore(','); // Speed Over Ground. Unit is knots.
streamSkipUntil(','); // Course Over Ground. Degrees.
streamSkipUntil(','); // Fix Mode
streamSkipUntil(','); // Reserved1
iaccuracy =
streamGetFloatBefore(','); // Horizontal Dilution Of Precision
streamSkipUntil(','); // Position Dilution Of Precision
streamSkipUntil(','); // Vertical Dilution Of Precision
streamSkipUntil(','); // Reserved2
ivsat = streamGetIntBefore(','); // GNSS Satellites in View
iusat = streamGetIntBefore(','); // GNSS Satellites Used
streamSkipUntil(','); // GLONASS Satellites Used
streamSkipUntil(','); // Reserved3
streamSkipUntil(','); // C/N0 max
streamSkipUntil(','); // HPA
streamSkipUntil('\n'); // VPA
// Set pointers
if (lat != NULL) *lat = ilat;
if (lon != NULL) *lon = ilon;
if (speed != NULL) *speed = ispeed;
if (alt != NULL) *alt = ialt;
if (vsat != NULL) *vsat = ivsat;
if (usat != NULL) *usat = iusat;
if (accuracy != NULL) *accuracy = iaccuracy;
if (iyear < 2000) iyear += 2000;
if (year != NULL) *year = iyear;
if (month != NULL) *month = imonth;
if (day != NULL) *day = iday;
if (hour != NULL) *hour = ihour;
if (minute != NULL) *minute = imin;
if (second != NULL) *second = static_cast<int>(secondWithSS);
waitResponse(); waitResponse();
return fix;
}
// get GPS time
// works only with SIM808 V2
bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) {
bool fix = false;
char chr_buffer[12];
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return false;
}
for (int i = 0; i < 3; i++) {
String buffer = stream.readStringUntil(',');
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
switch (i) {
case 0:
//mode
break;
case 1:
//fixstatus
if ( buffer.toInt() == 1 ) {
fix = buffer.toInt();
}
break;
case 2:
*year = buffer.substring(0,4).toInt();
*month = buffer.substring(4,6).toInt();
*day = buffer.substring(6,8).toInt();
*hour = buffer.substring(8,10).toInt();
*minute = buffer.substring(10,12).toInt();
*second = buffer.substring(12,14).toInt();
break;
default:
// if nothing else matches, do the default
// default is optional
break;
}
}
String res = stream.readStringUntil('\n');
waitResponse();
if (fix) {
return true; return true;
} else {
return false;
}
} }
streamSkipUntil('\n'); // toss the row of commas
waitResponse();
return false;
}
}; };
#endif #endif // SRC_TINYGSMCLIENTSIM808_H_

File diff suppressed because it is too large Load Diff

View File

@@ -6,30 +6,32 @@
* @date Jan 2019 * @date Jan 2019
*/ */
#ifndef TinyGsmClientSequansMonarch_h #ifndef SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
#define TinyGsmClientSequansMonarch_h #define SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
#define TINY_GSM_MUX_COUNT 6 #define TINY_GSM_MUX_COUNT 6
#define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
#include <TinyGsmCommon.h> #include "TinyGsmCalling.tpp"
#include "TinyGsmGPRS.tpp"
#include "TinyGsmModem.tpp"
#include "TinyGsmSMS.tpp"
#include "TinyGsmSSL.tpp"
#include "TinyGsmTCP.tpp"
#include "TinyGsmTemperature.tpp"
#include "TinyGsmTime.tpp"
#define GSM_NL "\r\n" #define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
#if defined TINY_GSM_DEBUG
enum SimStatus { static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
SIM_ERROR = 0, #endif
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus { enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0, REG_UNREGISTERED = 0,
REG_SEARCHING = 2, REG_SEARCHING = 2,
REG_DENIED = 3, REG_DENIED = 3,
@@ -48,29 +50,41 @@ enum SocketStatus {
SOCK_OPENING = 6, SOCK_OPENING = 6,
}; };
class TinyGsmSequansMonarch class TinyGsmSequansMonarch
{ : public TinyGsmModem<TinyGsmSequansMonarch>,
public TinyGsmGPRS<TinyGsmSequansMonarch>,
public TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>,
public TinyGsmSSL<TinyGsmSequansMonarch>,
public TinyGsmCalling<TinyGsmSequansMonarch>,
public TinyGsmSMS<TinyGsmSequansMonarch>,
public TinyGsmTime<TinyGsmSequansMonarch>,
public TinyGsmTemperature<TinyGsmSequansMonarch> {
friend class TinyGsmModem<TinyGsmSequansMonarch>;
friend class TinyGsmGPRS<TinyGsmSequansMonarch>;
friend class TinyGsmTCP<TinyGsmSequansMonarch, TINY_GSM_MUX_COUNT>;
friend class TinyGsmSSL<TinyGsmSequansMonarch>;
friend class TinyGsmCalling<TinyGsmSequansMonarch>;
friend class TinyGsmSMS<TinyGsmSequansMonarch>;
friend class TinyGsmTime<TinyGsmSequansMonarch>;
friend class TinyGsmTemperature<TinyGsmSequansMonarch>;
/*
* Inner Client
*/
public: public:
class GsmClientSequansMonarch : public GsmClient {
class GsmClient : public Client
{
friend class TinyGsmSequansMonarch; friend class TinyGsmSequansMonarch;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public: public:
GsmClient() {} GsmClientSequansMonarch() {}
GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) { explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem,
uint8_t mux = 1) {
init(&modem, mux); init(&modem, mux);
} }
virtual ~GsmClient(){}
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) { bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
this->at = modem; this->at = modem;
this->mux = mux;
sock_available = 0; sock_available = 0;
prev_check = 0; prev_check = 0;
sock_connected = false; sock_connected = false;
@@ -78,6 +92,11 @@ public:
// adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers // adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
// using modulus will force 6 back to 0 // using modulus will force 6 back to 0
if (mux >= 1 && mux <= TINY_GSM_MUX_COUNT) {
this->mux = mux;
} else {
this->mux = (mux % TINY_GSM_MUX_COUNT) + 1;
}
at->sockets[mux % TINY_GSM_MUX_COUNT] = this; at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
return true; return true;
@@ -91,59 +110,42 @@ public:
sock_connected = at->modemConnect(host, port, mux, false, timeout_s); sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
TINY_GSM_CLIENT_CONNECT_OVERLOADS() void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
at->sendAT(GF("+SQNSH="), mux); at->sendAT(GF("+SQNSH="), mux);
sock_connected = false; sock_connected = false;
at->waitResponse(); at->waitResponse();
} }
void stop() override {
virtual void stop() { stop(15000L); } stop(15000L);
}
TINY_GSM_CLIENT_WRITE()
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
/* /*
* Extended API * Extended API
*/ */
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmSequansMonarch* at;
uint8_t mux;
uint16_t sock_available;
uint32_t prev_check;
bool sock_connected;
bool got_data;
RxFifo rx;
}; };
/*
class GsmClientSecure : public GsmClient * Inner Secure Client
{ */
public: public:
GsmClientSecure() {} class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch {
public:
GsmClientSecureSequansMonarch() {}
GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1) explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem,
: GsmClient(modem, mux) uint8_t mux = 1)
{} : GsmClientSequansMonarch(modem, mux) {}
virtual ~GsmClientSecure(){}
protected: protected:
bool strictSSL = false; bool strictSSL = false;
public: public:
virtual int connect(const char *host, uint16_t port, int timeout_s) { int connect(const char* host, uint16_t port, int timeout_s) override {
stop(); stop();
TINY_GSM_YIELD(); TINY_GSM_YIELD();
rx.clear(); rx.clear();
@@ -152,7 +154,8 @@ public:
if (strictSSL) { if (strictSSL) {
// require minimum of TLS 1.2 (3) // require minimum of TLS 1.2 (3)
// only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256 // only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
// verify server certificate against imported CA certs 0 and enforce validity period (3) // verify server certificate against imported CA certs 0 and enforce
// validity period (3)
at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\"")); at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
} else { } else {
// use TLS 1.0 or higher (1) // use TLS 1.0 or higher (1)
@@ -168,69 +171,102 @@ public:
sock_connected = at->modemConnect(host, port, mux, true, timeout_s); sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected; return sock_connected;
} }
TINY_GSM_CLIENT_CONNECT_OVERRIDES
void setStrictSSL(bool strict) { void setStrictSSL(bool strict) {
strictSSL = strict; strictSSL = strict;
} }
}; };
/*
* Constructor
*/
public: public:
explicit TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
TinyGsmSequansMonarch(Stream& stream)
: stream(stream)
{
memset(sockets, 0, sizeof(sockets)); memset(sockets, 0, sizeof(sockets));
} }
virtual ~TinyGsmSequansMonarch() {}
/* /*
* Basic functions * Basic functions
*/ */
protected:
bool begin(const char* pin = NULL) { bool initImpl(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("E0")); // Echo Off sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { if (waitResponse() != 1) { return false; }
return false;
} #ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
#else
sendAT(GF("+CMEE=0")); // turn off error codes
#endif
waitResponse();
DBG(GF("### Modem:"), getModemName()); DBG(GF("### Modem:"), getModemName());
int ret = getSimStatus(); // Make sure the module is enabled. Unlike others, the VZN20Q powers on
// with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full
// functionality The module cannot even detect the sim card if the cellular
// functionality is disabled so unless we explicitly enable the
// functionality the init will fail.
sendAT(GF("+CFUN=1"));
waitResponse();
// Disable time and time zone URC's
sendAT(GF("+CTZR=0"));
if (waitResponse(10000L) != 1) { return false; }
// Enable automatic time zome update
sendAT(GF("+CTZU=1"));
if (waitResponse(10000L) != 1) { return false; }
SimStatus ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim // if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin); simUnlock(pin);
return (getSimStatus() == SIM_READY); return (getSimStatus() == SIM_READY);
} } else {
// if the sim is ready, or it's locked but no pin has been provided, return // if the sim is ready, or it's locked but no pin has been provided,
// true // return true
else {
return (ret == SIM_READY || ret == SIM_LOCKED); return (ret == SIM_READY || ret == SIM_LOCKED);
} }
} }
String getModemName() { String getModemNameImpl() {
return "Sequans Monarch"; sendAT(GF("+CGMI"));
String res1;
if (waitResponse(1000L, res1) != 1) { return "unknown"; }
res1.replace("\r\nOK\r\n", "");
res1.replace("\rOK\r", "");
res1.trim();
sendAT(GF("+CGMM"));
String res2;
if (waitResponse(1000L, res2) != 1) { return "unknown"; }
res2.replace("\r\nOK\r\n", "");
res2.replace("\rOK\r", "");
res2.trim();
String name = res1 + String(' ') + res2;
DBG("### Modem:", name);
return name;
} }
TINY_GSM_MODEM_SET_BAUD_IPR() bool factoryDefaultImpl() {
sendAT(GF("&F0")); // Factory
waitResponse();
sendAT(GF("Z")); // default configuration
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
return waitResponse() == 1;
}
TINY_GSM_MODEM_TEST_AT() void maintainImpl() {
void maintain() {
for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) { for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) {
GsmClient* sock = sockets[mux % TINY_GSM_MUX_COUNT]; GsmClientSequansMonarch* sock = sockets[mux % TINY_GSM_MUX_COUNT];
if (sock && sock->got_data) { if (sock && sock->got_data) {
sock->got_data = false; sock->got_data = false;
sock->sock_available = modemGetAvailable(mux); sock->sock_available = modemGetAvailable(mux);
@@ -238,147 +274,73 @@ TINY_GSM_MODEM_TEST_AT()
modemGetConnected(); modemGetConnected();
} }
} }
while (stream.available()) { while (stream.available()) { waitResponse(15, NULL, NULL); }
waitResponse(15, NULL, NULL);
}
}
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
waitResponse();
sendAT(GF("+IFC=0,0")); // No Flow Control
waitResponse();
sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
waitResponse();
sendAT(GF("+CSCLK=0")); // Disable Slow Clock
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
return true;
} }
/* /*
* Power functions * Power functions
*/ */
protected:
bool restart() { bool restartImpl() {
if (!testAT()) { if (!testAT()) { return false; }
return false;
}
sendAT(GF("+CFUN=0")); sendAT(GF("+CFUN=0"));
int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ; int8_t res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR),
if (res != 1 && res != 3) { GF("+SYSSTART"));
return false; if (res != 1 && res != 3) { return false; }
}
sendAT(GF("+CFUN=1,1")); sendAT(GF("+CFUN=1,1"));
res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)); res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR));
if (res != 1 && res != 3) { if (res != 1 && res != 3) { return false; }
return false;
}
delay(1000); delay(1000);
return init(); return init();
} }
bool poweroff() { bool powerOffImpl() {
// NOTE: The only way to turn the modem back on after this shutdown is with
// a hard reset
sendAT(GF("+SQNSSHDN")); sendAT(GF("+SQNSSHDN"));
return waitResponse(); return waitResponse();
} }
bool radioOff() { // When power saving is enabled, UART0 interface is activated with sleep mode
sendAT(GF("+CFUN=0")); // support. Module power state is controlled by RTS0 line. When no activity
if (waitResponse(10000L) != 1) { // on UART, CTS line will be set to OFF state (driven high level) <timeout>
return false; // milliseconds (100ms to 10s, default 5s) after the last sent character,
} // then module will go to sleep mode as soon as DTE set RTS line to OFF state
delay(3000); // (driver high level).
return true; bool sleepEnableImpl(bool enable = true) {
}
/*
When power saving is enabled, UART0 interface is activated with sleep mode support.
Module power state is controlled by RTS0 line. When no activity on UART, CTS line
will be set to OFF state (driven high level) <timeout> milliseconds (100ms to 10s,
default 5s) after the last sent character, then module will go to sleep mode as soon
as DTE set RTS line to OFF state (driver high level).
*/
bool sleepEnable(bool enable = true) {
sendAT(GF("+SQNIPSCFG="), enable); sendAT(GF("+SQNIPSCFG="), enable);
return waitResponse() == 1; return waitResponse() == 1;
} }
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
sendAT(GF("+SQNCCID"));
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CEREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/* /*
* Generic network functions * Generic network functions
*/ */
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CEREG");
}
TINY_GSM_MODEM_GET_CSQ() protected:
bool isNetworkConnectedImpl() {
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus(); RegStatus s = getRegistrationStatus();
if (s == REG_OK_HOME || s == REG_OK_ROAMING) { return (s == REG_OK_HOME || s == REG_OK_ROAMING);
// DBG(F("connected with status:"), s);
return true;
} else {
return false;
} }
String getLocalIPImpl() {
sendAT(GF("+CGPADDR=3"));
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; }
String res = stream.readStringUntil('\"');
waitResponse();
return res;
} }
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/* /*
* GPRS functions * GPRS functions
*/ */
protected:
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect(); gprsDisconnect();
// Define the PDP context (This uses context #3!) // Define the PDP context (This uses context #3!)
@@ -397,123 +359,71 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// Attach to GPRS // Attach to GPRS
sendAT(GF("+CGATT=1")); sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) if (waitResponse(60000L) != 1) { return false; }
return false;
return true; return true;
} }
bool gprsDisconnect() { bool gprsDisconnectImpl() {
sendAT(GF("+CGATT=0")); sendAT(GF("+CGATT=0"));
if (waitResponse(60000L) != 1) if (waitResponse(60000L) != 1) { return false; }
return false;
return true; return true;
} }
bool isGprsConnected() {
sendAT(GF("+CGATT?"));
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
return false;
}
int res = stream.readStringUntil('\n').toInt();
waitResponse();
if (res != 1)
return false;
return true;
}
/* /*
* IP Address functions * SIM card functions
*/ */
protected:
String getLocalIP() { String getSimCCIDImpl() {
sendAT(GF("+CGPADDR=3")); sendAT(GF("+SQNCCID"));
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; }
return ""; String res = stream.readStringUntil('\n');
}
String res = stream.readStringUntil('\"');
waitResponse(); waitResponse();
res.trim();
return res; return res;
} }
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/* /*
* Phone Call functions * Phone Call functions
*/ */
protected:
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
bool dtmfSendImpl(char cmd,
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/* /*
* Location functions * Messaging functions
*/ */
protected:
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; // Follows all messaging functions per template
/* /*
* Battery & temperature functions * Time functions
*/ */
protected:
// Can follow the standard CCLK function in the template
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; /*
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; * Temperature functions
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; */
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; protected:
float getTemperatureImpl() {
float getTemperature() {
sendAT(GF("+SMDTH")); sendAT(GF("+SMDTH"));
if (waitResponse(10000L, GF("+SMDTH: ")) != 1) { if (waitResponse(10000L, GF("+SMDTH: ")) != 1) {
return (float)-9999; return static_cast<float>(-9999);
} }
String res; String res;
if (waitResponse(1000L, res) != 1) { if (waitResponse(1000L, res) != 1) { return static_cast<float>(-9999); }
return (float)-9999; if (res.indexOf("ERROR") >= 0) { return static_cast<float>(-9999); }
}
if (res.indexOf("ERROR") >=0) {
return (float)-9999;
}
return res.toFloat(); return res.toFloat();
} }
protected: protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) bool ssl = false, int timeout_s = 75) {
{ int8_t rsp;
int rsp; uint32_t startMillis = millis();
unsigned long startMillis = millis();
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
if (ssl) { if (ssl) {
@@ -529,22 +439,26 @@ protected:
// Socket configuration // Socket configuration
// AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1> // AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
// <connId1> = Connection ID = mux // <connId1> = Connection ID = mux
// <cid1> = PDP context ID = 3 - this is number set up above in the GprsConnect function // <cid1> = PDP context ID = 3 - this is number set up above in the
// GprsConnect function
// <pktSz1> = Packet Size, used for online data mode only = 300 (default) // <pktSz1> = Packet Size, used for online data mode only = 300 (default)
// <maxTo1> = Max timeout in seconds = 90 (default) // <maxTo1> = Max timeout in seconds = 90 (default)
// <connTo1> = Connection timeout in hundreds of milliseconds = 600 (default) // <connTo1> = Connection timeout in hundreds of milliseconds
// <txTo1> = Data sending timeout in hundreds of milliseconds, used for online data mode only = 50 (default) // = 600 (default)
// <txTo1> = Data sending timeout in hundreds of milliseconds,
// used for online data mode only = 50 (default)
sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50")); sendAT(GF("+SQNSCFG="), mux, GF(",3,300,90,600,50"));
waitResponse(5000L); waitResponse(5000L);
// Socket configuration extended // Socket configuration extended
//AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>, <listenAutoRsp1>, <sendDataMode1> // AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>,
// <listenAutoRsp1>, <sendDataMode1>
// <connId1> = Connection ID = mux // <connId1> = Connection ID = mux
// <srMode1> = Send/Receive URC model = 1 - data amount mode // <srMode1> = Send/Receive URC model = 1 - data amount mode
// <recvDataMode1> = Receive data mode = 0 - data as text (1 would be as hex) // <recvDataMode1> = Receive data mode = 0 - data as text (1 for hex)
// <keepalive1> = unused = 0 // <keepalive1> = unused = 0
// <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated // <listenAutoRsp1> = Listen auto-response mode = 0 - deactivated
// <sendDataMode1> = Send data mode = 0 - data as text (1 would be as hex) // <sendDataMode1> = Send data mode = 0 - data as text (1 for hex)
sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0")); sendAT(GF("+SQNSCFGEXT="), mux, GF(",1,0,0,0,0"));
waitResponse(5000L); waitResponse(5000L);
@@ -553,20 +467,20 @@ protected:
// <connId> = Connection ID = mux // <connId> = Connection ID = mux
// <txProt> = Transmission protocol = 0 - TCP (1 for UDP) // <txProt> = Transmission protocol = 0 - TCP (1 for UDP)
// <rPort> = Remote host port to contact // <rPort> = Remote host port to contact
// <IPaddr> = Any valid IP address in the format xxx.xxx.xxx.xxx or any host name solved with a DNS query // <IPaddr> = Any valid IP address in the format xxx.xxx.xxx.xxx or any
// <closureType> = Socket closure behaviour for TCP, has no effect for UDP = 0 - local port closes when remote does (default) // host name solved with a DNS query
// <closureType> = Socket closure behaviour for TCP, has no effect for UDP
// = 0 - local port closes when remote does (default)
// <lPort> = UDP connection local port, has no effect for TCP connections. // <lPort> = UDP connection local port, has no effect for TCP connections.
// <connMode> = Connection mode = 1 - command mode connection // <connMode> = Connection mode = 1 - command mode connection
// <acceptAnyRemote> = Applies to UDP only // <acceptAnyRemote> = Applies to UDP only
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), ",0,0,1"); sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""),
rsp = waitResponse((timeout_ms - (millis() - startMillis)), ",0,0,1");
GFP(GSM_OK), rsp = waitResponse((timeout_ms - (millis() - startMillis)), GFP(GSM_OK),
GFP(GSM_ERROR), GFP(GSM_ERROR), GF("NO CARRIER" GSM_NL));
GF("NO CARRIER" GSM_NL)
);
// creation of socket failed immediately. // creation of socket failed immediately.
if (rsp != 1) return false; if (rsp != 1) { return false; }
// wait until we get a good status // wait until we get a good status
bool connected = false; bool connected = false;
@@ -577,7 +491,6 @@ protected:
return connected; return connected;
} }
int modemSend(const void* buff, size_t len, uint8_t mux) { int modemSend(const void* buff, size_t len, uint8_t mux) {
if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) { if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) {
DBG("### Sock closed, cannot send data!"); DBG("### Sock closed, cannot send data!");
@@ -586,7 +499,7 @@ protected:
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len); sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
waitResponse(10000L, GF(GSM_NL "> ")); waitResponse(10000L, GF(GSM_NL "> "));
stream.write((uint8_t*)buff, len); stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush(); stream.flush();
if (waitResponse() != 1) { if (waitResponse() != 1) {
DBG("### no OK after send"); DBG("### no OK after send");
@@ -605,8 +518,8 @@ protected:
// delay(50); // delay(50);
// } // }
// if (gotPrompt) { // if (gotPrompt) {
// stream.write((uint8_t*)buff, len); // stream.write(reinterpret_cast<const uint8_t*>(buff), len);
// stream.write((char)0x1A); // stream.write(reinterpret_cast<char>0x1A);
// stream.flush(); // stream.flush();
// if (waitResponse() != 1) { // if (waitResponse() != 1) {
// DBG("### no OK after send"); // DBG("### no OK after send");
@@ -617,21 +530,22 @@ protected:
// return 0; // return 0;
} }
size_t modemRead(size_t size, uint8_t mux) { size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size); sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+SQNSRECV: ")) != 1) { if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; }
return 0;
}
streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip mux
int len = stream.readStringUntil('\n').toInt(); int16_t len = streamGetIntBefore('\n');
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
uint32_t startMillis = millis(); \ uint32_t startMillis = millis();
while (!stream.available() && ((millis() - startMillis) < sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) { TINY_GSM_YIELD(); } \ while (!stream.available() &&
char c = stream.read(); \ ((millis() - startMillis) <
sockets[mux % TINY_GSM_MUX_COUNT]->_timeout)) {
TINY_GSM_YIELD();
}
char c = stream.read();
sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c); sockets[mux % TINY_GSM_MUX_COUNT]->rx.put(c);
} }
DBG("### Read:", len, "from", mux); // DBG("### READ:", len, "from", mux);
waitResponse(); waitResponse();
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = modemGetAvailable(mux); sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = modemGetAvailable(mux);
return len; return len;
@@ -644,10 +558,10 @@ protected:
streamSkipUntil(','); // Skip mux streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip total sent streamSkipUntil(','); // Skip total sent
streamSkipUntil(','); // Skip total received streamSkipUntil(','); // Skip total received
result = stream.readStringUntil(',').toInt(); // keep data not yet read result = streamGetIntBefore(','); // keep data not yet read
waitResponse(); waitResponse();
} }
DBG("### Available:", result, "on", mux); // DBG("### Available:", result, "on", mux);
return result; return result;
} }
@@ -656,11 +570,9 @@ protected:
// six possible sockets. // six possible sockets.
sendAT(GF("+SQNSS")); sendAT(GF("+SQNSS"));
for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; }
break;
};
uint8_t status = 0; uint8_t status = 0;
// if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no // if (streamGetIntBefore(',') != muxNo) { // check the mux no
// DBG("### Warning: misaligned mux numbers!"); // DBG("### Warning: misaligned mux numbers!");
// } // }
streamSkipUntil(','); // skip mux [use muxNo] streamSkipUntil(','); // skip mux [use muxNo]
@@ -675,26 +587,28 @@ protected:
// SOCK_LISTENING = 4, // SOCK_LISTENING = 4,
// SOCK_INCOMING = 5, // SOCK_INCOMING = 5,
// SOCK_OPENING = 6, // SOCK_OPENING = 6,
sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \ sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected =
((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING)); ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) &&
(status != SOCK_OPENING));
} }
waitResponse(); // Should be an OK at the end waitResponse(); // Should be an OK at the end
return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected; return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected;
} }
public:
/* /*
Utilities * Utilities
*/ */
public:
TINY_GSM_MODEM_STREAM_UTILITIES() // TODO(vshymanskyy): Optimize this!
int8_t waitResponse(uint32_t timeout_ms, String& data,
// TODO: Optimize this! GsmConstStr r1 = GFP(GSM_OK),
uint8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), #if defined TINY_GSM_DEBUG
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r3 = GFP(GSM_CME_ERROR),
{ #else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim(); /*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim(); String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim(); String r3s(r3); r3s.trim();
@@ -702,15 +616,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim(); String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64); data.reserve(64);
int index = 0; uint8_t index = 0;
unsigned long startMillis = millis(); uint32_t startMillis = millis();
do { do {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
while (stream.available() > 0) { while (stream.available() > 0) {
TINY_GSM_YIELD(); TINY_GSM_YIELD();
int a = stream.read(); int8_t a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a; data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) { if (r1 && data.endsWith(r1)) {
index = 1; index = 1;
goto finish; goto finish;
@@ -718,6 +632,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 2; index = 2;
goto finish; goto finish;
} else if (r3 && data.endsWith(r3)) { } else if (r3 && data.endsWith(r3)) {
#if defined TINY_GSM_DEBUG
if (r3 == GFP(GSM_CME_ERROR)) {
streamSkipUntil('\n'); // Read out the error
}
#endif
index = 3; index = 3;
goto finish; goto finish;
} else if (r4 && data.endsWith(r4)) { } else if (r4 && data.endsWith(r4)) {
@@ -727,17 +646,19 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5; index = 5;
goto finish; goto finish;
} else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) { } else if (data.endsWith(GF(GSM_NL "+SQNSRING:"))) {
int mux = stream.readStringUntil(',').toInt(); int8_t mux = streamGetIntBefore(',');
int len = stream.readStringUntil('\n').toInt(); int16_t len = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true; sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len; sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
} }
data = ""; data = "";
DBG("### URC Data Received:", len, "on", mux); DBG("### URC Data Received:", len, "on", mux);
} else if (data.endsWith(GF("SQNSH: "))) { } else if (data.endsWith(GF("SQNSH: "))) {
int mux = stream.readStringUntil('\n').toInt(); int8_t mux = streamGetIntBefore('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux % TINY_GSM_MUX_COUNT]) { if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false; sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected = false;
} }
data = ""; data = "";
@@ -748,9 +669,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
finish: finish:
if (!index) { if (!index) {
data.trim(); data.trim();
if (data.length()) { if (data.length()) { DBG("### Unhandled:", data); }
DBG("### Unhandled:", data);
}
data = ""; data = "";
} }
// data.replace(GSM_NL, "/"); // data.replace(GSM_NL, "/");
@@ -758,25 +677,33 @@ finish:
return index; return index;
} }
uint8_t waitResponse(uint32_t timeout_ms, int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) #if defined TINY_GSM_DEBUG
{ GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data; String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
} }
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) GsmConstStr r2 = GFP(GSM_ERROR),
{ #if defined TINY_GSM_DEBUG
GsmConstStr r3 = GFP(GSM_CME_ERROR),
#else
GsmConstStr r3 = NULL,
#endif
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
return waitResponse(1000, r1, r2, r3, r4, r5); return waitResponse(1000, r1, r2, r3, r4, r5);
} }
public:
Stream& stream;
protected: protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT]; Stream& stream;
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
}; };
#endif #endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,11 +6,11 @@
* @date Nov 2016 * @date Nov 2016
*/ */
#ifndef TinyGsmCommon_h #ifndef SRC_TINYGSMCOMMON_H_
#define TinyGsmCommon_h #define SRC_TINYGSMCOMMON_H_
// The current library version number // The current library version number
#define TINYGSM_VERSION "0.9.17" #define TINYGSM_VERSION "0.10.0"
#if defined(SPARK) || defined(PARTICLE) #if defined(SPARK) || defined(PARTICLE)
#include "Particle.h" #include "Particle.h"
@@ -28,17 +28,17 @@
#include <Client.h> #include <Client.h>
#endif #endif
#include <TinyGsmFifo.h>
#ifndef TINY_GSM_YIELD_MS #ifndef TINY_GSM_YIELD_MS
#define TINY_GSM_YIELD_MS 0 #define TINY_GSM_YIELD_MS 0
#endif #endif
#ifndef TINY_GSM_YIELD #ifndef TINY_GSM_YIELD
#define TINY_GSM_YIELD() { delay(TINY_GSM_YIELD_MS); } #define TINY_GSM_YIELD() \
{ delay(TINY_GSM_YIELD_MS); }
#endif #endif
#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type"))) #define TINY_GSM_ATTR_NOT_AVAILABLE \
__attribute__((error("Not available on this modem type")))
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented"))) #define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
#if defined(__AVR__) #if defined(__AVR__)
@@ -74,37 +74,36 @@ namespace {
TINY_GSM_DEBUG.print(GF("] ")); TINY_GSM_DEBUG.print(GF("] "));
DBG_PLAIN(args...); DBG_PLAIN(args...);
} }
} } // namespace
#else #else
#define DBG_PLAIN(...) #define DBG_PLAIN(...)
#define DBG(...) #define DBG(...)
#endif #endif
template <class T> template <class T>
const T& TinyGsmMin(const T& a, const T& b) const T& TinyGsmMin(const T& a, const T& b) {
{
return (b < a) ? b : a; return (b < a) ? b : a;
} }
template <class T> template <class T>
const T& TinyGsmMax(const T& a, const T& b) const T& TinyGsmMax(const T& a, const T& b) {
{
return (b < a) ? a : b; return (b < a) ? a : b;
} }
template <class T> template <class T>
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200) uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600,
{ uint32_t maximum = 115200) {
static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 }; static uint32_t rates[] = {115200, 57600, 38400, 19200, 9600, 74400, 74880,
230400, 460800, 2400, 4800, 14400, 28800};
for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) { for (uint8_t i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
uint32_t rate = rates[i]; uint32_t rate = rates[i];
if (rate < minimum || rate > maximum) continue; if (rate < minimum || rate > maximum) continue;
DBG("Trying baud rate", rate, "..."); DBG("Trying baud rate", rate, "...");
SerialAT.begin(rate); SerialAT.begin(rate);
delay(10); delay(10);
for (int i=0; i<10; i++) { for (int j = 0; j < 10; j++) {
SerialAT.print("AT\r\n"); SerialAT.print("AT\r\n");
String input = SerialAT.readString(); String input = SerialAT.readString();
if (input.indexOf("OK") >= 0) { if (input.indexOf("OK") >= 0) {
@@ -113,536 +112,8 @@ uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum
} }
} }
} }
SerialAT.begin(minimum);
return 0; return 0;
} }
static inline #endif // SRC_TINYGSMCOMMON_H_
IPAddress TinyGsmIpFromString(const String& strIP) {
int Parts[4] = {0, };
int Part = 0;
for (uint8_t i=0; i<strIP.length(); i++) {
char c = strIP[i];
if (c == '.') {
Part++;
if (Part > 3) {
return IPAddress(0,0,0,0);
}
continue;
} else if (c >= '0' && c <= '9') {
Parts[Part] *= 10;
Parts[Part] += c - '0';
} else {
if (Part == 3) break;
}
}
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
}
static inline
String TinyGsmDecodeHex7bit(String &instr) {
String result;
byte reminder = 0;
int bitstate = 7;
for (unsigned i=0; i<instr.length(); i+=2) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
byte b = strtol(buf, NULL, 16);
byte bb = b << (7 - bitstate);
char c = (bb + reminder) & 0x7F;
result += c;
reminder = b >> bitstate;
bitstate--;
if (bitstate == 0) {
char c = reminder;
result += c;
reminder = 0;
bitstate = 7;
}
}
return result;
}
static inline
String TinyGsmDecodeHex8bit(String &instr) {
String result;
for (unsigned i=0; i<instr.length(); i+=2) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
char b = strtol(buf, NULL, 16);
result += b;
}
return result;
}
static inline
String TinyGsmDecodeHex16bit(String &instr) {
String result;
for (unsigned i=0; i<instr.length(); i+=4) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
char b = strtol(buf, NULL, 16);
if (b) { // If high byte is non-zero, we can't handle it ;(
#if defined(TINY_GSM_UNICODE_TO_HEX)
result += "\\x";
result += instr.substring(i, i+4);
#else
result += "?";
#endif
} else {
buf[0] = instr[i+2];
buf[1] = instr[i+3];
b = strtol(buf, NULL, 16);
result += b;
}
}
return result;
}
// Connect to a IP address given as an IPAddress object by
// converting said IP address to text
#define TINY_GSM_CLIENT_CONNECT_OVERLOADS() \
virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { \
String host; host.reserve(16); \
host += ip[0]; \
host += "."; \
host += ip[1]; \
host += "."; \
host += ip[2]; \
host += "."; \
host += ip[3]; \
return connect(host.c_str(), port, timeout_s); \
} \
virtual int connect(const char *host, uint16_t port) { \
return connect(host, port, 75); \
} \
virtual int connect(IPAddress ip, uint16_t port) { \
return connect(ip, port, 75); \
}
// Writes data out on the client using the modem send functionality
#define TINY_GSM_CLIENT_WRITE() \
virtual size_t write(const uint8_t *buf, size_t size) { \
TINY_GSM_YIELD(); \
at->maintain(); \
return at->modemSend(buf, size, mux); \
} \
\
virtual size_t write(uint8_t c) {\
return write(&c, 1); \
}\
\
virtual size_t write(const char *str) { \
if (str == NULL) return 0; \
return write((const uint8_t *)str, strlen(str)); \
}
// Returns the combined number of characters available in the TinyGSM fifo
// and the modem chips internal fifo, doing an extra check-in with the
// modem to see if anything has arrived without a UURC.
#define TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() \
virtual int available() { \
TINY_GSM_YIELD(); \
if (!rx.size()) { \
/* Workaround: sometimes module forgets to notify about data arrival.
TODO: Currently we ping the module periodically,
but maybe there's a better indicator that we need to poll */ \
if (millis() - prev_check > 500) { \
got_data = true; \
prev_check = millis(); \
} \
at->maintain(); \
} \
return rx.size() + sock_available; \
}
// Returns the combined number of characters available in the TinyGSM fifo and
// the modem chips internal fifo. Use this if you don't expect to miss any URC's.
#define TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() \
virtual int available() { \
TINY_GSM_YIELD(); \
if (!rx.size()) { \
at->maintain(); \
} \
return rx.size() + sock_available; \
}
// Returns the number of characters available in the TinyGSM fifo
// Assumes the modem chip has no internal fifo
#define TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() \
virtual int available() { \
TINY_GSM_YIELD(); \
if (!rx.size() && sock_connected) { \
at->maintain(); \
} \
return rx.size(); \
}
#define TINY_GSM_CLIENT_READ_OVERLOAD() \
virtual int read() { \
uint8_t c; \
if (read(&c, 1) == 1) { \
return c; \
} \
return -1; \
}
// Reads characters out of the TinyGSM fifo, and from the modem chips internal
// fifo if avaiable, also double checking with the modem if data has arrived
// without issuing a UURC.
#define TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() \
virtual int read(uint8_t *buf, size_t size) { \
TINY_GSM_YIELD(); \
at->maintain(); \
size_t cnt = 0; \
while (cnt < size) { \
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
if (chunk > 0) { \
rx.get(buf, chunk); \
buf += chunk; \
cnt += chunk; \
continue; \
} \
/* Workaround: sometimes module forgets to notify about data arrival.
TODO: Currently we ping the module periodically,
but maybe there's a better indicator that we need to poll */ \
if (millis() - prev_check > 500) { \
got_data = true; \
prev_check = millis(); \
} \
/* TODO: Read directly into user buffer? */ \
at->maintain(); \
if (sock_available > 0) { \
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
if (n == 0) break; \
} else { \
break; \
} \
} \
return cnt; \
} \
TINY_GSM_CLIENT_READ_OVERLOAD()
// Reads characters out of the TinyGSM fifo, and from the modem chips internal
// fifo if avaiable. Use this if you don't expect to miss any URC's.
#define TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() \
virtual int read(uint8_t *buf, size_t size) { \
TINY_GSM_YIELD(); \
at->maintain(); \
size_t cnt = 0; \
while (cnt < size) { \
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
if (chunk > 0) { \
rx.get(buf, chunk); \
buf += chunk; \
cnt += chunk; \
continue; \
} \
/* TODO: Read directly into user buffer? */ \
at->maintain(); \
if (sock_available > 0) { \
int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
if (n == 0) break; \
} else { \
break; \
} \
} \
return cnt; \
} \
TINY_GSM_CLIENT_READ_OVERLOAD()
// Reads characters out of the TinyGSM fifo, waiting for any URC's from the
// modem for new data if there's nothing in the fifo. This assumes the
//modem chip itself has no fifo.
#define TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() \
virtual int read(uint8_t *buf, size_t size) { \
TINY_GSM_YIELD(); \
size_t cnt = 0; \
uint32_t _startMillis = millis(); \
while (cnt < size && millis() - _startMillis < _timeout) { \
size_t chunk = TinyGsmMin(size-cnt, rx.size()); \
if (chunk > 0) { \
rx.get(buf, chunk); \
buf += chunk; \
cnt += chunk; \
continue; \
} \
/* TODO: Read directly into user buffer? */ \
if (!rx.size() && sock_connected) { \
at->maintain(); \
} \
} \
return cnt; \
} \
\
virtual int read() { \
uint8_t c; \
if (read(&c, 1) == 1) { \
return c; \
} \
return -1; \
}
// Read and dump anything remaining in the modem's internal buffer.
// Using this in the client stop() function.
// The socket will appear open in response to connected() even after it
// closes until all data is read from the buffer.
// Doing it this way allows the external mcu to find and get all of the data
// that it wants from the socket even if it was closed externally.
#define TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() \
TINY_GSM_YIELD(); \
rx.clear(); \
at->maintain(); \
unsigned long startMillis = millis(); \
while (sock_available > 0 && (millis() - startMillis < maxWaitMs)) { \
at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux); \
rx.clear(); \
at->maintain(); \
}
// The peek, flush, and connected functions
#define TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() \
virtual int peek() { return -1; } /* TODO */ \
\
virtual void flush() { at->stream.flush(); } \
\
virtual uint8_t connected() { \
if (available()) { \
return true; \
} \
return sock_connected; \
} \
virtual operator bool() { return connected(); }
// Set baud rate via the V.25TER standard IPR command
#define TINY_GSM_MODEM_SET_BAUD_IPR() \
void setBaud(unsigned long baud) { \
sendAT(GF("+IPR="), baud); \
}
// Test response to AT commands
#define TINY_GSM_MODEM_TEST_AT() \
bool testAT(unsigned long timeout_ms = 10000L) { \
for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \
sendAT(GF("")); \
if (waitResponse(200) == 1) return true; \
delay(100); \
} \
return false; \
}
// Keeps listening for modem URC's and iterates through sockets
// to see if any data is avaiable
#define TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() \
void maintain() { \
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { \
GsmClient* sock = sockets[mux]; \
if (sock && sock->got_data) { \
sock->got_data = false; \
sock->sock_available = modemGetAvailable(mux); \
} \
} \
while (stream.available()) { \
waitResponse(15, NULL, NULL); \
} \
}
// Keeps listening for modem URC's - doesn't check socks because
// modem has no internal fifo
#define TINY_GSM_MODEM_MAINTAIN_LISTEN() \
void maintain() { \
waitResponse(100, NULL, NULL); \
}
// Asks for modem information via the V.25TER standard ATI command
// NOTE: The actual value and style of the response is quite varied
#define TINY_GSM_MODEM_GET_INFO_ATI() \
String getModemInfo() { \
sendAT(GF("I")); \
String res; \
if (waitResponse(1000L, res) != 1) { \
return ""; \
} \
res.replace(GSM_NL "OK" GSM_NL, ""); \
res.replace(GSM_NL, " "); \
res.trim(); \
return res; \
}
// Unlocks a sim via the 3GPP TS command AT+CPIN
#define TINY_GSM_MODEM_SIM_UNLOCK_CPIN() \
bool simUnlock(const char *pin) { \
if (pin && strlen(pin) > 0) { \
sendAT(GF("+CPIN=\""), pin, GF("\"")); \
return waitResponse() == 1; \
} \
return true; \
}
// Gets the CCID of a sim card via AT+CCID
#define TINY_GSM_MODEM_GET_SIMCCID_CCID() \
String getSimCCID() { \
sendAT(GF("+CCID")); \
if (waitResponse(GF(GSM_NL "+CCID:")) != 1) { \
return ""; \
} \
String res = stream.readStringUntil('\n'); \
waitResponse(); \
res.trim(); \
return res; \
}
// Asks for TA Serial Number Identification (IMEI) via the V.25TER standard AT+GSN command
#define TINY_GSM_MODEM_GET_IMEI_GSN() \
String getIMEI() { \
sendAT(GF("+GSN")); \
if (waitResponse(GF(GSM_NL)) != 1) { \
return ""; \
} \
String res = stream.readStringUntil('\n'); \
waitResponse(); \
res.trim(); \
return res; \
}
// Gets the modem's registration status via CREG/CGREG/CEREG
// CREG = Generic network registration
// CGREG = GPRS service registration
// CEREG = EPS registration for LTE modules
#define TINY_GSM_MODEM_GET_REGISTRATION_XREG(regCommand) \
RegStatus getRegistrationStatus() { \
sendAT(GF("+" #regCommand "?")); \
if (waitResponse(GF(GSM_NL "+" #regCommand ":")) != 1) { \
return REG_UNKNOWN; \
} \
streamSkipUntil(','); /* Skip format (0) */ \
int status = stream.readStringUntil('\n').toInt(); \
waitResponse(); \
return (RegStatus)status; \
}
// Gets the current network operator via the 3GPP TS command AT+COPS
#define TINY_GSM_MODEM_GET_OPERATOR_COPS() \
String getOperator() { \
sendAT(GF("+COPS?")); \
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { \
return ""; \
} \
streamSkipUntil('"'); /* Skip mode and format */ \
String res = stream.readStringUntil('"'); \
waitResponse(); \
return res; \
}
// Waits for network attachment
#define TINY_GSM_MODEM_WAIT_FOR_NETWORK() \
bool waitForNetwork(unsigned long timeout_ms = 60000L) { \
for (unsigned long start = millis(); millis() - start < timeout_ms; ) { \
if (isNetworkConnected()) { \
return true; \
} \
delay(250); \
} \
return false; \
}
// Checks if current attached to GPRS/EPS service
#define TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() \
bool isGprsConnected() { \
sendAT(GF("+CGATT?")); \
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { \
return false; \
} \
int res = stream.readStringUntil('\n').toInt(); \
waitResponse(); \
if (res != 1) \
return false; \
\
return localIP() != IPAddress(0,0,0,0); \
}
// Gets signal quality report according to 3GPP TS command AT+CSQ
#define TINY_GSM_MODEM_GET_CSQ() \
int16_t getSignalQuality() { \
sendAT(GF("+CSQ")); \
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { \
return 99; \
} \
int res = stream.readStringUntil(',').toInt(); \
waitResponse(); \
return res; \
}
// Yields up to a time-out period and then reads a character from the stream into the mux FIFO
// TODO: Do we need to wait two _timeout periods for no character return? Will wait once in the first
// "while !stream.available()" and then will wait again in the stream.read() function.
#define TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT \
uint32_t startMillis = millis(); \
while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } \
char c = stream.read(); \
sockets[mux]->rx.put(c);
// Utility templates for writing/skipping characters on a stream
#define TINY_GSM_MODEM_STREAM_UTILITIES() \
template<typename T> \
void streamWrite(T last) { \
stream.print(last); \
} \
\
template<typename T, typename... Args> \
void streamWrite(T head, Args... tail) { \
stream.print(head); \
streamWrite(tail...); \
} \
\
template<typename... Args> \
void sendAT(Args... cmd) { \
streamWrite("AT", cmd..., GSM_NL); \
stream.flush(); \
TINY_GSM_YIELD(); \
/* DBG("### AT:", cmd...); */ \
} \
\
bool streamSkipUntil(const char c, const unsigned long timeout_ms = 1000L) { \
unsigned long startMillis = millis(); \
while (millis() - startMillis < timeout_ms) { \
while (millis() - startMillis < timeout_ms && !stream.available()) { \
TINY_GSM_YIELD(); \
} \
if (stream.read() == c) { \
return true; \
} \
} \
return false; \
}
#endif

171
src/TinyGsmGPRS.tpp Normal file
View File

@@ -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_

72
src/TinyGsmGPS.tpp Normal file
View File

@@ -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_

149
src/TinyGsmGSMLocation.tpp Normal file
View File

@@ -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_

330
src/TinyGsmModem.tpp Normal file
View File

@@ -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_

224
src/TinyGsmSMS.tpp Normal file
View File

@@ -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_

71
src/TinyGsmSSL.tpp Normal file
View File

@@ -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_

345
src/TinyGsmTCP.tpp Normal file
View File

@@ -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_

View File

@@ -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_

106
src/TinyGsmTime.tpp Normal file
View File

@@ -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_

49
src/TinyGsmWifi.tpp Normal file
View File

@@ -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_

View File

@@ -45,7 +45,9 @@
// Chips without internal buffering (A6/A7, ESP8266, M590) // Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response // need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail). // else data will be lost (and the http library will fail).
#ifndef TINY_GSM_RX_BUFFER
#define TINY_GSM_RX_BUFFER 1024 #define TINY_GSM_RX_BUFFER 1024
#endif
// See all AT commands, if wanted // See all AT commands, if wanted
// #define DUMP_AT_COMMANDS // #define DUMP_AT_COMMANDS
@@ -106,7 +108,7 @@ const char resource[] = "/TinyGSM/logo.txt";
TinyGsm modem(SerialAT); TinyGsm modem(SerialAT);
#endif #endif
#ifdef USE_SSL #ifdef USE_SSL && defined TINY_GSM_MODEM_HAS_SSL
TinyGsmClientSecure client(modem); TinyGsmClientSecure client(modem);
const int port = 443; const int port = 443;
#else #else
@@ -127,7 +129,7 @@ void setup() {
// Set GSM module baud rate // Set GSM module baud rate
// TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX); // TinyGsmAutoBaud(SerialAT,GSM_AUTOBAUD_MIN,GSM_AUTOBAUD_MAX);
SerialAT.begin(115200); SerialAT.begin(9600);
delay(3000); delay(3000);
} }
@@ -236,8 +238,8 @@ void loop() {
client.find("\r\n\r\n"); client.find("\r\n\r\n");
// Read data // Read data
unsigned long timeout = millis(); uint32_t timeout = millis();
unsigned long bytesReceived = 0; uint32_t bytesReceived = 0;
while (client.connected() && millis() - timeout < 10000L) { while (client.connected() && millis() - timeout < 10000L) {
while (client.available()) { while (client.available()) {
char c = client.read(); char c = client.read();

View File

@@ -48,7 +48,7 @@ void setup() {
delay(10); delay(10);
// Set GSM module baud rate // Set GSM module baud rate
SerialAT.begin(115200); SerialAT.begin(9600);
delay(3000); delay(3000);
if (!modem.init()) { if (!modem.init()) {

View File

@@ -1,59 +1,78 @@
/************************************************************** /**************************************************************
* *
* DO NOT USE THIS - this is just a compilation test! * DO NOT USE THIS - this is just a compilation test!
* This is NOT an example for use of this library!
* *
**************************************************************/ **************************************************************/
// #define TINY_GSM_MODEM_SIM800
#include <TinyGsmClient.h> #include <TinyGsmClient.h>
TinyGsm modem(Serial); TinyGsm modem(Serial);
TinyGsmClient client(modem);
#if defined(TINY_GSM_MODEM_HAS_SSL)
TinyGsmClientSecure client_secure(modem);
#endif
char server[] = "somewhere";
char resource[] = "something";
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
delay(3000); delay(3000);
modem.restart();
} }
void loop() { void loop() {
// Test the basic functions
// Test the start/restart functions
modem.restart();
modem.begin(); modem.begin();
modem.begin("1234");
modem.init();
modem.init("1234");
modem.setBaud(115200);
modem.testAT(); modem.testAT();
modem.getModemInfo();
modem.getModemName();
modem.factoryDefault(); modem.factoryDefault();
// Test the SIM card functions // Test Power functions
modem.restart();
// modem.sleepEnable(); // Not available for all modems
// modem.radioOff(); // Not available for all modems
modem.poweroff();
// Test generic network functions
modem.getRegistrationStatus();
modem.isNetworkConnected();
modem.waitForNetwork();
modem.waitForNetwork(15000L);
modem.getSignalQuality();
modem.getLocalIP();
modem.localIP();
// Test the GPRS and SIM card functions
#if defined(TINY_GSM_MODEM_HAS_GPRS) #if defined(TINY_GSM_MODEM_HAS_GPRS)
modem.simUnlock("1234");
modem.getSimCCID(); modem.getSimCCID();
modem.getIMEI(); modem.getIMEI();
modem.getIMSI();
modem.getSimStatus(); modem.getSimStatus();
modem.getRegistrationStatus();
modem.gprsConnect("myAPN");
modem.gprsConnect("myAPN", "myUser");
modem.gprsConnect("myAPN", "myAPNUser", "myAPNPass");
modem.gprsDisconnect();
modem.getOperator(); modem.getOperator();
#endif #endif
// Test WiFi Functions
// Test the Networking functions
modem.getSignalQuality();
modem.localIP();
#if defined(TINY_GSM_MODEM_HAS_GPRS)
modem.waitForNetwork();
modem.gprsConnect("YourAPN", "", "");
#endif
#if defined(TINY_GSM_MODEM_HAS_WIFI) #if defined(TINY_GSM_MODEM_HAS_WIFI)
modem.networkConnect("YourSSID", "YourPWD"); modem.networkConnect("mySSID", "mySSIDPassword");
modem.waitForNetwork(); modem.networkDisconnect();
#endif #endif
// Test TCP functions
modem.maintain();
TinyGsmClient client;
TinyGsmClient client2(modem);
TinyGsmClient client3(modem, 1);
client.init(&modem);
client.init(&modem, 1);
char server[] = "somewhere";
char resource[] = "something";
client.connect(server, 80); client.connect(server, 80);
// Make a HTTP GET request: // Make a HTTP GET request:
@@ -61,7 +80,7 @@ void loop() {
client.print(String("Host: ") + server + "\r\n"); client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n"); client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis(); uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) { while (client.connected() && millis() - timeout < 10000L) {
while (client.available()) { while (client.available()) {
client.read(); client.read();
@@ -71,10 +90,125 @@ void loop() {
client.stop(); client.stop();
#if defined(TINY_GSM_MODEM_HAS_GPRS) #if defined(TINY_GSM_MODEM_HAS_SSL)
modem.gprsDisconnect(); // modem.addCertificate(); // not yet impemented
// modem.deleteCertificate(); // not yet impemented
TinyGsmClientSecure client_secure(modem);
TinyGsmClientSecure client_secure2(modem);
TinyGsmClientSecure client_secure3(modem, 1);
client_secure.init(&modem);
client_secure.init(&modem, 1);
client_secure.connect(server, 443);
// Make a HTTP GET request:
client_secure.print(String("GET ") + resource + " HTTP/1.0\r\n");
client_secure.print(String("Host: ") + server + "\r\n");
client_secure.print("Connection: close\r\n\r\n");
timeout = millis();
while (client_secure.connected() && millis() - timeout < 10000L) {
while (client_secure.available()) {
client_secure.read();
timeout = millis();
}
}
client_secure.stop();
#endif #endif
#if defined(TINY_GSM_MODEM_HAS_WIFI)
modem.networkDisconnect(); // Test the calling functions
#if defined(TINY_GSM_MODEM_HAS_CALLING)
modem.callNumber(String("+380000000000"));
modem.callHangup();
#if not defined(TINY_GSM_MODEM_SEQUANS_MONARCH)
modem.callAnswer();
modem.dtmfSend('A', 1000);
#endif
#endif
// Test the SMS functions
#if defined(TINY_GSM_MODEM_HAS_SMS)
modem.sendSMS(String("+380000000000"), String("Hello from "));
#if not defined(TINY_GSM_MODEM_XBEE) && not defined(TINY_GSM_MODEM_SARAR4)
modem.sendUSSD("*111#");
#endif
#if not defined(TINY_GSM_MODEM_XBEE) && not defined(TINY_GSM_MODEM_M590) && \
not defined(TINY_GSM_MODEM_SARAR4)
modem.sendSMS_UTF16("+380000000000", "Hello", 5);
#endif
#endif
// Test the GSM location functions
#if defined(TINY_GSM_MODEM_HAS_GSM_LOCATION)
modem.getGsmLocationRaw();
modem.getGsmLocation();
float glatitude = -9999;
float glongitude = -9999;
float gacc = 0;
int gyear = 0;
int gmonth = 0;
int gday = 0;
int ghour = 0;
int gmin = 0;
int gsec = 0;
modem.getGsmLocation(&glatitude, &glongitude);
modem.getGsmLocation(&glatitude, &glongitude, &gacc, &gyear, &gmonth, &gday,
&ghour, &gmin, &gsec);
modem.getGsmLocationTime(&gyear, &gmonth, &gday, &ghour, &gmin, &gsec);
#endif
// Test the GPS functions
#if defined(TINY_GSM_MODEM_HAS_GPS)
modem.enableGPS();
modem.getGPSraw();
float latitude = -9999;
float longitude = -9999;
float speed = 0;
float alt = 0;
int vsat = 0;
int usat = 0;
float acc = 0;
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
modem.getGPS(&latitude, &longitude);
modem.getGPS(&latitude, &longitude, &speed, &alt, &vsat, &usat, &acc, &year,
&month, &day, &hour, &minute, &second);
modem.disableGPS();
#endif
// Test the Network time function
#if defined(TINY_GSM_MODEM_HAS_TIME)
modem.getGSMDateTime(DATE_FULL);
int year3 = 0;
int month3 = 0;
int day3 = 0;
int hour3 = 0;
int min3 = 0;
int sec3 = 0;
float timezone = 0;
modem.getNetworkTime(&year3, &month3, &day3, &hour3, &min3, &sec3, &timezone);
#endif
// Test Battery functions
#if defined(TINY_GSM_MODEM_HAS_BATTERY)
uint8_t chargeState = 0;
int8_t chargePercent = 0;
uint16_t milliVolts = 0;
modem.getBattStats(chargeState, chargePercent, milliVolts);
#endif
// Test the temperature function
#if defined(TINY_GSM_MODEM_HAS_TEMPERATURE)
modem.getTemperature();
#endif #endif
} }